Merge tag 'spdx-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / drivers / input / misc / palmas-pwrbutton.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Texas Instruments' Palmas Power Button Input Driver
4  *
5  * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/
6  *      Girish S Ghongdemath
7  *      Nishanth Menon
8  */
9
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>
20
21 #define PALMAS_LPK_TIME_MASK            0x0c
22 #define PALMAS_PWRON_DEBOUNCE_MASK      0x03
23 #define PALMAS_PWR_KEY_Q_TIME_MS        20
24
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
31  */
32 struct palmas_pwron {
33         struct palmas *palmas;
34         struct input_dev *input_dev;
35         struct delayed_work input_work;
36         int irq;
37 };
38
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
43  */
44 struct palmas_pwron_config {
45         u8 long_press_time_val;
46         u8 pwron_debounce_val;
47 };
48
49 /**
50  * palmas_power_button_work() - Detects the button release event
51  * @work:       work item to detect button release
52  */
53 static void palmas_power_button_work(struct work_struct *work)
54 {
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;
61
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));
75         }
76 }
77
78 /**
79  * pwron_irq() - button press isr
80  * @irq:                irq
81  * @palmas_pwron:       pwron struct
82  *
83  * Return: IRQ_HANDLED
84  */
85 static irqreturn_t pwron_irq(int irq, void *palmas_pwron)
86 {
87         struct palmas_pwron *pwron = palmas_pwron;
88         struct input_dev *input_dev = pwron->input_dev;
89
90         input_report_key(input_dev, KEY_POWER, 1);
91         pm_wakeup_event(input_dev->dev.parent, 0);
92         input_sync(input_dev);
93
94         mod_delayed_work(system_wq, &pwron->input_work,
95                          msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
96
97         return IRQ_HANDLED;
98 }
99
100 /**
101  * palmas_pwron_params_ofinit() - device tree parameter parser
102  * @dev:        palmas button device
103  * @config:     configuration params that this fills up
104  */
105 static void palmas_pwron_params_ofinit(struct device *dev,
106                                        struct palmas_pwron_config *config)
107 {
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 };
113
114         memset(config, 0, sizeof(*config));
115
116         /* Default config parameters */
117         config->long_press_time_val = ARRAY_SIZE(lpk_times) - 1;
118
119         np = dev->of_node;
120         if (!np)
121                 return;
122
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;
129                         }
130                 }
131         }
132
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;
141                         }
142                 }
143         }
144
145         dev_info(dev, "h/w controlled shutdown duration=%d seconds\n",
146                  lpk_times[config->long_press_time_val]);
147 }
148
149 /**
150  * palmas_pwron_probe() - probe
151  * @pdev:       platform device for the button
152  *
153  * Return: 0 for successful probe else appropriate error
154  */
155 static int palmas_pwron_probe(struct platform_device *pdev)
156 {
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;
164
165         palmas_pwron_params_ofinit(dev, &config);
166
167         pwron = kzalloc(sizeof(*pwron), GFP_KERNEL);
168         if (!pwron)
169                 return -ENOMEM;
170
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;
176         }
177
178         input_dev->name = "palmas_pwron";
179         input_dev->phys = "palmas_pwron/input0";
180         input_dev->dev.parent = dev;
181
182         input_set_capability(input_dev, EV_KEY, KEY_POWER);
183
184         /*
185          * Setup default hardware shutdown option (long key press)
186          * and debounce.
187          */
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;
198         }
199
200         pwron->palmas = palmas;
201         pwron->input_dev = input_dev;
202
203         INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
204
205         pwron->irq = platform_get_irq(pdev, 0);
206         if (pwron->irq < 0) {
207                 error = pwron->irq;
208                 goto err_free_input;
209         }
210
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;
219         }
220
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;
225         }
226
227         platform_set_drvdata(pdev, pwron);
228         device_init_wakeup(dev, true);
229
230         return 0;
231
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;
240 }
241
242 /**
243  * palmas_pwron_remove() - Cleanup on removal
244  * @pdev:       platform device for the button
245  *
246  * Return: 0
247  */
248 static int palmas_pwron_remove(struct platform_device *pdev)
249 {
250         struct palmas_pwron *pwron = platform_get_drvdata(pdev);
251
252         free_irq(pwron->irq, pwron);
253         cancel_delayed_work_sync(&pwron->input_work);
254
255         input_unregister_device(pwron->input_dev);
256         kfree(pwron);
257
258         return 0;
259 }
260
261 /**
262  * palmas_pwron_suspend() - suspend handler
263  * @dev:        power button device
264  *
265  * Cancel all pending work items for the power button, setup irq for wakeup
266  *
267  * Return: 0
268  */
269 static int __maybe_unused palmas_pwron_suspend(struct device *dev)
270 {
271         struct platform_device *pdev = to_platform_device(dev);
272         struct palmas_pwron *pwron = platform_get_drvdata(pdev);
273
274         cancel_delayed_work_sync(&pwron->input_work);
275
276         if (device_may_wakeup(dev))
277                 enable_irq_wake(pwron->irq);
278
279         return 0;
280 }
281
282 /**
283  * palmas_pwron_resume() - resume handler
284  * @dev:        power button device
285  *
286  * Just disable the wakeup capability of irq here.
287  *
288  * Return: 0
289  */
290 static int __maybe_unused palmas_pwron_resume(struct device *dev)
291 {
292         struct platform_device *pdev = to_platform_device(dev);
293         struct palmas_pwron *pwron = platform_get_drvdata(pdev);
294
295         if (device_may_wakeup(dev))
296                 disable_irq_wake(pwron->irq);
297
298         return 0;
299 }
300
301 static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
302                          palmas_pwron_suspend, palmas_pwron_resume);
303
304 #ifdef CONFIG_OF
305 static const struct of_device_id of_palmas_pwr_match[] = {
306         { .compatible = "ti,palmas-pwrbutton" },
307         { },
308 };
309
310 MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
311 #endif
312
313 static struct platform_driver palmas_pwron_driver = {
314         .probe  = palmas_pwron_probe,
315         .remove = palmas_pwron_remove,
316         .driver = {
317                 .name   = "palmas_pwrbutton",
318                 .of_match_table = of_match_ptr(of_palmas_pwr_match),
319                 .pm     = &palmas_pwron_pm,
320         },
321 };
322 module_platform_driver(palmas_pwron_driver);
323
324 MODULE_ALIAS("platform:palmas-pwrbutton");
325 MODULE_DESCRIPTION("Palmas Power Button");
326 MODULE_LICENSE("GPL v2");
327 MODULE_AUTHOR("Texas Instruments Inc.");