diff options
author | Johan Palsson <johan.palsson@stericsson.com> | 2011-01-20 14:01:03 +0100 |
---|---|---|
committer | Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | 2011-01-21 06:28:10 +0100 |
commit | 22dff6f0f30b30e9e0dd9f80e70a181dad2396ac (patch) | |
tree | a1d4fad013e473e1ec0046a7188baaa259c2ebaa /drivers/power | |
parent | 83a81bc90d08c07fb0c3a23654c34eb66549709d (diff) |
power: ab8500_bm: Low battery IRQ is now handled correctly
This patch fixes the problem with reporting 0% capacity once the low
battery IRQ has been triggered. We will allow single dips in
battery voltage without reporting 0% capacity
ST-Ericsson ID: ER320113
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I6e6a25c36c697c7401ac89a2c8569690d672c3b6
Signed-off-by: Johan Palsson <johan.palsson@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/13035
Reviewed-by: QATOOLS
Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/ab8500_fg.c | 64 |
1 files changed, 55 insertions, 9 deletions
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 542f304005b..8fcd08d4aee 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -35,6 +35,8 @@ #define NBR_AVG_SAMPLES 20 +#define LOW_BAT_CHECK_INTERVAL (2 * HZ) + #define interpolate(x, x1, y1, x2, y2) \ ((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1)))); @@ -101,6 +103,7 @@ struct ab8500_fg_flags { bool conv_done; bool charging; bool fully_charged; + bool low_bat_delay; bool low_bat; bool bat_ovv; }; @@ -130,6 +133,7 @@ struct ab8500_fg_flags { * @fg_psy: Structure that holds the FG specific battery properties * @fg_wq: Work queue for running the FG algorithm * @fg_periodic_work: Work to run the FG algorithm periodically + * @fg_low_bat_work: Work to check low bat condition * @fg_work: Work to run the FG algorithm instantly * @fg_acc_cur_work: Work to read the FG accumulator * @cc_lock: Mutex for locking the CC @@ -158,6 +162,7 @@ struct ab8500_fg { struct power_supply fg_psy; struct workqueue_struct *fg_wq; struct delayed_work fg_periodic_work; + struct delayed_work fg_low_bat_work; struct work_struct fg_work; struct work_struct fg_acc_cur_work; struct mutex cc_lock; @@ -877,6 +882,7 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) di->bat_cap.permille); di->bat_cap.prev_percent = di->bat_cap.permille / 10; di->bat_cap.prev_mah = di->bat_cap.mah; + changed = true; } else { dev_dbg(di->dev, "capacity not allowed to go up since " @@ -1178,6 +1184,44 @@ static void ab8500_fg_periodic_work(struct work_struct *work) } /** + * ab8500_fg_low_bat_work() - Check LOW_BAT condition + * @work: pointer to the work_struct structure + * + * Work queue function for checking the LOW_BAT condition + */ +static void ab8500_fg_low_bat_work(struct work_struct *work) +{ + int vbat; + + struct ab8500_fg *di = container_of(work, struct ab8500_fg, + fg_low_bat_work.work); + + vbat = ab8500_fg_bat_voltage(di); + + /* Check if LOW_BAT still fulfilled */ + if (vbat < di->bat->fg_params->lowbat_threshold) { + di->flags.low_bat = true; + dev_warn(di->dev, "Battery voltage still LOW\n"); + + /* + * We need to re-schedule this check to be able to detect + * if the voltage increases again during charging + */ + queue_delayed_work(di->fg_wq, &di->fg_low_bat_work, + round_jiffies(LOW_BAT_CHECK_INTERVAL)); + } else { + di->flags.low_bat = false; + dev_warn(di->dev, "Battery voltage OK again\n"); + } + + /* This is needed to dispatch LOW_BAT */ + ab8500_fg_check_capacity_limits(di, false); + + /* Set this flag to check if LOW_BAT IRQ still occurs */ + di->flags.low_bat_delay = false; +} + +/** * ab8500_fg_instant_work() - Run the FG state machine instantly * @work: pointer to the work_struct structure * @@ -1236,17 +1280,15 @@ static irqreturn_t ab8500_fg_lowbatf_handler(int irq, void *_di) { struct ab8500_fg *di = _di; - if (!di->flags.low_bat) { - dev_dbg(di->dev, "Battery voltage is below LOW threshold\n"); - + if (!di->flags.low_bat_delay) { + dev_warn(di->dev, "Battery voltage is below LOW threshold\n"); + di->flags.low_bat_delay = true; /* - * This flag is checked in ab8500_fg_capacity_level and - * POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL is propagated - * to the application framework + * Start a timer to check LOW_BAT again after some time + * This is done to avoid shutdown on single voltage dips */ - di->flags.low_bat = true; - - queue_work(di->fg_wq, &di->fg_work); + queue_delayed_work(di->fg_wq, &di->fg_low_bat_work, + round_jiffies(LOW_BAT_CHECK_INTERVAL)); } return IRQ_HANDLED; } @@ -1594,6 +1636,10 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) INIT_DELAYED_WORK_DEFERRABLE(&di->fg_periodic_work, ab8500_fg_periodic_work); + /* Work to check low battery condition */ + INIT_DELAYED_WORK_DEFERRABLE(&di->fg_low_bat_work, + ab8500_fg_low_bat_work); + /* Initialize OVV, and other registers */ ret = ab8500_fg_init_hw_registers(di); if (ret) { |