Input: pmic8xxx-pwrkey - switch to using managed resources
[cascardo/linux.git] / drivers / input / misc / pmic8xxx-pwrkey.c
1 /* Copyright (c) 2010-2011, 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/input.h>
19 #include <linux/interrupt.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22 #include <linux/log2.h>
23
24 #include <linux/input/pmic8xxx-pwrkey.h>
25
26 #define PON_CNTL_1 0x1C
27 #define PON_CNTL_PULL_UP BIT(7)
28 #define PON_CNTL_TRIG_DELAY_MASK (0x7)
29
30 /**
31  * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
32  * @key_press_irq: key press irq number
33  */
34 struct pmic8xxx_pwrkey {
35         int key_press_irq;
36 };
37
38 static irqreturn_t pwrkey_press_irq(int irq, void *_pwr)
39 {
40         struct input_dev *pwr = _pwr;
41
42         input_report_key(pwr, KEY_POWER, 1);
43         input_sync(pwr);
44
45         return IRQ_HANDLED;
46 }
47
48 static irqreturn_t pwrkey_release_irq(int irq, void *_pwr)
49 {
50         struct input_dev *pwr = _pwr;
51
52         input_report_key(pwr, KEY_POWER, 0);
53         input_sync(pwr);
54
55         return IRQ_HANDLED;
56 }
57
58 #ifdef CONFIG_PM_SLEEP
59 static int pmic8xxx_pwrkey_suspend(struct device *dev)
60 {
61         struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
62
63         if (device_may_wakeup(dev))
64                 enable_irq_wake(pwrkey->key_press_irq);
65
66         return 0;
67 }
68
69 static int pmic8xxx_pwrkey_resume(struct device *dev)
70 {
71         struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
72
73         if (device_may_wakeup(dev))
74                 disable_irq_wake(pwrkey->key_press_irq);
75
76         return 0;
77 }
78 #endif
79
80 static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
81                 pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
82
83 static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
84 {
85         struct input_dev *pwr;
86         int key_release_irq = platform_get_irq(pdev, 0);
87         int key_press_irq = platform_get_irq(pdev, 1);
88         int err;
89         unsigned int delay;
90         unsigned int pon_cntl;
91         struct regmap *regmap;
92         struct pmic8xxx_pwrkey *pwrkey;
93         const struct pm8xxx_pwrkey_platform_data *pdata =
94                                         dev_get_platdata(&pdev->dev);
95
96         if (!pdata) {
97                 dev_err(&pdev->dev, "power key platform data not supplied\n");
98                 return -EINVAL;
99         }
100
101         if (pdata->kpd_trigger_delay_us > 62500) {
102                 dev_err(&pdev->dev, "invalid power key trigger delay\n");
103                 return -EINVAL;
104         }
105
106         regmap = dev_get_regmap(pdev->dev.parent, NULL);
107         if (!regmap) {
108                 dev_err(&pdev->dev, "failed to locate regmap for the device\n");
109                 return -ENODEV;
110         }
111
112         pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL);
113         if (!pwrkey)
114                 return -ENOMEM;
115
116         pwrkey->key_press_irq = key_press_irq;
117
118         pwr = devm_input_allocate_device(&pdev->dev);
119         if (!pwr) {
120                 dev_dbg(&pdev->dev, "Can't allocate power button\n");
121                 return -ENOMEM;
122         }
123
124         input_set_capability(pwr, EV_KEY, KEY_POWER);
125
126         pwr->name = "pmic8xxx_pwrkey";
127         pwr->phys = "pmic8xxx_pwrkey/input0";
128
129         delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
130         delay = 1 + ilog2(delay);
131
132         err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
133         if (err < 0) {
134                 dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
135                 return err;
136         }
137
138         pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
139         pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
140         if (pdata->pull_up)
141                 pon_cntl |= PON_CNTL_PULL_UP;
142         else
143                 pon_cntl &= ~PON_CNTL_PULL_UP;
144
145         err = regmap_write(regmap, PON_CNTL_1, pon_cntl);
146         if (err < 0) {
147                 dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
148                 return err;
149         }
150
151         err = devm_request_irq(&pdev->dev, key_press_irq, pwrkey_press_irq,
152                                IRQF_TRIGGER_RISING,
153                                "pmic8xxx_pwrkey_press", pwr);
154         if (err) {
155                 dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
156                         key_press_irq, err);
157                 return err;
158         }
159
160         err = devm_request_irq(&pdev->dev, key_release_irq, pwrkey_release_irq,
161                                IRQF_TRIGGER_RISING,
162                                "pmic8xxx_pwrkey_release", pwr);
163         if (err) {
164                 dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
165                         key_release_irq, err);
166                 return err;
167         }
168
169         err = input_register_device(pwr);
170         if (err) {
171                 dev_err(&pdev->dev, "Can't register power key: %d\n", err);
172                 return err;
173         }
174
175         platform_set_drvdata(pdev, pwrkey);
176         device_init_wakeup(&pdev->dev, pdata->wakeup);
177
178         return 0;
179 }
180
181 static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
182 {
183         device_init_wakeup(&pdev->dev, 0);
184
185         return 0;
186 }
187
188 static struct platform_driver pmic8xxx_pwrkey_driver = {
189         .probe          = pmic8xxx_pwrkey_probe,
190         .remove         = pmic8xxx_pwrkey_remove,
191         .driver         = {
192                 .name   = PM8XXX_PWRKEY_DEV_NAME,
193                 .owner  = THIS_MODULE,
194                 .pm     = &pm8xxx_pwr_key_pm_ops,
195         },
196 };
197 module_platform_driver(pmic8xxx_pwrkey_driver);
198
199 MODULE_ALIAS("platform:pmic8xxx_pwrkey");
200 MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
201 MODULE_LICENSE("GPL v2");
202 MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");