Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / input / misc / atc260x-onkey.c
blob999aabf9dcbd0a2decf60b39370da2bfbd07bd0c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Onkey driver for Actions Semi ATC260x PMICs.
5 * Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
6 */
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>
17 /* <2s for short press, >2s for long press */
18 #define KEY_PRESS_TIME_SEC 2
20 /* Driver internals */
21 enum atc260x_onkey_reset_status {
22 KEY_RESET_HW_DEFAULT,
23 KEY_RESET_DISABLED,
24 KEY_RESET_USER_SEL,
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;
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;
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,
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,
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)
78 u32 reg_bm, reg_val;
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;
86 reg_val = reg_bm | press_time;
87 reg_bm |= onkey->params->press_time_bm;
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;
97 return regmap_update_bits(onkey->atc260x->regmap,
98 onkey->params->reg_int_ctl, reg_bm, reg_val);
101 static void atc260x_onkey_query(struct atc260x_onkey *onkey)
103 u32 reg_bits;
104 int ret, key_down;
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;
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.
121 if (key_down) {
122 schedule_delayed_work(&onkey->work, msecs_to_jiffies(200));
123 return;
127 * The key-down status bit is cleared when the On/Off button
128 * is released.
130 input_report_key(onkey->input_dev, KEY_POWER, 0);
131 input_sync(onkey->input_dev);
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;
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);
144 static void atc260x_onkey_work(struct work_struct *work)
146 struct atc260x_onkey *onkey = container_of(work, struct atc260x_onkey,
147 work.work);
148 atc260x_onkey_query(onkey);
151 static irqreturn_t atc260x_onkey_irq(int irq, void *data)
153 struct atc260x_onkey *onkey = data;
154 int ret;
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);
165 input_report_key(onkey->input_dev, KEY_POWER, 1);
166 input_sync(onkey->input_dev);
168 atc260x_onkey_query(onkey);
170 return IRQ_HANDLED;
173 static int atc260x_onkey_open(struct input_dev *dev)
175 struct atc260x_onkey *onkey = input_get_drvdata(dev);
177 enable_irq(onkey->irq);
179 return 0;
182 static void atc260x_onkey_close(struct input_dev *dev)
184 struct atc260x_onkey *onkey = input_get_drvdata(dev);
186 disable_irq(onkey->irq);
187 cancel_delayed_work_sync(&onkey->work);
190 static int atc260x_onkey_probe(struct platform_device *pdev)
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;
199 onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
200 if (!onkey)
201 return -ENOMEM;
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;
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");
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;
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;
248 onkey->input_dev = input_dev;
249 onkey->atc260x = atc260x;
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;
256 input_set_capability(input_dev, EV_KEY, KEY_POWER);
257 input_set_drvdata(input_dev, onkey);
259 INIT_DELAYED_WORK(&onkey->work, atc260x_onkey_work);
261 onkey->irq = platform_get_irq(pdev, 0);
262 if (onkey->irq < 0)
263 return onkey->irq;
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;
274 /* Keep IRQ disabled until atc260x_onkey_open() is called. */
275 disable_irq(onkey->irq);
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;
284 error = atc2603x_onkey_hw_init(onkey, reset_status,
285 reset_time, press_time);
286 if (error)
287 return error;
289 device_init_wakeup(&pdev->dev, true);
291 return 0;
294 static struct platform_driver atc260x_onkey_driver = {
295 .probe = atc260x_onkey_probe,
296 .driver = {
297 .name = "atc260x-onkey",
301 module_platform_driver(atc260x_onkey_driver);
303 MODULE_DESCRIPTION("Onkey driver for ATC260x PMICs");
304 MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
305 MODULE_LICENSE("GPL");