GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / input / misc / palmas-pwrbutton.c
1 /*
2  * Texas Instruments' Palmas Power Button Input Driver
3  *
4  * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/
5  *      Girish S Ghongdemath
6  *      Nishanth Menon
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
13  * kind, whether express or implied; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/bitfield.h>
19 #include <linux/init.h>
20 #include <linux/input.h>
21 #include <linux/interrupt.h>
22 #include <linux/kernel.h>
23 #include <linux/mfd/palmas.h>
24 #include <linux/module.h>
25 #include <linux/of.h>
26 #include <linux/platform_device.h>
27 #include <linux/slab.h>
28
29 #define PALMAS_LPK_TIME_MASK            0x0c
30 #define PALMAS_PWRON_DEBOUNCE_MASK      0x03
31 #define PALMAS_PWR_KEY_Q_TIME_MS        20
32
33 /**
34  * struct palmas_pwron - Palmas power on data
35  * @palmas:             pointer to palmas device
36  * @input_dev:          pointer to input device
37  * @input_work:         work for detecting release of key
38  * @irq:                irq that we are hooked on to
39  */
40 struct palmas_pwron {
41         struct palmas *palmas;
42         struct input_dev *input_dev;
43         struct delayed_work input_work;
44         int irq;
45 };
46
47 /**
48  * struct palmas_pwron_config - configuration of palmas power on
49  * @long_press_time_val:        value for long press h/w shutdown event
50  * @pwron_debounce_val:         value for debounce of power button
51  */
52 struct palmas_pwron_config {
53         u8 long_press_time_val;
54         u8 pwron_debounce_val;
55 };
56
57 /**
58  * palmas_power_button_work() - Detects the button release event
59  * @work:       work item to detect button release
60  */
61 static void palmas_power_button_work(struct work_struct *work)
62 {
63         struct palmas_pwron *pwron = container_of(work,
64                                                   struct palmas_pwron,
65                                                   input_work.work);
66         struct input_dev *input_dev = pwron->input_dev;
67         unsigned int reg;
68         int error;
69
70         error = palmas_read(pwron->palmas, PALMAS_INTERRUPT_BASE,
71                             PALMAS_INT1_LINE_STATE, &reg);
72         if (error) {
73                 dev_err(input_dev->dev.parent,
74                         "Cannot read palmas PWRON status: %d\n", error);
75         } else if (reg & BIT(1)) {
76                 /* The button is released, report event. */
77                 input_report_key(input_dev, KEY_POWER, 0);
78                 input_sync(input_dev);
79         } else {
80                 /* The button is still depressed, keep checking. */
81                 schedule_delayed_work(&pwron->input_work,
82                                 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
83         }
84 }
85
86 /**
87  * pwron_irq() - button press isr
88  * @irq:                irq
89  * @palmas_pwron:       pwron struct
90  *
91  * Return: IRQ_HANDLED
92  */
93 static irqreturn_t pwron_irq(int irq, void *palmas_pwron)
94 {
95         struct palmas_pwron *pwron = palmas_pwron;
96         struct input_dev *input_dev = pwron->input_dev;
97
98         input_report_key(input_dev, KEY_POWER, 1);
99         pm_wakeup_event(input_dev->dev.parent, 0);
100         input_sync(input_dev);
101
102         mod_delayed_work(system_wq, &pwron->input_work,
103                          msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
104
105         return IRQ_HANDLED;
106 }
107
108 /**
109  * palmas_pwron_params_ofinit() - device tree parameter parser
110  * @dev:        palmas button device
111  * @config:     configuration params that this fills up
112  */
113 static void palmas_pwron_params_ofinit(struct device *dev,
114                                        struct palmas_pwron_config *config)
115 {
116         struct device_node *np;
117         u32 val;
118         int i, error;
119         static const u8 lpk_times[] = { 6, 8, 10, 12 };
120         static const int pwr_on_deb_ms[] = { 15, 100, 500, 1000 };
121
122         memset(config, 0, sizeof(*config));
123
124         /* Default config parameters */
125         config->long_press_time_val = ARRAY_SIZE(lpk_times) - 1;
126
127         np = dev->of_node;
128         if (!np)
129                 return;
130
131         error = of_property_read_u32(np, "ti,palmas-long-press-seconds", &val);
132         if (!error) {
133                 for (i = 0; i < ARRAY_SIZE(lpk_times); i++) {
134                         if (val <= lpk_times[i]) {
135                                 config->long_press_time_val = i;
136                                 break;
137                         }
138                 }
139         }
140
141         error = of_property_read_u32(np,
142                                      "ti,palmas-pwron-debounce-milli-seconds",
143                                      &val);
144         if (!error) {
145                 for (i = 0; i < ARRAY_SIZE(pwr_on_deb_ms); i++) {
146                         if (val <= pwr_on_deb_ms[i]) {
147                                 config->pwron_debounce_val = i;
148                                 break;
149                         }
150                 }
151         }
152
153         dev_info(dev, "h/w controlled shutdown duration=%d seconds\n",
154                  lpk_times[config->long_press_time_val]);
155 }
156
157 /**
158  * palmas_pwron_probe() - probe
159  * @pdev:       platform device for the button
160  *
161  * Return: 0 for successful probe else appropriate error
162  */
163 static int palmas_pwron_probe(struct platform_device *pdev)
164 {
165         struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
166         struct device *dev = &pdev->dev;
167         struct input_dev *input_dev;
168         struct palmas_pwron *pwron;
169         struct palmas_pwron_config config;
170         int val;
171         int error;
172
173         palmas_pwron_params_ofinit(dev, &config);
174
175         pwron = kzalloc(sizeof(*pwron), GFP_KERNEL);
176         if (!pwron)
177                 return -ENOMEM;
178
179         input_dev = input_allocate_device();
180         if (!input_dev) {
181                 dev_err(dev, "Can't allocate power button\n");
182                 error = -ENOMEM;
183                 goto err_free_mem;
184         }
185
186         input_dev->name = "palmas_pwron";
187         input_dev->phys = "palmas_pwron/input0";
188         input_dev->dev.parent = dev;
189
190         input_set_capability(input_dev, EV_KEY, KEY_POWER);
191
192         /*
193          * Setup default hardware shutdown option (long key press)
194          * and debounce.
195          */
196         val = FIELD_PREP(PALMAS_LPK_TIME_MASK, config.long_press_time_val) |
197               FIELD_PREP(PALMAS_PWRON_DEBOUNCE_MASK, config.pwron_debounce_val);
198         error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
199                                    PALMAS_LONG_PRESS_KEY,
200                                    PALMAS_LPK_TIME_MASK |
201                                         PALMAS_PWRON_DEBOUNCE_MASK,
202                                    val);
203         if (error) {
204                 dev_err(dev, "LONG_PRESS_KEY_UPDATE failed: %d\n", error);
205                 goto err_free_input;
206         }
207
208         pwron->palmas = palmas;
209         pwron->input_dev = input_dev;
210
211         INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
212
213         pwron->irq = platform_get_irq(pdev, 0);
214         if (pwron->irq < 0) {
215                 error = pwron->irq;
216                 goto err_free_input;
217         }
218
219         error = request_threaded_irq(pwron->irq, NULL, pwron_irq,
220                                      IRQF_TRIGGER_HIGH |
221                                         IRQF_TRIGGER_LOW |
222                                         IRQF_ONESHOT,
223                                      dev_name(dev), pwron);
224         if (error) {
225                 dev_err(dev, "Can't get IRQ for pwron: %d\n", error);
226                 goto err_free_input;
227         }
228
229         error = input_register_device(input_dev);
230         if (error) {
231                 dev_err(dev, "Can't register power button: %d\n", error);
232                 goto err_free_irq;
233         }
234
235         platform_set_drvdata(pdev, pwron);
236         device_init_wakeup(dev, true);
237
238         return 0;
239
240 err_free_irq:
241         cancel_delayed_work_sync(&pwron->input_work);
242         free_irq(pwron->irq, pwron);
243 err_free_input:
244         input_free_device(input_dev);
245 err_free_mem:
246         kfree(pwron);
247         return error;
248 }
249
250 /**
251  * palmas_pwron_remove() - Cleanup on removal
252  * @pdev:       platform device for the button
253  *
254  * Return: 0
255  */
256 static int palmas_pwron_remove(struct platform_device *pdev)
257 {
258         struct palmas_pwron *pwron = platform_get_drvdata(pdev);
259
260         free_irq(pwron->irq, pwron);
261         cancel_delayed_work_sync(&pwron->input_work);
262
263         input_unregister_device(pwron->input_dev);
264         kfree(pwron);
265
266         return 0;
267 }
268
269 /**
270  * palmas_pwron_suspend() - suspend handler
271  * @dev:        power button device
272  *
273  * Cancel all pending work items for the power button, setup irq for wakeup
274  *
275  * Return: 0
276  */
277 static int __maybe_unused palmas_pwron_suspend(struct device *dev)
278 {
279         struct platform_device *pdev = to_platform_device(dev);
280         struct palmas_pwron *pwron = platform_get_drvdata(pdev);
281
282         cancel_delayed_work_sync(&pwron->input_work);
283
284         if (device_may_wakeup(dev))
285                 enable_irq_wake(pwron->irq);
286
287         return 0;
288 }
289
290 /**
291  * palmas_pwron_resume() - resume handler
292  * @dev:        power button device
293  *
294  * Just disable the wakeup capability of irq here.
295  *
296  * Return: 0
297  */
298 static int __maybe_unused palmas_pwron_resume(struct device *dev)
299 {
300         struct platform_device *pdev = to_platform_device(dev);
301         struct palmas_pwron *pwron = platform_get_drvdata(pdev);
302
303         if (device_may_wakeup(dev))
304                 disable_irq_wake(pwron->irq);
305
306         return 0;
307 }
308
309 static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
310                          palmas_pwron_suspend, palmas_pwron_resume);
311
312 #ifdef CONFIG_OF
313 static const struct of_device_id of_palmas_pwr_match[] = {
314         { .compatible = "ti,palmas-pwrbutton" },
315         { },
316 };
317
318 MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
319 #endif
320
321 static struct platform_driver palmas_pwron_driver = {
322         .probe  = palmas_pwron_probe,
323         .remove = palmas_pwron_remove,
324         .driver = {
325                 .name   = "palmas_pwrbutton",
326                 .of_match_table = of_match_ptr(of_palmas_pwr_match),
327                 .pm     = &palmas_pwron_pm,
328         },
329 };
330 module_platform_driver(palmas_pwron_driver);
331
332 MODULE_ALIAS("platform:palmas-pwrbutton");
333 MODULE_DESCRIPTION("Palmas Power Button");
334 MODULE_LICENSE("GPL v2");
335 MODULE_AUTHOR("Texas Instruments Inc.");