Commit 5bf2b994bfe11bfe86231050897b2d881ca544d9

Authored by Philipp Zabel
Committed by Anton Vorontsov
1 parent cc52a29e62

pda_power: Add optional OTG transceiver and voltage regulator support

This patch allows machines to use an OTG transceiver driver instead of
supplying a custom is_usb_online callback to check USB power.
Also, in the case that the OTG transceiver handles charger control when
connected to USB, a regulator named "ac_draw" can be supplied instead of
the custom set_charge callback to control the charger when connected to
AC.

The check for (transceiver->state == OTG_STATE_B_PERIPHERAL) in
otg_is_usb_online is probably too simple, I'm just using this with a
peripheral only device and gpio_vbus + bq24022. I'm not sure which other
OTG states can supply power.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>

Showing 2 changed files with 79 additions and 12 deletions Side-by-side Diff

drivers/power/pda_power.c
... ... @@ -12,11 +12,14 @@
12 12  
13 13 #include <linux/module.h>
14 14 #include <linux/platform_device.h>
  15 +#include <linux/err.h>
15 16 #include <linux/interrupt.h>
16 17 #include <linux/power_supply.h>
17 18 #include <linux/pda_power.h>
  19 +#include <linux/regulator/consumer.h>
18 20 #include <linux/timer.h>
19 21 #include <linux/jiffies.h>
  22 +#include <linux/usb/otg.h>
