twl4030_charger: remember to clean up USB regulator
[pandora-kernel.git] / drivers / power / twl4030_charger.c
index fe36810..575407a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/usb/otg.h>
 #include <linux/ratelimit.h>
 #include <linux/regulator/machine.h>
+#include <linux/leds.h>
 
 #define TWL4030_BCIMSTATEC     0x02
 #define TWL4030_BCIICHG                0x08
@@ -101,6 +102,9 @@ struct twl4030_bci {
        int                     irq_check_count;
        int                     irq_check_ac_disabled;
 
+       struct led_trigger      *charging_any_trig;
+       int                     was_charging_any;
+
        unsigned long           event;
        struct ratelimit_state  ratelimit;
 };
@@ -665,7 +669,8 @@ static int twl4030_bci_get_property(struct power_supply *psy,
                                    union power_supply_propval *val)
 {
        struct twl4030_bci *bci = dev_get_drvdata(psy->dev->parent);
-       int is_charging;
+       int is_charging_any = 0;
+       int is_charging = 0;
        int state;
        int ret;
 
@@ -673,10 +678,22 @@ static int twl4030_bci_get_property(struct power_supply *psy,
        if (state < 0)
                return state;
 
-       if (psy->type == POWER_SUPPLY_TYPE_USB)
-               is_charging = state & TWL4030_MSTATEC_USB;
-       else
-               is_charging = state & TWL4030_MSTATEC_AC;
+       if (twl4030_bci_state_to_status(state) ==
+           POWER_SUPPLY_STATUS_CHARGING) {
+               is_charging_any =
+                       state & (TWL4030_MSTATEC_USB | TWL4030_MSTATEC_AC);
+               if (psy->type == POWER_SUPPLY_TYPE_USB)
+                       is_charging = state & TWL4030_MSTATEC_USB;
+               else
+                       is_charging = state & TWL4030_MSTATEC_AC;
+       }
+
+       if (is_charging_any != bci->was_charging_any) {
+               led_trigger_event(bci->charging_any_trig,
+                       is_charging_any ? LED_FULL : LED_OFF);
+               bci->was_charging_any = is_charging_any;
+       }
+
        if (is_charging && psy->type != bci->current_supply) {
                if (psy->type == POWER_SUPPLY_TYPE_USB)
                        set_charge_current(bci, bci->usb_current);
@@ -758,7 +775,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
        bci->irq_chg = platform_get_irq(pdev, 0);
        bci->irq_bci = platform_get_irq(pdev, 1);
        bci->ac_current = 860; /* ~1.2A */
-       bci->usb_current = 360; /* ~600mA */
+       bci->usb_current = 330; /* ~560mA */
        bci->irq_had_charger = -1;
        bci->irq_check_count_time = jiffies;
 
@@ -766,6 +783,9 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
        ratelimit_state_init(&bci->ratelimit, HZ, 2);
 
+       led_trigger_register_simple("twl4030_bci-charging",
+               &bci->charging_any_trig);
+
        bci->ac.name = "twl4030_ac";
        bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
        bci->ac.properties = twl4030_charger_props;
@@ -875,7 +895,15 @@ fail_chg_irq:
        power_supply_unregister(&bci->usb);
 fail_register_usb:
        power_supply_unregister(&bci->ac);
+
+       if (bci->usb_reg) {
+               if (bci->usb_enabled)
+                       regulator_disable(bci->usb_reg);
+               regulator_put(bci->usb_reg);
+       }
+
 fail_register_ac:
+       led_trigger_unregister_simple(bci->charging_any_trig);
        platform_set_drvdata(pdev, NULL);
        kfree(bci);
 
@@ -906,6 +934,14 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
        free_irq(bci->irq_chg, bci);
        power_supply_unregister(&bci->usb);
        power_supply_unregister(&bci->ac);
+
+       if (bci->usb_reg) {
+               if (bci->usb_enabled)
+                       regulator_disable(bci->usb_reg);
+               regulator_put(bci->usb_reg);
+       }
+
+       led_trigger_unregister_simple(bci->charging_any_trig);
        platform_set_drvdata(pdev, NULL);
        kfree(bci);