rk312x:rt5025:support pmic rt5025
[firefly-linux-kernel-4.4.55.git] / drivers / power / rt-power.c
1 /*
2  *  drivers/power/rt-power.c
3  *  Driver for Richtek RT PMIC Power driver
4  *
5  *  Copyright (C) 2014 Richtek Technology Corp.
6  *  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; either version 2
11  * of the License, or (at your option) any later version.
12  */
13
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/version.h>
18 #include <linux/err.h>
19 #include <linux/platform_device.h>
20 #include <linux/power_supply.h>
21 #include <linux/workqueue.h>
22 #include <linux/wakelock.h>
23
24 #include <linux/power/rt-power.h>
25
26 struct rt_power_info {
27         struct device *dev;
28         struct power_supply ac_psy;
29         struct power_supply usb_psy;
30         struct wake_lock usbdet_wakelock;
31         struct delayed_work usbdet_work;
32         int chg_volt;
33         int acchg_icc;
34         int usbtachg_icc;
35         int usbchg_icc;
36         unsigned char ac_online:1;
37         unsigned char usbta_online:1;
38         unsigned char usb_online:1;
39         unsigned char suspend:1;
40         unsigned char usbcnt;
41 };
42
43 #define RT_USBCNT_MAX 60
44
45 static char *rtpower_supply_list[] = {
46         "battery",
47 };
48
49 static enum power_supply_property rtpower_props[] = {
50         POWER_SUPPLY_PROP_ONLINE,
51 };
52
53 static int rtpower_set_charger(struct rt_power_info *pi)
54 {
55         struct power_supply *chg_psy;
56         union power_supply_propval pval;
57         int rc = 0, is_chg_on = 0;
58
59         chg_psy = power_supply_get_by_name("rt-charger");
60         if (chg_psy) {
61                 rc = chg_psy->get_property(chg_psy, POWER_SUPPLY_PROP_ONLINE, &pval);
62                 if (rc < 0)
63                         dev_err(pi->dev, "get chg online prop fail\n");
64                 else
65                         is_chg_on = pval.intval;
66                 if (pi->ac_online) {
67                         pval.intval = pi->acchg_icc;
68                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
69                                 &pval);
70                         if (rc < 0)
71                                 dev_err(pi->dev, "set acchg aicr fail\n");
72                         pval.intval = 500;
73                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
74                                 &pval);
75                         if (rc < 0)
76                                 dev_err(pi->dev, "set acchg icc fail\n");
77                         pval.intval = POWER_SUPPLY_TYPE_MAINS;
78                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
79                                 &pval);
80                         if (rc < 0)
81                                 dev_err(pi->dev, "set charge cable fail\n");
82                         if (!is_chg_on) {
83                                 pval.intval = pi->chg_volt;
84                                 rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
85                                         &pval);
86                                 if (rc < 0)
87                                         dev_err(pi->dev, "set chg voltage fail\n");
88                                 pval.intval = 1;
89                                 rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
90                                         &pval);
91                                 if (rc < 0)
92                                         dev_err(pi->dev, "set charger online fail\n");
93                         }
94                         pval.intval = 1;
95                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
96                                 &pval);
97                         if (rc < 0)
98                                 dev_err(pi->dev, "set charger present fail\n");
99                 } else if (pi->usbta_online) {
100                         pval.intval = pi->usbtachg_icc;
101                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
102                                 &pval);
103                         if (rc < 0)
104                                 dev_err(pi->dev, "set usbtachg aicr fail\n");
105                         pval.intval = 500;
106                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
107                                 &pval);
108                         if (rc < 0)
109                                 dev_err(pi->dev, "set usbtachg icc fail\n");
110                         pval.intval = POWER_SUPPLY_TYPE_USB_DCP;
111                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
112                                 &pval);
113                         if (rc < 0)
114                                 dev_err(pi->dev, "set charge cable fail\n");
115                         if (!is_chg_on) {
116                                 pval.intval = pi->chg_volt;
117                                 rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
118                                         &pval);
119                                 if (rc < 0)
120                                         dev_err(pi->dev, "set chg voltage fail\n");
121                                 pval.intval = 1;
122                                 rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
123                                         &pval);
124                                 if (rc < 0)
125                                         dev_err(pi->dev, "set charger online fail\n");
126                         }
127                         pval.intval = 1;
128                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
129                                 &pval);
130                         if (rc < 0)
131                                 dev_err(pi->dev, "set charger present fail\n");
132                 } else if (pi->usb_online) {
133                         pval.intval = pi->usbchg_icc;
134                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
135                                 &pval);
136                         if (rc < 0)
137                                 dev_err(pi->dev, "set usbchg aicr fail\n");
138                         pval.intval = 500;
139                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
140                                 &pval);
141                         if (rc < 0)
142                                 dev_err(pi->dev, "set usbchg icc fail\n");
143                         pval.intval = POWER_SUPPLY_TYPE_USB;
144                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
145                                 &pval);
146                         if (rc < 0)
147                                 dev_err(pi->dev, "set charge cable fail\n");
148                         if (!is_chg_on) {
149                                 pval.intval = pi->chg_volt;
150                                 rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
151                                         &pval);
152                                 if (rc < 0)
153                                         dev_err(pi->dev, "set chg voltage fail\n");
154                                 pval.intval = 1;
155                                 rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
156                                         &pval);
157                                 if (rc < 0)
158                                         dev_err(pi->dev, "set charger online fail\n");
159                         }
160                         pval.intval = 1;
161                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
162                                 &pval);
163                         if (rc < 0)
164                                 dev_err(pi->dev, "set charger present fail\n");
165
166                 } else {
167                         pval.intval = 0;
168                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
169                                 &pval);
170                         if (rc < 0)
171                                 dev_err(pi->dev, "set charger online fail\n");
172                         pval.intval = 0;
173                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
174                                 &pval);
175                         if (rc < 0)
176                                 dev_err(pi->dev, "set charge cable fail\n");
177                         pval.intval = pi->chg_volt;
178                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
179                                 &pval);
180                         if (rc < 0)
181                                 dev_err(pi->dev, "set chg voltage fail\n");
182                         pval.intval = 500;
183                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
184                                 &pval);
185                         if (rc < 0)
186                                 dev_err(pi->dev, "set chg aicr fail\n");
187                         pval.intval = 500;
188                         rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
189                                 &pval);
190                         if (rc < 0)
191                                 dev_err(pi->dev, "set chg icc fail\n");
192                 }
193                 power_supply_changed(chg_psy);
194         } else {
195                 rc = -EINVAL;
196                 dev_err(pi->dev, "cannot get rt-charger psy\n");
197         }
198         return rc;
199 }
200
201 static int rtpower_get_property(struct power_supply *psy, enum power_supply_property psp, \
202                         union power_supply_propval *val)
203 {
204         struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent);
205         int rc = 0;
206
207         switch (psp) {
208         case POWER_SUPPLY_PROP_ONLINE:
209                 if (psy->type == POWER_SUPPLY_TYPE_MAINS)
210                         val->intval = (pi->ac_online || pi->usbta_online)?1 : 0;
211                 else if (psy->type == POWER_SUPPLY_TYPE_USB)
212                         val->intval = pi->usb_online;
213                 else
214                         rc = -EINVAL;
215                 break;
216         default:
217                 rc = -EINVAL;
218                 break;
219         }
220         return rc;
221 }
222
223 static int rtpower_set_property(struct power_supply *psy, enum power_supply_property psp, \
224                                 const union power_supply_propval *val)
225 {
226         struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent);
227         int rc = 0;
228
229         switch (psp) {
230         case POWER_SUPPLY_PROP_ONLINE:
231                 if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
232                         if (pi->ac_online != val->intval) {
233                                 pi->ac_online = val->intval;
234                                 rc = rtpower_set_charger(pi);
235                         }
236                 } else if (psy->type == POWER_SUPPLY_TYPE_USB) {
237                         if (pi->usb_online != val->intval) {
238                                 pi->usb_online = val->intval;
239                                 if (val->intval) {
240                                         pi->usbcnt = 0;
241                                         wake_lock(&pi->usbdet_wakelock);
242                                         schedule_delayed_work(&pi->usbdet_work, 1*HZ);
243                                 } else {
244                                         pi->usbcnt = RT_USBCNT_MAX;
245                                         schedule_delayed_work(&pi->usbdet_work, 0);
246                                         if (pi->usbta_online) {
247                                                 pi->usbta_online = 0;
248                                                 power_supply_changed(&pi->ac_psy);
249                                         }
250                                 }
251                                 rc = rtpower_set_charger(pi);
252                         }
253                 } else {
254                                 rc = -EINVAL;
255                 }
256                 break;
257         default:
258                 rc = -EINVAL;
259                 break;
260         }
261         return rc;
262 }
263
264 extern int dwc_otg_check_dpdm(bool wait);
265 static void usbdet_work_func(struct work_struct *work)
266 {
267         struct rt_power_info *pi = container_of(work, struct rt_power_info, \
268                         usbdet_work.work);
269         int usb_det = dwc_otg_check_dpdm(0);
270
271         switch (usb_det) {
272         case 2:
273                 dev_info(pi->dev, "usb ta checked\n");
274                 if (pi->usb_online) {
275                         pi->usbta_online = 1;
276                         rtpower_set_charger(pi);
277                         power_supply_changed(&pi->ac_psy);
278                 }
279                 pi->usbcnt = RT_USBCNT_MAX;
280                 break;
281         case 1:
282         case 0:
283                 dev_info(pi->dev, "normal usb\n");
284                 break;
285         default:
286                 break;
287         }
288         if (pi->usbcnt < RT_USBCNT_MAX) {
289                 pi->usbcnt++;
290                 schedule_delayed_work(&pi->usbdet_work, 1*HZ);
291         } else {
292                 wake_unlock(&pi->usbdet_wakelock);
293         }
294 }
295
296 static int rt_power_probe(struct platform_device *pdev)
297 {
298         struct rt_power_info *pi;
299         struct rt_power_data *rt_power_pdata = pdev->dev.platform_data;
300         int ret = 0;
301
302         pi = devm_kzalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL);
303         if (!pi)
304                 return -ENOMEM;
305         pi->dev = &pdev->dev;
306         wake_lock_init(&pi->usbdet_wakelock, WAKE_LOCK_SUSPEND, "rt-usb-det");
307         INIT_DELAYED_WORK(&pi->usbdet_work, usbdet_work_func);
308         pi->chg_volt = rt_power_pdata->chg_volt;
309         pi->acchg_icc = rt_power_pdata->acchg_icc;
310         pi->usbtachg_icc = rt_power_pdata->usbtachg_icc;
311         pi->usbchg_icc = rt_power_pdata->usbchg_icc;
312         platform_set_drvdata(pdev, pi);
313
314         /* ac power supply register*/
315         pi->ac_psy.name = RT_AC_NAME;
316         pi->ac_psy.type = POWER_SUPPLY_TYPE_MAINS;
317         pi->ac_psy.supplied_to = rtpower_supply_list;
318         pi->ac_psy.properties = rtpower_props;
319         pi->ac_psy.num_properties = ARRAY_SIZE(rtpower_props);
320         pi->ac_psy.get_property = rtpower_get_property;
321         pi->ac_psy.set_property = rtpower_set_property;
322         ret = power_supply_register(&pdev->dev, &pi->ac_psy);
323         if (ret < 0) {
324                 dev_err(&pdev->dev, " create ac power supply fail\n");
325                 goto err_init;
326         }
327         /*usb power supply register*/
328         pi->usb_psy.name = RT_USB_NAME;
329         pi->usb_psy.type = POWER_SUPPLY_TYPE_USB;
330         pi->usb_psy.supplied_to = rtpower_supply_list;
331         pi->usb_psy.properties = rtpower_props;
332         pi->usb_psy.num_properties = ARRAY_SIZE(rtpower_props);
333         pi->usb_psy.get_property = rtpower_get_property;
334         pi->usb_psy.set_property = rtpower_set_property;
335         ret = power_supply_register(&pdev->dev, &pi->usb_psy);
336         if (ret < 0) {
337                 dev_err(&pdev->dev, " create usb power supply fail\n");
338                 goto err_acpsy;
339         }
340         return 0;
341
342 err_acpsy:
343         power_supply_unregister(&pi->ac_psy);
344 err_init:
345         wake_lock_destroy(&pi->usbdet_wakelock);
346         return ret;
347 }
348
349 static int rt_power_remove(struct platform_device *pdev)
350 {
351         struct rt_power_info *pi = platform_get_drvdata(pdev);
352
353         power_supply_unregister(&pi->usb_psy);
354         power_supply_unregister(&pi->ac_psy);
355         wake_lock_destroy(&pi->usbdet_wakelock);
356         return 0;
357 }
358
359 static int rt_power_suspend(struct platform_device *pdev, pm_message_t state)
360 {
361         struct rt_power_info *pi = platform_get_drvdata(pdev);
362
363         pi->suspend = 1;
364         return 0;
365 }
366
367 static int rt_power_resume(struct platform_device *pdev)
368 {
369         struct rt_power_info *pi = platform_get_drvdata(pdev);
370
371         pi->suspend = 0;
372         return 0;
373 }
374
375 static const struct of_device_id rt_match_table[] = {
376         { .compatible = "rt,rt-power",},
377         {},
378 };
379
380 static struct platform_driver rt_power_driver = {
381         .driver = {
382                 .name = "rt-power",
383                 .owner = THIS_MODULE,
384                 .of_match_table = rt_match_table,
385         },
386         .probe = rt_power_probe,
387         .remove = rt_power_remove,
388         .suspend = rt_power_suspend,
389         .resume = rt_power_resume,
390 };
391 static int rt_power_init(void)
392 {
393         return platform_driver_register(&rt_power_driver);
394 }
395 subsys_initcall(rt_power_init);
396
397 static void rt_power_exit(void)
398 {
399         platform_driver_unregister(&rt_power_driver);
400 }
401 module_exit(rt_power_exit);
402
403 MODULE_LICENSE("GPL");
404 MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
405 MODULE_DESCRIPTION("RT Power driver");
406 MODULE_ALIAS("platform:rt-power");
407 MODULE_VERSION("1.0.0_G");