d37232f9abc3edb2f5f1c6f36ce142846d02f25a
[firefly-linux-kernel-4.4.55.git] / drivers / power / rt5025-power.c
1 /* drivers/power/rt5025-power.c
2  * I2C Driver for Richtek RT5025 PMIC
3  * Multi function device - multi functional baseband PMIC Power part
4  *
5  * Copyright (C) 2013
6  * Author: CY Huang <cy_huang@richtek.com>
7  *
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.
11  */
12
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/mfd/rt5025.h>
23 #include <linux/power/rt5025-power.h>
24 #include <linux/power/rt5025-gauge.h>
25 #include <linux/delay.h>
26
27
28 static enum power_supply_property rt5025_adap_props[] = {
29         POWER_SUPPLY_PROP_ONLINE,
30 };
31
32 static char *rt5025_supply_list[] = {
33         "rt5025-battery",
34 };
35
36 static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
37 {
38         int ret;
39         if (onoff)
40                 ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
41         else
42                 ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
43         return ret;
44 }
45
46 static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
47 {
48         int ret;
49         if (onoff)
50                 ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
51         else
52                 ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
53         return ret;
54 }
55
56 static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_val)
57 {
58         int ret = 0;
59         switch (new_val)
60         {
61                 case 0x00:
62                         rt5025_set_charging_current_switch(info->i2c, 1);
63                         rt5025_set_charging_buck(info->i2c, 1);
64                         info->chg_stat = 0x00;
65                         if (info->event_callback)
66                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
67                         break;
68                 case 0x01:
69                         //rt5025_set_charging_current_switch(info->i2c, 1);
70                         info->chg_stat = 0x01;
71                         if (info->event_callback)
72                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
73                         break;
74                 case 0x02:
75                         rt5025_set_charging_current_switch(info->i2c, 0);
76                         info->chg_stat = 0x02;
77                         if (info->event_callback)
78                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL);
79                         break;
80                 case 0x03:
81                         rt5025_set_charging_buck(info->i2c, 0);
82                         rt5025_set_charging_current_switch(info->i2c, 0);
83                         info->chg_stat = 0x03;
84                         if (info->event_callback)
85                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
86                         break;
87                 default:
88                         break;
89         }
90         return ret;
91 }
92
93 int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
94 {
95         if (info->event_callback)
96                 info->event_callback->rt5025_gauge_irq_handler();
97         return 0;
98 }
99 EXPORT_SYMBOL(rt5025_power_passirq_to_gauge);
100
101 int rt5025_power_charge_detect(struct rt5025_power_info *info)
102 {
103         int ret = 0;
104         unsigned char chgstatval = 0;
105         unsigned old_usbval, old_acval, old_chgval, new_usbval, new_acval, new_chgval;
106
107         old_acval = info->ac_online;
108         old_usbval = info->usb_online;
109         old_chgval = info->chg_stat;
110         
111         ret = rt5025_reg_read(info->i2c, RT5025_REG_CHGSTAT);
112         if (ret<0)
113         {
114                 dev_err(info->dev, "read chg stat reg fail\n");
115                 return ret;
116         }
117         chgstatval = ret;
118
119         new_acval = (chgstatval&RT5025_CHG_ACONLINE)>>RT5025_CHG_ACSHIFT;
120         if (old_acval != new_acval)
121         {
122                 info->ac_online = new_acval;
123                 power_supply_changed(&info->ac);
124         }
125         new_usbval = (chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT;
126         if (old_usbval != new_usbval)
127         {
128                 info->usb_online = new_usbval;
129                 power_supply_changed(&info->usb);
130         }
131
132         new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT;
133         if (new_acval || new_usbval)
134         {
135                 if (old_chgval != new_chgval)
136                 {
137                         ret = rt5025_chgstat_changed(info, new_chgval);
138                 }
139         }
140         else
141         {
142                 rt5025_set_charging_buck(info->i2c, 0);
143                 rt5025_set_charging_current_switch(info->i2c, 0);
144                 info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
145                 if (info->event_callback)
146                         info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING);
147         }
148
149         return ret;
150 }
151 EXPORT_SYMBOL(rt5025_power_charge_detect);
152
153 static int rt5025_adap_get_props(struct power_supply *psy,
154                                 enum power_supply_property psp,
155                                 union power_supply_propval *val)
156 {
157         struct rt5025_power_info *info = dev_get_drvdata(psy->dev->parent);
158         switch(psp)
159         {
160                 case POWER_SUPPLY_PROP_ONLINE:
161                         if (psy->type == POWER_SUPPLY_TYPE_MAINS)
162                                 val->intval = info->ac_online;
163                         else if (psy->type == POWER_SUPPLY_TYPE_USB)
164                                 val->intval = info->usb_online;
165                         else
166                                 return -EINVAL;
167                         break;
168                 default:
169                         return -EINVAL;
170         }
171         return 0;
172 }
173
174 static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd)
175 {
176         info->ac_online = 0;
177         info->usb_online =0;
178         //init charger buckck & charger current en to disable stat
179         info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
180         if (info->event_callback)
181                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
182         rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK);
183         udelay(200);
184         //init register setting
185         rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL2, pd->CHGControl2.val);
186         rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL3, pd->CHGControl3.val);
187         rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL4, pd->CHGControl4.val);
188         rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL5, pd->CHGControl5.val);
189         rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL6, pd->CHGControl6.val);
190         rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
191         
192         rt5025_power_charge_detect(info);
193
194         return 0;
195 }
196
197 static int __devinit rt5025_power_probe(struct platform_device *pdev)
198 {
199         struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
200         struct rt5025_platform_data *pdata = chip->dev->platform_data;
201         struct rt5025_power_info *pi;
202         int ret = 0;
203         printk("%s,line=%d\n", __func__,__LINE__);      
204
205         pi = kzalloc(sizeof(*pi), GFP_KERNEL);
206         if (!pi)
207                 return -ENOMEM;
208
209         pi->i2c = chip->i2c;
210         pi->dev = &pdev->dev;
211
212         ret = rt5025_gauge_init(pi);
213         if (ret)
214                 goto out;
215
216         platform_set_drvdata(pdev, pi);
217
218         pi->ac.name = "rt5025-ac";
219         pi->ac.type = POWER_SUPPLY_TYPE_MAINS;
220         pi->ac.supplied_to = rt5025_supply_list;
221         pi->ac.properties = rt5025_adap_props;
222         pi->ac.num_properties = ARRAY_SIZE(rt5025_adap_props);
223         pi->ac.get_property = rt5025_adap_get_props;
224         ret = power_supply_register(&pdev->dev, &pi->ac);
225         if (ret)
226                 goto out;
227
228         pi->usb.name = "rt5025-usb";
229         pi->usb.type = POWER_SUPPLY_TYPE_USB;
230         pi->ac.supplied_to = rt5025_supply_list;
231         pi->usb.properties = rt5025_adap_props;
232         pi->usb.num_properties = ARRAY_SIZE(rt5025_adap_props);
233         pi->usb.get_property = rt5025_adap_get_props;
234         ret = power_supply_register(&pdev->dev, &pi->usb);
235         if (ret)
236                 goto out_usb;
237
238         rt5025_init_charger(pi, pdata->power_data);
239         chip->power_info = pi;
240
241         return ret;
242 out_usb:
243         power_supply_unregister(&pi->ac);
244 out:
245         kfree(pi);
246
247         return ret;
248 }
249
250 static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state)
251 {
252         struct rt5025_power_info *pi = platform_get_drvdata(pdev);
253
254         if (pi->event_callback)
255                 pi->event_callback->rt5025_gauge_suspend();
256         return 0;
257 }
258
259 static int rt5025_power_resume(struct platform_device *pdev)
260 {
261         struct rt5025_power_info *pi = platform_get_drvdata(pdev);
262         if (pi->event_callback)
263                 pi->event_callback->rt5025_gauge_resume();
264         return 0;
265 }
266
267 static int __devexit rt5025_power_remove(struct platform_device *pdev)
268 {
269         struct rt5025_power_info *pi = platform_get_drvdata(pdev);
270         struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
271
272         if (pi->event_callback)
273                 pi->event_callback->rt5025_gauge_remove();
274         power_supply_unregister(&pi->usb);
275         power_supply_unregister(&pi->ac);
276         chip->power_info = NULL;
277         kfree(pi);
278
279         return 0;
280 }
281
282 static struct platform_driver rt5025_power_driver = 
283 {
284         .driver = {
285                 .name = RT5025_DEVICE_NAME "-power",
286                 .owner = THIS_MODULE,
287         },
288         .probe = rt5025_power_probe,
289         .remove = __devexit_p(rt5025_power_remove),
290         .suspend = rt5025_power_suspend,
291         .resume = rt5025_power_resume,
292 };
293
294 static int __init rt5025_power_init(void)
295 {
296         return platform_driver_register(&rt5025_power_driver);
297 }
298 subsys_initcall_sync(rt5025_power_init);
299
300 static void __exit rt5025_power_exit(void)
301 {
302         platform_driver_unregister(&rt5025_power_driver);
303 }
304 module_exit(rt5025_power_exit);
305
306
307 MODULE_LICENSE("GPL v2");
308 MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
309 MODULE_DESCRIPTION("Power/Gauge driver for RT5025");
310 MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-power");