diff options
author | Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org> | 2016-06-22 20:22:03 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-06-23 16:45:54 -0400 |
commit | fcd6eb50eadd83f857eac55f99316f1789707cdb (patch) | |
tree | b9fc026f0ffc6eb0208bad32d6203b8b82a3c06a | |
parent | f695c240a7609584323c3cc0a11bbb9da7071cc0 (diff) |
Input: add powerkey driver for HISI 65xx SoC
This driver provides a input driver for the power button on the
HiSi 65xx SoC for boards like HiKey.
This driver was originally by Zhiliang Xue <xuezhiliang@huawei.com>
then basically rewritten by Jorge, but preserving the original
module author credits.
Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
[jstultz: Reworked commit message, folded in other fixes/cleanups
from Jorge, implemented some larger cleanups suggested by DmitryT]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/misc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/hisi_powerkey.c | 142 |
3 files changed, 152 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 27d6da0e354a..efb0ca871327 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -810,4 +810,13 @@ config INPUT_DRV2667_HAPTICS | |||
810 | To compile this driver as a module, choose M here: the | 810 | To compile this driver as a module, choose M here: the |
811 | module will be called drv2667-haptics. | 811 | module will be called drv2667-haptics. |
812 | 812 | ||
813 | config INPUT_HISI_POWERKEY | ||
814 | tristate "Hisilicon PMIC ONKEY support" | ||
815 | depends on ARCH_HISI || COMPILE_TEST | ||
816 | help | ||
817 | Say Y to enable support for PMIC ONKEY. | ||
818 | |||
819 | To compile this driver as a module, choose M here: the | ||
820 | module will be called hisi_powerkey. | ||
821 | |||
813 | endif | 822 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 5373f493f370..6a1e5e20fc1c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o | |||
35 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o | 35 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o |
36 | obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o | 36 | obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o |
37 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o | 37 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o |
38 | obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o | ||
38 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | 39 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
39 | obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o | 40 | obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o |
40 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | 41 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o |
diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c new file mode 100644 index 000000000000..675539c529ce --- /dev/null +++ b/drivers/input/misc/hisi_powerkey.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * Hisilicon PMIC powerkey driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Hisilicon Ltd. | ||
5 | * Copyright (C) 2015, 2016 Linaro Ltd. | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file "COPYING" in the main directory of this | ||
9 | * archive for more details. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/reboot.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of_irq.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | /* the held interrupt will trigger after 4 seconds */ | ||
27 | #define MAX_HELD_TIME (4 * MSEC_PER_SEC) | ||
28 | |||
29 | static irqreturn_t hi65xx_power_press_isr(int irq, void *q) | ||
30 | { | ||
31 | struct input_dev *input = q; | ||
32 | |||
33 | pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); | ||
34 | input_report_key(input, KEY_POWER, 1); | ||
35 | input_sync(input); | ||
36 | |||
37 | return IRQ_HANDLED; | ||
38 | } | ||
39 | |||
40 | static irqreturn_t hi65xx_power_release_isr(int irq, void *q) | ||
41 | { | ||
42 | struct input_dev *input = q; | ||
43 | |||
44 | pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); | ||
45 | input_report_key(input, KEY_POWER, 0); | ||
46 | input_sync(input); | ||
47 | |||
48 | return IRQ_HANDLED; | ||
49 | } | ||
50 | |||
51 | static irqreturn_t hi65xx_restart_toggle_isr(int irq, void *q) | ||
52 | { | ||
53 | struct input_dev *input = q; | ||
54 | int value = test_bit(KEY_RESTART, input->key); | ||
55 | |||
56 | pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); | ||
57 | input_report_key(input, KEY_RESTART, !value); | ||
58 | input_sync(input); | ||
59 | |||
60 | return IRQ_HANDLED; | ||
61 | } | ||
62 | |||
63 | static const struct { | ||
64 | const char *name; | ||
65 | irqreturn_t (*handler)(int irq, void *q); | ||
66 | } hi65xx_irq_info[] = { | ||
67 | { "down", hi65xx_power_press_isr }, | ||
68 | { "up", hi65xx_power_release_isr }, | ||
69 | { "hold 4s", hi65xx_restart_toggle_isr }, | ||
70 | }; | ||
71 | |||
72 | static int hi65xx_powerkey_probe(struct platform_device *pdev) | ||
73 | { | ||
74 | struct device *dev = &pdev->dev; | ||
75 | struct input_dev *input; | ||
76 | int irq, i, error; | ||
77 | |||
78 | input = devm_input_allocate_device(&pdev->dev); | ||
79 | if (!input) { | ||
80 | dev_err(&pdev->dev, "failed to allocate input device\n"); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | |||
84 | input->phys = "hisi_on/input0"; | ||
85 | input->name = "HISI 65xx PowerOn Key"; | ||
86 | |||
87 | input_set_capability(input, EV_KEY, KEY_POWER); | ||
88 | input_set_capability(input, EV_KEY, KEY_RESTART); | ||
89 | |||
90 | for (i = 0; i < ARRAY_SIZE(hi65xx_irq_info); i++) { | ||
91 | |||
92 | irq = platform_get_irq_byname(pdev, hi65xx_irq_info[i].name); | ||
93 | if (irq < 0) { | ||
94 | error = irq; | ||
95 | dev_err(dev, "couldn't get irq %s: %d\n", | ||
96 | hi65xx_irq_info[i].name, error); | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | error = devm_request_any_context_irq(dev, irq, | ||
101 | hi65xx_irq_info[i].handler, | ||
102 | IRQF_ONESHOT, | ||
103 | hi65xx_irq_info[i].name, | ||
104 | input); | ||
105 | if (error < 0) { | ||
106 | dev_err(dev, "couldn't request irq %s: %d\n", | ||
107 | hi65xx_irq_info[i].name, error); | ||
108 | return error; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | error = input_register_device(input); | ||
113 | if (error) { | ||
114 | dev_err(&pdev->dev, "failed to register input device: %d\n", | ||
115 | error); | ||
116 | return error; | ||
117 | } | ||
118 | |||
119 | device_init_wakeup(&pdev->dev, 1); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int hi65xx_powerkey_remove(struct platform_device *pdev) | ||
125 | { | ||
126 | device_init_wakeup(&pdev->dev, 0); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct platform_driver hi65xx_powerkey_driver = { | ||
132 | .driver = { | ||
133 | .name = "hi65xx-powerkey", | ||
134 | }, | ||
135 | .probe = hi65xx_powerkey_probe, | ||
136 | .remove = hi65xx_powerkey_remove, | ||
137 | }; | ||
138 | module_platform_driver(hi65xx_powerkey_driver); | ||
139 | |||
140 | MODULE_AUTHOR("Zhiliang Xue <xuezhiliang@huawei.com"); | ||
141 | MODULE_DESCRIPTION("Hisi PMIC Power key driver"); | ||
142 | MODULE_LICENSE("GPL v2"); | ||