Commit 77686517977e77d101c8a7b397717df00a88922b
Committed by
Dmitry Torokhov
1 parent
144c0f8833
Exists in
master
and in
39 other branches
Input: add support for PowerOn button on the AB8500 MFD
Add the PowerOn (PonKey) button support to detect power on/off events. Acked-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Sundar R Iyer <sundar.iyer@stericsson.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 4 changed files with 188 additions and 0 deletions Side-by-side Diff
drivers/input/misc/Kconfig
... | ... | @@ -22,6 +22,16 @@ |
22 | 22 | To compile this driver as a module, choose M here: the module |
23 | 23 | will be called 88pm860x_onkey. |
24 | 24 | |
25 | +config INPUT_AB8500_PONKEY | |
26 | + tristate "AB8500 Pon (PowerOn) Key" | |
27 | + depends on AB8500_CORE | |
28 | + help | |
29 | + Say Y here to use the PowerOn Key for ST-Ericsson's AB8500 | |
30 | + Mix-Sig PMIC. | |
31 | + | |
32 | + To compile this driver as a module, choose M here: the module | |
33 | + will be called ab8500-ponkey. | |
34 | + | |
25 | 35 | config INPUT_AD714X |
26 | 36 | tristate "Analog Devices AD714x Capacitance Touch Sensor" |
27 | 37 | help |
drivers/input/misc/Makefile
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | # Each configuration option enables a list of files. |
6 | 6 | |
7 | 7 | obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o |
8 | +obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o | |
8 | 9 | obj-$(CONFIG_INPUT_AD714X) += ad714x.o |
9 | 10 | obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o |
10 | 11 | obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o |
drivers/input/misc/ab8500-ponkey.c
1 | +/* | |
2 | + * Copyright (C) ST-Ericsson SA 2010 | |
3 | + * | |
4 | + * License Terms: GNU General Public License v2 | |
5 | + * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson | |
6 | + * | |
7 | + * AB8500 Power-On Key handler | |
8 | + */ | |
9 | + | |
10 | +#include <linux/kernel.h> | |
11 | +#include <linux/module.h> | |
12 | +#include <linux/platform_device.h> | |
13 | +#include <linux/input.h> | |
14 | +#include <linux/interrupt.h> | |
15 | +#include <linux/mfd/ab8500.h> | |
16 | +#include <linux/slab.h> | |
17 | + | |
18 | +/** | |
19 | + * struct ab8500_ponkey - ab8500 ponkey information | |
20 | + * @input_dev: pointer to input device | |
21 | + * @ab8500: ab8500 parent | |
22 | + * @irq_dbf: irq number for falling transition | |
23 | + * @irq_dbr: irq number for rising transition | |
24 | + */ | |
25 | +struct ab8500_ponkey { | |
26 | + struct input_dev *idev; | |
27 | + struct ab8500 *ab8500; | |
28 | + int irq_dbf; | |
29 | + int irq_dbr; | |
30 | +}; | |
31 | + | |
32 | +/* AB8500 gives us an interrupt when ONKEY is held */ | |
33 | +static irqreturn_t ab8500_ponkey_handler(int irq, void *data) | |
34 | +{ | |
35 | + struct ab8500_ponkey *ponkey = data; | |
36 | + | |
37 | + if (irq == ponkey->irq_dbf) | |
38 | + input_report_key(ponkey->idev, KEY_POWER, true); | |
39 | + else if (irq == ponkey->irq_dbr) | |
40 | + input_report_key(ponkey->idev, KEY_POWER, false); | |
41 | + | |
42 | + input_sync(ponkey->idev); | |
43 | + | |
44 | + return IRQ_HANDLED; | |
45 | +} | |
46 | + | |
47 | +static int __devinit ab8500_ponkey_probe(struct platform_device *pdev) | |
48 | +{ | |
49 | + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); | |
50 | + struct ab8500_ponkey *ponkey; | |
51 | + struct input_dev *input; | |
52 | + int irq_dbf, irq_dbr; | |
53 | + int error; | |
54 | + | |
55 | + irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF"); | |
56 | + if (irq_dbf < 0) { | |
57 | + dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf); | |
58 | + return irq_dbf; | |
59 | + } | |
60 | + | |
61 | + irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR"); | |
62 | + if (irq_dbr < 0) { | |
63 | + dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr); | |
64 | + return irq_dbr; | |
65 | + } | |
66 | + | |
67 | + ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL); | |
68 | + input = input_allocate_device(); | |
69 | + if (!ponkey || !input) { | |
70 | + error = -ENOMEM; | |
71 | + goto err_free_mem; | |
72 | + } | |
73 | + | |
74 | + ponkey->idev = input; | |
75 | + ponkey->ab8500 = ab8500; | |
76 | + ponkey->irq_dbf = irq_dbf; | |
77 | + ponkey->irq_dbr = irq_dbr; | |
78 | + | |
79 | + input->name = "AB8500 POn(PowerOn) Key"; | |
80 | + input->dev.parent = &pdev->dev; | |
81 | + | |
82 | + input_set_capability(input, EV_KEY, KEY_POWER); | |
83 | + | |
84 | + error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler, | |
85 | + 0, "ab8500-ponkey-dbf", ponkey); | |
86 | + if (error < 0) { | |
87 | + dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n", | |
88 | + ponkey->irq_dbf, error); | |
89 | + goto err_free_mem; | |
90 | + } | |
91 | + | |
92 | + error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler, | |
93 | + 0, "ab8500-ponkey-dbr", ponkey); | |
94 | + if (error < 0) { | |
95 | + dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n", | |
96 | + ponkey->irq_dbr, error); | |
97 | + goto err_free_dbf_irq; | |
98 | + } | |
99 | + | |
100 | + error = input_register_device(ponkey->idev); | |
101 | + if (error) { | |
102 | + dev_err(ab8500->dev, "Can't register input device: %d\n", error); | |
103 | + goto err_free_dbr_irq; | |
104 | + } | |
105 | + | |
106 | + platform_set_drvdata(pdev, ponkey); | |
107 | + return 0; | |
108 | + | |
109 | +err_free_dbr_irq: | |
110 | + free_irq(ponkey->irq_dbf, ponkey); | |
111 | +err_free_dbf_irq: | |
112 | + free_irq(ponkey->irq_dbf, ponkey); | |
113 | +err_free_mem: | |
114 | + input_free_device(input); | |
115 | + kfree(ponkey); | |
116 | + | |
117 | + return error; | |
118 | +} | |
119 | + | |
120 | +static int __devexit ab8500_ponkey_remove(struct platform_device *pdev) | |
121 | +{ | |
122 | + struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev); | |
123 | + | |
124 | + free_irq(ponkey->irq_dbf, ponkey); | |
125 | + free_irq(ponkey->irq_dbr, ponkey); | |
126 | + input_unregister_device(ponkey->idev); | |
127 | + kfree(ponkey); | |
128 | + | |
129 | + platform_set_drvdata(pdev, NULL); | |
130 | + | |
131 | + return 0; | |
132 | +} | |
133 | + | |
134 | +static struct platform_driver ab8500_ponkey_driver = { | |
135 | + .driver = { | |
136 | + .name = "ab8500-poweron-key", | |
137 | + .owner = THIS_MODULE, | |
138 | + }, | |
139 | + .probe = ab8500_ponkey_probe, | |
140 | + .remove = __devexit_p(ab8500_ponkey_remove), | |
141 | +}; | |
142 | + | |
143 | +static int __init ab8500_ponkey_init(void) | |
144 | +{ | |
145 | + return platform_driver_register(&ab8500_ponkey_driver); | |
146 | +} | |
147 | +module_init(ab8500_ponkey_init); | |
148 | + | |
149 | +static void __exit ab8500_ponkey_exit(void) | |
150 | +{ | |
151 | + platform_driver_unregister(&ab8500_ponkey_driver); | |
152 | +} | |
153 | +module_exit(ab8500_ponkey_exit); | |
154 | + | |
155 | +MODULE_LICENSE("GPL v2"); | |
156 | +MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>"); | |
157 | +MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver"); |
drivers/mfd/ab8500-core.c
... | ... | @@ -338,6 +338,21 @@ |
338 | 338 | }, |
339 | 339 | }; |
340 | 340 | |
341 | +static struct resource ab8500_poweronkey_db_resources[] = { | |
342 | + { | |
343 | + .name = "ONKEY_DBF", | |
344 | + .start = AB8500_INT_PON_KEY1DB_F, | |
345 | + .end = AB8500_INT_PON_KEY1DB_F, | |
346 | + .flags = IORESOURCE_IRQ, | |
347 | + }, | |
348 | + { | |
349 | + .name = "ONKEY_DBR", | |
350 | + .start = AB8500_INT_PON_KEY1DB_R, | |
351 | + .end = AB8500_INT_PON_KEY1DB_R, | |
352 | + .flags = IORESOURCE_IRQ, | |
353 | + }, | |
354 | +}; | |
355 | + | |
341 | 356 | static struct mfd_cell ab8500_devs[] = { |
342 | 357 | { |
343 | 358 | .name = "ab8500-gpadc", |
... | ... | @@ -354,6 +369,11 @@ |
354 | 369 | { .name = "ab8500-usb", }, |
355 | 370 | { .name = "ab8500-pwm", }, |
356 | 371 | { .name = "ab8500-regulator", }, |
372 | + { | |
373 | + .name = "ab8500-poweron-key", | |
374 | + .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), | |
375 | + .resources = ab8500_poweronkey_db_resources, | |
376 | + }, | |
357 | 377 | }; |
358 | 378 | |
359 | 379 | int __devinit ab8500_init(struct ab8500 *ab8500) |