drm/panel: samsung-s6e88a0-ams452ef01: transition to mipi_dsi wrapped functions
[drm/drm-misc.git] / drivers / input / misc / palmas-pwrbutton.c
blob39fc451c56e924691e1d007cc8ada9b64c2952e2
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Texas Instruments' Palmas Power Button Input Driver
5 * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/
6 * Girish S Ghongdemath
7 * Nishanth Menon
8 */
10 #include <linux/bitfield.h>
11 #include <linux/init.h>
12 #include <linux/input.h>
13 #include <linux/interrupt.h>
14 #include <linux/kernel.h>
15 #include <linux/mfd/palmas.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
21 #define PALMAS_LPK_TIME_MASK 0x0c
22 #define PALMAS_PWRON_DEBOUNCE_MASK 0x03
23 #define PALMAS_PWR_KEY_Q_TIME_MS 20
25 /**
26 * struct palmas_pwron - Palmas power on data
27 * @palmas: pointer to palmas device
28 * @input_dev: pointer to input device
29 * @input_work: work for detecting release of key
30 * @irq: irq that we are hooked on to
32 struct palmas_pwron {
33 struct palmas *palmas;
34 struct input_dev *input_dev;
35 struct delayed_work input_work;
36 int irq;
39 /**
40 * struct palmas_pwron_config - configuration of palmas power on
41 * @long_press_time_val: value for long press h/w shutdown event
42 * @pwron_debounce_val: value for debounce of power button
44 struct palmas_pwron_config {
45 u8 long_press_time_val;
46 u8 pwron_debounce_val;
49 /**
50 * palmas_power_button_work() - Detects the button release event
51 * @work: work item to detect button release
53 static void palmas_power_button_work(struct work_struct *work)
55 struct palmas_pwron *pwron = container_of(work,
56 struct palmas_pwron,
57 input_work.work);
58 struct input_dev *input_dev = pwron->input_dev;
59 unsigned int reg;
60 int error;
62 error = palmas_read(pwron->palmas, PALMAS_INTERRUPT_BASE,
63 PALMAS_INT1_LINE_STATE, &reg);
64 if (error) {
65 dev_err(input_dev->dev.parent,
66 "Cannot read palmas PWRON status: %d\n", error);
67 } else if (reg & BIT(1)) {
68 /* The button is released, report event. */
69 input_report_key(input_dev, KEY_POWER, 0);
70 input_sync(input_dev);
71 } else {
72 /* The button is still depressed, keep checking. */
73 schedule_delayed_work(&pwron->input_work,
74 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
78 /**
79 * pwron_irq() - button press isr
80 * @irq: irq
81 * @palmas_pwron: pwron struct
83 * Return: IRQ_HANDLED
85 static irqreturn_t pwron_irq(int irq, void *palmas_pwron)
87 struct palmas_pwron *pwron = palmas_pwron;
88 struct input_dev *input_dev = pwron->input_dev;
90 input_report_key(input_dev, KEY_POWER, 1);
91 pm_wakeup_event(input_dev->dev.parent, 0);
92 input_sync(input_dev);
94 mod_delayed_work(system_wq, &pwron->input_work,
95 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
97 return IRQ_HANDLED;
101 * palmas_pwron_params_ofinit() - device tree parameter parser
102 * @dev: palmas button device
103 * @config: configuration params that this fills up
105 static void palmas_pwron_params_ofinit(struct device *dev,
106 struct palmas_pwron_config *config)
108 struct device_node *np;
109 u32 val;
110 int i, error;
111 static const u8 lpk_times[] = { 6, 8, 10, 12 };
112 static const int pwr_on_deb_ms[] = { 15, 100, 500, 1000 };
114 memset(config, 0, sizeof(*config));
116 /* Default config parameters */
117 config->long_press_time_val = ARRAY_SIZE(lpk_times) - 1;
119 np = dev->of_node;
120 if (!np)
121 return;
123 error = of_property_read_u32(np, "ti,palmas-long-press-seconds", &val);
124 if (!error) {
125 for (i = 0; i < ARRAY_SIZE(lpk_times); i++) {
126 if (val <= lpk_times[i]) {
127 config->long_press_time_val = i;
128 break;
133 error = of_property_read_u32(np,
134 "ti,palmas-pwron-debounce-milli-seconds",
135 &val);
136 if (!error) {
137 for (i = 0; i < ARRAY_SIZE(pwr_on_deb_ms); i++) {
138 if (val <= pwr_on_deb_ms[i]) {
139 config->pwron_debounce_val = i;
140 break;
145 dev_info(dev, "h/w controlled shutdown duration=%d seconds\n",
146 lpk_times[config->long_press_time_val]);
150 * palmas_pwron_probe() - probe
151 * @pdev: platform device for the button
153 * Return: 0 for successful probe else appropriate error
155 static int palmas_pwron_probe(struct platform_device *pdev)
157 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
158 struct device *dev = &pdev->dev;
159 struct input_dev *input_dev;
160 struct palmas_pwron *pwron;
161 struct palmas_pwron_config config;
162 int val;
163 int error;
165 palmas_pwron_params_ofinit(dev, &config);
167 pwron = kzalloc(sizeof(*pwron), GFP_KERNEL);
168 if (!pwron)
169 return -ENOMEM;
171 input_dev = input_allocate_device();
172 if (!input_dev) {
173 dev_err(dev, "Can't allocate power button\n");
174 error = -ENOMEM;
175 goto err_free_mem;
178 input_dev->name = "palmas_pwron";
179 input_dev->phys = "palmas_pwron/input0";
180 input_dev->dev.parent = dev;
182 input_set_capability(input_dev, EV_KEY, KEY_POWER);
185 * Setup default hardware shutdown option (long key press)
186 * and debounce.
188 val = FIELD_PREP(PALMAS_LPK_TIME_MASK, config.long_press_time_val) |
189 FIELD_PREP(PALMAS_PWRON_DEBOUNCE_MASK, config.pwron_debounce_val);
190 error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
191 PALMAS_LONG_PRESS_KEY,
192 PALMAS_LPK_TIME_MASK |
193 PALMAS_PWRON_DEBOUNCE_MASK,
194 val);
195 if (error) {
196 dev_err(dev, "LONG_PRESS_KEY_UPDATE failed: %d\n", error);
197 goto err_free_input;
200 pwron->palmas = palmas;
201 pwron->input_dev = input_dev;
203 INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
205 pwron->irq = platform_get_irq(pdev, 0);
206 if (pwron->irq < 0) {
207 error = pwron->irq;
208 goto err_free_input;
211 error = request_threaded_irq(pwron->irq, NULL, pwron_irq,
212 IRQF_TRIGGER_HIGH |
213 IRQF_TRIGGER_LOW |
214 IRQF_ONESHOT,
215 dev_name(dev), pwron);
216 if (error) {
217 dev_err(dev, "Can't get IRQ for pwron: %d\n", error);
218 goto err_free_input;
221 error = input_register_device(input_dev);
222 if (error) {
223 dev_err(dev, "Can't register power button: %d\n", error);
224 goto err_free_irq;
227 platform_set_drvdata(pdev, pwron);
228 device_init_wakeup(dev, true);
230 return 0;
232 err_free_irq:
233 cancel_delayed_work_sync(&pwron->input_work);
234 free_irq(pwron->irq, pwron);
235 err_free_input:
236 input_free_device(input_dev);
237 err_free_mem:
238 kfree(pwron);
239 return error;
243 * palmas_pwron_remove() - Cleanup on removal
244 * @pdev: platform device for the button
246 * Return: 0
248 static void palmas_pwron_remove(struct platform_device *pdev)
250 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
252 free_irq(pwron->irq, pwron);
253 cancel_delayed_work_sync(&pwron->input_work);
255 input_unregister_device(pwron->input_dev);
256 kfree(pwron);
260 * palmas_pwron_suspend() - suspend handler
261 * @dev: power button device
263 * Cancel all pending work items for the power button, setup irq for wakeup
265 * Return: 0
267 static int palmas_pwron_suspend(struct device *dev)
269 struct platform_device *pdev = to_platform_device(dev);
270 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
272 cancel_delayed_work_sync(&pwron->input_work);
274 if (device_may_wakeup(dev))
275 enable_irq_wake(pwron->irq);
277 return 0;
281 * palmas_pwron_resume() - resume handler
282 * @dev: power button device
284 * Just disable the wakeup capability of irq here.
286 * Return: 0
288 static int palmas_pwron_resume(struct device *dev)
290 struct platform_device *pdev = to_platform_device(dev);
291 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
293 if (device_may_wakeup(dev))
294 disable_irq_wake(pwron->irq);
296 return 0;
299 static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
300 palmas_pwron_suspend, palmas_pwron_resume);
302 #ifdef CONFIG_OF
303 static const struct of_device_id of_palmas_pwr_match[] = {
304 { .compatible = "ti,palmas-pwrbutton" },
305 { },
308 MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
309 #endif
311 static struct platform_driver palmas_pwron_driver = {
312 .probe = palmas_pwron_probe,
313 .remove = palmas_pwron_remove,
314 .driver = {
315 .name = "palmas_pwrbutton",
316 .of_match_table = of_match_ptr(of_palmas_pwr_match),
317 .pm = pm_sleep_ptr(&palmas_pwron_pm),
320 module_platform_driver(palmas_pwron_driver);
322 MODULE_ALIAS("platform:palmas-pwrbutton");
323 MODULE_DESCRIPTION("Palmas Power Button");
324 MODULE_LICENSE("GPL v2");
325 MODULE_AUTHOR("Texas Instruments Inc.");