power: bq24617: Fix scenario where charge indication is missed
authorGreg Meiste <w30289@motorola.com>
Wed, 26 Jan 2011 19:38:37 +0000 (13:38 -0600)
committerColin Cross <ccross@android.com>
Thu, 27 Jan 2011 01:34:50 +0000 (17:34 -0800)
On Stingray, the charge STAT pins are not connected to a wakeup
source.  Therefore, if the device enters LP0 after the charger is
detected, but before charging begins, charging will never be
reported to the UI since the edge on STAT1 is missed.  The device
is actually charging, but to see the indication, the charger would
have to be removed and re-inserted.  In addition, if charge
complete is reached while in LP0, the edge on STAT2 is missed, and
the UI never shows charge complete.  These issues were resolved by
adding a resume function to the driver.

In addition, the work function and wake_lock was removed from the
driver because the same functionality exists in the power supply
core driver.

Change-Id: Ieaeaf2b47adec21f51bd77910427d74780cb865d
Signed-off-by: Greg Meiste <w30289@motorola.com>
drivers/power/bq24617_charger.c

index 1e89da6937e4a8bc3b3811f6c628a9a704d0dc52..ef70b053e7c72e113b1ccd46e8e705388af9f1f6 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/wakelock.h>
 
 struct bq24617_data {
-       struct work_struct work;
        int stat1_irq;
        int stat2_irq;
        int detect_irq;
-       struct wake_lock wake_lock;
        struct power_supply ac;
        int ac_online;
 };
@@ -67,20 +63,8 @@ static int power_get_property(struct power_supply *psy,
        return 0;
 }
 
-static irqreturn_t bq24617_isr(int irq, void *data)
+static void bq24617_read_status(struct bq24617_data *bq_data)
 {
-       struct bq24617_data *bq_data = data;
-
-       wake_lock(&bq_data->wake_lock);
-       schedule_work(&bq_data->work);
-
-       return IRQ_HANDLED;
-}
-
-static void bq24617_work(struct work_struct *work)
-{
-       struct bq24617_data *bq_data =
-               container_of(work, struct bq24617_data, work);
        int detect = 0;
 
        /* STAT1 indicates charging, STAT2 indicates charge complete */
@@ -100,7 +84,14 @@ static void bq24617_work(struct work_struct *work)
                detect);
 
        power_supply_changed(&bq_data->ac);
-       wake_unlock(&bq_data->wake_lock);
+}
+
+static irqreturn_t bq24617_isr(int irq, void *data)
+{
+       struct bq24617_data *bq_data = data;
+
+       bq24617_read_status(bq_data);
+       return IRQ_HANDLED;
 }
 
 static int bq24617_probe(struct platform_device *pdev)
@@ -113,8 +104,6 @@ static int bq24617_probe(struct platform_device *pdev)
        if (bq_data == NULL)
                return -ENOMEM;
 
-       INIT_WORK(&bq_data->work, bq24617_work);
-       wake_lock_init(&bq_data->wake_lock, WAKE_LOCK_SUSPEND, "bq24617");
        platform_set_drvdata(pdev, bq_data);
 
        bq_data->stat1_irq = platform_get_irq_byname(pdev, "stat1");
@@ -174,7 +163,7 @@ static int bq24617_probe(struct platform_device *pdev)
                enable_irq_wake(bq_data->detect_irq);
        }
 
-       bq24617_work(&bq_data->work);
+       bq24617_read_status(bq_data);
 
        return 0;
 
@@ -185,7 +174,6 @@ free_stat2:
 free_stat1:
        free_irq(bq_data->stat1_irq, bq_data);
 free_mem:
-       wake_lock_destroy(&bq_data->wake_lock);
        kfree(bq_data);
 
        return retval;
@@ -195,7 +183,6 @@ static int bq24617_remove(struct platform_device *pdev)
 {
        struct bq24617_data *bq_data = platform_get_drvdata(pdev);
 
-       cancel_work_sync(&bq_data->work);
        power_supply_unregister(&bq_data->ac);
 
        free_irq(bq_data->stat1_irq, bq_data);
@@ -203,15 +190,33 @@ static int bq24617_remove(struct platform_device *pdev)
        if (bq_data->detect_irq >= 0)
                free_irq(bq_data->detect_irq, bq_data);
 
-       wake_lock_destroy(&bq_data->wake_lock);
        kfree(bq_data);
 
        return 0;
 }
 
+static int bq24617_resume(struct device *dev)
+{
+       struct bq24617_data *bq_data = dev_get_drvdata(dev);
+       int stat1 = gpio_get_value(irq_to_gpio(bq_data->stat1_irq));
+       int stat2 = gpio_get_value(irq_to_gpio(bq_data->stat2_irq));
+
+       if ((stat1 != bq24617_stat1_value) || (stat2 != bq24617_stat2_value)) {
+               pr_debug("%s: STAT pins changed while suspended\n", __func__);
+               bq24617_read_status(bq_data);
+       }
+
+       return 0;
+}
+
+static struct dev_pm_ops bq24617_pm_ops = {
+       .resume = bq24617_resume,
+};
+
 static struct platform_driver bq24617_pdrv = {
        .driver = {
                .name = "bq24617",
+               .pm = &bq24617_pm_ops,
        },
        .probe = bq24617_probe,
        .remove = bq24617_remove,