1 /* drivers/power/rt5025-power.c
2 * I2C Driver for Richtek RT5025 PMIC
3 * Multi function device - multi functional baseband PMIC Power part
6 * Author: CY Huang <cy_huang@richtek.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/i2c.h>
17 #include <linux/power_supply.h>
18 #include <linux/platform_device.h>
19 #include <linux/err.h>
20 #include <linux/version.h>
21 #include <linux/slab.h>
22 #include <linux/workqueue.h>
23 #include <linux/mfd/rt5025.h>
24 #include <linux/power/rt5025-power.h>
25 #include <linux/power/rt5025-gauge.h>
26 #include <linux/delay.h>
29 static enum power_supply_property rt5025_adap_props[] = {
30 POWER_SUPPLY_PROP_ONLINE,
33 static char *rt5025_supply_list[] = {
38 static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
42 ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
44 ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
48 static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
52 ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
54 ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
59 static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value)
67 else if (cur_value >= 500 && cur_value <= 2000)
69 data = (cur_value-500)/100;
77 else if (cur_value > 500 && cur_value <= 1000)
79 else if (cur_value > 100 && cur_value >= 500)
82 rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGCC_MASK, data);
86 static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_val)
93 rt5025_set_charging_current_switch(info->i2c, 1);
94 rt5025_set_charging_buck(info->i2c, 1);
96 info->chg_stat = 0x00;
97 if (info->event_callback)
98 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
101 //rt5025_set_charging_current_switch(info->i2c, 1);
102 info->chg_stat = 0x01;
103 if (info->event_callback)
104 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
108 rt5025_set_charging_current_switch(info->i2c, 0);
110 info->chg_stat = 0x02;
111 if (info->event_callback)
112 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL);
116 rt5025_set_charging_buck(info->i2c, 0);
117 rt5025_set_charging_current_switch(info->i2c, 0);
119 info->chg_stat = 0x03;
120 if (info->event_callback)
121 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
129 int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
131 if (info->event_callback)
132 info->event_callback->rt5025_gauge_irq_handler();
135 EXPORT_SYMBOL(rt5025_power_passirq_to_gauge);
137 int rt5025_power_charge_detect(struct rt5025_power_info *info)
140 unsigned char chgstatval = 0;
141 unsigned old_usbval, old_acval, old_chgval, new_usbval, new_acval, new_chgval;
143 old_acval = info->ac_online;
144 old_usbval = info->usb_online;
145 old_chgval = info->chg_stat;
147 ret = rt5025_reg_read(info->i2c, RT5025_REG_CHGSTAT);
150 dev_err(info->dev, "read chg stat reg fail\n");
155 new_acval = (chgstatval&RT5025_CHG_ACONLINE)>>RT5025_CHG_ACSHIFT;
156 if (old_acval != new_acval)
158 info->ac_online = new_acval;
159 power_supply_changed(&info->ac);
161 new_usbval = (chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT;
162 if (old_usbval != new_usbval)
164 info->usb_online = new_usbval;
165 power_supply_changed(&info->usb);
168 if (old_acval != new_acval || old_usbval != new_usbval)
169 schedule_delayed_work(&info->usb_detect_work, 0); //no delay
171 new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT;
172 if (new_acval || new_usbval)
174 if (old_chgval != new_chgval)
176 ret = rt5025_chgstat_changed(info, new_chgval);
182 rt5025_set_charging_buck(info->i2c, 0);
183 rt5025_set_charging_current_switch(info->i2c, 0);
185 info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
186 if (info->event_callback)
187 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING);
192 EXPORT_SYMBOL(rt5025_power_charge_detect);
194 static int rt5025_adap_get_props(struct power_supply *psy,
195 enum power_supply_property psp,
196 union power_supply_propval *val)
198 struct rt5025_power_info *info = dev_get_drvdata(psy->dev->parent);
201 case POWER_SUPPLY_PROP_ONLINE:
202 if (psy->type == POWER_SUPPLY_TYPE_MAINS)
203 val->intval = info->ac_online;
204 else if (psy->type == POWER_SUPPLY_TYPE_USB)
205 val->intval = info->usb_online;
215 extern int dwc_vbus_status(void);
217 static void usb_detect_work_func(struct work_struct *work)
219 struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work);
220 struct rt5025_power_info *pi = (struct rt5025_power_info *)container_of(delayed_work, struct rt5025_power_info, usb_detect_work);
222 pr_info("rt5025: %s ++", __func__);
224 mutex_lock(&pi->var_lock);
227 rt5025_set_charging_current(pi->i2c, 1000);
230 else if (pi->usb_online)
232 pr_info("%s: usb_cnt %d\n", __func__, pi->usb_cnt);
233 switch(dwc_vbus_status())
235 case 2: // USB Wall charger
236 rt5025_set_charging_current(pi->i2c, 1000);
237 pr_info("rt5025: detect usb wall charger\n");
241 rt5025_set_charging_current(pi->i2c, 500);
242 pr_info("rt5025: detect normal usb\n");
245 if (pi->usb_cnt++ < 60)
246 schedule_delayed_work(&pi->usb_detect_work, 1*HZ);
250 //default to prevent over current charging
251 rt5025_set_charging_current(pi->i2c, 500);
255 mutex_unlock(&pi->var_lock);
257 pr_info("rt5025: %s --", __func__);
260 static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd)
265 //init charger buckck & charger current en to disable stat
266 info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
267 if (info->event_callback)
268 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
269 rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK);
271 //init register setting
272 rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL2, pd->CHGControl2.val);
273 rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL3, pd->CHGControl3.val);
274 rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL4, pd->CHGControl4.val);
275 rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL5, pd->CHGControl5.val);
276 rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL6, pd->CHGControl6.val);
277 rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
279 rt5025_power_charge_detect(info);
285 static int __devinit rt5025_power_probe(struct platform_device *pdev)
287 struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
288 struct rt5025_platform_data *pdata = chip->dev->platform_data;
289 struct rt5025_power_info *pi;
291 printk("%s,line=%d\n", __func__,__LINE__);
293 pi = kzalloc(sizeof(*pi), GFP_KERNEL);
298 pi->dev = &pdev->dev;
299 pi->fcc = pdata->power_data->fcc;
300 mutex_init(&pi->var_lock);
301 INIT_DELAYED_WORK(&pi->usb_detect_work, usb_detect_work_func);
303 ret = rt5025_gauge_init(pi);
307 platform_set_drvdata(pdev, pi);
309 pi->ac.name = "rt5025-ac";
310 pi->ac.type = POWER_SUPPLY_TYPE_MAINS;
311 pi->ac.supplied_to = rt5025_supply_list;
312 pi->ac.properties = rt5025_adap_props;
313 pi->ac.num_properties = ARRAY_SIZE(rt5025_adap_props);
314 pi->ac.get_property = rt5025_adap_get_props;
315 ret = power_supply_register(&pdev->dev, &pi->ac);
319 pi->usb.name = "rt5025-usb";
320 pi->usb.type = POWER_SUPPLY_TYPE_USB;
321 pi->ac.supplied_to = rt5025_supply_list;
322 pi->usb.properties = rt5025_adap_props;
323 pi->usb.num_properties = ARRAY_SIZE(rt5025_adap_props);
324 pi->usb.get_property = rt5025_adap_get_props;
325 ret = power_supply_register(&pdev->dev, &pi->usb);
329 rt5025_init_charger(pi, pdata->power_data);
330 chip->power_info = pi;
334 power_supply_unregister(&pi->ac);
341 static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state)
343 struct rt5025_power_info *pi = platform_get_drvdata(pdev);
345 if (pi->event_callback)
346 pi->event_callback->rt5025_gauge_suspend();
350 static int rt5025_power_resume(struct platform_device *pdev)
352 struct rt5025_power_info *pi = platform_get_drvdata(pdev);
353 if (pi->event_callback)
354 pi->event_callback->rt5025_gauge_resume();
358 static int __devexit rt5025_power_remove(struct platform_device *pdev)
360 struct rt5025_power_info *pi = platform_get_drvdata(pdev);
361 struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
363 if (pi->event_callback)
364 pi->event_callback->rt5025_gauge_remove();
365 power_supply_unregister(&pi->usb);
366 power_supply_unregister(&pi->ac);
367 chip->power_info = NULL;
373 static struct platform_driver rt5025_power_driver =
376 .name = RT5025_DEVICE_NAME "-power",
377 .owner = THIS_MODULE,
379 .probe = rt5025_power_probe,
380 .remove = __devexit_p(rt5025_power_remove),
381 .suspend = rt5025_power_suspend,
382 .resume = rt5025_power_resume,
385 static int __init rt5025_power_init(void)
387 return platform_driver_register(&rt5025_power_driver);
389 subsys_initcall_sync(rt5025_power_init);
391 static void __exit rt5025_power_exit(void)
393 platform_driver_unregister(&rt5025_power_driver);
395 module_exit(rt5025_power_exit);
398 MODULE_LICENSE("GPL v2");
399 MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
400 MODULE_DESCRIPTION("Power/Gauge driver for RT5025");
401 MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-power");