Merge tag 'v4.4.2'
[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,
62                                            &pval);
63                 if (rc < 0)
64                         dev_err(pi->dev, "get chg online prop fail\n");
65                 else
66                         is_chg_on = pval.intval;
67                 if (pi->ac_online) {
68                         pval.intval = pi->acchg_icc;
69                         rc = chg_psy->set_property(chg_psy,
70                                         POWER_SUPPLY_PROP_CURRENT_AVG,
71                                         &pval);
72                         if (rc < 0)
73                                 dev_err(pi->dev, "set acchg aicr fail\n");
74                         pval.intval = 500;
75                         rc = chg_psy->set_property(chg_psy,
76                                         POWER_SUPPLY_PROP_CURRENT_NOW,
77                                         &pval);
78                         if (rc < 0)
79                                 dev_err(pi->dev, "set acchg icc fail\n");
80                         pval.intval = POWER_SUPPLY_TYPE_MAINS;
81                         rc = chg_psy->set_property(chg_psy,
82                                         POWER_SUPPLY_PROP_CHARGE_NOW,
83                                         &pval);
84                         if (rc < 0)
85                                 dev_err(pi->dev, "set charge cable fail\n");
86                         if (!is_chg_on) {
87                                 pval.intval = pi->chg_volt;
88                                 rc = chg_psy->set_property(chg_psy,
89                                         POWER_SUPPLY_PROP_VOLTAGE_NOW,
90                                         &pval);
91                                 if (rc < 0)
92                                         dev_err(pi->dev,
93                                                 "set chg voltage fail\n");
94                                 pval.intval = 1;
95                                 rc = chg_psy->set_property(chg_psy,
96                                         POWER_SUPPLY_PROP_ONLINE,
97                                         &pval);
98                                 if (rc < 0)
99                                         dev_err(pi->dev,
100                                                 "set charger online fail\n");
101                         }
102                         pval.intval = 1;
103                         rc = chg_psy->set_property(chg_psy,
104                                         POWER_SUPPLY_PROP_PRESENT,
105                                         &pval);
106                         if (rc < 0)
107                                 dev_err(pi->dev, "set charger present fail\n");
108                 } else if (pi->usbta_online) {
109                         pval.intval = pi->usbtachg_icc;
110                         rc = chg_psy->set_property(chg_psy,
111                                         POWER_SUPPLY_PROP_CURRENT_AVG,
112                                         &pval);
113                         if (rc < 0)
114                                 dev_err(pi->dev, "set usbtachg aicr fail\n");
115                         pval.intval = 500;
116                         rc = chg_psy->set_property(chg_psy,
117                                         POWER_SUPPLY_PROP_CURRENT_NOW,
118                                         &pval);
119                         if (rc < 0)
120                                 dev_err(pi->dev, "set usbtachg icc fail\n");
121                         pval.intval = POWER_SUPPLY_TYPE_USB_DCP;
122                         rc = chg_psy->set_property(chg_psy,
123                                         POWER_SUPPLY_PROP_CHARGE_NOW,
124                                         &pval);
125                         if (rc < 0)
126                                 dev_err(pi->dev, "set charge cable fail\n");
127                         if (!is_chg_on) {
128                                 pval.intval = pi->chg_volt;
129                                 rc = chg_psy->set_property(chg_psy,
130                                                 POWER_SUPPLY_PROP_VOLTAGE_NOW,
131                                                 &pval);
132                                 if (rc < 0)
133                                         dev_err(pi->dev,
134                                                 "set chg voltage fail\n");
135                                 pval.intval = 1;
136                                 rc = chg_psy->set_property(chg_psy,
137                                                 POWER_SUPPLY_PROP_ONLINE,
138                                                 &pval);
139                                 if (rc < 0)
140                                         dev_err(pi->dev,
141                                                 "set charger online fail\n");
142                         }
143                         pval.intval = 1;
144                         rc = chg_psy->set_property(chg_psy,
145                                                 POWER_SUPPLY_PROP_PRESENT,
146                                                 &pval);
147                         if (rc < 0)
148                                 dev_err(pi->dev, "set charger present fail\n");
149                 } else if (pi->usb_online) {
150                         pval.intval = pi->usbchg_icc;
151                         rc = chg_psy->set_property(chg_psy,
152                                         POWER_SUPPLY_PROP_CURRENT_AVG,
153                                         &pval);
154                         if (rc < 0)
155                                 dev_err(pi->dev, "set usbchg aicr fail\n");
156                         pval.intval = 500;
157                         rc = chg_psy->set_property(chg_psy,
158                                         POWER_SUPPLY_PROP_CURRENT_NOW,
159                                         &pval);
160                         if (rc < 0)
161                                 dev_err(pi->dev, "set usbchg icc fail\n");
162                         pval.intval = POWER_SUPPLY_TYPE_USB;
163                         rc = chg_psy->set_property(chg_psy,
164                                         POWER_SUPPLY_PROP_CHARGE_NOW,
165                                         &pval);
166                         if (rc < 0)
167                                 dev_err(pi->dev, "set charge cable fail\n");
168                         if (!is_chg_on) {
169                                 pval.intval = pi->chg_volt;
170                                 rc = chg_psy->set_property(chg_psy,
171                                                 POWER_SUPPLY_PROP_VOLTAGE_NOW,
172                                                 &pval);
173                                 if (rc < 0)
174                                         dev_err(pi->dev,
175                                                 "set chg voltage fail\n");
176                                 pval.intval = 1;
177                                 rc = chg_psy->set_property(chg_psy,
178                                                 POWER_SUPPLY_PROP_ONLINE,
179                                                 &pval);
180                                 if (rc < 0)
181                                         dev_err(pi->dev,
182                                                 "set charger online fail\n");
183                         }
184                         pval.intval = 1;
185                         rc = chg_psy->set_property(chg_psy,
186                                                    POWER_SUPPLY_PROP_PRESENT,
187                                                    &pval);
188                         if (rc < 0)
189                                 dev_err(pi->dev, "set charger present fail\n");
190                 } else {
191                         pval.intval = 0;
192                         rc = chg_psy->set_property(chg_psy,
193                                                    POWER_SUPPLY_PROP_ONLINE,
194                                                    &pval);
195                         if (rc < 0)
196                                 dev_err(pi->dev, "set charger online fail\n");
197                         pval.intval = 0;
198                         rc = chg_psy->set_property(chg_psy,
199                                                    POWER_SUPPLY_PROP_CHARGE_NOW,
200                                                    &pval);
201                         if (rc < 0)
202                                 dev_err(pi->dev, "set charge cable fail\n");
203                         pval.intval = pi->chg_volt;
204                         rc = chg_psy->set_property(chg_psy,
205                                         POWER_SUPPLY_PROP_VOLTAGE_NOW,
206                                         &pval);
207                         if (rc < 0)
208                                 dev_err(pi->dev, "set chg voltage fail\n");
209                         pval.intval = 500;
210                         rc = chg_psy->set_property(chg_psy,
211                                         POWER_SUPPLY_PROP_CURRENT_AVG,
212                                         &pval);
213                         if (rc < 0)
214                                 dev_err(pi->dev, "set chg aicr fail\n");
215                         pval.intval = 500;
216                         rc = chg_psy->set_property(chg_psy,
217                                         POWER_SUPPLY_PROP_CURRENT_NOW,
218                                         &pval);
219                         if (rc < 0)
220                                 dev_err(pi->dev, "set chg icc fail\n");
221                 }
222                 power_supply_changed(chg_psy);
223         } else {
224                 rc = -EINVAL;
225                 dev_err(pi->dev, "cannot get rt-charger psy\n");
226         }
227         return rc;
228 }
229
230 static int rtpower_get_property(struct power_supply *psy,
231                                 enum power_supply_property psp,
232                                 union power_supply_propval *val)
233 {
234         struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent);
235         int rc = 0;
236
237         switch (psp) {
238         case POWER_SUPPLY_PROP_ONLINE:
239                 if (psy->type == POWER_SUPPLY_TYPE_MAINS)
240                         val->intval = (pi->ac_online
241                                        || pi->usbta_online) ? 1 : 0;
242                 else if (psy->type == POWER_SUPPLY_TYPE_USB)
243                         val->intval = pi->usb_online;
244                 else
245                         rc = -EINVAL;
246                 break;
247         default:
248                 rc = -EINVAL;
249                 break;
250         }
251         return rc;
252 }
253
254 static int rtpower_set_property(struct power_supply *psy,
255                                 enum power_supply_property psp,
256                                 const union power_supply_propval *val)
257 {
258         struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent);
259         int rc = 0;
260
261         switch (psp) {
262         case POWER_SUPPLY_PROP_ONLINE:
263                 if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
264                         if (pi->ac_online != val->intval) {
265                                 pi->ac_online = val->intval;
266                                 rc = rtpower_set_charger(pi);
267                         }
268                 } else if (psy->type == POWER_SUPPLY_TYPE_USB) {
269                         if (pi->usb_online != val->intval) {
270                                 pi->usb_online = val->intval;
271                                 if (val->intval) {
272                                         pi->usbcnt = 0;
273                                         wake_lock(&pi->usbdet_wakelock);
274                                         schedule_delayed_work(&pi->usbdet_work,
275                                                               1 * HZ);
276                                 } else {
277                                         pi->usbcnt = RT_USBCNT_MAX;
278                                         schedule_delayed_work(&pi->usbdet_work,
279                                                               0);
280                                         if (pi->usbta_online) {
281                                                 pi->usbta_online = 0;
282                                                 power_supply_changed
283                                                     (&pi->ac_psy);
284                                         }
285                                 }
286                                 rc = rtpower_set_charger(pi);
287                         }
288                 } else {
289                                 rc = -EINVAL;
290                 }
291                 break;
292         default:
293                 rc = -EINVAL;
294                 break;
295         }
296         return rc;
297 }
298
299 extern int dwc_otg_check_dpdm(bool wait);
300 static void usbdet_work_func(struct work_struct *work)
301 {
302         struct rt_power_info *pi = container_of(work, struct rt_power_info, \
303                         usbdet_work.work);
304         int usb_det = dwc_otg_check_dpdm(0);
305
306         switch (usb_det) {
307         case 2:
308                 dev_info(pi->dev, "usb ta checked\n");
309                 if (pi->usb_online) {
310                         pi->usbta_online = 1;
311                         rtpower_set_charger(pi);
312                         power_supply_changed(&pi->ac_psy);
313                 }
314                 pi->usbcnt = RT_USBCNT_MAX;
315                 break;
316         case 1:
317         case 0:
318                 dev_info(pi->dev, "normal usb\n");
319                 break;
320         default:
321                 break;
322         }
323         if (pi->usbcnt < RT_USBCNT_MAX) {
324                 pi->usbcnt++;
325                 schedule_delayed_work(&pi->usbdet_work, 1*HZ);
326         } else {
327                 wake_unlock(&pi->usbdet_wakelock);
328         }
329 }
330
331 static int rt_power_probe(struct platform_device *pdev)
332 {
333         struct rt_power_info *pi;
334         struct rt_power_data *rt_power_pdata = pdev->dev.platform_data;
335         int ret = 0;
336
337         pi = devm_kzalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL);
338         if (!pi)
339                 return -ENOMEM;
340         pi->dev = &pdev->dev;
341         wake_lock_init(&pi->usbdet_wakelock, WAKE_LOCK_SUSPEND, "rt-usb-det");
342         INIT_DELAYED_WORK(&pi->usbdet_work, usbdet_work_func);
343         pi->chg_volt = rt_power_pdata->chg_volt;
344         pi->acchg_icc = rt_power_pdata->acchg_icc;
345         pi->usbtachg_icc = rt_power_pdata->usbtachg_icc;
346         pi->usbchg_icc = rt_power_pdata->usbchg_icc;
347         platform_set_drvdata(pdev, pi);
348
349         /* ac power supply register*/
350         pi->ac_psy.name = RT_AC_NAME;
351         pi->ac_psy.type = POWER_SUPPLY_TYPE_MAINS;
352         pi->ac_psy.supplied_to = rtpower_supply_list;
353         pi->ac_psy.properties = rtpower_props;
354         pi->ac_psy.num_properties = ARRAY_SIZE(rtpower_props);
355         pi->ac_psy.get_property = rtpower_get_property;
356         pi->ac_psy.set_property = rtpower_set_property;
357         ret = power_supply_register(&pdev->dev, &pi->ac_psy);
358         if (ret < 0) {
359                 dev_err(&pdev->dev, " create ac power supply fail\n");
360                 goto err_init;
361         }
362         /*usb power supply register*/
363         pi->usb_psy.name = RT_USB_NAME;
364         pi->usb_psy.type = POWER_SUPPLY_TYPE_USB;
365         pi->usb_psy.supplied_to = rtpower_supply_list;
366         pi->usb_psy.properties = rtpower_props;
367         pi->usb_psy.num_properties = ARRAY_SIZE(rtpower_props);
368         pi->usb_psy.get_property = rtpower_get_property;
369         pi->usb_psy.set_property = rtpower_set_property;
370         ret = power_supply_register(&pdev->dev, &pi->usb_psy);
371         if (ret < 0) {
372                 dev_err(&pdev->dev, " create usb power supply fail\n");
373                 goto err_acpsy;
374         }
375         return 0;
376
377 err_acpsy:
378         power_supply_unregister(&pi->ac_psy);
379 err_init:
380         wake_lock_destroy(&pi->usbdet_wakelock);
381         return ret;
382 }
383
384 static int rt_power_remove(struct platform_device *pdev)
385 {
386         struct rt_power_info *pi = platform_get_drvdata(pdev);
387
388         power_supply_unregister(&pi->usb_psy);
389         power_supply_unregister(&pi->ac_psy);
390         wake_lock_destroy(&pi->usbdet_wakelock);
391         return 0;
392 }
393
394 static int rt_power_suspend(struct platform_device *pdev, pm_message_t state)
395 {
396         struct rt_power_info *pi = platform_get_drvdata(pdev);
397
398         pi->suspend = 1;
399         return 0;
400 }
401
402 static int rt_power_resume(struct platform_device *pdev)
403 {
404         struct rt_power_info *pi = platform_get_drvdata(pdev);
405
406         pi->suspend = 0;
407         return 0;
408 }
409
410 static const struct of_device_id rt_match_table[] = {
411         { .compatible = "rt,rt-power",},
412         {},
413 };
414
415 static struct platform_driver rt_power_driver = {
416         .driver = {
417                 .name = "rt-power",
418                 .owner = THIS_MODULE,
419                 .of_match_table = rt_match_table,
420         },
421         .probe = rt_power_probe,
422         .remove = rt_power_remove,
423         .suspend = rt_power_suspend,
424         .resume = rt_power_resume,
425 };
426 static int rt_power_init(void)
427 {
428         return platform_driver_register(&rt_power_driver);
429 }
430 subsys_initcall(rt_power_init);
431
432 static void rt_power_exit(void)
433 {
434         platform_driver_unregister(&rt_power_driver);
435 }
436 module_exit(rt_power_exit);
437
438 MODULE_LICENSE("GPL");
439 MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
440 MODULE_DESCRIPTION("RT Power driver");
441 MODULE_ALIAS("platform:rt-power");
442 MODULE_VERSION("1.0.0_G");