diff options
author | Gerrit <chrome-bot@google.com> | 2012-03-02 22:43:09 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@gerrit.golo.chromium.org> | 2012-03-02 22:43:09 -0800 |
commit | acfbecebe4c60917db3c83f5a725ca1a16838fbc (patch) | |
tree | dafa5525341ddacb07a5070a8ad42ecd625c6516 | |
parent | fe1f1c2d21a22e8fa8efcbdabdf9dafcd02b4e67 (diff) | |
parent | 1c70e29165120ce7f5f68c1faeb36ae9c81bcf9c (diff) | |
download | chrome-ec-acfbecebe4c60917db3c83f5a725ca1a16838fbc.tar.gz |
Merge "Add battery charge state machine and task"
-rw-r--r-- | board/link/board.h | 1 | ||||
-rw-r--r-- | board/link/ec.tasklist | 3 | ||||
-rw-r--r-- | common/battery_atl706486.c | 86 | ||||
-rw-r--r-- | common/battery_pack.h | 24 | ||||
-rw-r--r-- | common/build.mk | 3 | ||||
-rw-r--r-- | common/charge_state.c | 365 | ||||
-rw-r--r-- | include/smart_battery.h | 17 |
7 files changed, 497 insertions, 2 deletions
diff --git a/board/link/board.h b/board/link/board.h index aaa17d7ee2..5c9bacc158 100644 --- a/board/link/board.h +++ b/board/link/board.h @@ -81,6 +81,7 @@ enum adc_channel /* Battery module */ #define CONFIG_SMART_BATTERY +#define CONFIG_BATTERY_ATL706486 /* I2C ports */ #define I2C_PORT_BATTERY 0 diff --git a/board/link/ec.tasklist b/board/link/ec.tasklist index a2d83316af..a02023e820 100644 --- a/board/link/ec.tasklist +++ b/board/link/ec.tasklist @@ -23,4 +23,5 @@ TASK(X86POWER, x86_power_task, NULL) \ TASK(CONSOLE, console_task, NULL) \ TASK(HOSTCMD, host_command_task, NULL) \ - TASK(I8042CMD, i8042_command_task, NULL) + TASK(I8042CMD, i8042_command_task, NULL) \ + TASK(POWERSTATE, charge_state_machine_task, NULL) diff --git a/common/battery_atl706486.c b/common/battery_atl706486.c new file mode 100644 index 0000000000..1bf973a7c7 --- /dev/null +++ b/common/battery_atl706486.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Battery pack vendor provided charging profile for ATL706486 + */ + +#include "battery_pack.h" + +/* Convert Celsius degree to Deci Kelvin degree */ +static inline int celsius_to_deci_kelvin(int degree_c) +{ + return degree_c * 10 + 2731; +} + +static inline void limit_value(int *val, int limit) +{ + if (*val > limit) + *val = limit; +} + +/* Vendor provided parameters for battery charging */ +void battery_vendor_params(struct batt_params *batt) +{ + /* Designed capacity + * Battery capacity = 8400 mAh + * 1C = 8400 mA + */ + const int C = 8400; + const int C_01 = C * 0.1; + const int C_02 = C * 0.2; + const int C_05 = C * 0.5; + const int C_07 = C * 0.7; + + /* Designed voltage + * max = 8.4V + * normal = 7.4V + */ + const int V_max = 8400; + + /* Operation temperation range + * 0 <= T_charge <= 45 + * -20 <= T_discharge <= 60 + */ + const int T_charge_min = 0; + const int T_charge_max = 45; + + int *desired_current = &batt->desired_current; + + /* Hard limits + * - charging voltage < 8.4V + * - charging temperature range 0 ~ 45 degree Celcius + * */ + if (batt->desired_voltage > V_max) + batt->desired_voltage = V_max; + if (batt->temperature >= celsius_to_deci_kelvin(T_charge_max) || + batt->temperature <= celsius_to_deci_kelvin(T_charge_min)) { + batt->desired_voltage = 0; + batt->desired_current = 0; + } + + /* Vendor provided charging method + * temp : I - V , I - V + * - 0 ~ 10 : 0.2C - 8.0V, 0.1C to 8.4V + * - 10 ~ 23 : 0.5C - 8.0V, 0.2C to 8.4V + * - 23 ~ 45 : 0.7C - 8.0V, 0.2C to 8.4V + */ + if (batt->temperature <= celsius_to_deci_kelvin(10)) { + if (batt->voltage < 8000) + limit_value(desired_current, C_02); + else + limit_value(desired_current, C_01); + } else if (batt->temperature <= celsius_to_deci_kelvin(23)) { + if (batt->voltage < 8000) + limit_value(desired_current, C_05); + else + limit_value(desired_current, C_02); + } else { + if (batt->voltage < 8000) + limit_value(desired_current, C_07); + else + limit_value(desired_current, C_02); + } +} + + diff --git a/common/battery_pack.h b/common/battery_pack.h new file mode 100644 index 0000000000..25ec8595c0 --- /dev/null +++ b/common/battery_pack.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Common API for battery pack vendor provided charging profile + */ +#ifndef __CROS_EC_BATTERY_PACK_H +#define __CROS_EC_BATTERY_PACK_H + +/* Battery parameters */ +struct batt_params { + int temperature; + int state_of_charge; + int voltage; + int current; + int desired_voltage; + int desired_current; +}; + +/* Vendor provided parameters for battery charging */ +void battery_vendor_params(struct batt_params *batt); + +#endif //__CROS_EC_BATTERY_PACK_H + diff --git a/common/build.mk b/common/build.mk index 82a49bf079..b3bddde5e1 100644 --- a/common/build.mk +++ b/common/build.mk @@ -23,4 +23,5 @@ common-$(CONFIG_LIGHTBAR)+=leds.o # Board driver modules common-$(CONFIG_CHARGER_BQ24725)+=charger_bq24725.o -common-$(CONFIG_SMART_BATTERY)+=smart_battery.o +common-$(CONFIG_BATTERY_ATL706486)+=battery_atl706486.o +common-$(CONFIG_SMART_BATTERY)+=smart_battery.o charge_state.o diff --git a/common/charge_state.c b/common/charge_state.c new file mode 100644 index 0000000000..d721fab5dc --- /dev/null +++ b/common/charge_state.c @@ -0,0 +1,365 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Battery charging task and state machine. + */ + + +#include "battery_pack.h" +#include "board.h" +#include "console.h" +#include "charger.h" +#include "gpio.h" +#include "smart_battery.h" +#include "timer.h" +#include "uart.h" +#include "util.h" + +/* Stop charge when state of charge reaches this percentage */ +#define STOP_CHARGE_THRESHOLD 100 + +/* power state task polling period in usec */ +#define POLL_PERIOD_LONG 500000 +#define POLL_PERIOD_CHARGE 250000 +#define POLL_PERIOD_SHORT 100000 +#define MIN_SLEEP_USEC 50000 + +/* Power states */ +enum power_state { + PWR_STATE_UNCHANGE = 0, + PWR_STATE_INIT, + PWR_STATE_IDLE, + PWR_STATE_DISCHARGE, + PWR_STATE_CHARGE, + PWR_STATE_ERROR +}; +/* Debugging constants, in the same order as power_state. + * This state name table and debug print will be removed + * before production. + */ +const static char *_state_name[] = { + "null", + "init", + "idle", + "discharge", + "charge", + "error" +}; + + +/* helper function(s) */ +static inline int get_ac(void) +{ + return gpio_get_level(GPIO_AC_PRESENT); +} + +/* Get battery charging parameters from battery and + * battery pack vendor table + */ +static int battery_params(struct batt_params *batt) +{ + int rv; + rv = battery_temperature(&batt->temperature); + if (rv) + return rv; + rv = battery_voltage(&batt->voltage); + if (rv) + return rv; + rv = battery_current(&batt->current); + if (rv) + return rv; + rv = battery_desired_voltage(&batt->desired_voltage); + if (rv) + return rv; + rv = battery_desired_current(&batt->desired_current); + if (rv) + return rv; + + battery_vendor_params(batt); + + return EC_SUCCESS; +} + +/* Init state handler + * - check ac, charger, battery and temperature + * - initialize charger + * - new states: DISCHARGE, IDLE + */ +static enum power_state state_init(void) +{ + int rv, val; + + /* Stop charger, unconditionally */ + charger_set_current(0); + charger_set_voltage(0); + + /* Detect AC, init charger */ + if (!get_ac()) + return PWR_STATE_DISCHARGE; + + /* Initialize charger to power on reset mode */ + rv = charger_post_init(); + if (rv) + return PWR_STATE_ERROR; + /* Check if charger is online */ + rv = charger_get_status(&val); + if (rv) + return PWR_STATE_ERROR; + + /* Detect battery */ + if (battery_temperature(&val)) + return PWR_STATE_ERROR; + + return PWR_STATE_IDLE; +} + +/* Idle state handler + * - both charger and battery are online + * - detect charger and battery status change + * - new states: CHARGE, INIT + */ +static enum power_state state_idle(void) +{ + int voltage, current, state_of_charge; + struct batt_params batt; + + if (!get_ac()) + return PWR_STATE_INIT; + + /* Prevent charging in idle mode */ + if (charger_get_voltage(&voltage)) + return PWR_STATE_ERROR; + if (charger_get_current(¤t)) + return PWR_STATE_ERROR; + if (voltage || current) + return PWR_STATE_INIT; + + if (battery_state_of_charge(&state_of_charge)) + return PWR_STATE_ERROR; + + if (state_of_charge >= STOP_CHARGE_THRESHOLD) + return PWR_STATE_UNCHANGE; + + /* Check if the batter is good to charge */ + if (battery_params(&batt)) + return PWR_STATE_ERROR; + + /* Configure init charger state and switch to charge state */ + if (batt.desired_voltage && batt.desired_current) { + if (charger_set_voltage(batt.desired_voltage)) + return PWR_STATE_ERROR; + if (charger_set_current(batt.desired_current)) + return PWR_STATE_ERROR; + return PWR_STATE_CHARGE; + } + + return PWR_STATE_UNCHANGE; +} + +/* Charge state handler + * - detect battery status change + * - new state: INIT + */ +static enum power_state state_charge(void) +{ + int chg_voltage, chg_current; + struct batt_params batt; + + if (!get_ac()) + return PWR_STATE_INIT; + + if (charger_get_voltage(&chg_voltage)) + return PWR_STATE_ERROR; + if (charger_get_current(&chg_current)) + return PWR_STATE_ERROR; + /* Check charger reset */ + if (chg_voltage == 0 || chg_current == 0) + return PWR_STATE_INIT; + + if (battery_params(&batt)) + return PWR_STATE_ERROR; + + if (batt.desired_voltage != chg_voltage) + if (charger_set_voltage(batt.desired_voltage)) + return PWR_STATE_ERROR; + if (batt.desired_current != chg_current) + if (charger_set_current(batt.desired_current)) + return PWR_STATE_ERROR; + + if (battery_state_of_charge(&batt.state_of_charge)) + return PWR_STATE_ERROR; + + if (batt.state_of_charge >= STOP_CHARGE_THRESHOLD) { + if (charger_set_voltage(0) || charger_set_current(0)) + return PWR_STATE_ERROR; + return PWR_STATE_IDLE; + } + + return PWR_STATE_UNCHANGE; +} + +/* Discharge state handler + * - detect ac status + * - new state: INIT + */ +static enum power_state state_discharge(void) +{ + if (get_ac()) + return PWR_STATE_INIT; + + /* TODO: handle overtemp in discharge mode */ + + return PWR_STATE_UNCHANGE; +} + +/* Error state handler + * - check charger and battery communication + * - log error + * - new state: INIT + */ +static enum power_state state_error(void) +{ + enum { F_CHG_V, F_CHG_I, F_BAT_V, F_BAT_I, + F_DES_V, F_DES_I, F_BAT_T, F_LAST }; + static int last_error_flags; + int error_flags = 0; + int ac = 0; + int bat_v = -1, bat_i = -1, bat_temp = -1; + int desired_v = -1, desired_i = -1; + + ac = get_ac(); + if (ac) { + if (charger_set_voltage(0)) + error_flags |= (1 << F_CHG_V); + if (charger_set_current(0)) + error_flags |= (1 << F_CHG_I); + } + + if (battery_voltage(&bat_v)) + error_flags |= (1 << F_BAT_V); + if (battery_current(&bat_i)) + error_flags |= (1 << F_BAT_I); + if (battery_temperature(&bat_temp)) + error_flags |= (1 << F_BAT_T); + if (battery_desired_voltage(&desired_v)) + error_flags |= (1 << F_DES_V); + if (battery_desired_current(&desired_i)) + error_flags |= (1 << F_DES_I); + + if (error_flags == 0) { + last_error_flags = 0; + return PWR_STATE_INIT; + } + + if (error_flags != last_error_flags) { + uart_printf("errors : %02x\n", error_flags); + uart_printf("previous : %02x\n", last_error_flags); + last_error_flags = error_flags; + uart_printf("ac : %d\n", ac); + uart_puts("charger\n"); + if (ac) + if (error_flags & (F_CHG_V | F_CHG_I)) + uart_puts(" error\n"); + else + uart_puts(" ok\n"); + else + uart_puts(" offline\n"); + + uart_puts("battery\n"); + uart_printf(" voltage: %d\n", bat_v); + uart_printf(" current: %d\n", bat_i); + uart_printf(" temp : %d\n", bat_temp); + uart_printf(" des_vol: %d\n", desired_v); + uart_printf(" des_cur: %d\n", desired_i); + } + + return PWR_STATE_UNCHANGE; +} + +static void charging_progress(void) +{ + static int state_of_charge; + int d; + + if (battery_state_of_charge(&d)) + return; + + if (d != state_of_charge) { + state_of_charge = d; + if (get_ac()) + battery_time_to_full(&d); + else + battery_time_to_empty(&d); + + uart_printf("[Battery %3d%% / %dh:%d]\n", state_of_charge, + d / 60, d % 60); + } + +} + +/* Battery charging task */ +void charge_state_machine_task(void) +{ + timestamp_t prev_ts, ts; + int sleep_usec, diff_usec; + enum power_state current_state, new_state; + + prev_ts.val = 0; + current_state = PWR_STATE_INIT; + + while (1) { + ts = get_time(); + + switch (current_state) { + case PWR_STATE_INIT: + new_state = state_init(); + break; + case PWR_STATE_IDLE: + new_state = state_idle(); + break; + case PWR_STATE_DISCHARGE: + new_state = state_discharge(); + break; + case PWR_STATE_CHARGE: + new_state = state_charge(); + break; + case PWR_STATE_ERROR: + new_state = state_error(); + break; + default: + new_state = PWR_STATE_ERROR; + } + + if (new_state) + uart_printf("CHARGE: %s --> %s\n", + _state_name[current_state], + _state_name[new_state]); + + switch (new_state) { + case PWR_STATE_IDLE: + case PWR_STATE_DISCHARGE: + sleep_usec = POLL_PERIOD_LONG; + break; + case PWR_STATE_CHARGE: + sleep_usec = POLL_PERIOD_CHARGE; + break; + default: + sleep_usec = POLL_PERIOD_SHORT; + } + + diff_usec = (int)(ts.val - prev_ts.val); + sleep_usec -= diff_usec; + if (sleep_usec < MIN_SLEEP_USEC) + sleep_usec = MIN_SLEEP_USEC; + + prev_ts = ts; + usleep(sleep_usec); + + if (new_state) + current_state = new_state; + + charging_progress(); + } +} + diff --git a/include/smart_battery.h b/include/smart_battery.h index 0d45fae937..916de76898 100644 --- a/include/smart_battery.h +++ b/include/smart_battery.h @@ -225,5 +225,22 @@ static inline int battery_design_voltage(int *voltage) static inline int battery_serial_number(int *serial) { return sb_read(SB_SERIAL_NUMBER, serial); } +/* Read battery discharging current + * unit: mA + * negative value: charging + */ +int battery_current(int *current); +int battery_average_current(int *current); + +/* Calculate battery time in minutes, under a charging rate + * rate > 0: charging, negative time to full + * rate < 0: discharging, positive time to empty + * rate == 0: invalid input, time = 0 + */ +int battery_time_at_rate(int rate, int *minutes); + +/* Read manufacturer date */ +int battery_manufacturer_date(int *year, int *month, int *day); + #endif /* __CROS_EC_SMART_BATTERY_H */ |