diff options
-rw-r--r-- | common/battery.c | 3 | ||||
-rw-r--r-- | common/battery_bq27541.c | 22 | ||||
-rw-r--r-- | common/charge_state.c | 131 | ||||
-rw-r--r-- | common/smart_battery.c | 34 | ||||
-rw-r--r-- | include/battery.h | 13 | ||||
-rw-r--r-- | include/config.h | 11 |
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 */ |