]>
Commit | Line | Data |
---|---|---|
fcd6eb50 JRO |
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 | ||
a0d86ecd | 78 | input = devm_input_allocate_device(dev); |
fcd6eb50 | 79 | if (!input) { |
a0d86ecd | 80 | dev_err(dev, "failed to allocate input device\n"); |
fcd6eb50 JRO |
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) { | |
a0d86ecd | 114 | dev_err(dev, "failed to register input device: %d\n", error); |
fcd6eb50 JRO |
115 | return error; |
116 | } | |
117 | ||
a0d86ecd | 118 | device_init_wakeup(dev, 1); |
fcd6eb50 JRO |
119 | |
120 | return 0; | |
121 | } | |
122 | ||
fcd6eb50 JRO |
123 | static struct platform_driver hi65xx_powerkey_driver = { |
124 | .driver = { | |
125 | .name = "hi65xx-powerkey", | |
126 | }, | |
127 | .probe = hi65xx_powerkey_probe, | |
fcd6eb50 JRO |
128 | }; |
129 | module_platform_driver(hi65xx_powerkey_driver); | |
130 | ||
131 | MODULE_AUTHOR("Zhiliang Xue <xuezhiliang@huawei.com"); | |
132 | MODULE_DESCRIPTION("Hisi PMIC Power key driver"); | |
133 | MODULE_LICENSE("GPL v2"); |