summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerrit <chrome-bot@google.com>2012-03-02 22:43:09 -0800
committerGerrit Code Review <gerrit@gerrit.golo.chromium.org>2012-03-02 22:43:09 -0800
commitacfbecebe4c60917db3c83f5a725ca1a16838fbc (patch)
treedafa5525341ddacb07a5070a8ad42ecd625c6516
parentfe1f1c2d21a22e8fa8efcbdabdf9dafcd02b4e67 (diff)
parent1c70e29165120ce7f5f68c1faeb36ae9c81bcf9c (diff)
downloadchrome-ec-acfbecebe4c60917db3c83f5a725ca1a16838fbc.tar.gz
Merge "Add battery charge state machine and task"
-rw-r--r--board/link/board.h1
-rw-r--r--board/link/ec.tasklist3
-rw-r--r--common/battery_atl706486.c86
-rw-r--r--common/battery_pack.h24
-rw-r--r--common/build.mk3
-rw-r--r--common/charge_state.c365
-rw-r--r--include/smart_battery.h17
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(&current))
+ 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 */