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