temp revert rk change
[firefly-linux-kernel-4.4.55.git] / drivers / power / bq24617_charger.c
1 /*
2  * Copyright (C) 2010 Motorola, Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include <linux/err.h>
15 #include <linux/gpio.h>
16 #include <linux/interrupt.h>
17 #include <linux/irq.h>
18 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/power_supply.h>
21 #include <linux/slab.h>
22 #include <linux/spinlock.h>
23 #include <linux/workqueue.h>
24
25 struct bq24617_data {
26         int stat1_irq;
27         int stat2_irq;
28         int detect_irq;
29
30         struct power_supply ac;
31         int ac_online;
32
33         struct delayed_work work;
34
35         bool stat_irq_en;
36         spinlock_t stat_irq_lock;
37 };
38
39 static int bq24617_stat1_value = 1; /* 0 = charging in progress */
40 static int bq24617_stat2_value = 1; /* 0 = charge complete */
41
42 static char *bq24617_supply_list[] = {
43         "battery",
44 };
45
46 static enum power_supply_property bq24617_power_props[] = {
47         POWER_SUPPLY_PROP_ONLINE,
48 };
49
50 int is_ac_charging(void)
51 {
52         return (!bq24617_stat1_value || !bq24617_stat2_value);
53 }
54
55 int is_ac_charge_complete(void)
56 {
57         return !bq24617_stat2_value;
58 }
59
60 static int power_get_property(struct power_supply *psy,
61                               enum power_supply_property psp,
62                               union power_supply_propval *val)
63 {
64         struct bq24617_data *bq_data =
65                 container_of(psy, struct bq24617_data, ac);
66
67         if (psp != POWER_SUPPLY_PROP_ONLINE)
68                 return -EINVAL;
69
70         val->intval = bq_data->ac_online;
71         return 0;
72 }
73
74 static void bq24617_read_status(struct bq24617_data *bq_data)
75 {
76         int detect = 0;
77
78         /* STAT1 indicates charging, STAT2 indicates charge complete */
79         bq24617_stat1_value = gpio_get_value(irq_to_gpio(bq_data->stat1_irq));
80         bq24617_stat2_value = gpio_get_value(irq_to_gpio(bq_data->stat2_irq));
81
82         if (bq_data->detect_irq >= 0)
83                 detect = gpio_get_value(irq_to_gpio(bq_data->detect_irq));
84
85         if (!bq24617_stat1_value || !bq24617_stat2_value || detect)
86                 bq_data->ac_online = 1;
87         else
88                 bq_data->ac_online = 0;
89
90         pr_debug("%s: ac_online=%d (stat1=%d, stat2=%d, detect=%d)\n", __func__,
91                 bq_data->ac_online, bq24617_stat1_value, bq24617_stat2_value,
92                 detect);
93
94         power_supply_changed(&bq_data->ac);
95 }
96
97 static irqreturn_t bq24617_stat_isr(int irq, void *data)
98 {
99         struct bq24617_data *bq_data = data;
100
101         bq24617_read_status(bq_data);
102         return IRQ_HANDLED;
103 }
104
105 static irqreturn_t bq24617_detect_isr(int irq, void *data)
106 {
107         struct bq24617_data *bq_data = data;
108         unsigned long flags;
109
110         cancel_delayed_work(&bq_data->work);
111
112         spin_lock_irqsave(&bq_data->stat_irq_lock, flags);
113         if (bq_data->stat_irq_en) {
114                 disable_irq(bq_data->stat1_irq);
115                 disable_irq(bq_data->stat2_irq);
116                 bq_data->stat_irq_en = false;
117         }
118         spin_unlock_irqrestore(&bq_data->stat_irq_lock, flags);
119
120         /* The STAT lines cannot be trusted immediately after a charger
121          * insertion. Default the STAT lines to their "not charging" values.
122          */
123         bq24617_stat1_value = 1;
124         bq24617_stat2_value = 1;
125
126         bq_data->ac_online = gpio_get_value(irq_to_gpio(bq_data->detect_irq));
127         pr_debug("%s: ac_online=%d\n", __func__, bq_data->ac_online);
128
129         power_supply_changed(&bq_data->ac);
130
131         /* Give time for STAT lines to settle before enabling the IRQs. */
132         if (bq_data->ac_online)
133                 schedule_delayed_work(&bq_data->work, msecs_to_jiffies(500));
134
135         return IRQ_HANDLED;
136 }
137
138 static void bq24617_work(struct work_struct *work)
139 {
140         struct bq24617_data *bq_data =
141                 container_of(work, struct bq24617_data, work.work);
142         unsigned long flags;
143
144         spin_lock_irqsave(&bq_data->stat_irq_lock, flags);
145         enable_irq(bq_data->stat1_irq);
146         enable_irq(bq_data->stat2_irq);
147         bq_data->stat_irq_en = true;
148         spin_unlock_irqrestore(&bq_data->stat_irq_lock, flags);
149 }
150
151 static int bq24617_probe(struct platform_device *pdev)
152 {
153         struct bq24617_data *bq_data;
154         int retval;
155         unsigned int flags;
156
157         bq_data = kzalloc(sizeof(*bq_data), GFP_KERNEL);
158         if (bq_data == NULL)
159                 return -ENOMEM;
160
161         INIT_DELAYED_WORK(&bq_data->work, bq24617_work);
162         bq_data->stat_irq_en = true;
163         spin_lock_init(&bq_data->stat_irq_lock);
164         platform_set_drvdata(pdev, bq_data);
165
166         bq_data->stat1_irq = platform_get_irq_byname(pdev, "stat1");
167         bq_data->stat2_irq = platform_get_irq_byname(pdev, "stat2");
168         if ((bq_data->stat1_irq < 0) || (bq_data->stat2_irq < 0)) {
169                 dev_err(&pdev->dev, "Resources not set properly\n");
170                 retval = -ENODEV;
171                 goto free_mem;
172         }
173
174         flags = IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
175
176         retval = request_irq(bq_data->stat1_irq, bq24617_stat_isr, flags,
177                              "bq24617_stat1", bq_data);
178         if (retval) {
179                 dev_err(&pdev->dev, "Failed requesting STAT1 IRQ\n");
180                 goto free_mem;
181         }
182
183         retval = request_irq(bq_data->stat2_irq, bq24617_stat_isr, flags,
184                              "bq24617_stat2", bq_data);
185         if (retval) {
186                 dev_err(&pdev->dev, "Failed requesting STAT2 IRQ\n");
187                 goto free_stat1;
188         }
189
190         enable_irq_wake(bq_data->stat1_irq);
191         enable_irq_wake(bq_data->stat2_irq);
192
193         bq_data->ac.name = "ac";
194         bq_data->ac.type = POWER_SUPPLY_TYPE_MAINS;
195         bq_data->ac.supplied_to = bq24617_supply_list;
196         bq_data->ac.num_supplicants = ARRAY_SIZE(bq24617_supply_list);
197         bq_data->ac.properties = bq24617_power_props;
198         bq_data->ac.num_properties = ARRAY_SIZE(bq24617_power_props);
199         bq_data->ac.get_property = power_get_property;
200
201         retval = power_supply_register(&pdev->dev, &bq_data->ac);
202         if (retval) {
203                 dev_err(&pdev->dev, "Failed registering power supply\n");
204                 goto free_stat2;
205         }
206
207         bq_data->detect_irq = platform_get_irq_byname(pdev, "detect");
208         if (bq_data->detect_irq < 0)
209                 dev_info(&pdev->dev, "Only using STAT lines for detection.\n");
210         else {
211                 dev_info(&pdev->dev, "Using STAT and DETECT for detection.\n");
212
213                 retval = request_irq(bq_data->detect_irq, bq24617_detect_isr,
214                                      flags, "bq24617_detect", bq_data);
215                 if (retval) {
216                         dev_err(&pdev->dev, "Failed requesting DETECT IRQ\n");
217                         goto free_all;
218                 }
219
220                 enable_irq_wake(bq_data->detect_irq);
221         }
222
223         bq24617_read_status(bq_data);
224
225         return 0;
226
227 free_all:
228         power_supply_unregister(&bq_data->ac);
229 free_stat2:
230         free_irq(bq_data->stat2_irq, bq_data);
231 free_stat1:
232         free_irq(bq_data->stat1_irq, bq_data);
233 free_mem:
234         kfree(bq_data);
235
236         return retval;
237 }
238
239 static int bq24617_remove(struct platform_device *pdev)
240 {
241         struct bq24617_data *bq_data = platform_get_drvdata(pdev);
242
243         cancel_delayed_work_sync(&bq_data->work);
244
245         power_supply_unregister(&bq_data->ac);
246
247         free_irq(bq_data->stat1_irq, bq_data);
248         free_irq(bq_data->stat2_irq, bq_data);
249         if (bq_data->detect_irq >= 0)
250                 free_irq(bq_data->detect_irq, bq_data);
251
252         kfree(bq_data);
253
254         return 0;
255 }
256
257 static int bq24617_resume(struct device *dev)
258 {
259         struct bq24617_data *bq_data = dev_get_drvdata(dev);
260         int stat1;
261         int stat2;
262
263         if (delayed_work_pending(&bq_data->work)) {
264                 pr_debug("%s: STAT check skipped\n", __func__);
265                 return 0;
266         }
267
268         stat1 = gpio_get_value(irq_to_gpio(bq_data->stat1_irq));
269         stat2 = gpio_get_value(irq_to_gpio(bq_data->stat2_irq));
270
271         if ((stat1 != bq24617_stat1_value) || (stat2 != bq24617_stat2_value)) {
272                 pr_debug("%s: STAT pins changed while suspended\n", __func__);
273                 bq24617_read_status(bq_data);
274         }
275
276         return 0;
277 }
278
279 static struct dev_pm_ops bq24617_pm_ops = {
280         .resume = bq24617_resume,
281 };
282
283 static struct platform_driver bq24617_pdrv = {
284         .driver = {
285                 .name = "bq24617",
286                 .pm = &bq24617_pm_ops,
287         },
288         .probe = bq24617_probe,
289         .remove = bq24617_remove,
290 };
291
292 static int __init bq24617_init(void)
293 {
294         return platform_driver_register(&bq24617_pdrv);
295 }
296
297 static void __exit bq24617_exit(void)
298 {
299         platform_driver_unregister(&bq24617_pdrv);
300 }
301
302 module_init(bq24617_init);
303 module_exit(bq24617_exit);
304
305 MODULE_ALIAS("platform:bq24617_charger");
306 MODULE_LICENSE("GPL");
307 MODULE_AUTHOR("Motorola");
308 MODULE_DESCRIPTION("bq24617 charger driver");