blob: d8bb88445e68a923db6f036054e75aca3b8b4927 [file] [log] [blame]
Anirudh Ghayal963b5122012-05-23 18:53:59 +05301/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/slab.h>
18#include <linux/spmi.h>
19#include <linux/of.h>
20#include <linux/of_device.h>
21#include <linux/interrupt.h>
22#include <linux/input.h>
23
24#define QPNP_PON_RT_STS(base) (base + 0x10)
25#define QPNP_PON_PULL_CTL(base) (base + 0x70)
26#define QPNP_PON_DBC_CTL(base) (base + 0x71)
27
28#define QPNP_PON_CNTL_PULL_UP BIT(1)
29#define QPNP_PON_CNTL_TRIG_DELAY_MASK (0x7)
30#define QPNP_PON_KPDPWR_N_SET BIT(0)
31
32struct qpnp_pon {
33 struct spmi_device *spmi;
34 struct input_dev *pon_input;
35 u32 key_status_irq;
36 u16 base;
37};
38
39static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
40{
41 u8 pon_rt_sts;
42 int rc;
43 struct qpnp_pon *pon = _pon;
44
45 rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
46 QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
47 if (rc) {
48 dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
49 return IRQ_HANDLED;
50 }
51
52 input_report_key(pon->pon_input, KEY_POWER,
53 !(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
54 input_sync(pon->pon_input);
55
56 return IRQ_HANDLED;
57}
58
59static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
60{
61 int rc = 0;
62 u32 pullup, delay;
63 u8 pon_cntl;
64
65 pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
66 NULL, "power-key");
67 if (pon->key_status_irq < 0) {
68 dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
69 return -ENXIO;
70 }
71
72 rc = of_property_read_u32(pon->spmi->dev.of_node,
73 "qcom,pon-key-dbc-delay", &delay);
74 if (rc) {
75 delay = (delay << 6) / USEC_PER_SEC;
76 delay = ilog2(delay);
77
78 rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
79 QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
80 if (rc) {
81 dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
82 QPNP_PON_DBC_CTL(pon->base));
83 return rc;
84 }
85 pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
86 pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
87 rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
88 QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
89 if (rc) {
90 dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
91 QPNP_PON_DBC_CTL(pon->base));
92 return rc;
93 }
94 }
95
96 rc = of_property_read_u32(pon->spmi->dev.of_node,
97 "qcom,pon-key-pull-up", &pullup);
98 if (!rc) {
99 rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
100 QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
101 if (rc) {
102 dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
103 QPNP_PON_PULL_CTL(pon->base));
104 return rc;
105 }
106 if (pullup)
107 pon_cntl |= QPNP_PON_CNTL_PULL_UP;
108 else
109 pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
110
111 rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
112 QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
113 if (rc) {
114 dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
115 QPNP_PON_PULL_CTL(pon->base));
116 return rc;
117 }
118 }
119
120 pon->pon_input = input_allocate_device();
121 if (!pon->pon_input) {
122 dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
123 return -ENOMEM;
124 }
125
126 input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
127 pon->pon_input->name = "qpnp_pon_key";
128 pon->pon_input->phys = "qpnp_pon_key/input0";
129
130 rc = input_register_device(pon->pon_input);
131 if (rc) {
132 dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
133 goto free_input_dev;
134 }
135
136 rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
137 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
138 "qpnp_pon_key_status", pon);
139 if (rc < 0) {
140 dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
141 pon->key_status_irq, rc);
142 goto unreg_input_dev;
143 }
144
145 device_init_wakeup(&pon->spmi->dev, 1);
146 enable_irq_wake(pon->key_status_irq);
147
148 return rc;
149
150unreg_input_dev:
151 input_unregister_device(pon->pon_input);
152free_input_dev:
153 input_free_device(pon->pon_input);
154 return rc;
155}
156
157static int __devinit qpnp_pon_probe(struct spmi_device *spmi)
158{
159 struct qpnp_pon *pon;
160 struct resource *pon_resource;
161 u32 pon_key_enable = 0;
162 int rc = 0;
163
164 pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
165 GFP_KERNEL);
166 if (!pon) {
167 dev_err(&spmi->dev, "Can't allocate qpnp_pon\n");
168 return -ENOMEM;
169 }
170
171 pon->spmi = spmi;
172
173 pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
174 if (!pon_resource) {
175 dev_err(&spmi->dev, "Unable to get PON base address\n");
176 return -ENXIO;
177 }
178 pon->base = pon_resource->start;
179
180 dev_set_drvdata(&spmi->dev, pon);
181
182 /* pon-key-enable property must be set to register pon key */
183 rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
184 &pon_key_enable);
185 if (rc && rc != -EINVAL) {
186 dev_err(&spmi->dev,
187 "Error reading 'pon-key-enable' property (%d)", rc);
188 return rc;
189 }
190
191 if (pon_key_enable) {
192 rc = qpnp_pon_key_init(pon);
193 if (rc < 0) {
194 dev_err(&spmi->dev, "Failed to register pon-key\n");
195 return rc;
196 }
197 }
198
199 return 0;
200}
201
202static int qpnp_pon_remove(struct spmi_device *spmi)
203{
204 struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
205
206 if (pon->pon_input) {
207 free_irq(pon->key_status_irq, pon);
208 input_unregister_device(pon->pon_input);
209 }
210
211 return 0;
212}
213
214static struct of_device_id spmi_match_table[] = {
215 { .compatible = "qcom,qpnp-power-on",
216 }
217};
218
219static struct spmi_driver qpnp_pon_driver = {
220 .driver = {
221 .name = "qcom,qpnp-power-on",
222 .of_match_table = spmi_match_table,
223 },
224 .probe = qpnp_pon_probe,
225 .remove = __devexit_p(qpnp_pon_remove),
226};
227
228static int __init qpnp_pon_init(void)
229{
230 return spmi_driver_register(&qpnp_pon_driver);
231}
232module_init(qpnp_pon_init);
233
234static void __exit qpnp_pon_exit(void)
235{
236 return spmi_driver_unregister(&qpnp_pon_driver);
237}
238module_exit(qpnp_pon_exit);
239
240MODULE_DESCRIPTION("QPNP PMIC POWER-ON driver");
241MODULE_LICENSE("GPL v2");