diff options
-rw-r--r-- | drivers/power/pda_power.c | 147 |
1 files changed, 92 insertions, 55 deletions
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 35dc25973f3..d6c6dbc20e2 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -33,6 +33,16 @@ static struct resource *ac_irq, *usb_irq; static struct timer_list charger_timer; static struct timer_list supply_timer; +enum { + PDA_PSY_OFFLINE = 0, + PDA_PSY_ONLINE = 1, + PDA_PSY_TO_CHANGE, +}; +static int new_ac_status = -1; +static int new_usb_status = -1; +static int ac_status = -1; +static int usb_status = -1; + static int pda_power_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -61,36 +71,44 @@ static char *pda_power_supplied_to[] = { "backup-battery", }; -static struct power_supply pda_power_supplies[] = { - { - .name = "ac", - .type = POWER_SUPPLY_TYPE_MAINS, - .supplied_to = pda_power_supplied_to, - .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), - .properties = pda_power_props, - .num_properties = ARRAY_SIZE(pda_power_props), - .get_property = pda_power_get_property, - }, - { - .name = "usb", - .type = POWER_SUPPLY_TYPE_USB, - .supplied_to = pda_power_supplied_to, - .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), - .properties = pda_power_props, - .num_properties = ARRAY_SIZE(pda_power_props), - .get_property = pda_power_get_property, - }, +static struct power_supply pda_psy_ac = { + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .supplied_to = pda_power_supplied_to, + .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), + .properties = pda_power_props, + .num_properties = ARRAY_SIZE(pda_power_props), + .get_property = pda_power_get_property, +}; + +static struct power_supply pda_psy_usb = { + .name = "usb", + .type = POWER_SUPPLY_TYPE_USB, + .supplied_to = pda_power_supplied_to, + .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), + .properties = pda_power_props, + .num_properties = ARRAY_SIZE(pda_power_props), + .get_property = pda_power_get_property, }; +static void update_status(void) +{ + if (pdata->is_ac_online) + new_ac_status = !!pdata->is_ac_online(); + + if (pdata->is_usb_online) + new_usb_status = !!pdata->is_usb_online(); +} + static void update_charger(void) { if (!pdata->set_charge) return; - if (pdata->is_ac_online && pdata->is_ac_online()) { + if (new_ac_status > 0) { dev_dbg(dev, "charger on (AC)\n"); pdata->set_charge(PDA_POWER_CHARGE_AC); - } else if (pdata->is_usb_online && pdata->is_usb_online()) { + } else if (new_usb_status > 0) { dev_dbg(dev, "charger on (USB)\n"); pdata->set_charge(PDA_POWER_CHARGE_USB); } else { @@ -99,31 +117,53 @@ static void update_charger(void) } } -static void supply_timer_func(unsigned long power_supply_ptr) +static void supply_timer_func(unsigned long unused) { - void *power_supply = (void *)power_supply_ptr; + if (ac_status == PDA_PSY_TO_CHANGE) { + ac_status = new_ac_status; + power_supply_changed(&pda_psy_ac); + } - power_supply_changed(power_supply); + if (usb_status == PDA_PSY_TO_CHANGE) { + usb_status = new_usb_status; + power_supply_changed(&pda_psy_usb); + } } -static void charger_timer_func(unsigned long power_supply_ptr) +static void psy_changed(void) { update_charger(); - /* Okay, charger set. Now wait a bit before notifying supplicants, - * charge power should stabilize. */ - supply_timer.data = power_supply_ptr; + /* + * Okay, charger set. Now wait a bit before notifying supplicants, + * charge power should stabilize. + */ mod_timer(&supply_timer, jiffies + msecs_to_jiffies(pdata->wait_for_charger)); } +static void charger_timer_func(unsigned long unused) +{ + update_status(); + psy_changed(); +} + static irqreturn_t power_changed_isr(int irq, void *power_supply) { - /* Wait a bit before reading ac/usb line status and setting charger, - * because ac/usb status readings may lag from irq. */ - charger_timer.data = (unsigned long)power_supply; + if (power_supply == &pda_psy_ac) + ac_status = PDA_PSY_TO_CHANGE; + else if (power_supply == &pda_psy_usb) + usb_status = PDA_PSY_TO_CHANGE; + else + return IRQ_NONE; + + /* + * Wait a bit before reading ac/usb line status and setting charger, + * because ac/usb status readings may lag from irq. + */ mod_timer(&charger_timer, jiffies + msecs_to_jiffies(pdata->wait_for_status)); + return IRQ_HANDLED; } @@ -142,6 +182,7 @@ static int pda_power_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; + update_status(); update_charger(); if (!pdata->wait_for_status) @@ -155,31 +196,26 @@ static int pda_power_probe(struct platform_device *pdev) ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); - if (!ac_irq && !usb_irq) { - dev_err(dev, "no ac/usb irq specified\n"); - ret = -ENODEV; - goto noirqs; - } if (pdata->supplied_to) { - pda_power_supplies[0].supplied_to = pdata->supplied_to; - pda_power_supplies[1].supplied_to = pdata->supplied_to; - pda_power_supplies[0].num_supplicants = pdata->num_supplicants; - pda_power_supplies[1].num_supplicants = pdata->num_supplicants; + pda_psy_ac.supplied_to = pdata->supplied_to; + pda_psy_ac.num_supplicants = pdata->num_supplicants; + pda_psy_usb.supplied_to = pdata->supplied_to; + pda_psy_usb.num_supplicants = pdata->num_supplicants; } if (pdata->is_ac_online) { - ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); + ret = power_supply_register(&pdev->dev, &pda_psy_ac); if (ret) { dev_err(dev, "failed to register %s power supply\n", - pda_power_supplies[0].name); + pda_psy_ac.name); goto ac_supply_failed; } if (ac_irq) { ret = request_irq(ac_irq->start, power_changed_isr, get_irq_flags(ac_irq), ac_irq->name, - &pda_power_supplies[0]); + &pda_psy_ac); if (ret) { dev_err(dev, "request ac irq failed\n"); goto ac_irq_failed; @@ -188,18 +224,17 @@ static int pda_power_probe(struct platform_device *pdev) } if (pdata->is_usb_online) { - ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); + ret = power_supply_register(&pdev->dev, &pda_psy_usb); if (ret) { dev_err(dev, "failed to register %s power supply\n", - pda_power_supplies[1].name); + pda_psy_usb.name); goto usb_supply_failed; } if (usb_irq) { ret = request_irq(usb_irq->start, power_changed_isr, get_irq_flags(usb_irq), - usb_irq->name, - &pda_power_supplies[1]); + usb_irq->name, &pda_psy_usb); if (ret) { dev_err(dev, "request usb irq failed\n"); goto usb_irq_failed; @@ -213,15 +248,14 @@ static int pda_power_probe(struct platform_device *pdev) usb_irq_failed: if (pdata->is_usb_online) - power_supply_unregister(&pda_power_supplies[1]); + power_supply_unregister(&pda_psy_usb); usb_supply_failed: if (pdata->is_ac_online && ac_irq) - free_irq(ac_irq->start, &pda_power_supplies[0]); + free_irq(ac_irq->start, &pda_psy_ac); ac_irq_failed: if (pdata->is_ac_online) - power_supply_unregister(&pda_power_supplies[0]); + power_supply_unregister(&pda_psy_ac); ac_supply_failed: -noirqs: wrongid: return ret; } @@ -229,15 +263,18 @@ wrongid: static int pda_power_remove(struct platform_device *pdev) { if (pdata->is_usb_online && usb_irq) - free_irq(usb_irq->start, &pda_power_supplies[1]); + free_irq(usb_irq->start, &pda_psy_usb); if (pdata->is_ac_online && ac_irq) - free_irq(ac_irq->start, &pda_power_supplies[0]); + free_irq(ac_irq->start, &pda_psy_ac); + del_timer_sync(&charger_timer); del_timer_sync(&supply_timer); + if (pdata->is_usb_online) - power_supply_unregister(&pda_power_supplies[1]); + power_supply_unregister(&pda_psy_usb); if (pdata->is_ac_online) - power_supply_unregister(&pda_power_supplies[0]); + power_supply_unregister(&pda_psy_ac); + return 0; } |