rk3188:pmu:rt5025:modify some bug for pmu charger & irq & guage
[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/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>
27
28
29 static enum power_supply_property rt5025_adap_props[] = {
30         POWER_SUPPLY_PROP_ONLINE,
31 };
32
33 static char *rt5025_supply_list[] = {
34         "rt5025-battery",
35 };
36
37 #if 0
38 static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
39 {
40         int ret;
41         if (onoff)
42                 ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
43         else
44                 ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
45         return ret;
46 }
47
48 static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
49 {
50         int ret;
51         if (onoff)
52                 ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
53         else
54                 ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
55         return ret;
56 }
57 #endif
58
59 static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value)
60 {
61         int ret = 0;
62         u8 data = 0;
63
64         //ICC Setting
65         if (cur_value > 2000)
66                 data |= 0x0f<<3;
67         else if (cur_value >= 500 && cur_value <= 2000)
68         {
69                 data = (cur_value-500)/100;
70                 data<<=3;
71         }
72         
73
74         //AICR Setting
75         if (cur_value > 1000)
76                 data |= 0x03<<1;
77         else if (cur_value > 500 && cur_value <= 1000)
78                 data |= 0x02<<1;
79         else if (cur_value > 100 && cur_value >= 500)
80                 data |= 0x01<<1;
81
82         rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGCC_MASK, data);
83         return ret;
84 }
85
86 static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_val)
87 {
88         int ret = 0;
89         switch (new_val)
90         {
91                 case 0x00:
92                         #if 0
93                         rt5025_set_charging_current_switch(info->i2c, 1);
94                         rt5025_set_charging_buck(info->i2c, 1);
95                         #endif
96                         info->chg_stat = 0x00;
97                         if (info->event_callback)
98                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
99                         break;
100                 case 0x01:
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);
105                         break;
106                 case 0x02:
107                         #if 0
108                         rt5025_set_charging_current_switch(info->i2c, 0);
109                         #endif
110                         info->chg_stat = 0x02;
111                         if (info->event_callback)
112                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL);
113                         break;
114                 case 0x03:
115                         #if 0
116                         rt5025_set_charging_buck(info->i2c, 0);
117                         rt5025_set_charging_current_switch(info->i2c, 0);
118                         #endif
119                         info->chg_stat = 0x03;
120                         if (info->event_callback)
121                                 info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
122                         break;
123                 default:
124                         break;
125         }
126         return ret;
127 }
128
129 int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
130 {
131         if (info->event_callback)
132                 info->event_callback->rt5025_gauge_irq_handler();
133         return 0;
134 }
135 EXPORT_SYMBOL(rt5025_power_passirq_to_gauge);
136
137 int rt5025_power_charge_detect(struct rt5025_power_info *info)
138 {
139         int ret = 0;
140         unsigned char chgstatval = 0;
141         unsigned old_usbval, old_acval, old_chgval, new_usbval, new_acval, new_chgval;
142
143         old_acval = info->ac_online;
144         old_usbval = info->usb_online;
145         old_chgval = info->chg_stat;
146         
147         ret = rt5025_reg_read(info->i2c, RT5025_REG_CHGSTAT);
148         if (ret<0)
149         {
150                 dev_err(info->dev, "read chg stat reg fail\n");
151                 return ret;
152         }
153         chgstatval = ret;
154
155         new_acval = (chgstatval&RT5025_CHG_ACONLINE)>>RT5025_CHG_ACSHIFT;
156         if (old_acval != new_acval)
157         {
158                 info->ac_online = new_acval;
159                 power_supply_changed(&info->ac);
160         }
161         new_usbval = (chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT;
162         if (old_usbval != new_usbval)
163         {
164                 info->usb_online = new_usbval;
165                 power_supply_changed(&info->usb);
166         }
167
168         if (old_acval != new_acval || old_usbval != new_usbval)
169                 schedule_delayed_work(&info->usb_detect_work, 0); //no delay
170
171         new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT;
172         if (new_acval || new_usbval)
173         {
174                 if (old_chgval != new_chgval)
175                 {
176                         ret = rt5025_chgstat_changed(info, new_chgval);
177                 }
178         }
179         else
180         {
181                 #if 0
182                 rt5025_set_charging_buck(info->i2c, 0);
183                 rt5025_set_charging_current_switch(info->i2c, 0);
184                 #endif
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);
188         }
189
190         return ret;
191 }
192 EXPORT_SYMBOL(rt5025_power_charge_detect);
193
194 static int rt5025_adap_get_props(struct power_supply *psy,
195                                 enum power_supply_property psp,
196                                 union power_supply_propval *val)
197 {
198         struct rt5025_power_info *info = dev_get_drvdata(psy->dev->parent);
199         switch(psp)
200         {
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;
206                         else
207                                 return -EINVAL;
208                         break;
209                 default:
210                         return -EINVAL;
211         }
212         return 0;
213 }
214
215 extern int dwc_vbus_status(void);
216
217 static void usb_detect_work_func(struct work_struct *work)
218 {
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);
221         
222         pr_info("rt5025: %s ++", __func__);
223
224         mutex_lock(&pi->var_lock);
225         if (pi->ac_online)
226         {
227                 rt5025_set_charging_current(pi->i2c, 1000);
228                 pi->usb_cnt = 0;
229         }
230         else if (pi->usb_online)
231         {
232                 pr_info("%s: usb_cnt %d\n", __func__, pi->usb_cnt);
233                 switch(dwc_vbus_status())
234                 {
235                         case 2: // USB Wall charger
236                                 rt5025_set_charging_current(pi->i2c, 1000);
237                                 pr_info("rt5025: detect usb wall charger\n");
238                                 break;
239                         case 1: //normal USB
240                         default:
241                                 rt5025_set_charging_current(pi->i2c, 500);
242                                 pr_info("rt5025: detect normal usb\n");
243                                 break;
244                 }
245                 if (pi->usb_cnt++ < 60)
246                         schedule_delayed_work(&pi->usb_detect_work, 1*HZ);
247         }
248         else
249         {
250                 //default to prevent over current charging
251                 rt5025_set_charging_current(pi->i2c, 500);
252                 //reset usb_cnt;
253                 pi->usb_cnt = 0;
254         }
255         mutex_unlock(&pi->var_lock);
256
257         pr_info("rt5025: %s --", __func__);
258 }
259
260 static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd)
261 {
262         RTINFO("++\n");
263         info->ac_online = 0;
264         info->usb_online =0;
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);
270         udelay(200);
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);
278         
279         rt5025_power_charge_detect(info);
280
281         RTINFO("--\n");
282         return 0;
283 }
284
285 static int __devinit rt5025_power_probe(struct platform_device *pdev)
286 {
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;
290         int ret = 0;
291         printk("%s,line=%d\n", __func__,__LINE__);      
292
293         pi = kzalloc(sizeof(*pi), GFP_KERNEL);
294         if (!pi)
295                 return -ENOMEM;
296
297         pi->i2c = chip->i2c;
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);
302
303         ret = rt5025_gauge_init(pi);
304         if (ret)
305                 goto out;
306
307         platform_set_drvdata(pdev, pi);
308
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);
316         if (ret)
317                 goto out;
318
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);
326         if (ret)
327                 goto out_usb;
328
329         rt5025_init_charger(pi, pdata->power_data);
330         chip->power_info = pi;
331
332         return ret;
333 out_usb:
334         power_supply_unregister(&pi->ac);
335 out:
336         kfree(pi);
337
338         return ret;
339 }
340
341 static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state)
342 {
343         struct rt5025_power_info *pi = platform_get_drvdata(pdev);
344
345         if (pi->event_callback)
346                 pi->event_callback->rt5025_gauge_suspend();
347         return 0;
348 }
349
350 static int rt5025_power_resume(struct platform_device *pdev)
351 {
352         struct rt5025_power_info *pi = platform_get_drvdata(pdev);
353         if (pi->event_callback)
354                 pi->event_callback->rt5025_gauge_resume();
355         return 0;
356 }
357
358 static int __devexit rt5025_power_remove(struct platform_device *pdev)
359 {
360         struct rt5025_power_info *pi = platform_get_drvdata(pdev);
361         struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
362
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;
368         kfree(pi);
369
370         return 0;
371 }
372
373 static struct platform_driver rt5025_power_driver = 
374 {
375         .driver = {
376                 .name = RT5025_DEVICE_NAME "-power",
377                 .owner = THIS_MODULE,
378         },
379         .probe = rt5025_power_probe,
380         .remove = __devexit_p(rt5025_power_remove),
381         .suspend = rt5025_power_suspend,
382         .resume = rt5025_power_resume,
383 };
384
385 static int __init rt5025_power_init(void)
386 {
387         return platform_driver_register(&rt5025_power_driver);
388 }
389 subsys_initcall_sync(rt5025_power_init);
390
391 static void __exit rt5025_power_exit(void)
392 {
393         platform_driver_unregister(&rt5025_power_driver);
394 }
395 module_exit(rt5025_power_exit);
396
397
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");