summaryrefslogtreecommitdiff
path: root/common/pmu_tps65090_charger.c
diff options
context:
space:
mode:
authorRong Chang <rongchang@chromium.org>2012-08-15 04:48:34 +0800
committerGerrit <chrome-bot@google.com>2012-08-16 03:36:19 -0700
commitcebbe4c0e708be36140c8c0fdce45a106f824650 (patch)
tree365ddbf198f5b87046241d7607e0af928e755602 /common/pmu_tps65090_charger.c
parent9c45a309b9d462358dfecd4713340ea23d9f12f2 (diff)
downloadchrome-ec-cebbe4c0e708be36140c8c0fdce45a106f824650.tar.gz
daisy: Modify charging flow to comply charging specification
This change corrects charger interrupt event handling, charger enable gpio, battery full condition, EC deep sleep mode support when AC unplugged, and lid controlled power off. Signed-off-by: Rong Chang <rongchang@chromium.org> BRANCH=snow BUG=chrome-os-partner:12573,12574,12575 TEST=manual - ec console command 'gpioget': - SPI1_MISO should be 0 when AP off - CHARGER_EN should be 0 after AC unplugged - charging led should be off after AC unplugged - when battery remaining charge < 3%, system should be powered off without AC. - ec console command 'sleepmask 0', turn off AP: - deep sleep only when AC unplugged Change-Id: I0f63835dae67d90de7a8c8c6c3537ca9a16faed4 Reviewed-on: https://gerrit.chromium.org/gerrit/30316 Commit-Ready: Rong Chang <rongchang@chromium.org> Reviewed-by: Rong Chang <rongchang@chromium.org> Tested-by: Rong Chang <rongchang@chromium.org>
Diffstat (limited to 'common/pmu_tps65090_charger.c')
-rw-r--r--common/pmu_tps65090_charger.c219
1 files changed, 148 insertions, 71 deletions
diff --git a/common/pmu_tps65090_charger.c b/common/pmu_tps65090_charger.c
index 29f6dda19c..c717216b88 100644
--- a/common/pmu_tps65090_charger.c
+++ b/common/pmu_tps65090_charger.c
@@ -6,8 +6,10 @@
*/
#include "board.h"
+#include "clock.h"
#include "chipset.h"
#include "console.h"
+#include "hooks.h"
#include "gpio.h"
#include "pmu_tpschrome.h"
#include "smart_battery.h"
@@ -25,13 +27,18 @@
ALARM_OVER_CHARGED | \
ALARM_OVER_TEMP)
+/* Maximum retry count to revive a extremely low charge battery */
+#define PRE_CHARGING_RETRY 3
/* Time delay in usec for idle, charging and discharging.
* Defined in battery charging flow.
*/
-#define T1_USEC 5000000
-#define T2_USEC 10000000
-#define T3_USEC 10000000
+#define SECOND (1000 * 1000)
+#define T1_OFF_USEC (60 * SECOND)
+#define T1_SUSPEND_USEC (60 * SECOND)
+#define T1_USEC (5 * SECOND)
+#define T2_USEC (10 * SECOND)
+#define T3_USEC (10 * SECOND)
/* Non-SBS charging states */
enum charging_state {
@@ -84,24 +91,6 @@ static int battery_discharging_range(int t)
return (t < 70);
}
-static int wait_t1_idle(void)
-{
- usleep(T1_USEC);
- return ST_IDLE;
-}
-
-static int wait_t2_charging(void)
-{
- usleep(T2_USEC);
- return ST_CHARGING;
-}
-
-static int wait_t3_discharging(void)
-{
- usleep(T3_USEC);
- return ST_DISCHARGING;
-}
-
/*
* Turn off the host application processor
*/
@@ -109,10 +98,8 @@ static int system_off(void)
{
if (chipset_in_state(CHIPSET_STATE_ON)) {
CPUTS("[pmu] turn system off\n");
- chipset_exit_hard_off();
-
- /* TODO(rongchang): After have impl in chipset_exit_hard_off(),
- * remove these gpio hack
+ /* TODO(rongchang): need chipset_force_hard_off(),
+ * and remove these gpio hack
*/
gpio_set_level(GPIO_EN_PP3300, 0);
gpio_set_level(GPIO_EN_PP1350, 0);
@@ -120,7 +107,7 @@ static int system_off(void)
gpio_set_level(GPIO_EN_PP5000, 0);
}
- return wait_t1_idle();
+ return ST_IDLE;
}
/*
@@ -142,72 +129,82 @@ static int notify_battery_low(void)
return ST_DISCHARGING;
}
+static int config_low_current_charging(int charge)
+{
+ /* Disable low current termination */
+ if (charge < 40)
+ return pmu_low_current_charging(1);
+
+ /* Enable low current termination */
+ if (charge > 60)
+ return pmu_low_current_charging(0);
+
+ return EC_SUCCESS;
+}
+
static int calc_next_state(int state)
{
int batt_temp, alarm, capacity, charge;
switch (state) {
case ST_IDLE:
-
/* Check AC and chiset state */
if (!pmu_get_ac()) {
if (chipset_in_state(CHIPSET_STATE_ON))
return ST_DISCHARGING;
-
- /* Enable charging and wait ac on */
- enable_charging(1);
- return wait_t1_idle();
+ return ST_IDLE;
}
/* Enable charging when battery doesn't respond */
if (battery_temperature(&batt_temp)) {
- enable_charging(1);
- wait_t1_idle();
+ if (config_low_current_charging(0))
+ return ST_IDLE;
return ST_PRE_CHARGING;
}
/* Turn off charger when battery temperature is out
* of the start charging range.
*/
- if (!battery_start_charging_range(batt_temp)) {
- enable_charging(0);
- return wait_t1_idle();
- }
+ if (!battery_start_charging_range(batt_temp))
+ return ST_IDLE;
/* Turn off charger on battery charging alarm */
- if (battery_status(&alarm) || (alarm & ALARM_CHARGING)) {
- if (!(alarm & ALARM_TERMINATE_CHARGE))
- CPRINTF("[pmu] idle %016b\n", alarm);
- enable_charging(0);
- return wait_t1_idle();
- }
+ if (battery_status(&alarm) || (alarm & ALARM_CHARGING))
+ return ST_IDLE;
/* Start charging only when battery charge lower than 100% */
- if (!battery_state_of_charge(&charge) && charge < 100) {
- enable_charging(1);
- wait_t1_idle();
- return ST_CHARGING;
+ if (!battery_state_of_charge(&charge)) {
+ config_low_current_charging(charge);
+ if (charge < 100)
+ return ST_CHARGING;
}
- return wait_t1_idle();
+ return ST_IDLE;
case ST_PRE_CHARGING:
if (!pmu_get_ac())
- return wait_t1_idle();
+ return ST_IDLE;
/* If the battery goes online after enable the charger,
* go into charging state.
*/
- if (battery_temperature(&batt_temp) == EC_SUCCESS)
+ if (battery_temperature(&batt_temp) == EC_SUCCESS) {
+ if (!battery_start_charging_range(batt_temp))
+ return ST_IDLE;
+ if (!battery_state_of_charge(&charge)) {
+ config_low_current_charging(charge);
+ if (charge >= 100)
+ return ST_IDLE;
+ }
return ST_CHARGING;
+ }
- wait_t1_idle();
return ST_PRE_CHARGING;
case ST_CHARGING:
/* Go back to idle state when AC is unplugged */
if (!pmu_get_ac())
- break;
+ return ST_IDLE;
/*
* Disable charging on battery access error, or charging
@@ -216,14 +213,12 @@ static int calc_next_state(int state)
if (battery_temperature(&batt_temp)) {
CPUTS("[pmu] charging: unable to get battery "
"temperature\n");
- enable_charging(0);
- break;
+ return ST_IDLE;
} else if (!battery_charging_range(batt_temp)) {
CPRINTF("[pmu] charging: temperature out of range "
"%dC\n",
battery_temperature_celsius(batt_temp));
- enable_charging(0);
- break;
+ return ST_IDLE;
}
/*
@@ -233,8 +228,7 @@ static int calc_next_state(int state)
*/
if (battery_status(&alarm) || (alarm & ALARM_CHARGING)) {
CPUTS("[pmu] charging: battery alarm\n");
- enable_charging(0);
- break;
+ return ST_IDLE;
}
/*
@@ -244,16 +238,19 @@ static int calc_next_state(int state)
*/
if (pmu_is_charger_alarm()) {
CPUTS("[pmu] charging: charger alarm\n");
- enable_charging(0);
- break;
+ return ST_IDLE;
}
- return wait_t2_charging();
+ return ST_CHARGING;
case ST_DISCHARGING:
/* Go back to idle state when AC is plugged */
if (pmu_get_ac())
- return wait_t1_idle();
+ return ST_IDLE;
+
+ /* Prepare EC sleep after system stopped discharging */
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ return ST_IDLE;
/* Check battery discharging temperature range */
if (battery_temperature(&batt_temp) == 0) {
@@ -261,7 +258,6 @@ static int calc_next_state(int state)
CPRINTF("[pmu] discharging: temperature out of"
"range %dC\n",
battery_temperature_celsius(batt_temp));
- enable_charging(0);
return system_off();
}
}
@@ -269,36 +265,117 @@ static int calc_next_state(int state)
if (!battery_status(&alarm) && (alarm & ALARM_DISCHARGING)) {
CPRINTF("[pmu] discharging: battery alarm %016b\n",
alarm);
- enable_charging(0);
return system_off();
}
/* Check remaining charge % */
- if (battery_state_of_charge(&capacity) == 0 && capacity < 10)
- return notify_battery_low();
+ if (battery_state_of_charge(&capacity) == 0) {
+ if (capacity < 3) {
+ system_off();
+ return ST_IDLE;
+ } else if (capacity < 10) {
+ notify_battery_low();
+ }
+ }
- return wait_t3_discharging();
+ return ST_DISCHARGING;
}
- return wait_t1_idle();
+ return ST_IDLE;
}
void pmu_charger_task(void)
{
int state = ST_IDLE;
int next_state;
+ int event = 0;
+ int wait_time = T1_USEC;
+ unsigned int pre_charging_count = 0;
+
+ pmu_init();
+ /*
+ * EC STOP mode support
+ * The charging loop can be stopped in idle state with AC unplugged.
+ * Charging loop will be resumed by TPSCHROME interrupt.
+ */
+ enable_charging(0);
+ disable_sleep(SLEEP_MASK_CHARGING);
while (1) {
pmu_clear_irq();
- next_state = calc_next_state(state);
+ /*
+ * When battery is extremely low, the internal voltage can not
+ * power on its gas guage IC. Charging loop will enable the
+ * charger and turn on trickle charging. For safty reason,
+ * charger should be disabled if the communication to battery
+ * failed.
+ */
+ next_state = pre_charging_count > PRE_CHARGING_RETRY ?
+ calc_next_state(ST_IDLE) :
+ calc_next_state(state);
+
if (next_state != state) {
+ pre_charging_count = 0;
CPRINTF("[batt] state %s -> %s\n",
state_list[state],
state_list[next_state]);
state = next_state;
+ if (state == ST_PRE_CHARGING || state == ST_CHARGING)
+ enable_charging(1);
+ else
+ enable_charging(0);
}
- /* TODO(sjg@chromium.org): root cause crosbug.com/p/11285 */
- task_wait_event(5000 * 1000);
+ switch (state) {
+ case ST_CHARGING:
+ wait_time = T2_USEC;
+ break;
+ case ST_DISCHARGING:
+ wait_time = T3_USEC;
+ break;
+ case ST_PRE_CHARGING:
+ wait_time = T1_USEC;
+ if (pre_charging_count > PRE_CHARGING_RETRY)
+ enable_charging(0);
+ else
+ pre_charging_count++;
+ break;
+ default:
+ if (pmu_get_ac()) {
+ wait_time = T1_USEC;
+ break;
+ } else if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ wait_time = T1_OFF_USEC;
+ enable_sleep(SLEEP_MASK_CHARGING);
+ } else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
+ wait_time = T1_SUSPEND_USEC;
+ } else {
+ wait_time = T1_USEC;
+ }
+ }
+
+ /*
+ * Throttle the charging loop. If previous loop was waked up
+ * by an event, sleep 0.5 seconds instead of wait for next
+ * event.
+ */
+ if (event & TASK_EVENT_WAKE) {
+ usleep(0.5 * SECOND);
+ event = 0;
+ } else {
+ event = task_wait_event(wait_time);
+ disable_sleep(SLEEP_MASK_CHARGING);
+ }
}
}
+
+/* Wake charging task on chipset events */
+static int pmu_chipset_events(void)
+{
+ task_wake(TASK_ID_PMU_TPS65090_CHARGER);
+ return 0;
+}
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, pmu_chipset_events, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, pmu_chipset_events, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, pmu_chipset_events, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, pmu_chipset_events, HOOK_PRIO_DEFAULT);