aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/input/ti,palmas-pwrbutton.txt36
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/palmas-pwrbutton.c330
4 files changed, 377 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/ti,palmas-pwrbutton.txt b/Documentation/devicetree/bindings/input/ti,palmas-pwrbutton.txt
new file mode 100644
index 000000000000..a3dde8c30e67
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ti,palmas-pwrbutton.txt
@@ -0,0 +1,36 @@
1Texas Instruments Palmas family power button module
2
3This module is part of the Palmas family of PMICs. For more details
4about the whole chip see:
5Documentation/devicetree/bindings/mfd/palmas.txt.
6
7This module provides a simple power button event via an Interrupt.
8
9Required properties:
10- compatible: should be one of the following
11 - "ti,palmas-pwrbutton": For Palmas compatible power on button
12- interrupt-parent: Parent interrupt device, must be handle of palmas node.
13- interrupts: Interrupt number of power button submodule on device.
14
15Optional Properties:
16
17- ti,palmas-long-press-seconds: Duration in seconds which the power
18 button should be kept pressed for Palmas to power off automatically.
19 NOTE: This depends on OTP support and POWERHOLD signal configuration
20 on platform. Valid values are 6, 8, 10 and 12.
21- ti,palmas-pwron-debounce-milli-seconds: Duration in milliseconds
22 which the power button should be kept pressed for Palmas to register
23 a press for debouncing purposes. NOTE: This depends on specific
24 Palmas variation capability. Valid values are 15, 100, 500 and 1000.
25
26Example:
27
28&palmas {
29 palmas_pwr_button: pwrbutton {
30 compatible = "ti,palmas-pwrbutton";
31 interrupt-parent = <&tps659038>;
32 interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
33 ti,palmas-long-press-seconds = <12>;
34 ti,palmas-pwron-debounce-milli-seconds = <15>;
35 };
36};
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 51891f67b7df..36382e5b7703 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -451,6 +451,16 @@ config HP_SDC_RTC
451 Say Y here if you want to support the built-in real time clock 451 Say Y here if you want to support the built-in real time clock
452 of the HP SDC controller. 452 of the HP SDC controller.
453 453
454config INPUT_PALMAS_PWRBUTTON
455 tristate "Palmas Power button Driver"
456 depends on MFD_PALMAS
457 help
458 Say Y here if you want to enable power key reporting via the
459 Palmas family of PMICs.
460
461 To compile this driver as a module, choose M here. The module will
462 be called palmas_pwrbutton.
463
454config INPUT_PCF50633_PMU 464config INPUT_PCF50633_PMU
455 tristate "PCF50633 PMU events" 465 tristate "PCF50633 PMU events"
456 depends on MFD_PCF50633 466 depends on MFD_PCF50633
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index e0cee1774579..e8b84d2c845f 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
42obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o 42obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
43obj-$(CONFIG_INPUT_MMA8450) += mma8450.o 43obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
44obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o 44obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o
45obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
45obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o 46obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
46obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o 47obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
47obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o 48obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c
new file mode 100644
index 000000000000..3f902110c293
--- /dev/null
+++ b/drivers/input/misc/palmas-pwrbutton.c
@@ -0,0 +1,330 @@
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 */
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 * 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 */
51struct 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 */
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, &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 */
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 * palmas_pwron_params_ofinit() - device tree parameter parser
109 * @dev: palmas button device
110 * @config: configuration params that this fills up
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 /* 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 */
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 * 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 | IRQF_TRIGGER_LOW,
215 dev_name(dev), pwron);
216 if (error) {
217 dev_err(dev, "Can't get IRQ for pwron: %d\n", error);
218 goto err_free_input;
219 }
220
221 error = input_register_device(input_dev);
222 if (error) {
223 dev_err(dev, "Can't register power button: %d\n", error);
224 goto err_free_irq;
225 }
226
227 platform_set_drvdata(pdev, pwron);
228 device_init_wakeup(dev, true);
229
230 return 0;
231
232err_free_irq:
233 cancel_delayed_work_sync(&pwron->input_work);
234 free_irq(pwron->irq, pwron);
235err_free_input:
236 input_free_device(input_dev);
237err_free_mem:
238 kfree(pwron);
239 return error;
240}
241
242/**
243 * palmas_pwron_remove() - Cleanup on removal
244 * @pdev: platform device for the button
245 *
246 * Return: 0
247 */
248static int palmas_pwron_remove(struct platform_device *pdev)
249{
250 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
251
252 free_irq(pwron->irq, pwron);
253 cancel_delayed_work_sync(&pwron->input_work);
254
255 input_unregister_device(pwron->input_dev);
256 kfree(pwron);
257
258 return 0;
259}
260
261#ifdef CONFIG_PM_SLEEP
262/**
263 * palmas_pwron_suspend() - suspend handler
264 * @dev: power button device
265 *
266 * Cancel all pending work items for the power button, setup irq for wakeup
267 *
268 * Return: 0
269 */
270static int palmas_pwron_suspend(struct device *dev)
271{
272 struct platform_device *pdev = to_platform_device(dev);
273 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
274
275 cancel_delayed_work_sync(&pwron->input_work);
276
277 if (device_may_wakeup(dev))
278 enable_irq_wake(pwron->irq);
279
280 return 0;
281}
282
283/**
284 * palmas_pwron_resume() - resume handler
285 * @dev: power button device
286 *
287 * Just disable the wakeup capability of irq here.
288 *
289 * Return: 0
290 */
291static int palmas_pwron_resume(struct device *dev)
292{
293 struct platform_device *pdev = to_platform_device(dev);
294 struct palmas_pwron *pwron = platform_get_drvdata(pdev);
295
296 if (device_may_wakeup(dev))
297 disable_irq_wake(pwron->irq);
298
299 return 0;
300}
301#endif
302
303static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
304 palmas_pwron_suspend, palmas_pwron_resume);
305
306#ifdef CONFIG_OF
307static struct of_device_id of_palmas_pwr_match[] = {
308 { .compatible = "ti,palmas-pwrbutton" },
309 { },
310};
311
312MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
313#endif
314
315static struct platform_driver palmas_pwron_driver = {
316 .probe = palmas_pwron_probe,
317 .remove = palmas_pwron_remove,
318 .driver = {
319 .name = "palmas_pwrbutton",
320 .owner = THIS_MODULE,
321 .of_match_table = of_match_ptr(of_palmas_pwr_match),
322 .pm = &palmas_pwron_pm,
323 },
324};
325module_platform_driver(palmas_pwron_driver);
326
327MODULE_ALIAS("platform:palmas-pwrbutton");
328MODULE_DESCRIPTION("Palmas Power Button");
329MODULE_LICENSE("GPL V2");
330MODULE_AUTHOR("Texas Instruments Inc.");