2 * Copyright (C) 2010 Motorola, Inc.
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.
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.
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>
30 struct power_supply ac;
33 struct delayed_work work;
36 spinlock_t stat_irq_lock;
39 static int bq24617_stat1_value = 1; /* 0 = charging in progress */
40 static int bq24617_stat2_value = 1; /* 0 = charge complete */
42 static char *bq24617_supply_list[] = {
46 static enum power_supply_property bq24617_power_props[] = {
47 POWER_SUPPLY_PROP_ONLINE,
50 int is_ac_charging(void)
52 return (!bq24617_stat1_value || !bq24617_stat2_value);
55 int is_ac_charge_complete(void)
57 return !bq24617_stat2_value;
60 static int power_get_property(struct power_supply *psy,
61 enum power_supply_property psp,
62 union power_supply_propval *val)
64 struct bq24617_data *bq_data =
65 container_of(psy, struct bq24617_data, ac);
67 if (psp != POWER_SUPPLY_PROP_ONLINE)
70 val->intval = bq_data->ac_online;
74 static void bq24617_read_status(struct bq24617_data *bq_data)
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));
82 if (bq_data->detect_irq >= 0)
83 detect = gpio_get_value(irq_to_gpio(bq_data->detect_irq));
85 if (!bq24617_stat1_value || !bq24617_stat2_value || detect)
86 bq_data->ac_online = 1;
88 bq_data->ac_online = 0;
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,
94 power_supply_changed(&bq_data->ac);
97 static irqreturn_t bq24617_stat_isr(int irq, void *data)
99 struct bq24617_data *bq_data = data;
101 bq24617_read_status(bq_data);
105 static irqreturn_t bq24617_detect_isr(int irq, void *data)
107 struct bq24617_data *bq_data = data;
110 cancel_delayed_work(&bq_data->work);
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;
118 spin_unlock_irqrestore(&bq_data->stat_irq_lock, flags);
120 /* The STAT lines cannot be trusted immediately after a charger
121 * insertion. Default the STAT lines to their "not charging" values.
123 bq24617_stat1_value = 1;
124 bq24617_stat2_value = 1;
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);
129 power_supply_changed(&bq_data->ac);
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));
138 static void bq24617_work(struct work_struct *work)
140 struct bq24617_data *bq_data =
141 container_of(work, struct bq24617_data, work.work);
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);
151 static int bq24617_probe(struct platform_device *pdev)
153 struct bq24617_data *bq_data;
157 bq_data = kzalloc(sizeof(*bq_data), GFP_KERNEL);
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);
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");
174 flags = IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
176 retval = request_irq(bq_data->stat1_irq, bq24617_stat_isr, flags,
177 "bq24617_stat1", bq_data);
179 dev_err(&pdev->dev, "Failed requesting STAT1 IRQ\n");
183 retval = request_irq(bq_data->stat2_irq, bq24617_stat_isr, flags,
184 "bq24617_stat2", bq_data);
186 dev_err(&pdev->dev, "Failed requesting STAT2 IRQ\n");
190 enable_irq_wake(bq_data->stat1_irq);
191 enable_irq_wake(bq_data->stat2_irq);
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;
201 retval = power_supply_register(&pdev->dev, &bq_data->ac);
203 dev_err(&pdev->dev, "Failed registering power supply\n");
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");
211 dev_info(&pdev->dev, "Using STAT and DETECT for detection.\n");
213 retval = request_irq(bq_data->detect_irq, bq24617_detect_isr,
214 flags, "bq24617_detect", bq_data);
216 dev_err(&pdev->dev, "Failed requesting DETECT IRQ\n");
220 enable_irq_wake(bq_data->detect_irq);
223 bq24617_read_status(bq_data);
228 power_supply_unregister(&bq_data->ac);
230 free_irq(bq_data->stat2_irq, bq_data);
232 free_irq(bq_data->stat1_irq, bq_data);
239 static int bq24617_remove(struct platform_device *pdev)
241 struct bq24617_data *bq_data = platform_get_drvdata(pdev);
243 cancel_delayed_work_sync(&bq_data->work);
245 power_supply_unregister(&bq_data->ac);
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);
257 static int bq24617_resume(struct device *dev)
259 struct bq24617_data *bq_data = dev_get_drvdata(dev);
263 if (delayed_work_pending(&bq_data->work)) {
264 pr_debug("%s: STAT check skipped\n", __func__);
268 stat1 = gpio_get_value(irq_to_gpio(bq_data->stat1_irq));
269 stat2 = gpio_get_value(irq_to_gpio(bq_data->stat2_irq));
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);
279 static struct dev_pm_ops bq24617_pm_ops = {
280 .resume = bq24617_resume,
283 static struct platform_driver bq24617_pdrv = {
286 .pm = &bq24617_pm_ops,
288 .probe = bq24617_probe,
289 .remove = bq24617_remove,
292 static int __init bq24617_init(void)
294 return platform_driver_register(&bq24617_pdrv);
297 static void __exit bq24617_exit(void)
299 platform_driver_unregister(&bq24617_pdrv);
302 module_init(bq24617_init);
303 module_exit(bq24617_exit);
305 MODULE_ALIAS("platform:bq24617_charger");
306 MODULE_LICENSE("GPL");
307 MODULE_AUTHOR("Motorola");
308 MODULE_DESCRIPTION("bq24617 charger driver");