diff options
author | Philipp Zabel <philipp.zabel@gmail.com> | 2009-01-18 11:40:27 -0500 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2009-02-02 12:15:47 -0500 |
commit | 5bf2b994bfe11bfe86231050897b2d881ca544d9 (patch) | |
tree | dcd098222aab1385a24cc68e34967c8ffb71b665 /drivers/power | |
parent | cc52a29e6245acd9032fcfa0ffcab4cc612de986 (diff) |
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>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/pda_power.c | 89 |
1 files changed, 77 insertions, 12 deletions
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index b56a704409d2..a232de6a5703 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c | |||
@@ -12,11 +12,14 @@ | |||
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/err.h> | ||
15 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
16 | #include <linux/power_supply.h> | 17 | #include <linux/power_supply.h> |
17 | #include <linux/pda_power.h> | 18 | #include <linux/pda_power.h> |
19 | #include <linux/regulator/consumer.h> | ||
18 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
19 | #include <linux/jiffies.h> | 21 | #include <linux/jiffies.h> |
22 | #include <linux/usb/otg.h> | ||
20 | 23 | ||
21 | static inline unsigned int get_irq_flags(struct resource *res) | 24 | static inline unsigned int get_irq_flags(struct resource *res) |
22 | { | 25 | { |
@@ -35,6 +38,11 @@ static struct timer_list supply_timer; | |||
35 | static struct timer_list polling_timer; | 38 | static struct timer_list polling_timer; |
36 | static int polling; | 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 | enum { | 46 | enum { |
39 | PDA_PSY_OFFLINE = 0, | 47 | PDA_PSY_OFFLINE = 0, |
40 | PDA_PSY_ONLINE = 1, | 48 | PDA_PSY_ONLINE = 1, |
@@ -104,18 +112,35 @@ static void update_status(void) | |||
104 | 112 | ||
105 | static void update_charger(void) | 113 | static void update_charger(void) |
106 | { | 114 | { |
107 | if (!pdata->set_charge) | 115 | static int regulator_enabled; |
108 | return; | 116 | int max_uA = pdata->ac_max_uA; |
109 | 117 | ||
110 | if (new_ac_status > 0) { | 118 | if (pdata->set_charge) { |
111 | dev_dbg(dev, "charger on (AC)\n"); | 119 | if (new_ac_status > 0) { |
112 | pdata->set_charge(PDA_POWER_CHARGE_AC); | 120 | dev_dbg(dev, "charger on (AC)\n"); |
113 | } else if (new_usb_status > 0) { | 121 | pdata->set_charge(PDA_POWER_CHARGE_AC); |
114 | dev_dbg(dev, "charger on (USB)\n"); | 122 | } else if (new_usb_status > 0) { |
115 | pdata->set_charge(PDA_POWER_CHARGE_USB); | 123 | dev_dbg(dev, "charger on (USB)\n"); |
116 | } else { | 124 | pdata->set_charge(PDA_POWER_CHARGE_USB); |
117 | dev_dbg(dev, "charger off\n"); | 125 | } else { |
118 | pdata->set_charge(0); | 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 @@ static void polling_timer_func(unsigned long unused) | |||
194 | jiffies + msecs_to_jiffies(pdata->polling_interval)); | 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 | static int pda_power_probe(struct platform_device *pdev) | 229 | static int pda_power_probe(struct platform_device *pdev) |
198 | { | 230 | { |
199 | int ret = 0; | 231 | int ret = 0; |
@@ -227,6 +259,9 @@ static int pda_power_probe(struct platform_device *pdev) | |||
227 | if (!pdata->polling_interval) | 259 | if (!pdata->polling_interval) |
228 | pdata->polling_interval = 2000; | 260 | pdata->polling_interval = 2000; |
229 | 261 | ||
262 | if (!pdata->ac_max_uA) | ||
263 | pdata->ac_max_uA = 500000; | ||
264 | |||
230 | setup_timer(&charger_timer, charger_timer_func, 0); | 265 | setup_timer(&charger_timer, charger_timer_func, 0); |
231 | setup_timer(&supply_timer, supply_timer_func, 0); | 266 | setup_timer(&supply_timer, supply_timer_func, 0); |
232 | 267 | ||
@@ -240,6 +275,13 @@ static int pda_power_probe(struct platform_device *pdev) | |||
240 | pda_psy_usb.num_supplicants = pdata->num_supplicants; | 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 | if (pdata->is_ac_online) { | 285 | if (pdata->is_ac_online) { |
244 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); | 286 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); |
245 | if (ret) { | 287 | if (ret) { |
@@ -261,6 +303,13 @@ static int pda_power_probe(struct platform_device *pdev) | |||
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 | if (pdata->is_usb_online) { | 313 | if (pdata->is_usb_online) { |
265 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); | 314 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); |
266 | if (ret) { | 315 | if (ret) { |
@@ -300,10 +349,18 @@ usb_irq_failed: | |||
300 | usb_supply_failed: | 349 | usb_supply_failed: |
301 | if (pdata->is_ac_online && ac_irq) | 350 | if (pdata->is_ac_online && ac_irq) |
302 | free_irq(ac_irq->start, &pda_psy_ac); | 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 | ac_irq_failed: | 356 | ac_irq_failed: |
304 | if (pdata->is_ac_online) | 357 | if (pdata->is_ac_online) |
305 | power_supply_unregister(&pda_psy_ac); | 358 | power_supply_unregister(&pda_psy_ac); |
306 | ac_supply_failed: | 359 | ac_supply_failed: |
360 | if (ac_draw) { | ||
361 | regulator_put(ac_draw); | ||
362 | ac_draw = NULL; | ||
363 | } | ||
307 | if (pdata->exit) | 364 | if (pdata->exit) |
308 | pdata->exit(dev); | 365 | pdata->exit(dev); |
309 | init_failed: | 366 | init_failed: |
@@ -327,6 +384,14 @@ static int pda_power_remove(struct platform_device *pdev) | |||
327 | power_supply_unregister(&pda_psy_usb); | 384 | power_supply_unregister(&pda_psy_usb); |
328 | if (pdata->is_ac_online) | 385 | if (pdata->is_ac_online) |
329 | power_supply_unregister(&pda_psy_ac); | 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 | if (pdata->exit) | 395 | if (pdata->exit) |
331 | pdata->exit(dev); | 396 | pdata->exit(dev); |
332 | 397 | ||