summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2013-09-04 20:59:44 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-09-05 07:20:18 +0000
commit30136468c0352a2bcce1a948d9d5e9e4851b294d (patch)
tree0c2099448dbaa47949d82ab7d7bacb8d5d427956
parent0492ff9204a527b7cc9bbe84766d9507f52260a6 (diff)
downloadchrome-ec-30136468c0352a2bcce1a948d9d5e9e4851b294d.tar.gz
Extend charge state machine to accommodate Kirby
Currently only x86 platform uses charge_state.c, and it's been tailored to fit smart battery and bq247xx charger family. For Kirby, we have different types of battery and charger, and thus need to make some change to accommodate them. This includes: - Abstract out smart battery specific bit mask - Implement missing functions required by GAIA chipset module - Add config flags for charging-enabled GPIO pin - Allow battery that doesn't report desired voltage and current BUG=chrome-os-partner:22055 TEST=Build all boards TEST=Boot Link and check it charges/discharges battery TEST=Test charging/discharging on Kirby along with the next two CLs BRANCH=None Change-Id: I910c030a45b4f775afffec0127cdc31e89b9dd55 Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/168005
-rw-r--r--common/battery.c3
-rw-r--r--common/battery_bq27541.c22
-rw-r--r--common/charge_state.c131
-rw-r--r--common/smart_battery.c34
-rw-r--r--include/battery.h13
-rw-r--r--include/config.h11
6 files changed, 184 insertions, 30 deletions
diff --git a/common/battery.c b/common/battery.c
index f92f538727..0aaeb3ef79 100644
--- a/common/battery.c
+++ b/common/battery.c
@@ -88,7 +88,8 @@ static int print_battery_info(void)
if (check_print_error(battery_get_battery_mode(&value)))
ccprintf("0x%04x\n", value);
- unit = battery_is_in_10mw_mode() ? "0 mW" : " mAh";
+ battery_is_in_10mw_mode(&value);
+ unit = value ? "0 mW" : " mAh";
print_item_name("Charge:");
if (check_print_error(battery_state_of_charge(&value)))
diff --git a/common/battery_bq27541.c b/common/battery_bq27541.c
index 0389579002..f733e8b893 100644
--- a/common/battery_bq27541.c
+++ b/common/battery_bq27541.c
@@ -184,6 +184,17 @@ int battery_design_voltage(int *voltage)
return EC_ERROR_UNIMPLEMENTED;
}
+int battery_charging_allowed(int *allowed)
+{
+ int rv, val;
+
+ rv = bq27541_read(REG_FLAGS, &val);
+ if (rv)
+ return rv;
+ *allowed = (val & 0x100);
+ return EC_SUCCESS;
+}
+
int battery_desired_current(int *current)
{
return EC_ERROR_UNIMPLEMENTED;
@@ -194,8 +205,15 @@ int battery_get_battery_mode(int *mode)
return EC_ERROR_UNIMPLEMENTED;
}
-int battery_is_in_10mw_mode(void)
+int battery_is_in_10mw_mode(int *val)
{
/* Always using mAh unit */
- return 0;
+ *val = 0;
+ return EC_SUCCESS;
+}
+
+int battery_set_10mw_mode(int enabled)
+{
+ /* Not supported by this battery chip */
+ return EC_ERROR_INVAL;
}
diff --git a/common/charge_state.c b/common/charge_state.c
index c42a695837..02d670a7ed 100644
--- a/common/charge_state.c
+++ b/common/charge_state.c
@@ -34,6 +34,10 @@
/* Timeout after AP battery shutdown warning before we kill the AP */
#define LOW_BATTERY_SHUTDOWN_TIMEOUT_US (30 * SECOND)
+#ifndef BATTERY_AP_OFF_LEVEL
+#define BATTERY_AP_OFF_LEVEL 0
+#endif
+
static const char * const state_name[] = POWER_STATE_NAME_TABLE;
static int state_machine_force_idle = 0;
@@ -124,6 +128,74 @@ static void low_battery_shutdown(struct power_state_context *ctx)
}
}
+int charge_keep_power_off(void)
+{
+ int charge;
+
+ if (BATTERY_AP_OFF_LEVEL == 0)
+ return 0;
+
+ if (battery_remaining_capacity(&charge))
+ return charge_get_state() != PWR_STATE_ERROR;
+
+ return charge <= BATTERY_AP_OFF_LEVEL;
+}
+
+#ifdef CONFIG_CHARGER_EN_GPIO
+#ifdef CONFIG_CHARGER_EN_ACTIVE_LOW
+static void charge_set_charger_en_gpio(int level)
+{
+ gpio_set_level(GPIO_CHARGER_EN_L, !level);
+}
+
+static int charge_get_charger_en_gpio(void)
+{
+ return !gpio_get_level(GPIO_CHARGER_EN_L);
+}
+#else
+static void charge_set_charger_en_gpio(int level)
+{
+ gpio_set_level(GPIO_CHARGER_EN, level);
+}
+
+static int charge_get_charger_en_gpio(void)
+{
+ return gpio_get_level(GPIO_CHARGER_EN);
+}
+#endif
+#endif
+
+/**
+ * Enable or disable charging, and set requested voltage and current. If either
+ * of voltage and current is set to 0, charging is disable.
+ *
+ * @param voltage Requested voltage in mV. Set -1 to preserve current value.
+ * @param current Requested current in mA. Set -1 to preserve current value.
+ */
+static int charge_request(int voltage, int current)
+{
+ int rv = EC_SUCCESS;
+
+ if (voltage == -1 && current == -1)
+ return EC_SUCCESS;
+
+#ifdef CONFIG_CHARGER_EN_GPIO
+ if (voltage == 0 || current == 0) {
+ charge_set_charger_en_gpio(0);
+ return EC_SUCCESS;
+ } else {
+ charge_set_charger_en_gpio(1);
+ }
+#endif
+
+ if (voltage != -1)
+ rv |= charger_set_voltage(voltage);
+ if (current != -1)
+ rv |= charger_set_current(current);
+
+ return rv;
+}
+
/**
* Common handler for charging states.
*
@@ -160,15 +232,19 @@ static int state_common(struct power_state_context *ctx)
if (curr->ac) {
*batt_flags |= EC_BATT_FLAG_AC_PRESENT;
if (charger_get_voltage(&curr->charging_voltage)) {
- charger_set_voltage(0);
- charger_set_current(0);
+ charge_request(0, 0);
curr->error |= F_CHARGER_VOLTAGE;
}
if (charger_get_current(&curr->charging_current)) {
- charger_set_voltage(0);
- charger_set_current(0);
+ charge_request(0, 0);
curr->error |= F_CHARGER_CURRENT;
}
+#ifdef CONFIG_CHARGER_EN_GPIO
+ if (!charge_get_charger_en_gpio()) {
+ curr->charging_voltage = 0;
+ curr->charging_current = 0;
+ }
+#endif
} else {
*batt_flags &= ~EC_BATT_FLAG_AC_PRESENT;
/* AC disconnected should get us out of force idle mode. */
@@ -194,8 +270,8 @@ static int state_common(struct power_state_context *ctx)
* battery pack with minimum current and maximum
* voltage for 30 seconds.
*/
- charger_set_voltage(ctx->battery->voltage_max);
- charger_set_current(ctx->battery->precharge_current);
+ charge_request(ctx->battery->voltage_max,
+ ctx->battery->precharge_current);
for (d = 0; d < 30; d++) {
sleep(1);
rv = battery_temperature(&batt->temperature);
@@ -225,11 +301,24 @@ static int state_common(struct power_state_context *ctx)
*ctx->memmap_batt_rate = batt->current < 0 ?
-batt->current : batt->current;
- if (battery_desired_voltage(&batt->desired_voltage))
- curr->error |= F_DESIRED_VOLTAGE;
-
- if (battery_desired_current(&batt->desired_current))
- curr->error |= F_DESIRED_CURRENT;
+ if (battery_charging_allowed(&d)) {
+ curr->error |= F_DESIRED_VOLTAGE | F_DESIRED_CURRENT;
+ } else if (d) {
+ rv = battery_desired_voltage(&batt->desired_voltage);
+ if (rv == EC_ERROR_UNIMPLEMENTED)
+ batt->desired_voltage = ctx->charger->voltage_max;
+ else if (rv != EC_SUCCESS)
+ curr->error |= F_DESIRED_VOLTAGE;
+
+ rv = battery_desired_current(&batt->desired_current);
+ if (rv == EC_ERROR_UNIMPLEMENTED)
+ batt->desired_current = ctx->charger->current_max;
+ else if (rv != EC_SUCCESS)
+ curr->error |= F_DESIRED_CURRENT;
+ } else { /* Charging not allowed */
+ batt->desired_voltage = 0;
+ batt->desired_current = 0;
+ }
if (fake_state_of_charge >= 0)
batt->state_of_charge = fake_state_of_charge;
@@ -289,11 +378,11 @@ static int state_common(struct power_state_context *ctx)
if (batt->desired_current > user_current_limit)
batt->desired_current = user_current_limit;
- if (battery_get_battery_mode(&d)) {
+ if (battery_is_in_10mw_mode(&d)) {
curr->error |= F_BATTERY_MODE;
- } else if (d & MODE_CAPACITY) {
+ } else if (d) {
/* Battery capacity mode was set to mW; reset it back to mAh */
- if (battery_set_battery_mode(d & ~MODE_CAPACITY))
+ if (battery_set_10mw_mode(0))
ctx->curr.error |= F_BATTERY_MODE;
}
@@ -319,8 +408,7 @@ static int state_common(struct power_state_context *ctx)
static enum power_state state_init(struct power_state_context *ctx)
{
/* Stop charger, unconditionally */
- charger_set_current(0);
- charger_set_voltage(0);
+ charge_request(0, 0);
/* Update static battery info */
update_battery_info();
@@ -379,8 +467,7 @@ static enum power_state state_idle(struct power_state_context *ctx)
CPRINTF("[%T Charge start %dmV %dmA]\n",
batt->desired_voltage, want_current);
- if (charger_set_voltage(batt->desired_voltage) ||
- charger_set_current(want_current))
+ if (charge_request(batt->desired_voltage, want_current))
return PWR_STATE_ERROR;
update_charger_time(ctx, get_time());
@@ -421,7 +508,7 @@ static enum power_state state_charge(struct power_state_context *ctx)
return PWR_STATE_REINIT;
if (batt->state_of_charge >= BATTERY_LEVEL_FULL) {
- if (charger_set_voltage(0) || charger_set_current(0))
+ if (charge_request(0, 0))
return PWR_STATE_ERROR;
return PWR_STATE_IDLE;
}
@@ -437,7 +524,7 @@ static enum power_state state_charge(struct power_state_context *ctx)
if (want_voltage != curr->charging_voltage) {
CPRINTF("[%T Charge voltage %dmV]\n", want_voltage);
- if (charger_set_voltage(want_voltage))
+ if (charge_request(want_voltage, -1))
return PWR_STATE_ERROR;
update_charger_time(ctx, now);
}
@@ -465,7 +552,7 @@ static enum power_state state_charge(struct power_state_context *ctx)
want_current, batt->desired_voltage);
}
- if (charger_set_current(want_current))
+ if (charge_request(-1, want_current))
return PWR_STATE_ERROR;
/* Update charger watchdog timer and debounce timer */
@@ -519,6 +606,8 @@ static enum power_state state_error(struct power_state_context *ctx)
return PWR_STATE_REINIT;
}
+ charge_request(0, 0);
+
/* Debug output */
if (ctx->curr.error != logged_error) {
CPRINTF("[%T Charge error: flag[%08b -> %08b], ac %d, "
diff --git a/common/smart_battery.c b/common/smart_battery.c
index 04f1eafb63..ef9136ee00 100644
--- a/common/smart_battery.c
+++ b/common/smart_battery.c
@@ -42,11 +42,27 @@ int battery_set_battery_mode(int mode)
return sb_write(SB_BATTERY_MODE, mode);
}
-int battery_is_in_10mw_mode(void)
+int battery_is_in_10mw_mode(int *ret)
{
int val;
- battery_get_battery_mode(&val);
- return val & MODE_CAPACITY;
+ int rv = battery_get_battery_mode(&val);
+ if (rv)
+ return rv;
+ *ret = val & MODE_CAPACITY;
+ return EC_SUCCESS;
+}
+
+int battery_set_10mw_mode(int enabled)
+{
+ int val, rv;
+ rv = battery_get_battery_mode(&val);
+ if (rv)
+ return rv;
+ if (enabled)
+ val |= MODE_CAPACITY;
+ else
+ val &= ~MODE_CAPACITY;
+ return battery_set_battery_mode(val);
}
/* Read battery temperature
@@ -124,6 +140,18 @@ int battery_desired_voltage(int *voltage)
return sb_read(SB_CHARGING_VOLTAGE, voltage);
}
+/* Check if battery allows charging */
+int battery_charging_allowed(int *allowed)
+{
+ int v, c, rv;
+
+ rv = battery_desired_voltage(&v) | battery_desired_current(&c);
+ if (rv)
+ return rv;
+ *allowed = (v != 0) && (c != 0);
+ return EC_SUCCESS;
+}
+
/* Read battery status */
int battery_status(int *status)
{
diff --git a/include/battery.h b/include/battery.h
index 39a7aea0d1..c5177d6cae 100644
--- a/include/battery.h
+++ b/include/battery.h
@@ -54,9 +54,13 @@ int battery_state_of_charge(int *percent);
int battery_state_of_charge_abs(int *percent);
/*
- * Return non-zero if the battery is reporting capacity in 10mW.
- * Otherwise, in mAh. */
-int battery_is_in_10mw_mode(void);
+ * Set 'val' to non-zero if the battery is reporting capacity in 10mW.
+ * Otherwise, in mAh.
+ */
+int battery_is_in_10mw_mode(int *val);
+
+/* Set battery capacity mode to mAh(=0) or 10mW(=1). */
+int battery_set_10mw_mode(int enabled);
/*
* Battery remaining capacity
@@ -85,6 +89,9 @@ int battery_desired_current(int *current);
*/
int battery_desired_voltage(int *voltage);
+/* Check if battery allows charging */
+int battery_charging_allowed(int *allowed);
+
/* Read battery status */
int battery_status(int *status);
diff --git a/include/config.h b/include/config.h
index 60911d7bc2..d46ae943f2 100644
--- a/include/config.h
+++ b/include/config.h
@@ -152,6 +152,17 @@
*/
#undef CONFIG_CHARGER_TIMEOUT_HOURS
+/*
+ * Board has an GPIO pin to enable or disable charging.
+ *
+ * This GPIO should be named GPIO_CHARGER_EN, if active high. Or
+ * GPIO_CHARGER_EN_L if active low.
+ */
+#undef CONFIG_CHARGER_EN_GPIO
+
+/* Charger enable GPIO is active low */
+#undef CONFIG_CHARGER_EN_ACTIVE_LOW
+
/*****************************************************************************/
/* Chipset config */