blob: 335d826163723c445ff415a5e7073e16a7762095 [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Anirudh Ghayal963b5122012-05-23 18:53:59 +05302 *
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>
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053019#include <linux/delay.h>
Anirudh Ghayal963b5122012-05-23 18:53:59 +053020#include <linux/of.h>
21#include <linux/of_device.h>
22#include <linux/interrupt.h>
23#include <linux/input.h>
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053024#include <linux/log2.h>
Anirudh Ghayal963b5122012-05-23 18:53:59 +053025
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053026/* PON common register addresses */
Anirudh Ghayal963b5122012-05-23 18:53:59 +053027#define QPNP_PON_RT_STS(base) (base + 0x10)
28#define QPNP_PON_PULL_CTL(base) (base + 0x70)
29#define QPNP_PON_DBC_CTL(base) (base + 0x71)
30
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053031/* PON/RESET sources register addresses */
32#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
33#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
34#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
35#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
36#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
37#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
38
39#define QPNP_PON_RESIN_PULL_UP BIT(0)
40#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
41#define QPNP_PON_S2_CNTL_EN BIT(7)
42#define QPNP_PON_S2_RESET_ENABLE BIT(7)
43
44#define QPNP_PON_S1_TIMER_MASK (0xF)
45#define QPNP_PON_S2_TIMER_MASK (0x7)
46#define QPNP_PON_S2_CNTL_TYPE_MASK (0xF)
47
48#define QPNP_PON_DBC_DELAY_MASK (0x7)
Anirudh Ghayal963b5122012-05-23 18:53:59 +053049#define QPNP_PON_KPDPWR_N_SET BIT(0)
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053050#define QPNP_PON_RESIN_N_SET BIT(1)
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +053051#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053052
53/* Ranges */
54#define QPNP_PON_S1_TIMER_MAX 10256
55#define QPNP_PON_S2_TIMER_MAX 2000
56#define QPNP_PON_RESET_TYPE_MAX 0xF
57#define PON_S1_COUNT_MAX 0xF
58
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +053059#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(500)
60
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053061enum pon_type {
62 PON_KPDPWR,
63 PON_RESIN,
64};
65
66struct qpnp_pon_config {
67 u32 pon_type;
68 u32 support_reset;
69 u32 key_code;
70 u32 s1_timer;
71 u32 s2_timer;
72 u32 s2_type;
73 u32 pull_up;
74 u32 state_irq;
75 u32 bark_irq;
76};
Anirudh Ghayal963b5122012-05-23 18:53:59 +053077
78struct qpnp_pon {
79 struct spmi_device *spmi;
80 struct input_dev *pon_input;
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053081 struct qpnp_pon_config *pon_cfg;
82 int num_pon_config;
Anirudh Ghayal963b5122012-05-23 18:53:59 +053083 u16 base;
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +053084 struct delayed_work bark_work;
Anirudh Ghayal963b5122012-05-23 18:53:59 +053085};
86
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053087static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
88 0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
89 3072, 4480, 6720, 10256
90};
Anirudh Ghayal963b5122012-05-23 18:53:59 +053091
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +053092static int
93qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
94{
95 int rc;
96 u8 reg;
97
98 rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
99 addr, &reg, 1);
100 if (rc) {
101 dev_err(&pon->spmi->dev,
102 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
103 return rc;
104 }
105
106 reg &= ~mask;
107 reg |= val & mask;
108 rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
109 addr, &reg, 1);
110 if (rc)
111 dev_err(&pon->spmi->dev,
112 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
113 return rc;
114}
115
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530116static struct qpnp_pon_config *
117qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
118{
119 int i;
120
121 for (i = 0; i < pon->num_pon_config; i++) {
122 if (pon_type == pon->pon_cfg[i].pon_type)
123 return &pon->pon_cfg[i];
124 }
125
126 return NULL;
127}
128
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530129static int
130qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
131{
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530132 int rc;
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530133 struct qpnp_pon_config *cfg = NULL;
134 u8 pon_rt_sts = 0, pon_rt_bit = 0;
135
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530136 cfg = qpnp_get_cfg(pon, pon_type);
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530137 if (!cfg)
138 return -EINVAL;
139
140 /* Check if key reporting is supported */
141 if (!cfg->key_code)
142 return 0;
143
144 /* check the RT status to get the current status of the line */
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530145 rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
146 QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
147 if (rc) {
148 dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530149 return rc;
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530150 }
151
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530152 switch (cfg->pon_type) {
153 case PON_KPDPWR:
154 pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
155 break;
156 case PON_RESIN:
157 pon_rt_bit = QPNP_PON_RESIN_N_SET;
158 break;
159 default:
160 return -EINVAL;
161 }
162
163 input_report_key(pon->pon_input, cfg->key_code,
164 (pon_rt_sts & pon_rt_bit));
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530165 input_sync(pon->pon_input);
166
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530167 return 0;
168}
169
170static irqreturn_t qpnp_kpdpwr_irq(int irq, void *_pon)
171{
172 int rc;
173 struct qpnp_pon *pon = _pon;
174
175 rc = qpnp_pon_input_dispatch(pon, PON_KPDPWR);
176 if (rc)
177 dev_err(&pon->spmi->dev, "Unable to send input event\n");
178
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530179 return IRQ_HANDLED;
180}
181
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530182static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon)
183{
184 return IRQ_HANDLED;
185}
186
187static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
188{
189 int rc;
190 struct qpnp_pon *pon = _pon;
191
192 rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
193 if (rc)
194 dev_err(&pon->spmi->dev, "Unable to send input event\n");
195 return IRQ_HANDLED;
196}
197
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530198static void bark_work_func(struct work_struct *work)
199{
200 int rc;
201 u8 pon_rt_sts = 0;
202 struct qpnp_pon_config *cfg;
203 struct qpnp_pon *pon =
204 container_of(work, struct qpnp_pon, bark_work.work);
205
206 /* enable reset */
207 rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
208 QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
209 if (rc) {
210 dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
211 goto err_return;
212 }
213 /* bark RT status update delay */
214 msleep(100);
215 /* read the bark RT status */
216 rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
217 QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
218 if (rc) {
219 dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
220 goto err_return;
221 }
222
223 if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
224 cfg = qpnp_get_cfg(pon, PON_RESIN);
225 if (!cfg) {
226 dev_err(&pon->spmi->dev, "Invalid config pointer\n");
227 goto err_return;
228 }
229 /* report the key event and enable the bark IRQ */
230 input_report_key(pon->pon_input, cfg->key_code, 0);
231 input_sync(pon->pon_input);
232 enable_irq(cfg->bark_irq);
233 } else {
234 /* disable reset */
235 rc = qpnp_pon_masked_write(pon,
236 QPNP_PON_RESIN_S2_CNTL(pon->base),
237 QPNP_PON_S2_CNTL_EN, 0);
238 if (rc) {
239 dev_err(&pon->spmi->dev,
240 "Unable to configure S2 enable\n");
241 goto err_return;
242 }
243 /* re-arm the work */
244 schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
245 }
246
247err_return:
248 return;
249}
250
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530251static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon)
252{
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530253 int rc;
254 struct qpnp_pon *pon = _pon;
255 struct qpnp_pon_config *cfg;
256
257 /* disable the bark interrupt */
258 disable_irq_nosync(irq);
259
260 /* disable reset */
261 rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
262 QPNP_PON_S2_CNTL_EN, 0);
263 if (rc) {
264 dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
265 goto err_exit;
266 }
267
268 cfg = qpnp_get_cfg(pon, PON_RESIN);
269 if (!cfg) {
270 dev_err(&pon->spmi->dev, "Invalid config pointer\n");
271 goto err_exit;
272 }
273
274 /* report the key event */
275 input_report_key(pon->pon_input, cfg->key_code, 1);
276 input_sync(pon->pon_input);
277 /* schedule work to check the bark status for key-release */
278 schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
279err_exit:
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530280 return IRQ_HANDLED;
281}
282
283static int __devinit
284qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
285{
286 int rc;
287 u8 pull_bit;
288
289 switch (cfg->pon_type) {
290 case PON_KPDPWR:
291 pull_bit = QPNP_PON_KPDPWR_PULL_UP;
292 break;
293 case PON_RESIN:
294 pull_bit = QPNP_PON_RESIN_PULL_UP;
295 break;
296 default:
297 return -EINVAL;
298 }
299
300 rc = qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon->base),
301 pull_bit, cfg->pull_up ? pull_bit : 0);
302 if (rc)
303 dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
304
305 return rc;
306}
307
308static int __devinit
309qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
310{
311 int rc;
312 u8 i;
313 u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
314
315 switch (cfg->pon_type) {
316 case PON_KPDPWR:
317 s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
318 s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
319 s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
320 break;
321 case PON_RESIN:
322 s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
323 s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
324 s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
325 break;
326 default:
327 return -EINVAL;
328 }
329 /* disable S2 reset */
330 rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
331 QPNP_PON_S2_CNTL_EN, 0);
332 if (rc) {
333 dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
334 return rc;
335 }
336
337 usleep(100);
338
339 /* configure s1 timer, s2 timer and reset type */
340 for (i = 0; i < PON_S1_COUNT_MAX + 1; i++) {
341 if (cfg->s1_timer <= s1_delay[i])
342 break;
343 }
344 rc = qpnp_pon_masked_write(pon, s1_timer_addr,
345 QPNP_PON_S1_TIMER_MASK, i);
346 if (rc) {
347 dev_err(&pon->spmi->dev, "Unable to configure S1 timer\n");
348 return rc;
349 }
350
351 i = 0;
352 if (cfg->s2_timer) {
353 i = cfg->s2_timer / 10;
354 i = ilog2(i + 1);
355 }
356
357 rc = qpnp_pon_masked_write(pon, s2_timer_addr,
358 QPNP_PON_S2_TIMER_MASK, i);
359 if (rc) {
360 dev_err(&pon->spmi->dev, "Unable to configure S2 timer\n");
361 return rc;
362 }
363
364 rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
365 QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
366 if (rc) {
367 dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
368 return rc;
369 }
370
371 /* enable S2 reset */
372 rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
373 QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
374 if (rc) {
375 dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
376 return rc;
377 }
378
379 return 0;
380}
381
382static int __devinit
383qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530384{
385 int rc = 0;
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530386
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530387 switch (cfg->pon_type) {
388 case PON_KPDPWR:
389 rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
390 qpnp_kpdpwr_irq,
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530391 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530392 "qpnp_kpdpwr_status", pon);
393 if (rc < 0) {
394 dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
395 cfg->state_irq);
396 return rc;
397 }
398 if (cfg->support_reset) {
399 rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
400 qpnp_kpdpwr_bark_irq,
401 IRQF_TRIGGER_RISING,
402 "qpnp_kpdpwr_bark", pon);
403 if (rc < 0) {
404 dev_err(&pon->spmi->dev,
405 "Can't request %d IRQ\n",
406 cfg->bark_irq);
407 return rc;
408 }
409 }
410 break;
411 case PON_RESIN:
412 rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
413 qpnp_resin_irq,
414 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
415 "qpnp_resin_status", pon);
416 if (rc < 0) {
417 dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
418 cfg->state_irq);
419 return rc;
420 }
421 if (cfg->support_reset) {
422 rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
423 qpnp_resin_bark_irq,
424 IRQF_TRIGGER_RISING,
425 "qpnp_resin_bark", pon);
426 if (rc < 0) {
427 dev_err(&pon->spmi->dev,
428 "Can't request %d IRQ\n",
429 cfg->bark_irq);
430 return rc;
431 }
432 }
433 break;
434 default:
435 return -EINVAL;
436 }
437
438 return rc;
439}
440
441static int __devinit
442qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
443{
444 if (!pon->pon_input) {
445 pon->pon_input = input_allocate_device();
446 if (!pon->pon_input) {
447 dev_err(&pon->spmi->dev,
448 "Can't allocate pon input device\n");
449 return -ENOMEM;
450 }
451 pon->pon_input->name = "qpnp_pon";
452 pon->pon_input->phys = "qpnp_pon/input0";
453 }
454
455 input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
456
457 return 0;
458}
459
460static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
461{
462 int rc = 0, i = 0;
463 struct device_node *pp = NULL;
464 struct qpnp_pon_config *cfg;
465
466 /* iterate through the list of pon configs */
467 while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
468
469 cfg = &pon->pon_cfg[i++];
470
471 rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
472 if (rc) {
473 dev_err(&pon->spmi->dev, "PON type not specified\n");
474 return rc;
475 }
476
477 switch (cfg->pon_type) {
478 case PON_KPDPWR:
479 cfg->state_irq = spmi_get_irq_byname(pon->spmi,
480 NULL, "kpdpwr");
481 if (cfg->state_irq < 0) {
482 dev_err(&pon->spmi->dev,
483 "Unable to get kpdpwr irq\n");
484 return cfg->state_irq;
485 }
486
487 rc = of_property_read_u32(pp, "qcom,support-reset",
488 &cfg->support_reset);
489 if (rc && rc != -EINVAL) {
490 dev_err(&pon->spmi->dev,
491 "Unable to read 'support-reset'\n");
492 return rc;
493 }
494
495 if (cfg->support_reset) {
496 cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
497 NULL, "kpdpwr-bark");
498 if (cfg->bark_irq < 0) {
499 dev_err(&pon->spmi->dev,
500 "Unable to get kpdpwr-bark irq\n");
501 return cfg->bark_irq;
502 }
503 }
504 break;
505 case PON_RESIN:
506 cfg->state_irq = spmi_get_irq_byname(pon->spmi,
507 NULL, "resin");
508 if (cfg->state_irq < 0) {
509 dev_err(&pon->spmi->dev,
510 "Unable to get resin irq\n");
511 return cfg->bark_irq;
512 }
513
514 rc = of_property_read_u32(pp, "qcom,support-reset",
515 &cfg->support_reset);
516 if (rc && rc != -EINVAL) {
517 dev_err(&pon->spmi->dev,
518 "Unable to read 'support-reset'\n");
519 return rc;
520 }
521
522 if (cfg->support_reset) {
523 cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
524 NULL, "resin-bark");
525 if (cfg->bark_irq < 0) {
526 dev_err(&pon->spmi->dev,
527 "Unable to get resin-bark irq\n");
528 return cfg->bark_irq;
529 }
530 }
531 break;
532 default:
533 dev_err(&pon->spmi->dev, "PON RESET %d not supported",
534 cfg->pon_type);
535 return -EINVAL;
536 }
537
538 if (cfg->support_reset) {
539 /*
540 * Get the reset parameters (bark debounce time and
541 * reset debounce time) for the reset line.
542 */
543 rc = of_property_read_u32(pp, "qcom,s1-timer",
544 &cfg->s1_timer);
545 if (rc) {
546 dev_err(&pon->spmi->dev,
547 "Unable to read s1-timer\n");
548 return rc;
549 }
550 if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
551 dev_err(&pon->spmi->dev,
552 "Incorrect S1 debounce time\n");
553 return -EINVAL;
554 }
555 rc = of_property_read_u32(pp, "qcom,s2-timer",
556 &cfg->s2_timer);
557 if (rc) {
558 dev_err(&pon->spmi->dev,
559 "Unable to read s2-timer\n");
560 return rc;
561 }
562 if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
563 dev_err(&pon->spmi->dev,
564 "Incorrect S2 debounce time\n");
565 return -EINVAL;
566 }
567 rc = of_property_read_u32(pp, "qcom,s2-type",
568 &cfg->s2_type);
569 if (rc) {
570 dev_err(&pon->spmi->dev,
571 "Unable to read s2-type\n");
572 return rc;
573 }
574 if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
575 dev_err(&pon->spmi->dev,
576 "Incorrect reset type specified\n");
577 return -EINVAL;
578 }
579 }
580 /*
581 * Get the standard-key parameters. This might not be
582 * specified if there is no key mapping on the reset line.
583 */
584 rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);
585 if (rc && rc == -EINVAL) {
586 dev_err(&pon->spmi->dev,
587 "Unable to read key-code\n");
588 return rc;
589 }
590 /* Register key configuration */
591 if (cfg->key_code) {
592 rc = qpnp_pon_config_input(pon, cfg);
593 if (rc < 0)
594 return rc;
595 }
596 /* get the pull-up configuration */
597 rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
598 if (rc && rc != -EINVAL) {
599 dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
600 return rc;
601 }
602 }
603
604 /* register the input device */
605 if (pon->pon_input) {
606 rc = input_register_device(pon->pon_input);
607 if (rc) {
608 dev_err(&pon->spmi->dev,
609 "Can't register pon key: %d\n", rc);
610 goto free_input_dev;
611 }
612 }
613
614 for (i = 0; i < pon->num_pon_config; i++) {
615 cfg = &pon->pon_cfg[i];
616 /* Configure the pull-up */
617 rc = qpnp_config_pull(pon, cfg);
618 if (rc) {
619 dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
620 goto unreg_input_dev;
621 }
622 /* Configure the reset-configuration */
623 if (cfg->support_reset) {
624 rc = qpnp_config_reset(pon, cfg);
625 if (rc) {
626 dev_err(&pon->spmi->dev,
627 "Unable to config pon reset\n");
628 goto unreg_input_dev;
629 }
630 }
631 rc = qpnp_pon_request_irqs(pon, cfg);
632 if (rc) {
633 dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
634 goto unreg_input_dev;
635 }
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530636 }
637
638 device_init_wakeup(&pon->spmi->dev, 1);
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530639
640 return rc;
641
642unreg_input_dev:
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530643 if (pon->pon_input)
644 input_unregister_device(pon->pon_input);
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530645free_input_dev:
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530646 if (pon->pon_input)
647 input_free_device(pon->pon_input);
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530648 return rc;
649}
650
651static int __devinit qpnp_pon_probe(struct spmi_device *spmi)
652{
653 struct qpnp_pon *pon;
654 struct resource *pon_resource;
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530655 struct device_node *itr = NULL;
656 u32 delay = 0;
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530657 int rc = 0;
658
659 pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
660 GFP_KERNEL);
661 if (!pon) {
662 dev_err(&spmi->dev, "Can't allocate qpnp_pon\n");
663 return -ENOMEM;
664 }
665
666 pon->spmi = spmi;
667
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530668 /* get the total number of pon configurations */
669 while ((itr = of_get_next_child(spmi->dev.of_node, itr)))
670 pon->num_pon_config++;
671
672 if (!pon->num_pon_config) {
673 /* No PON config., do not register the driver */
674 dev_err(&spmi->dev, "No PON config. specified\n");
675 return -EINVAL;
676 }
677
678 pon->pon_cfg = devm_kzalloc(&spmi->dev,
679 sizeof(struct qpnp_pon_config) * pon->num_pon_config,
680 GFP_KERNEL);
681
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530682 pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
683 if (!pon_resource) {
684 dev_err(&spmi->dev, "Unable to get PON base address\n");
685 return -ENXIO;
686 }
687 pon->base = pon_resource->start;
688
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530689 rc = of_property_read_u32(pon->spmi->dev.of_node,
690 "qcom,pon-dbc-delay", &delay);
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530691 if (rc && rc != -EINVAL) {
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530692 dev_err(&spmi->dev, "Unable to read debounce delay\n");
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530693 return rc;
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530694 } else {
695 delay = (delay << 6) / USEC_PER_SEC;
696 delay = ilog2(delay);
697 rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
698 QPNP_PON_DBC_DELAY_MASK, delay);
699 if (rc) {
700 dev_err(&spmi->dev, "Unable to set PON debounce\n");
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530701 return rc;
702 }
703 }
704
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530705 dev_set_drvdata(&spmi->dev, pon);
706
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530707 INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
708
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530709 /* register the PON configurations */
710 rc = qpnp_pon_config_init(pon);
711 if (rc) {
712 dev_err(&spmi->dev,
713 "Unable to intialize PON configurations\n");
714 return rc;
715 }
716
717 return rc;
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530718}
719
720static int qpnp_pon_remove(struct spmi_device *spmi)
721{
722 struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
723
Anirudh Ghayalce4da9c2012-08-07 14:17:59 +0530724 cancel_delayed_work_sync(&pon->bark_work);
725
Anirudh Ghayal0e18cd02012-08-02 11:48:36 +0530726 if (pon->pon_input)
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530727 input_unregister_device(pon->pon_input);
Anirudh Ghayal963b5122012-05-23 18:53:59 +0530728
729 return 0;
730}
731
732static struct of_device_id spmi_match_table[] = {
733 { .compatible = "qcom,qpnp-power-on",
734 }
735};
736
737static struct spmi_driver qpnp_pon_driver = {
738 .driver = {
739 .name = "qcom,qpnp-power-on",
740 .of_match_table = spmi_match_table,
741 },
742 .probe = qpnp_pon_probe,
743 .remove = __devexit_p(qpnp_pon_remove),
744};
745
746static int __init qpnp_pon_init(void)
747{
748 return spmi_driver_register(&qpnp_pon_driver);
749}
750module_init(qpnp_pon_init);
751
752static void __exit qpnp_pon_exit(void)
753{
754 return spmi_driver_unregister(&qpnp_pon_driver);
755}
756module_exit(qpnp_pon_exit);
757
758MODULE_DESCRIPTION("QPNP PMIC POWER-ON driver");
759MODULE_LICENSE("GPL v2");