xref: /linux/drivers/input/misc/palmas-pwrbutton.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
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/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  * struct palmas_pwron - Palmas power on data
34  * @palmas:		pointer to palmas device
35  * @input_dev:		pointer to input device
36  * @input_work:		work for detecting release of key
37  * @irq:		irq that we are hooked on to
38  */
39 struct 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  * struct palmas_pwron_config - configuration of palmas power on
48  * @long_press_time_val:	value for long press h/w shutdown event
49  * @pwron_debounce_val:		value for debounce of power button
50  */
51 struct palmas_pwron_config {
52 	u8 long_press_time_val;
53 	u8 pwron_debounce_val;
54 };
55 
56 /**
57  * palmas_power_button_work() - Detects the button release event
58  * @work:	work item to detect button release
59  */
60 static 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, &reg);
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 		/* The button is released, report event. */
76 		input_report_key(input_dev, KEY_POWER, 0);
77 		input_sync(input_dev);
78 	} else {
79 		/* The button is still depressed, keep checking. */
80 		schedule_delayed_work(&pwron->input_work,
81 				msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS));
82 	}
83 }
84 
85 /**
86  * pwron_irq() - button press isr
87  * @irq:		irq
88  * @palmas_pwron:	pwron struct
89  *
90  * Return: IRQ_HANDLED
91  */
92 static 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  * palmas_pwron_params_ofinit() - device tree parameter parser
109  * @dev:	palmas button device
110  * @config:	configuration params that this fills up
111  */
112 static 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 	/* Default config parameters */
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  * palmas_pwron_probe() - probe
158  * @pdev:	platform device for the button
159  *
160  * Return: 0 for successful probe else appropriate error
161  */
162 static 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 	 * Setup default hardware shutdown option (long key press)
193 	 * and debounce.
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 
234 err_free_irq:
235 	cancel_delayed_work_sync(&pwron->input_work);
236 	free_irq(pwron->irq, pwron);
237 err_free_input:
238 	input_free_device(input_dev);
239 err_free_mem:
240 	kfree(pwron);
241 	return error;
242 }
243 
244 /**
245  * palmas_pwron_remove() - Cleanup on removal
246  * @pdev:	platform device for the button
247  *
248  * Return: 0
249  */
250 static 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 /**
264  * palmas_pwron_suspend() - suspend handler
265  * @dev:	power button device
266  *
267  * Cancel all pending work items for the power button, setup irq for wakeup
268  *
269  * Return: 0
270  */
271 static int __maybe_unused palmas_pwron_suspend(struct device *dev)
272 {
273 	struct platform_device *pdev = to_platform_device(dev);
274 	struct palmas_pwron *pwron = platform_get_drvdata(pdev);
275 
276 	cancel_delayed_work_sync(&pwron->input_work);
277 
278 	if (device_may_wakeup(dev))
279 		enable_irq_wake(pwron->irq);
280 
281 	return 0;
282 }
283 
284 /**
285  * palmas_pwron_resume() - resume handler
286  * @dev:	power button device
287  *
288  * Just disable the wakeup capability of irq here.
289  *
290  * Return: 0
291  */
292 static int __maybe_unused palmas_pwron_resume(struct device *dev)
293 {
294 	struct platform_device *pdev = to_platform_device(dev);
295 	struct palmas_pwron *pwron = platform_get_drvdata(pdev);
296 
297 	if (device_may_wakeup(dev))
298 		disable_irq_wake(pwron->irq);
299 
300 	return 0;
301 }
302 
303 static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
304 			 palmas_pwron_suspend, palmas_pwron_resume);
305 
306 #ifdef CONFIG_OF
307 static const struct of_device_id of_palmas_pwr_match[] = {
308 	{ .compatible = "ti,palmas-pwrbutton" },
309 	{ },
310 };
311 
312 MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
313 #endif
314 
315 static struct platform_driver palmas_pwron_driver = {
316 	.probe	= palmas_pwron_probe,
317 	.remove	= palmas_pwron_remove,
318 	.driver	= {
319 		.name	= "palmas_pwrbutton",
320 		.of_match_table = of_match_ptr(of_palmas_pwr_match),
321 		.pm	= &palmas_pwron_pm,
322 	},
323 };
324 module_platform_driver(palmas_pwron_driver);
325 
326 MODULE_ALIAS("platform:palmas-pwrbutton");
327 MODULE_DESCRIPTION("Palmas Power Button");
328 MODULE_LICENSE("GPL v2");
329 MODULE_AUTHOR("Texas Instruments Inc.");
330