Merge tag 'spi-fix-v5.19-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/brooni...
[linux-2.6-microblaze.git] / drivers / input / misc / atc260x-onkey.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Onkey driver for Actions Semi ATC260x PMICs.
4  *
5  * Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
6  */
7
8 #include <linux/bitfield.h>
9 #include <linux/input.h>
10 #include <linux/interrupt.h>
11 #include <linux/mfd/atc260x/core.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
16
17 /* <2s for short press, >2s for long press */
18 #define KEY_PRESS_TIME_SEC      2
19
20 /* Driver internals */
21 enum atc260x_onkey_reset_status {
22         KEY_RESET_HW_DEFAULT,
23         KEY_RESET_DISABLED,
24         KEY_RESET_USER_SEL,
25 };
26
27 struct atc260x_onkey_params {
28         u32 reg_int_ctl;
29         u32 kdwn_state_bm;
30         u32 long_int_pnd_bm;
31         u32 short_int_pnd_bm;
32         u32 kdwn_int_pnd_bm;
33         u32 press_int_en_bm;
34         u32 kdwn_int_en_bm;
35         u32 press_time_bm;
36         u32 reset_en_bm;
37         u32 reset_time_bm;
38 };
39
40 struct atc260x_onkey {
41         struct atc260x *atc260x;
42         const struct atc260x_onkey_params *params;
43         struct input_dev *input_dev;
44         struct delayed_work work;
45         int irq;
46 };
47
48 static const struct atc260x_onkey_params atc2603c_onkey_params = {
49         .reg_int_ctl            = ATC2603C_PMU_SYS_CTL2,
50         .long_int_pnd_bm        = ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS,
51         .short_int_pnd_bm       = ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS,
52         .kdwn_int_pnd_bm        = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD,
53         .press_int_en_bm        = ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN,
54         .kdwn_int_en_bm         = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN,
55         .kdwn_state_bm          = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS,
56         .press_time_bm          = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
57         .reset_en_bm            = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN,
58         .reset_time_bm          = ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
59 };
60
61 static const struct atc260x_onkey_params atc2609a_onkey_params = {
62         .reg_int_ctl            = ATC2609A_PMU_SYS_CTL2,
63         .long_int_pnd_bm        = ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS,
64         .short_int_pnd_bm       = ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS,
65         .kdwn_int_pnd_bm        = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD,
66         .press_int_en_bm        = ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN,
67         .kdwn_int_en_bm         = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN,
68         .kdwn_state_bm          = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS,
69         .press_time_bm          = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
70         .reset_en_bm            = ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN,
71         .reset_time_bm          = ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
72 };
73
74 static int atc2603x_onkey_hw_init(struct atc260x_onkey *onkey,
75                                   enum atc260x_onkey_reset_status reset_status,
76                                   u32 reset_time, u32 press_time)
77 {
78         u32 reg_bm, reg_val;
79
80         reg_bm = onkey->params->long_int_pnd_bm |
81                  onkey->params->short_int_pnd_bm |
82                  onkey->params->kdwn_int_pnd_bm |
83                  onkey->params->press_int_en_bm |
84                  onkey->params->kdwn_int_en_bm;
85
86         reg_val = reg_bm | press_time;
87         reg_bm |= onkey->params->press_time_bm;
88
89         if (reset_status == KEY_RESET_DISABLED) {
90                 reg_bm |= onkey->params->reset_en_bm;
91         } else if (reset_status == KEY_RESET_USER_SEL) {
92                 reg_bm |= onkey->params->reset_en_bm |
93                           onkey->params->reset_time_bm;
94                 reg_val |= onkey->params->reset_en_bm | reset_time;
95         }
96
97         return regmap_update_bits(onkey->atc260x->regmap,
98                                   onkey->params->reg_int_ctl, reg_bm, reg_val);
99 }
100
101 static void atc260x_onkey_query(struct atc260x_onkey *onkey)
102 {
103         u32 reg_bits;
104         int ret, key_down;
105
106         ret = regmap_read(onkey->atc260x->regmap,
107                           onkey->params->reg_int_ctl, &key_down);
108         if (ret) {
109                 key_down = 1;
110                 dev_err(onkey->atc260x->dev,
111                         "Failed to read onkey status: %d\n", ret);
112         } else {
113                 key_down &= onkey->params->kdwn_state_bm;
114         }
115
116         /*
117          * The hardware generates interrupt only when the onkey pin is
118          * asserted. Hence, the deassertion of the pin is simulated through
119          * work queue.
120          */
121         if (key_down) {
122                 schedule_delayed_work(&onkey->work, msecs_to_jiffies(200));
123                 return;
124         }
125
126         /*
127          * The key-down status bit is cleared when the On/Off button
128          * is released.
129          */
130         input_report_key(onkey->input_dev, KEY_POWER, 0);
131         input_sync(onkey->input_dev);
132
133         reg_bits = onkey->params->long_int_pnd_bm |
134                    onkey->params->short_int_pnd_bm |
135                    onkey->params->kdwn_int_pnd_bm |
136                    onkey->params->press_int_en_bm |
137                    onkey->params->kdwn_int_en_bm;
138
139         /* Clear key press pending events and enable key press interrupts. */
140         regmap_update_bits(onkey->atc260x->regmap, onkey->params->reg_int_ctl,
141                            reg_bits, reg_bits);
142 }
143
144 static void atc260x_onkey_work(struct work_struct *work)
145 {
146         struct atc260x_onkey *onkey = container_of(work, struct atc260x_onkey,
147                                                    work.work);
148         atc260x_onkey_query(onkey);
149 }
150
151 static irqreturn_t atc260x_onkey_irq(int irq, void *data)
152 {
153         struct atc260x_onkey *onkey = data;
154         int ret;
155
156         /* Disable key press interrupts. */
157         ret = regmap_update_bits(onkey->atc260x->regmap,
158                                  onkey->params->reg_int_ctl,
159                                  onkey->params->press_int_en_bm |
160                                  onkey->params->kdwn_int_en_bm, 0);
161         if (ret)
162                 dev_err(onkey->atc260x->dev,
163                         "Failed to disable interrupts: %d\n", ret);
164
165         input_report_key(onkey->input_dev, KEY_POWER, 1);
166         input_sync(onkey->input_dev);
167
168         atc260x_onkey_query(onkey);
169
170         return IRQ_HANDLED;
171 }
172
173 static int atc260x_onkey_open(struct input_dev *dev)
174 {
175         struct atc260x_onkey *onkey = input_get_drvdata(dev);
176
177         enable_irq(onkey->irq);
178
179         return 0;
180 }
181
182 static void atc260x_onkey_close(struct input_dev *dev)
183 {
184         struct atc260x_onkey *onkey = input_get_drvdata(dev);
185
186         disable_irq(onkey->irq);
187         cancel_delayed_work_sync(&onkey->work);
188 }
189
190 static int atc260x_onkey_probe(struct platform_device *pdev)
191 {
192         struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);
193         struct atc260x_onkey *onkey;
194         struct input_dev *input_dev;
195         enum atc260x_onkey_reset_status reset_status;
196         u32 press_time = KEY_PRESS_TIME_SEC, reset_time = 0;
197         int val, error;
198
199         onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
200         if (!onkey)
201                 return -ENOMEM;
202
203         error = device_property_read_u32(pdev->dev.parent,
204                                          "reset-time-sec", &val);
205         if (error) {
206                 reset_status = KEY_RESET_HW_DEFAULT;
207         } else if (val) {
208                 if (val < 6 || val > 12) {
209                         dev_err(&pdev->dev, "reset-time-sec out of range\n");
210                         return -EINVAL;
211                 }
212
213                 reset_status = KEY_RESET_USER_SEL;
214                 reset_time = (val - 6) / 2;
215         } else {
216                 reset_status = KEY_RESET_DISABLED;
217                 dev_dbg(&pdev->dev, "Disabled reset on long-press\n");
218         }
219
220         switch (atc260x->ic_type) {
221         case ATC2603C:
222                 onkey->params = &atc2603c_onkey_params;
223                 press_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
224                                         press_time);
225                 reset_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
226                                         reset_time);
227                 break;
228         case ATC2609A:
229                 onkey->params = &atc2609a_onkey_params;
230                 press_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
231                                         press_time);
232                 reset_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
233                                         reset_time);
234                 break;
235         default:
236                 dev_err(&pdev->dev,
237                         "OnKey not supported for ATC260x PMIC type: %u\n",
238                         atc260x->ic_type);
239                 return -EINVAL;
240         }
241
242         input_dev = devm_input_allocate_device(&pdev->dev);
243         if (!input_dev) {
244                 dev_err(&pdev->dev, "Failed to allocate input device\n");
245                 return -ENOMEM;
246         }
247
248         onkey->input_dev = input_dev;
249         onkey->atc260x = atc260x;
250
251         input_dev->name = "atc260x-onkey";
252         input_dev->phys = "atc260x-onkey/input0";
253         input_dev->open = atc260x_onkey_open;
254         input_dev->close = atc260x_onkey_close;
255
256         input_set_capability(input_dev, EV_KEY, KEY_POWER);
257         input_set_drvdata(input_dev, onkey);
258
259         INIT_DELAYED_WORK(&onkey->work, atc260x_onkey_work);
260
261         onkey->irq = platform_get_irq(pdev, 0);
262         if (onkey->irq < 0)
263                 return onkey->irq;
264
265         error = devm_request_threaded_irq(&pdev->dev, onkey->irq, NULL,
266                                           atc260x_onkey_irq, IRQF_ONESHOT,
267                                           dev_name(&pdev->dev), onkey);
268         if (error) {
269                 dev_err(&pdev->dev,
270                         "Failed to register IRQ %d: %d\n", onkey->irq, error);
271                 return error;
272         }
273
274         /* Keep IRQ disabled until atc260x_onkey_open() is called. */
275         disable_irq(onkey->irq);
276
277         error = input_register_device(input_dev);
278         if (error) {
279                 dev_err(&pdev->dev,
280                         "Failed to register input device: %d\n", error);
281                 return error;
282         }
283
284         error = atc2603x_onkey_hw_init(onkey, reset_status,
285                                        reset_time, press_time);
286         if (error)
287                 return error;
288
289         device_init_wakeup(&pdev->dev, true);
290
291         return 0;
292 }
293
294 static struct platform_driver atc260x_onkey_driver = {
295         .probe  = atc260x_onkey_probe,
296         .driver = {
297                 .name = "atc260x-onkey",
298         },
299 };
300
301 module_platform_driver(atc260x_onkey_driver);
302
303 MODULE_DESCRIPTION("Onkey driver for ATC260x PMICs");
304 MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
305 MODULE_LICENSE("GPL");