aboutsummaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorJohan Palsson <johan.palsson@stericsson.com>2011-01-20 14:01:03 +0100
committerSrinidhi KASAGAR <srinidhi.kasagar@stericsson.com>2011-01-21 06:28:10 +0100
commit22dff6f0f30b30e9e0dd9f80e70a181dad2396ac (patch)
treea1d4fad013e473e1ec0046a7188baaa259c2ebaa /drivers/power
parent83a81bc90d08c07fb0c3a23654c34eb66549709d (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.c64
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) {