20 23  
21 24 static inline unsigned int get_irq_flags(struct resource *res)
22 25 {
... ... @@ -35,6 +38,11 @@
35 38 static struct timer_list polling_timer;
36 39 static int polling;
37 40  
  41 +#ifdef CONFIG_USB_OTG_UTILS
  42 +static struct otg_transceiver *transceiver;
  43 +#endif
  44 +static struct regulator *ac_draw;
  45 +
38 46 enum {
39 47 PDA_PSY_OFFLINE = 0,
40 48 PDA_PSY_ONLINE = 1,
41 49  
... ... @@ -104,18 +112,35 @@
104 112  
105 113 static void update_charger(void)
106 114 {
107   - if (!pdata->set_charge)
108   - return;
  115 + static int regulator_enabled;
  116 + int max_uA = pdata->ac_max_uA;
109 117  
110   - if (new_ac_status > 0) {
111   - dev_dbg(dev, "charger on (AC)\n");
112   - pdata->set_charge(PDA_POWER_CHARGE_AC);
113   - } else if (new_usb_status > 0) {
114   - dev_dbg(dev, "charger on (USB)\n");
115   - pdata->set_charge(PDA_POWER_CHARGE_USB);
116   - } else {
117   - dev_dbg(dev, "charger off\n");
118   - pdata->set_charge(0);
  118 + if (pdata->set_charge) {
  119 + if (new_ac_status > 0) {
  120 + dev_dbg(dev, "charger on (AC)\n");
  121 + pdata->set_charge(PDA_POWER_CHARGE_AC);
  122 + } else if (new_usb_status > 0) {
  123 + dev_dbg(dev, "charger on (USB)\n");
  124 + pdata->set_charge(PDA_POWER_CHARGE_USB);
  125 + } else {
  126 + dev_dbg(dev, "charger off\n");
  127 + pdata->set_charge(0);
  128 + }
  129 + } else if (ac_draw) {
  130 + if (new_ac_status > 0) {
  131 + regulator_set_current_limit(ac_draw, max_uA, max_uA);
  132 + if (!regulator_enabled) {
  133 + dev_dbg(dev, "charger on (AC)\n");
  134 + regulator_enable(ac_draw);
  135 + regulator_enabled = 1;
  136 + }
  137 + } else {
  138 + if (regulator_enabled) {
  139 + dev_dbg(dev, "charger off\n");
  140 + regulator_disable(ac_draw);
  141 + regulator_enabled = 0;
  142 + }
  143 + }
119 144 }
120 145 }
121 146  
... ... @@ -194,6 +219,13 @@
194 219 jiffies + msecs_to_jiffies(pdata->polling_interval));
195 220 }
196 221  
  222 +#ifdef CONFIG_USB_OTG_UTILS
  223 +static int otg_is_usb_online(void)
  224 +{
  225 + return (transceiver->state == OTG_STATE_B_PERIPHERAL);
  226 +}
  227 +#endif
  228 +
197 229 static int pda_power_probe(struct platform_device *pdev)
198 230 {
199 231 int ret = 0;
... ... @@ -227,6 +259,9 @@
227 259 if (!pdata->polling_interval)
228 260 pdata->polling_interval = 2000;
229 261  
  262 + if (!pdata->ac_max_uA)
  263 + pdata->ac_max_uA = 500000;
  264 +
230 265 setup_timer(&charger_timer, charger_timer_func, 0);
231 266 setup_timer(&supply_timer, supply_timer_func, 0);
232 267  
... ... @@ -240,6 +275,13 @@
240 275 pda_psy_usb.num_supplicants = pdata->num_supplicants;
241 276 }
242 277  
  278 + ac_draw = regulator_get(dev, "ac_draw");
  279 + if (IS_ERR(ac_draw)) {
  280 + dev_dbg(dev, "couldn't get ac_draw regulator\n");
  281 + ac_draw = NULL;
  282 + ret = PTR_ERR(ac_draw);
  283 + }
  284 +
243 285 if (pdata->is_ac_online) {
244 286 ret = power_supply_register(&pdev->dev, &pda_psy_ac);
245 287 if (ret) {
... ... @@ -261,6 +303,13 @@
261 303 }
262 304 }
263 305  
  306 +#ifdef CONFIG_USB_OTG_UTILS
  307 + transceiver = otg_get_transceiver();
  308 + if (transceiver && !pdata->is_usb_online) {
  309 + pdata->is_usb_online = otg_is_usb_online;
  310 + }
  311 +#endif
  312 +
264 313 if (pdata->is_usb_online) {
265 314 ret = power_supply_register(&pdev->dev, &pda_psy_usb);
266 315 if (ret) {
267 316  
... ... @@ -300,10 +349,18 @@
300 349 usb_supply_failed:
301 350 if (pdata->is_ac_online && ac_irq)
302 351 free_irq(ac_irq->start, &pda_psy_ac);
  352 +#ifdef CONFIG_USB_OTG_UTILS
  353 + if (transceiver)
  354 + otg_put_transceiver(transceiver);
  355 +#endif
303 356 ac_irq_failed:
304 357 if (pdata->is_ac_online)
305 358 power_supply_unregister(&pda_psy_ac);
306 359 ac_supply_failed:
  360 + if (ac_draw) {
  361 + regulator_put(ac_draw);
  362 + ac_draw = NULL;
  363 + }
307 364 if (pdata->exit)
308 365 pdata->exit(dev);
309 366 init_failed:
... ... @@ -327,6 +384,14 @@
327 384 power_supply_unregister(&pda_psy_usb);
328 385 if (pdata->is_ac_online)
329 386 power_supply_unregister(&pda_psy_ac);
  387 +#ifdef CONFIG_USB_OTG_UTILS
  388 + if (transceiver)
  389 + otg_put_transceiver(transceiver);
  390 +#endif
  391 + if (ac_draw) {
  392 + regulator_put(ac_draw);
  393 + ac_draw = NULL;
  394 + }
330 395 if (pdata->exit)
331 396 pdata->exit(dev);
332 397  
include/linux/pda_power.h
... ... @@ -31,6 +31,8 @@
31 31 unsigned int wait_for_status; /* msecs, default is 500 */
32 32 unsigned int wait_for_charger; /* msecs, default is 500 */
33 33 unsigned int polling_interval; /* msecs, default is 2000 */
  34 +
  35 + unsigned long ac_max_uA; /* current to draw when on AC */
34 36 };
35 37  
36 38 #endif /* __PDA_POWER_H__ */