1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/init.h>
19#include <linux/input.h>
20#include <linux/interrupt.h>
21#include <linux/kernel.h>
22#include <linux/mfd/palmas.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/platform_device.h>
26#include <linux/slab.h>
27
28#define PALMAS_LPK_TIME_MASK 0x0c
29#define PALMAS_PWRON_DEBOUNCE_MASK 0x03
30#define PALMAS_PWR_KEY_Q_TIME_MS 20
31
32
33
34
35
36
37
38
39struct palmas_pwron {
40 struct palmas *palmas;
41 struct input_dev *input_dev;
42 struct delayed_work input_work;
43 int irq;
44};
45
46
47
48
49
50
51struct palmas_pwron_config {
52 u8 long_press_time_val;
53 u8 pwron_debounce_val;
54};
55
56
57
58
59
60static void palmas_power_button_work(struct work_struct *work)
61{
62 struct palmas_pwron *pwron = container_of(work,
63 struct palmas_pwron,
64 input_work.work);
65 struct input_dev *input_dev = pwron->input_dev;
66 unsigned int reg;
67 int error;
68
69 error = palmas_read(pwron->palmas, PALMAS_INTERRUPT_BASE,
70 PALMAS_INT1_LINE_STATE, ®);
71 if (error) {
72 dev_err(input_dev->dev.parent,
73 "Cannot read palmas PWRON status: %d\n", error);
74 } else if (reg & BIT(1)) {
75
76 input_report_key(input_dev, KEY_POWER, 0);
77 input_sync(input_dev);
78 } else {
79
80 schedule_delayed_work(&pwron->input_work,
81 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
82 }
83}
84
85
86
87
88
89
90
91
92static irqreturn_t pwron_irq(int irq, void *palmas_pwron)
93{
94 struct palmas_pwron *pwron = palmas_pwron;
95 struct input_dev *input_dev = pwron->input_dev;
96
97 input_report_key(input_dev, KEY_POWER, 1);
98 pm_wakeup_event(input_dev->dev.parent, 0);
99 input_sync(input_dev);
100
101 mod_delayed_work(system_wq, &pwron->input_work,
102 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
103
104 return IRQ_HANDLED;
105}
106
107
108
109
110
111
112static void palmas_pwron_params_ofinit(struct device *dev,
113 struct palmas_pwron_config *config)
114{
115 struct device_node *np;
116 u32 val;
117 int i, error;
118 u8 lpk_times[] = { 6, 8, 10, 12 };
119 int pwr_on_deb_ms[] = { 15, 100, 500, 1000 };
120
121 memset(config, 0, sizeof(*config));
122
123
124 config->long_press_time_val = ARRAY_SIZE(lpk_times) - 1;
125
126 np = dev->of_node;
127 if (!np)
128 return;
129
130 error = of_property_read_u32(np, "ti,palmas-long-press-seconds", &val);
131 if (!error) {
132 for (i = 0; i < ARRAY_SIZE(lpk_times); i++) {
133 if (val <= lpk_times[i]) {
134 config->long_press_time_val = i;
135 break;
136 }
137 }
138 }
139
140 error = of_property_read_u32(np,
141 "ti,palmas-pwron-debounce-milli-seconds",
142 &val);
143 if (!error) {
144 for (i = 0; i < ARRAY_SIZE(pwr_on_deb_ms); i++) {
145 if (val <= pwr_on_deb_ms[i]) {
146 config->pwron_debounce_val = i;
147 break;
148 }
149 }
150 }
151
152 dev_info(dev, "h/w controlled shutdown duration=%d seconds\n",
153 lpk_times[config->long_press_time_val]);
154}
155
156
157
158
159
160
161
162static int palmas_pwron_probe(struct platform_device *pdev)
163{
164 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
165 struct device *dev = &pdev->dev;
166 struct input_dev *input_dev;
167 struct palmas_pwron *pwron;
168 struct palmas_pwron_config config;
169 int val;
170 int error;
171
172 palmas_pwron_params_ofinit(dev, &config);
173
174 pwron = kzalloc(sizeof(*pwron), GFP_KERNEL);
175 if (!pwron)
176 return -ENOMEM;
177
178 input_dev = input_allocate_device();
179 if (!input_dev) {
180 dev_err(dev, "Can't allocate power button\n");
181 error = -ENOMEM;
182 goto err_free_mem;
183 }
184
185 input_dev->name = "palmas_pwron";
186 input_dev->phys = "palmas_pwron/input0";
187 input_dev->dev.parent = dev;
188
189 input_set_capability(input_dev, EV_KEY, KEY_POWER);
190
191
192
193
194
195 val = config.long_press_time_val << __ffs(PALMAS_LPK_TIME_MASK);
196 val |= config.pwron_debounce_val << __ffs(PALMAS_PWRON_DEBOUNCE_MASK);
197 error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
198 PALMAS_LONG_PRESS_KEY,
199 PALMAS_LPK_TIME_MASK |
200 PALMAS_PWRON_DEBOUNCE_MASK,
201 val);
202 if (error) {
203 dev_err(dev, "LONG_PRESS_KEY_UPDATE failed: %d\n", error);
204 goto err_free_input;
205 }
206
207 pwron->palmas = palmas;
208 pwron->input_dev = input_dev;
209
210 INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
211
212 pwron->irq = platform_get_irq(pdev, 0);
213 error = request_threaded_irq(pwron->irq, NULL, pwron_irq,
214 IRQF_TRIGGER_HIGH |
215 IRQF_TRIGGER_LOW |
216 IRQF_ONESHOT,
217 dev_name(dev), pwron);
218 if (error) {
219 dev_err(dev, "Can't get IRQ for pwron: %d\n", error);
220 goto err_free_input;
221 }
222
223 error = input_register_device(input_dev);
224 if (error) {
225 dev_err(dev, "Can't register power button: %d\n", error);
226 goto err_free_irq;
227 }
228
229 platform_set_drvdata(pdev, pwron);
230 device_init_wakeup(dev, true);
231
232 return 0;
233
234err_free_irq:
235 cancel_delayed_work_sync(&pwron->input_work);
236 free_irq(pwron->irq, pwron);
237err_free_input:
238 input_free_device(input_dev);
239err_free_mem:
240 kfree(pwron);
241 return error;
242}
243
244
245
246
247
248
249
250static int palmas_pwron_remove(struct platform_device *pdev)
251{
252 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
253
254 free_irq(pwron->irq, pwron);
255 cancel_delayed_work_sync(&pwron->input_work);
256
257 input_unregister_device(pwron->input_dev);
258 kfree(pwron);
259
260 return 0;
261}
262
263#ifdef CONFIG_PM_SLEEP
264
265
266
267
268
269
270
271
272static int palmas_pwron_suspend(struct device *dev)
273{
274 struct platform_device *pdev = to_platform_device(dev);
275 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
276
277 cancel_delayed_work_sync(&pwron->input_work);
278
279 if (device_may_wakeup(dev))
280 enable_irq_wake(pwron->irq);
281
282 return 0;
283}
284
285
286
287
288
289
290
291
292
293static int palmas_pwron_resume(struct device *dev)
294{
295 struct platform_device *pdev = to_platform_device(dev);
296 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
297
298 if (device_may_wakeup(dev))
299 disable_irq_wake(pwron->irq);
300
301 return 0;
302}
303#endif
304
305static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
306 palmas_pwron_suspend, palmas_pwron_resume);
307
308#ifdef CONFIG_OF
309static struct of_device_id of_palmas_pwr_match[] = {
310 { .compatible = "ti,palmas-pwrbutton" },
311 { },
312};
313
314MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
315#endif
316
317static struct platform_driver palmas_pwron_driver = {
318 .probe = palmas_pwron_probe,
319 .remove = palmas_pwron_remove,
320 .driver = {
321 .name = "palmas_pwrbutton",
322 .owner = THIS_MODULE,
323 .of_match_table = of_match_ptr(of_palmas_pwr_match),
324 .pm = &palmas_pwron_pm,
325 },
326};
327module_platform_driver(palmas_pwron_driver);
328
329MODULE_ALIAS("platform:palmas-pwrbutton");
330MODULE_DESCRIPTION("Palmas Power Button");
331MODULE_LICENSE("GPL v2");
332MODULE_AUTHOR("Texas Instruments Inc.");
333