Skip to content

Commit

Permalink
pda_power: Add optional OTG transceiver and voltage regulator support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Philipp Zabel authored and Anton Vorontsov committed Feb 2, 2009
1 parent cc52a29 commit 5bf2b99
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 12 deletions.
89 changes: 77 additions & 12 deletions drivers/power/pda_power.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
#include <linux/pda_power.h>
#include <linux/regulator/consumer.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/usb/otg.h>

static inline unsigned int get_irq_flags(struct resource *res)
{
Expand All @@ -35,6 +38,11 @@ static struct timer_list supply_timer;
static struct timer_list polling_timer;
static int polling;

#ifdef CONFIG_USB_OTG_UTILS
static struct otg_transceiver *transceiver;
#endif
static struct regulator *ac_draw;

enum {
PDA_PSY_OFFLINE = 0,
PDA_PSY_ONLINE = 1,
Expand Down Expand Up @@ -104,18 +112,35 @@ static void update_status(void)

static void update_charger(void)
{
if (!pdata->set_charge)
return;

if (new_ac_status > 0) {
dev_dbg(dev, "charger on (AC)\n");
pdata->set_charge(PDA_POWER_CHARGE_AC);
} else if (new_usb_status > 0) {
dev_dbg(dev, "charger on (USB)\n");
pdata->set_charge(PDA_POWER_CHARGE_USB);
} else {
dev_dbg(dev, "charger off\n");
pdata->set_charge(0);
static int regulator_enabled;
int max_uA = pdata->ac_max_uA;

if (pdata->set_charge) {
if (new_ac_status > 0) {
dev_dbg(dev, "charger on (AC)\n");
pdata->set_charge(PDA_POWER_CHARGE_AC);
} else if (new_usb_status > 0) {
dev_dbg(dev, "charger on (USB)\n");
pdata->set_charge(PDA_POWER_CHARGE_USB);
} else {
dev_dbg(dev, "charger off\n");
pdata->set_charge(0);
}
} else if (ac_draw) {
if (new_ac_status > 0) {
regulator_set_current_limit(ac_draw, max_uA, max_uA);
if (!regulator_enabled) {
dev_dbg(dev, "charger on (AC)\n");
regulator_enable(ac_draw);
regulator_enabled = 1;
}
} else {
if (regulator_enabled) {
dev_dbg(dev, "charger off\n");
regulator_disable(ac_draw);
regulator_enabled = 0;
}
}
}
}

Expand Down Expand Up @@ -194,6 +219,13 @@ static void polling_timer_func(unsigned long unused)
jiffies + msecs_to_jiffies(pdata->polling_interval));
}

#ifdef CONFIG_USB_OTG_UTILS
static int otg_is_usb_online(void)
{
return (transceiver->state == OTG_STATE_B_PERIPHERAL);
}
#endif

static int pda_power_probe(struct platform_device *pdev)
{
int ret = 0;
Expand Down Expand Up @@ -227,6 +259,9 @@ static int pda_power_probe(struct platform_device *pdev)
if (!pdata->polling_interval)
pdata->polling_interval = 2000;

if (!pdata->ac_max_uA)
pdata->ac_max_uA = 500000;

setup_timer(&charger_timer, charger_timer_func, 0);
setup_timer(&supply_timer, supply_timer_func, 0);

Expand All @@ -240,6 +275,13 @@ static int pda_power_probe(struct platform_device *pdev)
pda_psy_usb.num_supplicants = pdata->num_supplicants;
}

ac_draw = regulator_get(dev, "ac_draw");
if (IS_ERR(ac_draw)) {
dev_dbg(dev, "couldn't get ac_draw regulator\n");
ac_draw = NULL;
ret = PTR_ERR(ac_draw);
}

if (pdata->is_ac_online) {
ret = power_supply_register(&pdev->dev, &pda_psy_ac);
if (ret) {
Expand All @@ -261,6 +303,13 @@ static int pda_power_probe(struct platform_device *pdev)
}
}

#ifdef CONFIG_USB_OTG_UTILS
transceiver = otg_get_transceiver();
if (transceiver && !pdata->is_usb_online) {
pdata->is_usb_online = otg_is_usb_online;
}
#endif

if (pdata->is_usb_online) {
ret = power_supply_register(&pdev->dev, &pda_psy_usb);
if (ret) {
Expand Down Expand Up @@ -300,10 +349,18 @@ static int pda_power_probe(struct platform_device *pdev)
usb_supply_failed:
if (pdata->is_ac_online && ac_irq)
free_irq(ac_irq->start, &pda_psy_ac);
#ifdef CONFIG_USB_OTG_UTILS
if (transceiver)
otg_put_transceiver(transceiver);
#endif
ac_irq_failed:
if (pdata->is_ac_online)
power_supply_unregister(&pda_psy_ac);
ac_supply_failed:
if (ac_draw) {
regulator_put(ac_draw);
ac_draw = NULL;
}
if (pdata->exit)
pdata->exit(dev);
init_failed:
Expand All @@ -327,6 +384,14 @@ static int pda_power_remove(struct platform_device *pdev)
power_supply_unregister(&pda_psy_usb);
if (pdata->is_ac_online)
power_supply_unregister(&pda_psy_ac);
#ifdef CONFIG_USB_OTG_UTILS
if (transceiver)
otg_put_transceiver(transceiver);
#endif
if (ac_draw) {
regulator_put(ac_draw);
ac_draw = NULL;
}
if (pdata->exit)
pdata->exit(dev);

Expand Down
2 changes: 2 additions & 0 deletions include/linux/pda_power.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct pda_power_pdata {
unsigned int wait_for_status; /* msecs, default is 500 */
unsigned int wait_for_charger; /* msecs, default is 500 */
unsigned int polling_interval; /* msecs, default is 2000 */

unsigned long ac_max_uA; /* current to draw when on AC */
};

#endif /* __PDA_POWER_H__ */

0 comments on commit 5bf2b99

Please sign in to comment.