summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */