From f5cfb505dc2f0123fdc053c100ce634b89036f8c Mon Sep 17 00:00:00 2001 From: Mary Ruthven Date: Tue, 5 Jan 2021 15:24:32 -0800 Subject: coil: remove charge_state_v2 This code uses coil terms we're removing, but we don't use it in platform/cr50. Remove the code instead of replacing the terms. BUG=b:175244613 TEST=make buildall -j Change-Id: I6b6004255f951497c5fc3d61e40b67433498a9d6 Signed-off-by: Mary Ruthven Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2613139 Reviewed-by: Namyoon Woo --- board/host/battery.c | 82 -- board/host/build.mk | 1 - board/host/charger.c | 152 --- common/build.mk | 2 - common/charge_ramp.c | 56 - common/charge_ramp_sw.c | 383 ------ common/charge_state_v2.c | 2644 ------------------------------------ common/charger.c | 211 --- common/charger_profile_override.c | 201 --- common/i2c_master.c | 1 - common/lightbar.c | 1 - include/charge_ramp.h | 89 -- include/charge_state.h | 154 --- include/charge_state_v2.h | 134 -- include/charger.h | 162 --- include/charger_detect.h | 17 - include/charger_profile_override.h | 86 -- 17 files changed, 4376 deletions(-) delete mode 100644 board/host/battery.c delete mode 100644 board/host/charger.c delete mode 100644 common/charge_ramp.c delete mode 100644 common/charge_ramp_sw.c delete mode 100644 common/charge_state_v2.c delete mode 100644 common/charger.c delete mode 100644 common/charger_profile_override.c delete mode 100644 include/charge_ramp.h delete mode 100644 include/charge_state.h delete mode 100644 include/charge_state_v2.h delete mode 100644 include/charger.h delete mode 100644 include/charger_detect.h delete mode 100644 include/charger_profile_override.h diff --git a/board/host/battery.c b/board/host/battery.c deleted file mode 100644 index 1228485ab7..0000000000 --- a/board/host/battery.c +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright 2013 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. - * - * Smart battery driver. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "common.h" -#include "console.h" -#include "test_util.h" -#include "util.h" - -static uint16_t mock_smart_battery[SB_MANUFACTURER_DATA + 1]; - -int sb_i2c_xfer(int port, uint16_t slave_addr_flags, - const uint8_t *out, int out_size, - uint8_t *in, int in_size, int flags) -{ - if (out_size == 0) - return EC_SUCCESS; - - if (port != I2C_PORT_BATTERY || slave_addr_flags != BATTERY_ADDR_FLAGS) - return EC_ERROR_INVAL; - if (out[0] >= ARRAY_SIZE(mock_smart_battery)) - return EC_ERROR_UNIMPLEMENTED; - if (out_size == 1) { - /* Read */ - if (in_size != 2) - /* We are not doing a read16, assume read string */ - return EC_SUCCESS; - else - *(uint16_t *)in = mock_smart_battery[out[0]]; - } else { - /* write */ - if (out_size != 3) - /* We are only expecting write 16 */ - return EC_ERROR_UNIMPLEMENTED; - else - mock_smart_battery[out[0]] = (out[2] << 8) | out[1]; - } - return EC_SUCCESS; -} -DECLARE_TEST_I2C_XFER(sb_i2c_xfer); - -int battery_time_at_rate(int rate, int *minutes) -{ - return EC_SUCCESS; -} - -static const struct battery_info bat_info = { - /* - * Design voltage - * max = 8.4V - * normal = 7.4V - * min = 6.0V - */ - .voltage_max = 8400, - .voltage_normal = 7400, - .voltage_min = 6000, - - /* Pre-charge current: I <= 0.01C */ - .precharge_current = 64, /* mA */ - - /* - * Operational temperature range - * 0 <= T_charge <= 50 deg C - * -20 <= T_discharge <= 60 deg C - */ - .start_charging_min_c = 0, - .start_charging_max_c = 50, - .charging_min_c = 0, - .charging_max_c = 50, - .discharging_min_c = -20, - .discharging_max_c = 60, -}; - -const struct battery_info *battery_get_info(void) -{ - return &bat_info; -} diff --git a/board/host/build.mk b/board/host/build.mk index 78e4df530c..7719998eda 100644 --- a/board/host/build.mk +++ b/board/host/build.mk @@ -10,5 +10,4 @@ CHIP:=host board-y=board.o board-$(HAS_TASK_CHIPSET)+=chipset.o -board-$(CONFIG_BATTERY_MOCK)+=battery.o charger.o board-$(CONFIG_FANS)+=fan.o diff --git a/board/host/charger.c b/board/host/charger.c deleted file mode 100644 index 1dd972a82e..0000000000 --- a/board/host/charger.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright 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. - * - * Mock battery charger driver. - */ - -#include "battery_smart.h" -#include "charger.h" -#include "console.h" -#include "common.h" -#include "util.h" - -static const struct charger_info mock_charger_info = { - .name = "MockCharger", - .voltage_max = 19200, - .voltage_min = 1024, - .voltage_step = 16, - .current_max = 8192, - .current_min = 128, - .current_step = 128, - .input_current_max = 8064, - .input_current_min = 128, - .input_current_step = 128, -}; - -#define OPTION_CHARGE_INHIBIT BIT(0) - -static uint32_t mock_option; -static uint32_t mock_mode; -static uint32_t mock_current; -static uint32_t mock_voltage; -static uint32_t mock_input_current; - -const struct charger_info *charger_get_info(void) -{ - return &mock_charger_info; -} - - -int charger_get_status(int *status) -{ - *status = CHARGER_LEVEL_2; - if (mock_mode & CHARGE_FLAG_INHIBIT_CHARGE) - *status |= CHARGER_CHARGE_INHIBITED; - - return EC_SUCCESS; -} - - -int charger_set_mode(int mode) -{ - if (mode & CHARGE_FLAG_INHIBIT_CHARGE) - mock_mode |= OPTION_CHARGE_INHIBIT; - else - mock_mode &= ~OPTION_CHARGE_INHIBIT; - return EC_SUCCESS; -} - - -int charger_get_current(int *current) -{ - *current = mock_current; - return EC_SUCCESS; -} - - -int charger_set_current(int current) -{ - const struct charger_info *info = charger_get_info(); - - if (current > 0 && current < info->current_min) - current = info->current_min; - if (current > info->current_max) - current = info->current_max; - - if (mock_current != current) - ccprintf("Charger set current: %d\n", current); - mock_current = current; - return EC_SUCCESS; -} - -int charger_get_voltage(int *voltage) -{ - *voltage = mock_voltage; - return EC_SUCCESS; -} - - -int charger_set_voltage(int voltage) -{ - mock_voltage = voltage; - ccprintf("Charger set voltage: %d\n", voltage); - return EC_SUCCESS; -} - - -int charger_get_option(int *option) -{ - *option = mock_option; - return EC_SUCCESS; -} - - -int charger_set_option(int option) -{ - mock_option = option; - return EC_SUCCESS; -} - - -int charger_manufacturer_id(int *id) -{ - return EC_SUCCESS; -} - - -int charger_device_id(int *id) -{ - return EC_SUCCESS; -} - - -int charger_get_input_current(int *input_current) -{ - *input_current = mock_input_current; - return EC_SUCCESS; -} - - -int charger_set_input_current(int current) -{ - const struct charger_info *info = charger_get_info(); - - if (current < info->input_current_min) - current = info->input_current_min; - if (current > info->input_current_max) - current = info->input_current_max; - - if (mock_input_current != current) - ccprintf("Charger set input current: %d\n", current); - - mock_input_current = current; - return EC_SUCCESS; -} - - -int charger_post_init(void) -{ - mock_current = mock_input_current = CONFIG_CHARGER_INPUT_CURRENT; - return EC_SUCCESS; -} diff --git a/common/build.mk b/common/build.mk index 8c7e290a93..d099433290 100644 --- a/common/build.mk +++ b/common/build.mk @@ -44,8 +44,6 @@ common-$(CONFIG_CASE_CLOSED_DEBUG_V1)+=ccd_config.o common-$(CONFIG_CEC)+=cec.o common-$(CONFIG_CROS_BOARD_INFO)+=cbi.o common-$(CONFIG_CMD_CHARGEN) += chargen.o -common-$(CONFIG_CHARGER)+=charger.o charge_state_v2.o -common-$(CONFIG_CHARGER_PROFILE_OVERRIDE_COMMON)+=charger_profile_override.o common-$(CONFIG_CMD_I2CWEDGE)+=i2c_wedge.o common-$(CONFIG_COMMON_GPIO)+=gpio.o gpio_commands.o common-$(CONFIG_IO_EXPANDER)+=ioexpander.o diff --git a/common/charge_ramp.c b/common/charge_ramp.c deleted file mode 100644 index 68a9c8ef96..0000000000 --- a/common/charge_ramp.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright 2017 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. - */ - -/* Charge input current limit ramp module for Chrome EC */ - -#include "charge_manager.h" -#include "common.h" -#include "system.h" -#include "usb_charge.h" -#include "util.h" - -#define TYPEC_DTS_RAMP_MAX 2400 - -test_mockable int chg_ramp_allowed(int supplier) -{ - /* Don't allow ramping in RO when write protected. */ - if (!system_is_in_rw() && system_is_locked()) - return 0; - - switch (supplier) { - case CHARGE_SUPPLIER_TYPEC_DTS: -#ifdef CONFIG_CHARGE_RAMP_HW - /* Need ramping for USB-C chargers as well to avoid voltage droops. */ - case CHARGE_SUPPLIER_PD: - case CHARGE_SUPPLIER_TYPEC: -#endif - return 1; - /* default: fall through */ - } - - /* Othewise ask the BC1.2 detect module */ - return usb_charger_ramp_allowed(supplier); -} - -test_mockable int chg_ramp_max(int supplier, int sup_curr) -{ - switch (supplier) { - case CHARGE_SUPPLIER_TYPEC_DTS: - /* - * Ramp DTS suppliers to advertised current or predetermined - * limit, whichever is greater. - */ - return MAX(TYPEC_DTS_RAMP_MAX, sup_curr); -#ifdef CONFIG_CHARGE_RAMP_HW - case CHARGE_SUPPLIER_PD: - case CHARGE_SUPPLIER_TYPEC: - return sup_curr; -#endif - /* default: fall through */ - } - - /* Otherwise ask the BC1.2 detect module */ - return usb_charger_ramp_max(supplier, sup_curr); -} diff --git a/common/charge_ramp_sw.c b/common/charge_ramp_sw.c deleted file mode 100644 index 2916894e8c..0000000000 --- a/common/charge_ramp_sw.c +++ /dev/null @@ -1,383 +0,0 @@ -/* Copyright 2017 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. - */ - -/* Charge input current limit ramp module for Chrome EC */ - -#include "charge_manager.h" -#include "charge_ramp.h" -#include "charge_state.h" -#include "common.h" -#include "console.h" -#include "ec_commands.h" -#include "task.h" -#include "timer.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) - -/* Number of times to ramp current searching for limit before stable charging */ -#define RAMP_COUNT 3 - -/* Maximum allowable time charger can be unplugged to be considered an OCP */ -#define OC_RECOVER_MAX_TIME (SECOND) - -/* Delay for running state machine when board is not consuming full current */ -#define CURRENT_DRAW_DELAY (5*SECOND) - -/* Current ramp increment */ -#define RAMP_CURR_INCR_MA 64 -#define RAMP_CURR_DELAY (500*MSEC) -#define RAMP_CURR_START_MA 500 - -/* How much to backoff the input current limit when limit has been found */ -#define RAMP_ICL_BACKOFF (2*RAMP_CURR_INCR_MA) - -/* Interval at which VBUS voltage is monitored in stable state */ -#define STABLE_VBUS_MONITOR_INTERVAL (SECOND) - -/* Time to delay for stablizing the charging current */ -#define STABLIZE_DELAY (5*SECOND) - -enum chg_ramp_state { - CHG_RAMP_DISCONNECTED, - CHG_RAMP_CHARGE_DETECT_DELAY, - CHG_RAMP_OVERCURRENT_DETECT, - CHG_RAMP_RAMP, - CHG_RAMP_STABILIZE, - CHG_RAMP_STABLE, -}; -static enum chg_ramp_state ramp_st; - -struct oc_info { - timestamp_t ts; - int oc_detected; - int sup; - int icl; -}; - -/* OCP info for each over-current */ -static struct oc_info oc_info[CONFIG_USB_PD_PORT_MAX_COUNT][RAMP_COUNT]; -static int oc_info_idx[CONFIG_USB_PD_PORT_MAX_COUNT]; -#define ACTIVE_OC_INFO (oc_info[active_port][oc_info_idx[active_port]]) - -/* Active charging information */ -static int active_port = CHARGE_PORT_NONE; -static int active_sup; -static int active_icl; -static int active_vtg; -static timestamp_t reg_time; - -static int stablize_port; -static int stablize_sup; - -/* Maximum/minimum input current limit for active charger */ -static int max_icl; -static int min_icl; - -void chg_ramp_charge_supplier_change(int port, int supplier, int current, - timestamp_t registration_time, int voltage) -{ - /* - * If the last active port was a valid port and the port - * has changed, then this may have been an over-current. - */ - if (active_port != CHARGE_PORT_NONE && - port != active_port) { - if (oc_info_idx[active_port] == RAMP_COUNT - 1) - oc_info_idx[active_port] = 0; - else - oc_info_idx[active_port]++; - ACTIVE_OC_INFO.ts = get_time(); - ACTIVE_OC_INFO.sup = active_sup; - ACTIVE_OC_INFO.icl = active_icl; - } - - /* Set new active port, set ramp state, and wake ramp task */ - active_port = port; - active_sup = supplier; - active_vtg = voltage; - - /* Set min and max input current limit based on if ramp is allowed */ - if (chg_ramp_allowed(active_sup)) { - min_icl = RAMP_CURR_START_MA; - max_icl = chg_ramp_max(active_sup, current); - } else { - min_icl = max_icl = current; - } - - reg_time = registration_time; - if (ramp_st != CHG_RAMP_STABILIZE) { - ramp_st = (active_port == CHARGE_PORT_NONE) ? - CHG_RAMP_DISCONNECTED : CHG_RAMP_CHARGE_DETECT_DELAY; - CPRINTS("Ramp reset: st%d", ramp_st); - task_wake(TASK_ID_CHG_RAMP); - } -} - -int chg_ramp_get_current_limit(void) -{ - /* - * If we are ramping or stable, then use the active input - * current limit. Otherwise, use the minimum input current - * limit. - */ - switch (ramp_st) { - case CHG_RAMP_RAMP: - case CHG_RAMP_STABILIZE: - case CHG_RAMP_STABLE: - return active_icl; - default: - return min_icl; - } -} - -int chg_ramp_is_detected(void) -{ - /* Charger detected (charge detect delay has passed) */ - return ramp_st > CHG_RAMP_CHARGE_DETECT_DELAY; -} - -int chg_ramp_is_stable(void) -{ - return ramp_st == CHG_RAMP_STABLE; -} - -void chg_ramp_task(void *u) -{ - int task_wait_time = -1; - int i, lim; - uint64_t detect_end_time_us = 0, time_us; - int last_active_port = CHARGE_PORT_NONE; - - enum chg_ramp_state ramp_st_prev = CHG_RAMP_DISCONNECTED, - ramp_st_new = CHG_RAMP_DISCONNECTED; - int active_icl_new; - - /* Clear last OCP supplier to guarantee we ramp on first connect */ - for (i = 0; i < board_get_usb_pd_port_count(); i++) - oc_info[i][0].sup = CHARGE_SUPPLIER_NONE; - - /* - * Sleep until chg_ramp_charge_supplier_change is called to avoid - * setting input current limit to zero. chg_ramp_charge_supplier_change - * won't be called until charge_manager is ready to call - * board_set_charge_limit by itself (if there is no chg_ramp_task). - */ - if (!IS_ENABLED(TEST_BUILD)) - task_wait_event(-1); - - while (1) { - ramp_st_new = ramp_st; - active_icl_new = active_icl; - switch (ramp_st) { - case CHG_RAMP_DISCONNECTED: - /* Do nothing */ - task_wait_time = -1; - break; - case CHG_RAMP_CHARGE_DETECT_DELAY: - /* Delay for charge_manager to determine supplier */ - /* - * On entry to state, or if port changes, check - * timestamps to determine if this was likely an - * OC event (check if we lost VBUS and it came back - * within OC_RECOVER_MAX_TIME). - */ - if (ramp_st_prev != ramp_st || - active_port != last_active_port) { - last_active_port = active_port; - if (reg_time.val < - ACTIVE_OC_INFO.ts.val + - OC_RECOVER_MAX_TIME) { - ACTIVE_OC_INFO.oc_detected = 1; - } else { - for (i = 0; i < RAMP_COUNT; ++i) - oc_info[active_port][i]. - oc_detected = 0; - } - detect_end_time_us = get_time().val + - CHARGE_DETECT_DELAY; - task_wait_time = CHARGE_DETECT_DELAY; - break; - } - - /* If detect delay has not passed, set wait time */ - time_us = get_time().val; - if (time_us < detect_end_time_us) { - task_wait_time = detect_end_time_us - time_us; - break; - } - - /* Detect delay is over, fall through to next state */ - ramp_st_new = CHG_RAMP_OVERCURRENT_DETECT; - /* notify host of power info change */ - pd_send_host_event(PD_EVENT_POWER_CHANGE); - case CHG_RAMP_OVERCURRENT_DETECT: - /* Check if we should ramp or go straight to stable */ - task_wait_time = SECOND; - - /* Skip ramp for specific suppliers */ - if (!chg_ramp_allowed(active_sup)) { - active_icl_new = min_icl; - ramp_st_new = CHG_RAMP_STABLE; - break; - } - - /* - * If we are not drawing full charge, then don't ramp, - * just wait in this state, until we are. - */ - if (!charge_is_consuming_full_input_current()) { - task_wait_time = CURRENT_DRAW_DELAY; - break; - } - - /* - * Compare recent OCP events, if all info matches, - * then we don't need to ramp anymore. - */ - for (i = 0; i < RAMP_COUNT; i++) { - if (oc_info[active_port][i].sup != active_sup || - !oc_info[active_port][i].oc_detected) - break; - } - - if (i == RAMP_COUNT) { - /* Found OC threshold! */ - active_icl_new = ACTIVE_OC_INFO.icl - - RAMP_ICL_BACKOFF; - ramp_st_new = CHG_RAMP_STABLE; - } else { - /* - * Need to ramp to find OC threshold, start - * at the minimum input current limit. - */ - active_icl_new = min_icl; - ramp_st_new = CHG_RAMP_RAMP; - } - break; - case CHG_RAMP_RAMP: - /* Keep ramping until we find the limit */ - task_wait_time = RAMP_CURR_DELAY; - - /* Pause ramping if we are not drawing full current */ - if (!charge_is_consuming_full_input_current()) { - task_wait_time = CURRENT_DRAW_DELAY; - break; - } - - /* If VBUS is sagging a lot, then stop ramping */ - if (board_is_vbus_too_low(active_port, - CHG_RAMP_VBUS_RAMPING)) { - CPRINTS("VBUS low"); - active_icl_new = MAX(min_icl, active_icl - - RAMP_ICL_BACKOFF); - ramp_st_new = CHG_RAMP_STABILIZE; - task_wait_time = STABLIZE_DELAY; - stablize_port = active_port; - stablize_sup = active_sup; - break; - } - - /* Ramp the current limit if we haven't reached max */ - if (active_icl == max_icl) - ramp_st_new = CHG_RAMP_STABLE; - else if (active_icl + RAMP_CURR_INCR_MA > max_icl) - active_icl_new = max_icl; - else - active_icl_new = active_icl + RAMP_CURR_INCR_MA; - break; - case CHG_RAMP_STABILIZE: - /* Wait for current to stabilize after ramp is done */ - /* Use default delay for exiting this state */ - task_wait_time = SECOND; - if (active_port == stablize_port && - active_sup == stablize_sup) { - ramp_st_new = CHG_RAMP_STABLE; - break; - } - - ramp_st_new = active_port == CHARGE_PORT_NONE ? - CHG_RAMP_DISCONNECTED : - CHG_RAMP_CHARGE_DETECT_DELAY; - break; - case CHG_RAMP_STABLE: - /* Maintain input current limit */ - /* On entry log charging stats */ - if (ramp_st_prev != ramp_st) { -#ifdef CONFIG_USB_PD_LOGGING - charge_manager_save_log(active_port); -#endif - /* notify host of power info change */ - pd_send_host_event(PD_EVENT_POWER_CHANGE); - } - - /* Keep an eye on VBUS and restart ramping if it dips */ - if (chg_ramp_allowed(active_sup) && - board_is_vbus_too_low(active_port, - CHG_RAMP_VBUS_STABLE)) { - CPRINTS("VBUS low; Re-ramp"); - max_icl = MAX(min_icl, - max_icl - RAMP_ICL_BACKOFF); - active_icl_new = min_icl; - ramp_st_new = CHG_RAMP_RAMP; - } - task_wait_time = STABLE_VBUS_MONITOR_INTERVAL; - break; - } - - ramp_st_prev = ramp_st; - ramp_st = ramp_st_new; - active_icl = active_icl_new; - - /* Skip setting limit if status is stable twice in a row */ - if (ramp_st_prev != CHG_RAMP_STABLE || - ramp_st != CHG_RAMP_STABLE) { - CPRINTS("Ramp p%d st%d %dmA %dmA", - active_port, ramp_st, min_icl, active_icl); - /* Set the input current limit */ - lim = chg_ramp_get_current_limit(); - board_set_charge_limit(active_port, active_sup, lim, - lim, active_vtg); - } - - if (ramp_st == CHG_RAMP_STABILIZE) - /* - * When in stabilize state, supplier/port may change - * and we don't want to wake up task until we have - * slept this amount of time. - */ - usleep(task_wait_time); - else - task_wait_event(task_wait_time); - } -} - -#ifdef CONFIG_CMD_CHGRAMP -static int command_chgramp(int argc, char **argv) -{ - int i; - int port; - - ccprintf("Chg Ramp:\nState: %d\nMin ICL: %d\nActive ICL: %d\n", - ramp_st, min_icl, active_icl); - - for (port = 0; port < board_get_usb_pd_port_count(); port++) { - ccprintf("Port %d:\n", port); - ccprintf(" OC idx:%d\n", oc_info_idx[port]); - for (i = 0; i < RAMP_COUNT; i++) { - ccprintf(" OC %d: s%d oc_det%d icl%d\n", i, - oc_info[port][i].sup, - oc_info[port][i].oc_detected, - oc_info[port][i].icl); - } - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(chgramp, command_chgramp, - "", - "Dump charge ramp state info"); -#endif diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c deleted file mode 100644 index 54d21a97a4..0000000000 --- a/common/charge_state_v2.c +++ /dev/null @@ -1,2644 +0,0 @@ -/* Copyright 2014 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.h" -#include "battery_smart.h" -#include "charge_manager.h" -#include "charger_profile_override.h" -#include "charge_state.h" -#include "charger.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "ec_ec_comm_master.h" -#include "ec_ec_comm_slave.h" -#include "extpower.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "i2c.h" -#include "math_util.h" -#include "printf.h" -#include "system.h" -#include "task.h" -#include "throttle_ap.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_CHARGER, outstr) -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) - -/* Extra debugging prints when allocating power between lid and base. */ -#undef CHARGE_ALLOCATE_EXTRA_DEBUG - -#define CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US \ - (CONFIG_BATTERY_CRITICAL_SHUTDOWN_TIMEOUT * SECOND) -#define PRECHARGE_TIMEOUT_US (PRECHARGE_TIMEOUT * SECOND) -#define LFCC_EVENT_THRESH 5 /* Full-capacity change reqd for host event */ - -#ifdef CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT -#ifndef CONFIG_HOSTCMD_EVENTS -#error "CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT needs CONFIG_HOSTCMD_EVENTS" -#endif /* CONFIG_HOSTCMD_EVENTS */ -#define BAT_OCP_TIMEOUT_US (60 * SECOND) -/* BAT_OCP_HYSTERESIS_PCT can be optionally overridden in board.h. */ -#ifndef BAT_OCP_HYSTERESIS_PCT -#define BAT_OCP_HYSTERESIS_PCT 10 -#endif /* BAT_OCP_HYSTERESIS_PCT */ -#define BAT_OCP_HYSTERESIS \ - (BAT_MAX_DISCHG_CURRENT * BAT_OCP_HYSTERESIS_PCT / 100) /* mA */ -#endif /* CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT */ - -#ifdef CONFIG_THROTTLE_AP_ON_BAT_VOLTAGE -#ifndef CONFIG_HOSTCMD_EVENTS -#error "CONFIG_THROTTLE_AP_ON_BAT_VOLTAGE needs CONFIG_HOSTCMD_EVENTS" -#endif /* CONFIG_HOSTCMD_EVENTS */ -#define BAT_UVP_TIMEOUT_US (60 * SECOND) -/* BAT_UVP_HYSTERESIS_PCT can be optionally overridden in board.h. */ -#ifndef BAT_UVP_HYSTERESIS_PCT -#define BAT_UVP_HYSTERESIS_PCT 3 -#endif /* BAT_UVP_HYSTERESIS_PCT */ -#define BAT_UVP_HYSTERESIS \ - (BAT_LOW_VOLTAGE_THRESH * BAT_UVP_HYSTERESIS_PCT / 100) /* mV */ -static timestamp_t uvp_throttle_start_time; -#endif /* CONFIG_THROTTLE_AP_ON_BAT_OLTAGE */ - -static int charge_request(int voltage, int current); - -static uint8_t battery_level_shutdown; - -/* - * State for charger_task(). Here so we can reset it on a HOOK_INIT, and - * because stack space is more limited than .bss - */ -static const struct battery_info *batt_info; -static struct charge_state_data curr; -static enum charge_state_v2 prev_state; -static int prev_ac, prev_charge, prev_full, prev_disp_charge; -static enum battery_present prev_bp; -static int is_full; /* battery not accepting current */ -static enum ec_charge_control_mode chg_ctl_mode; -static int manual_voltage; /* Manual voltage override (-1 = no override) */ -static int manual_current; /* Manual current override (-1 = no override) */ -static unsigned int user_current_limit = -1U; -test_export_static timestamp_t shutdown_target_time; -static timestamp_t precharge_start_time; - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER -static int base_connected; -/* Base has responded to one of our commands already. */ -static int base_responsive; -static int charge_base; -static int prev_charge_base; -static int prev_current_base; -static int prev_allow_charge_base; -static int prev_current_lid; - -/* - * In debugging mode, with AC, input current to allocate to base. Negative - * value disables manual mode. - */ -static int manual_ac_current_base = -1; -/* - * In debugging mode, when discharging, current to transfer from lid to base - * (negative to transfer from base to lid). Only valid when enabled is true. - */ -static int manual_noac_enabled; -static int manual_noac_current_base; -#else -static const int base_connected; -#endif - -/* Is battery connected but unresponsive after precharge? */ -static int battery_seems_to_be_dead; - -static int battery_seems_to_be_disconnected; - -/* - * Was battery removed? Set when we see BP_NO, cleared after the battery is - * reattached and becomes responsive. Used to indicate an error state after - * removal and trigger re-reading the battery static info when battery is - * reattached and responsive. - */ -static int battery_was_removed; - -static int problems_exist; -static int debugging; - - -/* Track problems in communicating with the battery or charger */ -enum problem_type { - PR_STATIC_UPDATE, - PR_SET_VOLTAGE, - PR_SET_CURRENT, - PR_SET_MODE, - PR_SET_INPUT_CURR, - PR_POST_INIT, - PR_CHG_FLAGS, - PR_BATT_FLAGS, - PR_CUSTOM, - - NUM_PROBLEM_TYPES -}; -static const char * const prob_text[] = { - "static update", - "set voltage", - "set current", - "set mode", - "set input current", - "post init", - "chg params", - "batt params", - "custom profile", -}; -BUILD_ASSERT(ARRAY_SIZE(prob_text) == NUM_PROBLEM_TYPES); - -/* - * TODO(crosbug.com/p/27639): When do we decide a problem is real and not - * just intermittent? And what do we do about it? - */ -static void problem(enum problem_type p, int v) -{ - static int __bss_slow last_prob_val[NUM_PROBLEM_TYPES]; - static timestamp_t __bss_slow last_prob_time[NUM_PROBLEM_TYPES]; - timestamp_t t_now, t_diff; - - if (last_prob_val[p] != v) { - t_now = get_time(); - t_diff.val = t_now.val - last_prob_time[p].val; - CPRINTS("charge problem: %s, 0x%x -> 0x%x after %.6" PRId64 "s", - prob_text[p], last_prob_val[p], v, t_diff.val); - last_prob_val[p] = v; - last_prob_time[p] = t_now; - } - problems_exist = 1; -} - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER -/* - * Parameters for dual-battery policy. - * TODO(b:71881017): This should be made configurable by AP in the future. - */ -struct dual_battery_policy { - /*** Policies when AC is not connected. ***/ - /* Voltage to use when using OTG mode between lid and base (mV) */ - uint16_t otg_voltage; - /* Maximum current to apply from base to lid (mA) */ - uint16_t max_base_to_lid_current; - /* - * Margin to apply between provided OTG output current and input current - * limit, to make sure that input charger does not overcurrent output - * charger. input_current = (1-margin) * output_current. (/128) - */ - uint8_t margin_otg_current; - - /* Only do base to lid OTG when base battery above this value (%) */ - uint8_t min_charge_base_otg; - - /* - * When base/lid battery percentage is below this value, do - * battery-to-battery charging. (%) - */ - uint8_t max_charge_base_batt_to_batt; - uint8_t max_charge_lid_batt_to_batt; - - /*** Policies when AC is connected. ***/ - /* Minimum power to allocate to base (mW), includes some margin to allow - * base to charge when critically low. - */ - uint16_t min_base_system_power; - - /* Smoothing factor for lid power (/128) */ - uint8_t lid_system_power_smooth; - /* - * Smoothing factor for base/lid battery power, when the battery power - * is decreasing only: we try to estimate the maximum power that the - * battery is willing to take and always reset it when it draws more - * than the estimate. (/128) - */ - uint8_t battery_power_smooth; - - /* - * Margin to add to requested base/lid battery power, to figure out how - * much current to allocate. allocation = (1+margin) * request. (/128) - */ - uint8_t margin_base_battery_power; - uint8_t margin_lid_battery_power; - - /* Maximum current to apply from lid to base (mA) */ - uint16_t max_lid_to_base_current; -}; - -static const struct dual_battery_policy db_policy = { - .otg_voltage = 12000, /* mV */ - .max_base_to_lid_current = 1800, /* mA, about 2000mA with margin. */ - .margin_otg_current = 13, /* /128 = 10.1% */ - .min_charge_base_otg = 5, /* % */ - .max_charge_base_batt_to_batt = 4, /* % */ - .max_charge_lid_batt_to_batt = 10, /* % */ - .min_base_system_power = 1300, /* mW */ - .lid_system_power_smooth = 32, /* 32/128 = 0.25 */ - .battery_power_smooth = 1, /* 1/128 = 0.008 */ - .margin_base_battery_power = 32, /* 32/128 = 0.25 */ - .margin_lid_battery_power = 32, /* 32/128 = 0.25 */ - .max_lid_to_base_current = 2000, /* mA */ -}; - -/* Add at most "value" to power_var, subtracting from total_power budget. */ -#define CHG_ALLOCATE(power_var, total_power, value) do { \ - int val_capped = MIN(value, total_power); \ - (power_var) += val_capped; \ - (total_power) -= val_capped; \ -} while (0) - -/* Update base battery information */ -static void update_base_battery_info(void) -{ - struct ec_response_battery_dynamic_info *const bd = - &battery_dynamic[BATT_IDX_BASE]; - - base_connected = board_is_base_connected(); - - if (!base_connected) { - const int invalid_flags = EC_BATT_FLAG_INVALID_DATA; - /* Invalidate static/dynamic information */ - if (bd->flags != invalid_flags) { - bd->flags = invalid_flags; - - host_set_single_event(EC_HOST_EVENT_BATTERY); - host_set_single_event(EC_HOST_EVENT_BATTERY_STATUS); - } - charge_base = -1; - base_responsive = 0; - prev_current_base = 0; - prev_allow_charge_base = 0; - } else if (base_responsive) { - int old_flags = bd->flags; - int flags_changed; - int old_full_capacity = bd->full_capacity; - - ec_ec_master_base_get_dynamic_info(); - flags_changed = (old_flags != bd->flags); - /* Fetch static information when flags change. */ - if (flags_changed) - ec_ec_master_base_get_static_info(); - - battery_memmap_refresh(BATT_IDX_BASE); - - /* Newly connected battery, or change in capacity. */ - if (old_flags & EC_BATT_FLAG_INVALID_DATA || - ((old_flags & EC_BATT_FLAG_BATT_PRESENT) != - (bd->flags & EC_BATT_FLAG_BATT_PRESENT)) || - old_full_capacity != bd->full_capacity) - host_set_single_event(EC_HOST_EVENT_BATTERY); - - if (flags_changed) - host_set_single_event(EC_HOST_EVENT_BATTERY_STATUS); - - /* Update charge_base */ - if (bd->flags & (BATT_FLAG_BAD_FULL_CAPACITY | - BATT_FLAG_BAD_REMAINING_CAPACITY)) - charge_base = -1; - else if (bd->full_capacity > 0) - charge_base = 100 * bd->remaining_capacity - / bd->full_capacity; - else - charge_base = 0; - } -} - -/** - * Setup current settings for base, and record previous values, if the base - * is responsive. - * - * @param current_base Current to be drawn by base (negative to provide power) - * @param allow_charge_base Whether base battery should be charged (only makes - * sense with positive current) - */ -static int set_base_current(int current_base, int allow_charge_base) -{ - /* "OTG" voltage from base to lid. */ - const int otg_voltage = db_policy.otg_voltage; - int ret; - - ret = ec_ec_master_base_charge_control(current_base, - otg_voltage, allow_charge_base); - if (ret) { - /* Ignore errors until the base is responsive. */ - if (base_responsive) - return ret; - } else { - base_responsive = 1; - prev_current_base = current_base; - prev_allow_charge_base = allow_charge_base; - } - - return EC_RES_SUCCESS; -} - -/** - * Setup current settings for lid and base, in a safe way. - * - * @param current_base Current to be drawn by base (negative to provide power) - * @param allow_charge_base Whether base battery should be charged (only makes - * sense with positive current) - * @param current_lid Current to be drawn by lid (negative to provide power) - * @param allow_charge_lid Whether lid battery should be charged - */ -static void set_base_lid_current(int current_base, int allow_charge_base, - int current_lid, int allow_charge_lid) -{ - /* "OTG" voltage from lid to base. */ - const int otg_voltage = db_policy.otg_voltage; - - int lid_first; - int ret; - - /* TODO(b:71881017): This is still quite verbose during charging. */ - if (prev_current_base != current_base || - prev_allow_charge_base != allow_charge_base || - prev_current_lid != current_lid) { - CPRINTS("Base/Lid: %d%s/%d%s mA", - current_base, allow_charge_base ? "+" : "", - current_lid, allow_charge_lid ? "+" : ""); - } - - /* - * To decide whether to first control the lid or the base, we first - * control the side that _reduces_ current that would be drawn, then - * setup one that would start providing power, then increase current. - */ - if (current_lid >= 0 && current_lid < prev_current_lid) - lid_first = 1; /* Lid decreases current */ - else if (current_base >= 0 && current_base < prev_current_base) - lid_first = 0; /* Base decreases current */ - else if (current_lid < 0) - lid_first = 1; /* Lid provide power */ - else - lid_first = 0; /* All other cases: control the base first */ - - if (!lid_first && base_connected) { - ret = set_base_current(current_base, allow_charge_base); - if (ret) - return; - } - - if (current_lid >= 0) { - ret = charge_set_output_current_limit(0, 0); - if (ret) - return; - ret = charger_set_input_current(current_lid); - if (ret) - return; - if (allow_charge_lid) - ret = charge_request(curr.requested_voltage, - curr.requested_current); - else - ret = charge_request(0, 0); - } else { - ret = charge_set_output_current_limit( - -current_lid, otg_voltage); - } - - if (ret) - return; - - prev_current_lid = current_lid; - - if (lid_first && base_connected) { - ret = set_base_current(current_base, allow_charge_base); - if (ret) - return; - } - - /* - * Make sure cross-power is enabled (it might not be enabled right after - * plugging the base, or when an adapter just got connected). - */ - if (base_connected && current_base != 0) - board_enable_base_power(1); -} - -/** - * Smooth power value, covering some edge cases. - * Compute s*curr+(1-s)*prev, where s is in 1/128 unit. - */ -static int smooth_value(int prev, int curr, int s) -{ - if (curr < 0) - curr = 0; - if (prev < 0) - return curr; - - return prev + s * (curr - prev) / 128; -} - -/** - * Add margin m to value. Compute (1+m)*value, where m is in 1/128 unit. - */ -static int add_margin(int value, int m) -{ - return value + m * value / 128; -} - -static void charge_allocate_input_current_limit(void) -{ - /* - * All the power numbers are in mW. - * - * Since we work with current and voltage in mA and mV, multiplying them - * gives numbers in uW, which are dangerously close to overflowing when - * doing intermediate computations (60W * 100 overflows a 32-bit int, - * for example). We therefore divide the product by 1000 and re-multiply - * the power numbers by 1000 when converting them back to current. - */ - int total_power = 0; - - static int prev_base_battery_power = -1; - int base_battery_power = 0; - int base_battery_power_max = 0; - - static int prev_lid_system_power = -1; - int lid_system_power; - - static int prev_lid_battery_power = -1; - int lid_battery_power = 0; - int lid_battery_power_max = 0; - - int power_base = 0; - int power_lid = 0; - - int current_base = 0; - int current_lid = 0; - - int charge_lid = charge_get_percent(); - - const struct ec_response_battery_dynamic_info *const base_bd = - &battery_dynamic[BATT_IDX_BASE]; - - - if (!base_connected) { - set_base_lid_current(0, 0, curr.desired_input_current, 1); - prev_base_battery_power = -1; - return; - } - - /* Charging */ - if (curr.desired_input_current > 0 && curr.input_voltage > 0) - total_power = - curr.desired_input_current * curr.input_voltage / 1000; - - /* - * TODO(b:71723024): We should be able to replace this test by curr.ac, - * but the value is currently wrong, especially during transitions. - */ - if (total_power <= 0) { - int base_critical = charge_base >= 0 && - charge_base < db_policy.max_charge_base_batt_to_batt; - - /* Discharging */ - prev_base_battery_power = -1; - prev_lid_system_power = -1; - prev_lid_battery_power = -1; - - /* Manual control */ - if (manual_noac_enabled) { - int lid_current, base_current; - - if (manual_noac_current_base > 0) { - base_current = -manual_noac_current_base; - lid_current = - add_margin(manual_noac_current_base, - db_policy.margin_otg_current); - } else { - lid_current = manual_noac_current_base; - base_current = - add_margin(-manual_noac_current_base, - db_policy.margin_otg_current); - } - - set_base_lid_current(base_current, 0, lid_current, 0); - return; - } - - /* - * System is off, cut power to the base. We'll reset the base - * when system restarts, or when AC is plugged. - */ - if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { - set_base_lid_current(0, 0, 0, 0); - if (base_responsive) { - /* Base still responsive, put it to sleep. */ - CPRINTF("Hibernating base\n"); - ec_ec_master_hibernate(); - base_responsive = 0; - board_enable_base_power(0); - } - return; - } - - /* - * System is suspended, let the lid and base run on their - * own power. However, if the base battery is critically low, we - * still want to provide power to the base, to make sure it - * stays alive to be able to wake the system on keyboard or - * touchpad events. - */ - if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND) && - !base_critical) { - set_base_lid_current(0, 0, 0, 0); - return; - } - - if (charge_base > db_policy.min_charge_base_otg) { - int lid_current = db_policy.max_base_to_lid_current; - int base_current = add_margin(lid_current, - db_policy.margin_otg_current); - /* Draw current from base to lid */ - set_base_lid_current(-base_current, 0, lid_current, - charge_lid < db_policy.max_charge_lid_batt_to_batt); - } else { - /* - * Base battery is too low, apply power to it, and allow - * it to charge if it is critically low. - * - * TODO(b:71881017): When suspended, this will make the - * battery charge oscillate between 3 and 4 percent, - * which might not be great for battery life. We need - * some hysteresis. - */ - /* - * TODO(b:71881017): Precompute (ideally, at build time) - * the base_current, so we do not need to do a division - * here. - */ - int base_current = - (db_policy.min_base_system_power * 1000) / - db_policy.otg_voltage; - int lid_current = add_margin(base_current, - db_policy.margin_otg_current); - - set_base_lid_current(base_current, base_critical, - -lid_current, 0); - } - - return; - } - - /* Manual control */ - if (manual_ac_current_base >= 0) { - int current_base = manual_ac_current_base; - int current_lid = - curr.desired_input_current - manual_ac_current_base; - - if (current_lid < 0) { - current_base = curr.desired_input_current; - current_lid = 0; - } - - set_base_lid_current(current_base, 1, current_lid, 1); - return; - } - - /* Estimate system power. */ - lid_system_power = charger_get_system_power() / 1000; - - /* Smooth system power, as it is very spiky */ - lid_system_power = smooth_value(prev_lid_system_power, - lid_system_power, db_policy.lid_system_power_smooth); - prev_lid_system_power = lid_system_power; - - /* - * TODO(b:71881017): Smoothing the battery power isn't necessarily a - * good idea: if the system takes up too much power, we may reduce the - * estimate power too quickly, leading to oscillations when the system - * power goes down. Instead, we should probably estimate the current - * based on remaining capacity. - */ - /* Estimate lid battery power. */ - if (!(curr.batt.flags & - (BATT_FLAG_BAD_VOLTAGE | BATT_FLAG_BAD_CURRENT))) - lid_battery_power = curr.batt.current * - curr.batt.voltage / 1000; - if (lid_battery_power < prev_lid_battery_power) - lid_battery_power = smooth_value(prev_lid_battery_power, - lid_battery_power, db_policy.battery_power_smooth); - if (!(curr.batt.flags & - (BATT_FLAG_BAD_DESIRED_VOLTAGE | - BATT_FLAG_BAD_DESIRED_CURRENT))) - lid_battery_power_max = curr.batt.desired_current * - curr.batt.desired_voltage / 1000; - - lid_battery_power = MIN(lid_battery_power, lid_battery_power_max); - - /* Estimate base battery power. */ - if (!(base_bd->flags & EC_BATT_FLAG_INVALID_DATA)) { - base_battery_power = base_bd->actual_current * - base_bd->actual_voltage / 1000; - base_battery_power_max = base_bd->desired_current * - base_bd->desired_voltage / 1000; - } - if (base_battery_power < prev_base_battery_power) - base_battery_power = smooth_value(prev_base_battery_power, - base_battery_power, db_policy.battery_power_smooth); - base_battery_power = MIN(base_battery_power, base_battery_power_max); - - if (debugging) { - CPRINTF("%s:\n", __func__); - CPRINTF("total power: %d\n", total_power); - CPRINTF("base battery power: %d (%d)\n", - base_battery_power, base_battery_power_max); - CPRINTF("lid system power: %d\n", lid_system_power); - CPRINTF("lid battery power: %d\n", lid_battery_power); - CPRINTF("percent base/lid: %d%% %d%%\n", - charge_base, charge_lid); - } - - prev_lid_battery_power = lid_battery_power; - prev_base_battery_power = base_battery_power; - - if (total_power > 0) { /* Charging */ - /* Allocate system power */ - CHG_ALLOCATE(power_base, total_power, - db_policy.min_base_system_power); - CHG_ALLOCATE(power_lid, total_power, lid_system_power); - - /* Allocate lid, then base battery power */ - lid_battery_power = add_margin(lid_battery_power, - db_policy.margin_lid_battery_power); - CHG_ALLOCATE(power_lid, total_power, lid_battery_power); - - base_battery_power = add_margin(base_battery_power, - db_policy.margin_base_battery_power); - CHG_ALLOCATE(power_base, total_power, base_battery_power); - - /* Give everything else to the lid. */ - CHG_ALLOCATE(power_lid, total_power, total_power); - if (debugging) - CPRINTF("power: base %d mW / lid %d mW\n", - power_base, power_lid); - - current_base = 1000 * power_base / curr.input_voltage; - current_lid = 1000 * power_lid / curr.input_voltage; - - if (current_base > db_policy.max_lid_to_base_current) { - current_lid += (current_base - - db_policy.max_lid_to_base_current); - current_base = db_policy.max_lid_to_base_current; - } - - if (debugging) - CPRINTF("current: base %d mA / lid %d mA\n", - current_base, current_lid); - - set_base_lid_current(current_base, 1, current_lid, 1); - } else { /* Discharging */ - } - - if (debugging) - CPRINTF("====\n"); -} -#endif /* CONFIG_EC_EC_COMM_BATTERY_MASTER */ - -#ifndef CONFIG_BATTERY_V2 -/* Returns zero if every item was updated. */ -static int update_static_battery_info(void) -{ - char *batt_str; - int batt_serial; - uint8_t batt_flags = 0; - /* - * The return values have type enum ec_error_list, but EC_SUCCESS is - * zero. We'll just look for any failures so we can try them all again. - */ - int rv; - - /* Smart battery serial number is 16 bits */ - batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_SERIAL); - memset(batt_str, 0, EC_MEMMAP_TEXT_MAX); - rv = battery_serial_number(&batt_serial); - if (!rv) - snprintf(batt_str, EC_MEMMAP_TEXT_MAX, "%04X", batt_serial); - - /* Design Capacity of Full */ - rv |= battery_design_capacity( - (int *)host_get_memmap(EC_MEMMAP_BATT_DCAP)); - - /* Design Voltage */ - rv |= battery_design_voltage( - (int *)host_get_memmap(EC_MEMMAP_BATT_DVLT)); - - /* Last Full Charge Capacity (this is only mostly static) */ - rv |= battery_full_charge_capacity( - (int *)host_get_memmap(EC_MEMMAP_BATT_LFCC)); - - /* Cycle Count */ - rv |= battery_cycle_count((int *)host_get_memmap(EC_MEMMAP_BATT_CCNT)); - - /* Battery Manufacturer string */ - batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_MFGR); - memset(batt_str, 0, EC_MEMMAP_TEXT_MAX); - rv |= battery_manufacturer_name(batt_str, EC_MEMMAP_TEXT_MAX); - - /* Battery Model string */ - batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_MODEL); - memset(batt_str, 0, EC_MEMMAP_TEXT_MAX); - rv |= battery_device_name(batt_str, EC_MEMMAP_TEXT_MAX); - - /* Battery Type string */ - batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_TYPE); - rv |= battery_device_chemistry(batt_str, EC_MEMMAP_TEXT_MAX); - - /* Zero the dynamic entries. They'll come next. */ - *(int *)host_get_memmap(EC_MEMMAP_BATT_VOLT) = 0; - *(int *)host_get_memmap(EC_MEMMAP_BATT_RATE) = 0; - *(int *)host_get_memmap(EC_MEMMAP_BATT_CAP) = 0; - *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC) = 0; - if (extpower_is_present()) - batt_flags |= EC_BATT_FLAG_AC_PRESENT; - *host_get_memmap(EC_MEMMAP_BATT_FLAG) = batt_flags; - - if (rv) - problem(PR_STATIC_UPDATE, rv); - else - /* No errors seen. Battery data is now present */ - *host_get_memmap(EC_MEMMAP_BATTERY_VERSION) = 1; - - return rv; -} - -static void update_dynamic_battery_info(void) -{ - /* The memmap address is constant. We should fix these calls somehow. */ - int *memmap_volt = (int *)host_get_memmap(EC_MEMMAP_BATT_VOLT); - int *memmap_rate = (int *)host_get_memmap(EC_MEMMAP_BATT_RATE); - int *memmap_cap = (int *)host_get_memmap(EC_MEMMAP_BATT_CAP); - int *memmap_lfcc = (int *)host_get_memmap(EC_MEMMAP_BATT_LFCC); - uint8_t *memmap_flags = host_get_memmap(EC_MEMMAP_BATT_FLAG); - uint8_t tmp; - int send_batt_status_event = 0; - int send_batt_info_event = 0; - static int __bss_slow batt_present; - - tmp = 0; - if (curr.ac) - tmp |= EC_BATT_FLAG_AC_PRESENT; - - if (curr.batt.is_present == BP_YES) { - tmp |= EC_BATT_FLAG_BATT_PRESENT; - batt_present = 1; - /* Tell the AP to read battery info if it is newly present. */ - if (!(*memmap_flags & EC_BATT_FLAG_BATT_PRESENT)) - send_batt_info_event++; - } else { - /* - * Require two consecutive updates with BP_NOT_SURE - * before reporting it gone to the host. - */ - if (batt_present) - tmp |= EC_BATT_FLAG_BATT_PRESENT; - else if (*memmap_flags & EC_BATT_FLAG_BATT_PRESENT) - send_batt_info_event++; - batt_present = 0; - } - - if (curr.batt.flags & EC_BATT_FLAG_INVALID_DATA) - tmp |= EC_BATT_FLAG_INVALID_DATA; - - if (!(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE)) - *memmap_volt = curr.batt.voltage; - - if (!(curr.batt.flags & BATT_FLAG_BAD_CURRENT)) - *memmap_rate = ABS(curr.batt.current); - - if (!(curr.batt.flags & BATT_FLAG_BAD_REMAINING_CAPACITY)) { - /* - * If we're running off the battery, it must have some charge. - * Don't report zero charge, as that has special meaning - * to Chrome OS powerd. - */ - if (curr.batt.remaining_capacity == 0 && !curr.batt_is_charging) - *memmap_cap = 1; - else - *memmap_cap = curr.batt.remaining_capacity; - } - - if (!(curr.batt.flags & BATT_FLAG_BAD_FULL_CAPACITY) && - (curr.batt.full_capacity <= (*memmap_lfcc - LFCC_EVENT_THRESH) || - curr.batt.full_capacity >= (*memmap_lfcc + LFCC_EVENT_THRESH))) { - *memmap_lfcc = curr.batt.full_capacity; - /* Poke the AP if the full_capacity changes. */ - send_batt_info_event++; - } - - if (curr.batt.is_present == BP_YES && - !(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - curr.batt.state_of_charge <= BATTERY_LEVEL_CRITICAL) - tmp |= EC_BATT_FLAG_LEVEL_CRITICAL; - - tmp |= curr.batt_is_charging ? EC_BATT_FLAG_CHARGING : - EC_BATT_FLAG_DISCHARGING; - - /* Tell the AP to re-read battery status if charge state changes */ - if (*memmap_flags != tmp) - send_batt_status_event++; - - /* Update flags before sending host events. */ - *memmap_flags = tmp; - - if (send_batt_info_event) - host_set_single_event(EC_HOST_EVENT_BATTERY); - if (send_batt_status_event) - host_set_single_event(EC_HOST_EVENT_BATTERY_STATUS); -} -#else /* CONFIG_BATTERY_V2 */ -static int update_static_battery_info(void) -{ - int batt_serial; - int val; - /* - * The return values have type enum ec_error_list, but EC_SUCCESS is - * zero. We'll just look for any failures so we can try them all again. - */ - int rv, ret; - - struct ec_response_battery_static_info *const bs = - &battery_static[BATT_IDX_MAIN]; - - /* Clear all static information. */ - memset(bs, 0, sizeof(*bs)); - - /* Smart battery serial number is 16 bits */ - rv = battery_serial_number(&batt_serial); - if (!rv) - snprintf(bs->serial, sizeof(bs->serial), "%04X", batt_serial); - - /* Design Capacity of Full */ - ret = battery_design_capacity(&val); - if (!ret) - bs->design_capacity = val; - rv |= ret; - - /* Design Voltage */ - ret = battery_design_voltage(&val); - if (!ret) - bs->design_voltage = val; - rv |= ret; - - /* Cycle Count */ - ret = battery_cycle_count(&val); - if (!ret) - bs->cycle_count = val; - rv |= ret; - - /* Battery Manufacturer string */ - rv |= battery_manufacturer_name(bs->manufacturer, - sizeof(bs->manufacturer)); - - /* Battery Model string */ - rv |= battery_device_name(bs->model, sizeof(bs->model)); - - /* Battery Type string */ - rv |= battery_device_chemistry(bs->type, sizeof(bs->type)); - - /* Zero the dynamic entries. They'll come next. */ - memset(&battery_dynamic[BATT_IDX_MAIN], 0, - sizeof(battery_dynamic[BATT_IDX_MAIN])); - - if (rv) - problem(PR_STATIC_UPDATE, rv); - -#ifdef HAS_TASK_HOSTCMD - battery_memmap_refresh(BATT_IDX_MAIN); -#endif - - return rv; -} - -static void update_dynamic_battery_info(void) -{ - static int __bss_slow batt_present; - uint8_t tmp; - int send_batt_status_event = 0; - int send_batt_info_event = 0; - - struct ec_response_battery_dynamic_info *const bd = - &battery_dynamic[BATT_IDX_MAIN]; - - tmp = 0; - if (curr.ac) - tmp |= EC_BATT_FLAG_AC_PRESENT; - - if (curr.batt.is_present == BP_YES) { - tmp |= EC_BATT_FLAG_BATT_PRESENT; - batt_present = 1; - /* Tell the AP to read battery info if it is newly present. */ - if (!(bd->flags & EC_BATT_FLAG_BATT_PRESENT)) - send_batt_info_event++; - } else { - /* - * Require two consecutive updates with BP_NOT_SURE - * before reporting it gone to the host. - */ - if (batt_present) - tmp |= EC_BATT_FLAG_BATT_PRESENT; - else if (bd->flags & EC_BATT_FLAG_BATT_PRESENT) - send_batt_info_event++; - batt_present = 0; - } - - if (curr.batt.flags & EC_BATT_FLAG_INVALID_DATA) - tmp |= EC_BATT_FLAG_INVALID_DATA; - - if (!(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE)) - bd->actual_voltage = curr.batt.voltage; - - if (!(curr.batt.flags & BATT_FLAG_BAD_CURRENT)) - bd->actual_current = curr.batt.current; - - if (!(curr.batt.flags & BATT_FLAG_BAD_DESIRED_VOLTAGE)) - bd->desired_voltage = curr.batt.desired_voltage; - - if (!(curr.batt.flags & BATT_FLAG_BAD_DESIRED_CURRENT)) - bd->desired_current = curr.batt.desired_current; - - if (!(curr.batt.flags & BATT_FLAG_BAD_REMAINING_CAPACITY)) { - /* - * If we're running off the battery, it must have some charge. - * Don't report zero charge, as that has special meaning - * to Chrome OS powerd. - */ - if (curr.batt.remaining_capacity == 0 && !curr.batt_is_charging) - bd->remaining_capacity = 1; - else - bd->remaining_capacity = curr.batt.remaining_capacity; - } - - if (!(curr.batt.flags & BATT_FLAG_BAD_FULL_CAPACITY) && - (curr.batt.full_capacity <= - (bd->full_capacity - LFCC_EVENT_THRESH) || - curr.batt.full_capacity >= - (bd->full_capacity + LFCC_EVENT_THRESH))) { - bd->full_capacity = curr.batt.full_capacity; - /* Poke the AP if the full_capacity changes. */ - send_batt_info_event++; - } - - if (curr.batt.is_present == BP_YES && - !(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - curr.batt.state_of_charge <= BATTERY_LEVEL_CRITICAL) - tmp |= EC_BATT_FLAG_LEVEL_CRITICAL; - - tmp |= curr.batt_is_charging ? EC_BATT_FLAG_CHARGING : - EC_BATT_FLAG_DISCHARGING; - - /* Tell the AP to re-read battery status if charge state changes */ - if (bd->flags != tmp) - send_batt_status_event++; - - bd->flags = tmp; - -#ifdef HAS_TASK_HOSTCMD - battery_memmap_refresh(BATT_IDX_MAIN); -#endif - -#ifdef CONFIG_HOSTCMD_EVENTS - if (send_batt_info_event) - host_set_single_event(EC_HOST_EVENT_BATTERY); - if (send_batt_status_event) - host_set_single_event(EC_HOST_EVENT_BATTERY_STATUS); -#endif -} -#endif /* CONFIG_BATTERY_V2 */ - -static const char * const state_list[] = { - "idle", "discharge", "charge", "precharge" -}; -BUILD_ASSERT(ARRAY_SIZE(state_list) == NUM_STATES_V2); -static const char * const batt_pres[] = { - "NO", "YES", "NOT_SURE", -}; - -static void dump_charge_state(void) -{ -#define DUMP(FLD, FMT) ccprintf(#FLD " = " FMT "\n", curr.FLD) -#define DUMP_CHG(FLD, FMT) ccprintf("\t" #FLD " = " FMT "\n", curr.chg. FLD) -#define DUMP_BATT(FLD, FMT) ccprintf("\t" #FLD " = " FMT "\n", curr.batt. FLD) - ccprintf("state = %s\n", state_list[curr.state]); - DUMP(ac, "%d"); - DUMP(batt_is_charging, "%d"); - ccprintf("chg.*:\n"); - DUMP_CHG(voltage, "%dmV"); - DUMP_CHG(current, "%dmA"); - DUMP_CHG(input_current, "%dmA"); - DUMP_CHG(status, "0x%x"); - DUMP_CHG(option, "0x%x"); - DUMP_CHG(flags, "0x%x"); - cflush(); - ccprintf("batt.*:\n"); - ccprintf("\ttemperature = %dC\n", - DECI_KELVIN_TO_CELSIUS(curr.batt.temperature)); - DUMP_BATT(state_of_charge, "%d%%"); - DUMP_BATT(voltage, "%dmV"); - DUMP_BATT(current, "%dmA"); - DUMP_BATT(desired_voltage, "%dmV"); - DUMP_BATT(desired_current, "%dmA"); - DUMP_BATT(flags, "0x%x"); - DUMP_BATT(remaining_capacity, "%dmAh"); - DUMP_BATT(full_capacity, "%dmAh"); - ccprintf("\tis_present = %s\n", batt_pres[curr.batt.is_present]); - cflush(); - DUMP(requested_voltage, "%dmV"); - DUMP(requested_current, "%dmA"); -#ifdef CONFIG_CHARGER_OTG - DUMP(output_current, "%dmA"); -#endif -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - DUMP(input_voltage, "%dmV"); -#endif - ccprintf("chg_ctl_mode = %d\n", chg_ctl_mode); - ccprintf("manual_voltage = %d\n", manual_voltage); - ccprintf("manual_current = %d\n", manual_current); - ccprintf("user_current_limit = %dmA\n", user_current_limit); - ccprintf("battery_seems_to_be_dead = %d\n", battery_seems_to_be_dead); - ccprintf("battery_seems_to_be_disconnected = %d\n", - battery_seems_to_be_disconnected); - ccprintf("battery_was_removed = %d\n", battery_was_removed); - ccprintf("debug output = %s\n", debugging ? "on" : "off"); -#undef DUMP -} - -static void show_charging_progress(void) -{ - int rv = 0, minutes, to_full; - -#ifdef CONFIG_BATTERY_SMART - /* - * Predicted remaining battery capacity based on AverageCurrent(). - * 65535 = Battery is not being discharged. - */ - if (!battery_time_to_empty(&minutes) && minutes != 65535) - to_full = 0; - /* - * Predicted time-to-full charge based on AverageCurrent(). - * 65535 = Battery is not being discharged. - */ - else if (!battery_time_to_full(&minutes) && minutes != 65535) - to_full = 1; - /* - * If both time to empty and time to full have invalid data, consider - * measured current from the coulomb counter and ac present status to - * decide whether battery is about to full or empty. - */ - else { - to_full = curr.batt_is_charging; - rv = EC_ERROR_UNKNOWN; - } -#else - if (!curr.batt_is_charging) { - rv = battery_time_to_empty(&minutes); - to_full = 0; - } else { - rv = battery_time_to_full(&minutes); - to_full = 1; - } -#endif - - if (rv) - CPRINTS("Battery %d%% (Display %d.%d %%) / ??h:?? %s%s", - curr.batt.state_of_charge, - curr.batt.display_charge / 10, - curr.batt.display_charge % 10, - to_full ? "to full" : "to empty", - is_full ? ", not accepting current" : ""); - else - CPRINTS("Battery %d%% (Display %d.%d %%) / %dh:%d %s%s", - curr.batt.state_of_charge, - curr.batt.display_charge / 10, - curr.batt.display_charge % 10, - minutes / 60, minutes % 60, - to_full ? "to full" : "to empty", - is_full ? ", not accepting current" : ""); - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - CPRINTS("Base battery %d%%", charge_base); -#endif - - if (debugging) { - ccprintf("battery:\n"); - print_battery_debug(); - ccprintf("charger:\n"); - print_charger_debug(); - ccprintf("chg:\n"); - dump_charge_state(); - } -} - -/* Calculate if battery is full based on whether it is accepting charge */ -static int calc_is_full(void) -{ - static int __bss_slow ret; - - /* If bad state of charge reading, return last value */ - if (curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE || - curr.batt.state_of_charge > 100) - return ret; - /* - * Battery is full when SoC is above 90% and battery desired current - * is 0. This is necessary because some batteries stop charging when - * the SoC still reports <100%, so we need to check desired current - * to know if it is actually full. - */ - ret = (curr.batt.state_of_charge >= 90 && - curr.batt.desired_current == 0); - return ret; -} - -/* - * Ask the charger for some voltage and current. If either value is 0, - * charging is disabled; otherwise it's enabled. Negative values are ignored. - */ -static int charge_request(int voltage, int current) -{ - int r1 = EC_SUCCESS, r2 = EC_SUCCESS, r3 = EC_SUCCESS; - static int __bss_slow prev_volt, prev_curr; - - if (!voltage || !current) { -#ifdef CONFIG_CHARGER_NARROW_VDC - current = 0; - /* - * With NVDC charger, keep VSYS voltage higher than battery, - * otherwise the BGATE FET body diode would conduct and - * discharge the battery. - */ - voltage = charger_closest_voltage( - curr.batt.voltage + charger_get_info()->voltage_step); - /* If the battery is full, request the max voltage. */ - if (is_full) - voltage = battery_get_info()->voltage_max; - /* And handle dead battery case */ - voltage = MAX(voltage, battery_get_info()->voltage_normal); -#else - voltage = current = 0; -#endif - } - - if (curr.ac) { - if (prev_volt != voltage || prev_curr != current) - CPRINTS("%s(%dmV, %dmA)", __func__, voltage, current); - } - - /* - * Set current before voltage so that if we are just starting - * to charge, we allow some time (i2c delay) for charging circuit to - * start at a voltage just above battery voltage before jumping - * up. This helps avoid large current spikes when connecting - * battery. - */ - if (current >= 0) - r2 = charger_set_current(current); - if (r2 != EC_SUCCESS) - problem(PR_SET_CURRENT, r2); - - if (voltage >= 0) - r1 = charger_set_voltage(voltage); - if (r1 != EC_SUCCESS) - problem(PR_SET_VOLTAGE, r1); - - /* - * Set the charge inhibit bit when possible as it appears to save - * power in some cases (e.g. Nyan with BQ24735). - */ - if (voltage > 0 || current > 0) - r3 = charger_set_mode(0); - else - r3 = charger_set_mode(CHARGE_FLAG_INHIBIT_CHARGE); - if (r3 != EC_SUCCESS) - problem(PR_SET_MODE, r3); - - /* - * Only update if the request worked, so we'll keep trying on failures. - */ - if (!r1 && !r2) { - prev_volt = voltage; - prev_curr = current; - } - - return r1 ? r1 : r2; -} - -void chgstate_set_manual_current(int curr_ma) -{ - if (curr_ma < 0) - manual_current = -1; - else - manual_current = charger_closest_current(curr_ma); -} - -void chgstate_set_manual_voltage(int volt_mv) -{ - manual_voltage = charger_closest_voltage(volt_mv); -} - -/* Force charging off before the battery is full. */ -static int set_chg_ctrl_mode(enum ec_charge_control_mode mode) -{ - if (mode == CHARGE_CONTROL_NORMAL) { - chg_ctl_mode = mode; - manual_current = -1; - manual_voltage = -1; - } else { - /* - * Changing mode is only meaningful if external power is - * present. If it's not present we can't charge anyway. - */ - if (!curr.ac) - return EC_ERROR_NOT_POWERED; - - chg_ctl_mode = mode; - manual_current = 0; - manual_voltage = 0; - } - - return EC_SUCCESS; -} - -/* True if we know the battery temp is too high or too low */ -static inline int battery_too_hot(int batt_temp_c) -{ - return (!(curr.batt.flags & BATT_FLAG_BAD_TEMPERATURE) && - (batt_temp_c > batt_info->discharging_max_c || - batt_temp_c < batt_info->discharging_min_c)); -} - -__attribute__((weak)) uint8_t board_set_battery_level_shutdown(void) -{ - return BATTERY_LEVEL_SHUTDOWN; -} - -/* True if we know the charge is too low, or we know the voltage is too low. */ -static inline int battery_too_low(void) -{ - return ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - curr.batt.state_of_charge < battery_level_shutdown) || - (!(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE) && - curr.batt.voltage <= batt_info->voltage_min)); -} - -__attribute__((weak)) -enum critical_shutdown board_critical_shutdown_check( - struct charge_state_data *curr) -{ -#ifdef CONFIG_BATTERY_CRITICAL_SHUTDOWN_CUT_OFF - return CRITICAL_SHUTDOWN_CUTOFF; -#elif defined(CONFIG_HIBERNATE) - return CRITICAL_SHUTDOWN_HIBERNATE; -#else - return CRITICAL_SHUTDOWN_IGNORE; -#endif -} - -static int is_battery_critical(void) -{ - int batt_temp_c = DECI_KELVIN_TO_CELSIUS(curr.batt.temperature); - - /* - * TODO(crosbug.com/p/27642): The thermal loop should watch the battery - * temp, so it can turn fans on. - */ - if (battery_too_hot(batt_temp_c)) { - CPRINTS("Batt temp out of range: %dC", batt_temp_c); - return 1; - } - - if (battery_too_low() && !curr.batt_is_charging) { - CPRINTS("Low battery: %d%%, %dmV", - curr.batt.state_of_charge, curr.batt.voltage); - return 1; - } - - return 0; -} - - /* - * If the battery is at extremely low charge (and discharging) or extremely - * high temperature, the EC will notify the AP and start a timer. If the - * critical condition is not corrected before the timeout expires, the EC - * will shut down the AP (if the AP is not already off) and then optionally - * hibernate or cut off battery. - */ -static int shutdown_on_critical_battery(void) -{ - if (!is_battery_critical()) { - /* Reset shutdown warning time */ - shutdown_target_time.val = 0; - return 0; - } - - if (!shutdown_target_time.val) { - /* Start count down timer */ - CPRINTS("Start shutdown due to critical battery"); - shutdown_target_time.val = get_time().val - + CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US; -#ifdef CONFIG_HOSTCMD_EVENTS - if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) - host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN); -#endif - return 1; - } - - if (!timestamp_expired(shutdown_target_time, 0)) - return 1; - - /* Timer has expired */ - if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { - switch (board_critical_shutdown_check(&curr)) { - case CRITICAL_SHUTDOWN_HIBERNATE: - CPRINTS("Hibernate due to critical battery"); - system_hibernate(0, 0); - break; - case CRITICAL_SHUTDOWN_CUTOFF: - CPRINTS("Cutoff due to critical battery"); - /* Ensure logs are flushed. */ - cflush(); - board_cut_off_battery(); - break; - case CRITICAL_SHUTDOWN_IGNORE: - default: - break; - } - } else { - /* Timeout waiting for AP to shut down, so kill it */ - CPRINTS( - "charge force shutdown due to critical battery"); - chipset_force_shutdown(CHIPSET_SHUTDOWN_BATTERY_CRIT); - } - - return 1; -} - -/* - * Send host events as the battery charge drops below certain thresholds. - * We handle forced shutdown and other actions elsewhere; this is just for the - * host events. We send these even if the AP is off, since the AP will read and - * discard any events it doesn't care about the next time it wakes up. - */ -static void notify_host_of_low_battery_charge(void) -{ - /* We can't tell what the current charge is. Assume it's okay. */ - if (curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) - return; - -#ifdef CONFIG_HOSTCMD_EVENTS - if (curr.batt.state_of_charge <= BATTERY_LEVEL_LOW && - prev_charge > BATTERY_LEVEL_LOW) - host_set_single_event(EC_HOST_EVENT_BATTERY_LOW); - - if (curr.batt.state_of_charge <= BATTERY_LEVEL_CRITICAL && - prev_charge > BATTERY_LEVEL_CRITICAL) - host_set_single_event(EC_HOST_EVENT_BATTERY_CRITICAL); -#endif -} - -static void set_charge_state(enum charge_state_v2 state) -{ - prev_state = curr.state; - curr.state = state; -} - -static void notify_host_of_low_battery_voltage(void) -{ -#ifdef CONFIG_THROTTLE_AP_ON_BAT_VOLTAGE - if ((curr.batt.flags & BATT_FLAG_BAD_VOLTAGE) || - chipset_in_state(CHIPSET_STATE_ANY_OFF)) - return; - - if (!uvp_throttle_start_time.val && - (curr.batt.voltage < BAT_LOW_VOLTAGE_THRESH)) { - throttle_ap(THROTTLE_ON, THROTTLE_SOFT, - THROTTLE_SRC_BAT_VOLTAGE); - uvp_throttle_start_time = get_time(); - } else if (uvp_throttle_start_time.val && - (curr.batt.voltage < BAT_LOW_VOLTAGE_THRESH + - BAT_UVP_HYSTERESIS)) { - /* - * Reset the timer when we are not sure if VBAT can stay - * above BAT_LOW_VOLTAGE_THRESH after we stop throttling. - */ - uvp_throttle_start_time = get_time(); - } else if (uvp_throttle_start_time.val && - (get_time().val > uvp_throttle_start_time.val + - BAT_UVP_TIMEOUT_US)) { - throttle_ap(THROTTLE_OFF, THROTTLE_SOFT, - THROTTLE_SRC_BAT_VOLTAGE); - uvp_throttle_start_time.val = 0; - } -#endif -} - -static void notify_host_of_over_current(struct batt_params *batt) -{ -#ifdef CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT - static timestamp_t ocp_throttle_start_time; - - if (batt->flags & BATT_FLAG_BAD_CURRENT) - return; - - if ((!ocp_throttle_start_time.val && - (batt->current < -BAT_MAX_DISCHG_CURRENT)) || - (ocp_throttle_start_time.val && - (batt->current < -BAT_MAX_DISCHG_CURRENT + BAT_OCP_HYSTERESIS))) { - ocp_throttle_start_time = get_time(); - throttle_ap(THROTTLE_ON, THROTTLE_SOFT, - THROTTLE_SRC_BAT_DISCHG_CURRENT); - } else if (ocp_throttle_start_time.val && - (get_time().val > ocp_throttle_start_time.val + - BAT_OCP_TIMEOUT_US)) { - /* - * Clear the timer and notify AP to stop throttling if - * we haven't seen over current for BAT_OCP_TIMEOUT_US. - */ - ocp_throttle_start_time.val = 0; - throttle_ap(THROTTLE_OFF, THROTTLE_SOFT, - THROTTLE_SRC_BAT_DISCHG_CURRENT); - } -#endif -} - -const struct batt_params *charger_current_battery_params(void) -{ - return &curr.batt; -} - -#ifdef CONFIG_BATTERY_CHECK_CHARGE_TEMP_LIMITS -/* Determine if the battery is outside of allowable temperature range */ -static int battery_outside_charging_temperature(void) -{ - const struct battery_info *batt_info = battery_get_info(); - /* battery temp in 0.1 deg C */ - int batt_temp_c = DECI_KELVIN_TO_CELSIUS(curr.batt.temperature); - int max_c, min_c; - - if (curr.batt.flags & BATT_FLAG_BAD_TEMPERATURE) - return 0; - - if((curr.batt.desired_voltage == 0) && - (curr.batt.desired_current == 0)){ - max_c = batt_info->start_charging_max_c; - min_c = batt_info->start_charging_min_c; - } else { - max_c = batt_info->charging_max_c; - min_c = batt_info->charging_min_c; - } - - - if ((batt_temp_c >= max_c) || - (batt_temp_c <= min_c)) { - return 1; - } - return 0; -} -#endif - -/*****************************************************************************/ -/* Hooks */ -void charger_init(void) -{ - /* Initialize current state */ - memset(&curr, 0, sizeof(curr)); - curr.batt.is_present = BP_NOT_SURE; - /* Manual voltage/current set to off */ - manual_voltage = -1; - manual_current = -1; -} -DECLARE_HOOK(HOOK_INIT, charger_init, HOOK_PRIO_DEFAULT); - -/* Wake up the task when something important happens */ -static void charge_wakeup(void) -{ - task_wake(TASK_ID_CHARGER); -} -DECLARE_HOOK(HOOK_CHIPSET_RESUME, charge_wakeup, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_AC_CHANGE, charge_wakeup, HOOK_PRIO_DEFAULT); - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER -/* Reset the base on S5->S0 transition. */ -DECLARE_HOOK(HOOK_CHIPSET_STARTUP, board_base_reset, HOOK_PRIO_DEFAULT); -#endif - -#ifdef CONFIG_THROTTLE_AP_ON_BAT_VOLTAGE -static void bat_low_voltage_throttle_reset(void) -{ - uvp_throttle_start_time.val = 0; -} -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, - bat_low_voltage_throttle_reset, - HOOK_PRIO_DEFAULT); -#endif - -static int get_desired_input_current(enum battery_present batt_present, - const struct charger_info * const info) -{ - if (batt_present == BP_YES || system_is_locked() || base_connected) { -#ifdef CONFIG_CHARGE_MANAGER - int ilim = charge_manager_get_charger_current(); - return ilim == CHARGE_CURRENT_UNINITIALIZED ? - CHARGE_CURRENT_UNINITIALIZED : - MAX(CONFIG_CHARGER_INPUT_CURRENT, ilim); -#else - return CONFIG_CHARGER_INPUT_CURRENT; -#endif - } else { -#ifdef CONFIG_USB_POWER_DELIVERY - return MIN(PD_MAX_CURRENT_MA, info->input_current_max); -#else - return info->input_current_max; -#endif - } -} - -/* Main loop */ -void charger_task(void *u) -{ - int sleep_usec; - int battery_critical; - int need_static = 1; - const struct charger_info * const info = charger_get_info(); - - /* Get the battery-specific values */ - batt_info = battery_get_info(); - - prev_ac = prev_charge = prev_disp_charge = -1; - chg_ctl_mode = CHARGE_CONTROL_NORMAL; - shutdown_target_time.val = 0UL; - battery_seems_to_be_dead = 0; -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - base_responsive = 0; - curr.input_voltage = CHARGE_VOLTAGE_UNINITIALIZED; - battery_dynamic[BATT_IDX_BASE].flags = EC_BATT_FLAG_INVALID_DATA; - charge_base = -1; -#endif - - /* - * If system is not locked and we don't have a battery to live on, - * then use max input current limit so that we can pull as much power - * as needed. - */ - battery_get_params(&curr.batt); - prev_bp = BP_NOT_INIT; - curr.desired_input_current = get_desired_input_current( - curr.batt.is_present, info); - - battery_level_shutdown = board_set_battery_level_shutdown(); - - while (1) { - - /* Let's see what's going on... */ - curr.ts = get_time(); - sleep_usec = 0; - problems_exist = 0; - battery_critical = 0; - curr.ac = extpower_is_present(); -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - /* - * When base is powering the system, make sure curr.ac stays 0. - * TODO(b:71723024): Fix extpower_is_present() in hardware - * instead. - */ - if (base_responsive && prev_current_base < 0) - curr.ac = 0; - - /* System is off: if AC gets connected, reset the base. */ - if (chipset_in_state(CHIPSET_STATE_ANY_OFF) && - !prev_ac && curr.ac) - board_base_reset(); -#endif - if (curr.ac != prev_ac) { - if (curr.ac) { - /* - * Some chargers are unpowered when the AC is - * off, so we'll reinitialize it when AC - * comes back and set the input current limit. - * Try again if it fails. - */ - int rv = charger_post_init(); - if (rv != EC_SUCCESS) { - problem(PR_POST_INIT, rv); - } else { - if (curr.desired_input_current != - CHARGE_CURRENT_UNINITIALIZED) - rv = charger_set_input_current( - curr.desired_input_current); - if (rv != EC_SUCCESS) - problem(PR_SET_INPUT_CURR, rv); - else - prev_ac = curr.ac; - } - } else { - /* Some things are only meaningful on AC */ - chg_ctl_mode = CHARGE_CONTROL_NORMAL; - battery_seems_to_be_dead = 0; - prev_ac = curr.ac; - } - } - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - update_base_battery_info(); -#endif - - charger_get_params(&curr.chg); - battery_get_params(&curr.batt); - - if (prev_bp != curr.batt.is_present) { - prev_bp = curr.batt.is_present; - - /* Update battery info due to change of battery */ - batt_info = battery_get_info(); - need_static = 1; - - curr.desired_input_current = - get_desired_input_current(prev_bp, info); - if (curr.desired_input_current != - CHARGE_CURRENT_UNINITIALIZED) - charger_set_input_current( - curr.desired_input_current); - hook_notify(HOOK_BATTERY_SOC_CHANGE); - } - - /* - * TODO(crosbug.com/p/27527). Sometimes the battery thinks its - * temperature is 6280C, which seems a bit high. Let's ignore - * anything above the boiling point of tungsten until this bug - * is fixed. If the battery is really that warm, we probably - * have more urgent problems. - */ - if (curr.batt.temperature > CELSIUS_TO_DECI_KELVIN(5660)) { - CPRINTS("ignoring ridiculous batt.temp of %dC", - DECI_KELVIN_TO_CELSIUS(curr.batt.temperature)); - curr.batt.flags |= BATT_FLAG_BAD_TEMPERATURE; - } - - /* If the battery thinks it's above 100%, don't believe it */ - if (curr.batt.state_of_charge > 100) { - CPRINTS("ignoring ridiculous batt.soc of %d%%", - curr.batt.state_of_charge); - curr.batt.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; - } - - notify_host_of_over_current(&curr.batt); - - /* - * Now decide what we want to do about it. We'll normally just - * pass along whatever the battery wants to the charger. Note - * that if battery_get_params() can't get valid values from the - * battery it uses (0, 0), which is probably safer than blindly - * applying power to a battery we can't talk to. - */ - curr.requested_voltage = curr.batt.desired_voltage; - curr.requested_current = curr.batt.desired_current; - - /* If we *know* there's no battery, wait for one to appear. */ - if (curr.batt.is_present == BP_NO) { - if (!curr.ac) - CPRINTS("running with no battery and no AC"); - set_charge_state(ST_IDLE); - curr.batt_is_charging = 0; - battery_was_removed = 1; - goto wait_for_it; - } - - /* - * If we had trouble talking to the battery or the charger, we - * should probably do nothing for a bit, and if it doesn't get - * better then flag it as an error. - */ - if (curr.chg.flags & CHG_FLAG_BAD_ANY) - problem(PR_CHG_FLAGS, curr.chg.flags); - if (curr.batt.flags & BATT_FLAG_BAD_ANY) - problem(PR_BATT_FLAGS, curr.batt.flags); - - /* - * If AC is present, check if input current is sufficient to - * actually charge battery. - */ - curr.batt_is_charging = curr.ac && (curr.batt.current >= 0); - - /* Don't let the battery hurt itself. */ - battery_critical = shutdown_on_critical_battery(); - - if (!curr.ac) { - set_charge_state(ST_DISCHARGE); - goto wait_for_it; - } - - /* Okay, we're on AC and we should have a battery. */ - - /* Used for factory tests. */ - if (chg_ctl_mode != CHARGE_CONTROL_NORMAL) { - set_charge_state(ST_IDLE); - goto wait_for_it; - } - - /* If the battery is not responsive, try to wake it up. */ - if (!(curr.batt.flags & BATT_FLAG_RESPONSIVE)) { - if (battery_seems_to_be_dead || battery_is_cut_off()) { - /* It's dead, do nothing */ - set_charge_state(ST_IDLE); - curr.requested_voltage = 0; - curr.requested_current = 0; - } else if (curr.state == ST_PRECHARGE && - (get_time().val > precharge_start_time.val + - PRECHARGE_TIMEOUT_US)) { - /* We've tried long enough, give up */ - CPRINTS("battery seems to be dead"); - battery_seems_to_be_dead = 1; - set_charge_state(ST_IDLE); - curr.requested_voltage = 0; - curr.requested_current = 0; - } else { - /* See if we can wake it up */ - if (curr.state != ST_PRECHARGE) { - CPRINTS("try to wake battery"); - precharge_start_time = get_time(); - need_static = 1; - } - set_charge_state(ST_PRECHARGE); - curr.requested_voltage = - batt_info->voltage_max; - curr.requested_current = - batt_info->precharge_current; - } - goto wait_for_it; - } else { - /* The battery is responding. Yay. Try to use it. */ -#ifdef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD - /* - * TODO (crosbug.com/p/29467): remove this workaround - * for dead battery that requests no voltage/current - */ - if (curr.requested_voltage == 0 && - curr.requested_current == 0 && -#ifdef CONFIG_BATTERY_DEAD_UNTIL_VALUE - curr.batt.state_of_charge < CONFIG_BATTERY_DEAD_UNTIL_VALUE) { -#else - curr.batt.state_of_charge == 0) { -#endif - /* Battery is dead, give precharge current */ - curr.requested_voltage = - batt_info->voltage_max; - curr.requested_current = - batt_info->precharge_current; - } else -#endif -#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT - /* - * Always check the disconnect state. This is because - * the battery disconnect state is one of the items used - * to decide whether or not to leave safe mode. - */ - battery_seems_to_be_disconnected = - battery_get_disconnect_state() == - BATTERY_DISCONNECTED; - - if (curr.requested_voltage == 0 && - curr.requested_current == 0 && - battery_seems_to_be_disconnected) { - /* - * Battery is in disconnect state. Apply a - * current to kick it out of this state. - */ - CPRINTS("found battery in disconnect state"); - curr.requested_voltage = - batt_info->voltage_max; - curr.requested_current = - batt_info->precharge_current; - } else -#endif - if (curr.state == ST_PRECHARGE || - battery_seems_to_be_dead || - battery_was_removed) { - CPRINTS("battery woke up"); - - /* Update the battery-specific values */ - batt_info = battery_get_info(); - need_static = 1; - } - - battery_seems_to_be_dead = battery_was_removed = 0; - set_charge_state(ST_CHARGE); - } - -wait_for_it: -#ifdef CONFIG_CHARGER_PROFILE_OVERRIDE - if (chg_ctl_mode == CHARGE_CONTROL_NORMAL) { - sleep_usec = charger_profile_override(&curr); - if (sleep_usec < 0) - problem(PR_CUSTOM, sleep_usec); - } -#endif - -#ifdef CONFIG_BATTERY_CHECK_CHARGE_TEMP_LIMITS - if (battery_outside_charging_temperature()) { - curr.requested_current = 0; - curr.requested_voltage = 0; - curr.batt.flags &= ~BATT_FLAG_WANT_CHARGE; - if (curr.state != ST_DISCHARGE) - curr.state = ST_IDLE; - } -#endif - -#ifdef CONFIG_CHARGE_MANAGER - if (curr.batt.state_of_charge >= - CONFIG_CHARGE_MANAGER_BAT_PCT_SAFE_MODE_EXIT && - !battery_seems_to_be_disconnected) { - /* - * Sometimes the fuel gauge will report that it has - * sufficient state of charge and remaining capacity, - * but in actuality it doesn't. When the EC sees that - * information, it trusts it and leaves charge manager - * safe mode. Doing so will allow CHARGE_PORT_NONE to - * be selected, thereby cutting off the input FETs. - * When the battery cannot provide the charge it claims, - * the system loses power, shuts down, and the battery - * is not charged even though the charger is plugged in. - * By waiting 500ms, we can avoid the selection of - * CHARGE_PORT_NONE around init time and not cut off the - * input FETs. - */ - msleep(500); - charge_manager_leave_safe_mode(); - } -#endif - - /* Keep the AP informed */ - if (need_static) - need_static = update_static_battery_info(); - /* Wait on the dynamic info until the static info is good. */ - if (!need_static) - update_dynamic_battery_info(); - notify_host_of_low_battery_charge(); - notify_host_of_low_battery_voltage(); - - /* And the EC console */ - is_full = calc_is_full(); - if ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - curr.batt.state_of_charge != prev_charge) || -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - (charge_base != prev_charge_base) || -#endif - (is_full != prev_full) || - (curr.state != prev_state) || - (curr.batt.display_charge != prev_disp_charge)) { - show_charging_progress(); - prev_charge = curr.batt.state_of_charge; - prev_disp_charge = curr.batt.display_charge; -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - prev_charge_base = charge_base; -#endif - hook_notify(HOOK_BATTERY_SOC_CHANGE); - } - prev_full = is_full; - -#ifndef CONFIG_CHARGER_MAINTAIN_VBAT - /* Turn charger off if it's not needed */ - if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) { - curr.requested_voltage = 0; - curr.requested_current = 0; - } -#endif - - /* Apply external limits */ - if (curr.requested_current > user_current_limit) - curr.requested_current = user_current_limit; - - /* Round to valid values */ - curr.requested_voltage = - charger_closest_voltage(curr.requested_voltage); - curr.requested_current = - charger_closest_current(curr.requested_current); - - /* Charger only accpets request when AC is on. */ - if (curr.ac) { - /* - * Some batteries would wake up after cut-off if we keep - * charging it. Thus, we only charge when AC is on and - * battery is not cut off yet. - */ - if (battery_is_cut_off()) { - curr.requested_voltage = 0; - curr.requested_current = 0; - } - /* - * As a safety feature, some chargers will stop - * charging if we don't communicate with it frequently - * enough. In manual mode, we'll just tell it what it - * knows. - */ - else { - if (manual_voltage != -1) - curr.requested_voltage = manual_voltage; - if (manual_current != -1) - curr.requested_current = manual_current; - } - } else { -#ifndef CONFIG_CHARGER_MAINTAIN_VBAT - curr.requested_voltage = charger_closest_voltage( - curr.batt.voltage + info->voltage_step); - curr.requested_current = -1; -#endif -#ifdef CONFIG_EC_EC_COMM_BATTERY_SLAVE - /* - * On EC-EC slave, do not charge if curr.ac is 0: there - * might still be some external power available but we - * do not want to use it for charging. - */ - curr.requested_current = 0; -#endif - } - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - charge_allocate_input_current_limit(); -#else - charge_request(curr.requested_voltage, curr.requested_current); -#endif - - /* How long to sleep? */ - if (problems_exist) - /* If there are errors, don't wait very long. */ - sleep_usec = CHARGE_POLL_PERIOD_SHORT; - else if (sleep_usec <= 0) { - /* default values depend on the state */ - if (!curr.ac && - (curr.state == ST_IDLE || - curr.state == ST_DISCHARGE)) { -#ifdef CONFIG_CHARGER_OTG - int output_current = curr.output_current; -#else - int output_current = 0; -#endif - /* - * If AP is off and we do not provide power, we - * can sleep a long time. - */ - if (chipset_in_state(CHIPSET_STATE_ANY_OFF | - CHIPSET_STATE_ANY_SUSPEND) - && output_current == 0) - sleep_usec = - CHARGE_POLL_PERIOD_VERY_LONG; - else - /* Discharging, not too urgent */ - sleep_usec = CHARGE_POLL_PERIOD_LONG; - } else { - /* AC present, so pay closer attention */ - sleep_usec = CHARGE_POLL_PERIOD_CHARGE; - } - } - - /* Adjust for time spent in this loop */ - sleep_usec -= (int)(get_time().val - curr.ts.val); - if (sleep_usec < CHARGE_MIN_SLEEP_USEC) - sleep_usec = CHARGE_MIN_SLEEP_USEC; - else if (sleep_usec > CHARGE_MAX_SLEEP_USEC) - sleep_usec = CHARGE_MAX_SLEEP_USEC; - - /* - * If battery is critical, ensure that the sleep time is not - * very long since we might want to hibernate or cut-off - * battery sooner. - */ - if (battery_critical && - (sleep_usec > CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US)) - sleep_usec = CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US; - - task_wait_event(sleep_usec); - } -} - - -/*****************************************************************************/ -/* Exported functions */ - -int charge_want_shutdown(void) -{ - return (curr.state == ST_DISCHARGE) && - !(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - (curr.batt.state_of_charge < battery_level_shutdown); -} - -int charge_prevent_power_on(int power_button_pressed) -{ - int prevent_power_on = 0; - struct batt_params params; - struct batt_params *current_batt_params = &curr.batt; -#ifdef CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON - static int automatic_power_on = 1; -#endif - - /* If battery params seem uninitialized then retrieve them */ - if (current_batt_params->is_present == BP_NOT_SURE) { - battery_get_params(¶ms); - current_batt_params = ¶ms; - } - -#ifdef CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON - - /* - * Remember that a power button was pressed, and assume subsequent - * power-ups are user-requested and non-automatic. - */ - if (power_button_pressed) - automatic_power_on = 0; - /* - * Require a minimum battery level to power on and ensure that the - * battery can provide power to the system. - */ - if (current_batt_params->is_present != BP_YES || -#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE - (current_batt_params->flags & BATT_FLAG_IMBALANCED_CELL && - current_batt_params->state_of_charge < - CONFIG_CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON) || -#endif -#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT - battery_get_disconnect_state() != BATTERY_NOT_DISCONNECTED || -#endif - current_batt_params->state_of_charge < - CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) - prevent_power_on = 1; - -#if defined(CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON) && \ - defined(CONFIG_CHARGE_MANAGER) - /* However, we can power on if a sufficient charger is present. */ - if (prevent_power_on) { - if (charge_manager_get_power_limit_uw() >= - CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON * 1000) - prevent_power_on = 0; -#if defined(CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON_WITH_BATT) && \ - defined(CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON_WITH_AC) - else if (charge_manager_get_power_limit_uw() >= - CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON_WITH_BATT * 1000 -#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT - && battery_get_disconnect_state() == - BATTERY_NOT_DISCONNECTED -#endif - && (current_batt_params->state_of_charge >= - CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON_WITH_AC)) - prevent_power_on = 0; -#endif - } -#endif /* CONFIG_CHARGE_MANAGER && CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON */ - - /* - * Factory override: Always allow power on if WP is disabled, - * except when auto-power-on at EC startup and the battery - * is physically present. - */ - prevent_power_on &= (system_is_locked() || (automatic_power_on -#ifdef CONFIG_BATTERY_HW_PRESENT_CUSTOM - && battery_hw_present() == BP_YES -#endif - )); -#endif /* CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON */ - -#ifdef CONFIG_CHARGE_MANAGER - /* Always prevent power on until charge current is initialized */ - if (extpower_is_present() && - (charge_manager_get_charger_current() == - CHARGE_CURRENT_UNINITIALIZED)) - prevent_power_on = 1; -#ifdef CONFIG_BATTERY_HW_PRESENT_CUSTOM - /* - * If battery is NOT physically present then prevent power on until - * a sufficient charger is present. - */ - if (extpower_is_present() && battery_hw_present() == BP_NO -#ifdef CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON - && charge_manager_get_power_limit_uw() < - CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON * 1000 -#endif /* CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON */ - ) - prevent_power_on = 1; -#endif /* CONFIG_BATTERY_HW_PRESENT_CUSTOM */ -#endif /* CONFIG_CHARGE_MANAGER */ - - /* - * Prevent power on if there is no battery nor ac power. This - * happens when the servo is powering the EC to flash it. Only include - * this logic for boards in initial bring up phase since this won't - * happen for released boards. - */ -#ifdef CONFIG_SYSTEM_UNLOCKED - if (!current_batt_params->is_present && !curr.ac) - prevent_power_on = 1; -#endif /* CONFIG_SYSTEM_UNLOCKED */ - - return prevent_power_on; -} - -static int battery_near_full(void) -{ - if (charge_get_percent() < BATTERY_LEVEL_NEAR_FULL) - return 0; - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - if (charge_base > -1 && charge_base < BATTERY_LEVEL_NEAR_FULL) - return 0; -#endif - - return 1; -} - -enum charge_state charge_get_state(void) -{ - switch (curr.state) { - case ST_IDLE: - if (battery_seems_to_be_dead || curr.batt.is_present == BP_NO) - return PWR_STATE_ERROR; - return PWR_STATE_IDLE; - case ST_DISCHARGE: -#ifdef CONFIG_PWR_STATE_DISCHARGE_FULL - if (battery_near_full()) - return PWR_STATE_DISCHARGE_FULL; - else -#endif - return PWR_STATE_DISCHARGE; - case ST_CHARGE: - /* The only difference here is what the LEDs display. */ - if (battery_near_full()) - return PWR_STATE_CHARGE_NEAR_FULL; - else - return PWR_STATE_CHARGE; - case ST_PRECHARGE: - /* we're in battery discovery mode */ - return PWR_STATE_IDLE; - default: - /* Anything else can be considered an error for LED purposes */ - return PWR_STATE_ERROR; - } -} - -uint32_t charge_get_flags(void) -{ - uint32_t flags = 0; - - if (chg_ctl_mode != CHARGE_CONTROL_NORMAL) - flags |= CHARGE_FLAG_FORCE_IDLE; - if (curr.ac) - flags |= CHARGE_FLAG_EXTERNAL_POWER; - if (curr.batt.flags & BATT_FLAG_RESPONSIVE) - flags |= CHARGE_FLAG_BATT_RESPONSIVE; - - return flags; -} - -int charge_get_percent(void) -{ - /* - * Since there's no way to indicate an error to the caller, we'll just - * return the last known value. Even if we've never been able to talk - * to the battery, that'll be zero, which is probably as good as - * anything. - */ - return is_full ? 100 : curr.batt.state_of_charge; -} - -int charge_get_display_charge(void) -{ - return curr.batt.display_charge; -} - -int charge_get_battery_temp(int idx, int *temp_ptr) -{ - if (curr.batt.flags & BATT_FLAG_BAD_TEMPERATURE) - return EC_ERROR_UNKNOWN; - - /* Battery temp is 10ths of degrees K, temp wants degrees K */ - *temp_ptr = curr.batt.temperature / 10; - return EC_SUCCESS; -} - -int charge_is_consuming_full_input_current(void) -{ - int chg_pct = charge_get_percent(); - - return chg_pct > 2 && chg_pct < 95; -} - -#ifdef CONFIG_CHARGER_OTG -int charge_set_output_current_limit(int ma, int mv) -{ - int ret; - int enable = ma > 0; - - if (enable) { - ret = charger_set_otg_current_voltage(ma, mv); - if (ret != EC_SUCCESS) - return ret; - } - - ret = charger_enable_otg_power(enable); - if (ret != EC_SUCCESS) - return ret; - - /* If we start/stop providing power, wake the charger task. */ - if ((curr.output_current == 0 && enable) || - (curr.output_current > 0 && !enable)) - task_wake(TASK_ID_CHARGER); - - curr.output_current = ma; - - return EC_SUCCESS; -} -#endif - -int charge_set_input_current_limit(int ma, int mv) -{ -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - curr.input_voltage = mv; -#endif - /* - * If battery is not present, we are not locked, and base is not - * connected then allow system to pull as much input current as needed. - * Yes, we might overcurrent the charger but this is no worse than - * browning out due to insufficient input current. - */ - if (curr.batt.is_present != BP_YES && !system_is_locked() && - !base_connected) { -#ifdef CONFIG_USB_POWER_DELIVERY -#if ((PD_MAX_POWER_MW * 1000) / PD_MAX_VOLTAGE_MV != PD_MAX_CURRENT_MA) - /* - * If battery is not present, input current is set to - * PD_MAX_CURRENT_MA. If the input power set is greater than - * the maximum allowed system power, system might get damaged. - * Hence, limit the input current to meet maximum allowed - * input system power. - */ - if (mv > 0 && mv * curr.desired_input_current > - PD_MAX_POWER_MW * 1000) - ma = (PD_MAX_POWER_MW * 1000) / mv; - else - return EC_SUCCESS; -#else - return EC_SUCCESS; -#endif -#endif /* CONFIG_USB_POWER_DELIVERY */ - } - -#ifdef CONFIG_CHARGER_MAX_INPUT_CURRENT - /* Limit input current limit to max limit for this board */ - ma = MIN(ma, CONFIG_CHARGER_MAX_INPUT_CURRENT); -#endif - curr.desired_input_current = ma; -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - /* Wake up charger task to allocate current between lid and base. */ - charge_wakeup(); - return EC_SUCCESS; -#else - return charger_set_input_current(ma); -#endif -} - -/*****************************************************************************/ -/* Host commands */ - -static enum ec_status -charge_command_charge_control(struct host_cmd_handler_args *args) -{ - const struct ec_params_charge_control *p = args->params; - int rv; - - rv = set_chg_ctrl_mode(p->mode); - if (rv != EC_SUCCESS) - return EC_RES_ERROR; - -#ifdef CONFIG_CHARGER_DISCHARGE_ON_AC -#ifdef CONFIG_CHARGER_DISCHARGE_ON_AC_CUSTOM - rv = board_discharge_on_ac(p->mode == CHARGE_CONTROL_DISCHARGE); -#else - rv = charger_discharge_on_ac(p->mode == CHARGE_CONTROL_DISCHARGE); -#endif - if (rv != EC_SUCCESS) - return EC_RES_ERROR; -#endif - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_CHARGE_CONTROL, charge_command_charge_control, - EC_VER_MASK(1)); - -static void reset_current_limit(void) -{ - user_current_limit = -1U; -} -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, reset_current_limit, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, reset_current_limit, HOOK_PRIO_DEFAULT); - -static enum ec_status -charge_command_current_limit(struct host_cmd_handler_args *args) -{ - const struct ec_params_current_limit *p = args->params; - - user_current_limit = p->limit; - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_CHARGE_CURRENT_LIMIT, charge_command_current_limit, - EC_VER_MASK(0)); - -static enum ec_status -charge_command_charge_state(struct host_cmd_handler_args *args) -{ - const struct ec_params_charge_state *in = args->params; - struct ec_response_charge_state *out = args->response; - uint32_t val; - int rv = EC_RES_SUCCESS; - - switch (in->cmd) { - - case CHARGE_STATE_CMD_GET_STATE: - out->get_state.ac = curr.ac; - out->get_state.chg_voltage = curr.chg.voltage; - out->get_state.chg_current = curr.chg.current; - out->get_state.chg_input_current = curr.chg.input_current; - out->get_state.batt_state_of_charge = curr.batt.state_of_charge; - args->response_size = sizeof(out->get_state); - break; - - case CHARGE_STATE_CMD_GET_PARAM: - val = 0; -#ifdef CONFIG_CHARGER_PROFILE_OVERRIDE - /* custom profile params */ - if (in->get_param.param >= CS_PARAM_CUSTOM_PROFILE_MIN && - in->get_param.param <= CS_PARAM_CUSTOM_PROFILE_MAX) { - rv = charger_profile_override_get_param( - in->get_param.param, &val); - } else -#endif -#ifdef CONFIG_CHARGE_STATE_DEBUG - /* debug params */ - if (in->get_param.param >= CS_PARAM_DEBUG_MIN && - in->get_param.param <= CS_PARAM_DEBUG_MAX) { - rv = charge_get_charge_state_debug( - in->get_param.param, &val); - } else -#endif - /* standard params */ - switch (in->get_param.param) { - case CS_PARAM_CHG_VOLTAGE: - val = curr.chg.voltage; - break; - case CS_PARAM_CHG_CURRENT: - val = curr.chg.current; - break; - case CS_PARAM_CHG_INPUT_CURRENT: - val = curr.chg.input_current; - break; - case CS_PARAM_CHG_STATUS: - val = curr.chg.status; - break; - case CS_PARAM_CHG_OPTION: - val = curr.chg.option; - break; - case CS_PARAM_LIMIT_POWER: -#ifdef CONFIG_CHARGER_LIMIT_POWER_THRESH_CHG_MW - /* - * LIMIT_POWER status is based on battery level - * and external charger power. - */ - if ((curr.batt.is_present != BP_YES || - curr.batt.state_of_charge < - CONFIG_CHARGER_LIMIT_POWER_THRESH_BAT_PCT) - && charge_manager_get_power_limit_uw() < - CONFIG_CHARGER_LIMIT_POWER_THRESH_CHG_MW - * 1000 && system_is_locked()) - val = 1; - else -#endif - val = 0; - break; - default: - rv = EC_RES_INVALID_PARAM; - } - - /* got something */ - out->get_param.value = val; - args->response_size = sizeof(out->get_param); - break; - - case CHARGE_STATE_CMD_SET_PARAM: - if (system_is_locked()) - return EC_RES_ACCESS_DENIED; - - val = in->set_param.value; -#ifdef CONFIG_CHARGER_PROFILE_OVERRIDE - /* custom profile params */ - if (in->set_param.param >= CS_PARAM_CUSTOM_PROFILE_MIN && - in->set_param.param <= CS_PARAM_CUSTOM_PROFILE_MAX) { - rv = charger_profile_override_set_param( - in->set_param.param, val); - } else -#endif - switch (in->set_param.param) { - case CS_PARAM_CHG_VOLTAGE: - chgstate_set_manual_voltage(val); - break; - case CS_PARAM_CHG_CURRENT: - chgstate_set_manual_current(val); - break; - case CS_PARAM_CHG_INPUT_CURRENT: - if (charger_set_input_current(val)) - rv = EC_RES_ERROR; - break; - case CS_PARAM_CHG_STATUS: - case CS_PARAM_LIMIT_POWER: - /* Can't set this */ - rv = EC_RES_ACCESS_DENIED; - break; - case CS_PARAM_CHG_OPTION: - if (charger_set_option(val)) - rv = EC_RES_ERROR; - break; - default: - rv = EC_RES_INVALID_PARAM; - - } - break; - - default: - CPRINTS("EC_CMD_CHARGE_STATE: bad cmd 0x%x", in->cmd); - rv = EC_RES_INVALID_PARAM; - } - - return rv; -} - -DECLARE_HOST_COMMAND(EC_CMD_CHARGE_STATE, charge_command_charge_state, - EC_VER_MASK(0)); - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_PWR_AVG - -static int command_pwr_avg(int argc, char **argv) -{ - int avg_mv; - int avg_ma; - int avg_mw; - - if (argc != 1) - return EC_ERROR_PARAM_COUNT; - - avg_mv = battery_get_avg_voltage(); - if (avg_mv < 0) - return EC_ERROR_UNKNOWN; - avg_ma = battery_get_avg_current(); - avg_mw = avg_mv * avg_ma / 1000; - - ccprintf("mv = %d\nma = %d\nmw = %d\n", - avg_mv, avg_ma, avg_mw); - return EC_SUCCESS; -} - -DECLARE_CONSOLE_COMMAND(pwr_avg, command_pwr_avg, - NULL, - "Get 1 min power average"); - -#endif /* CONFIG_CMD_PWR_AVG */ - -static int command_chgstate(int argc, char **argv) -{ - int rv; - int val; - - if (argc > 1) { - if (!strcasecmp(argv[1], "idle")) { - if (argc <= 2) - return EC_ERROR_PARAM_COUNT; - if (!parse_bool(argv[2], &val)) - return EC_ERROR_PARAM2; - rv = set_chg_ctrl_mode(val ? CHARGE_CONTROL_IDLE : - CHARGE_CONTROL_NORMAL); - if (rv) - return rv; -#ifdef CONFIG_CHARGER_DISCHARGE_ON_AC - } else if (!strcasecmp(argv[1], "discharge")) { - if (argc <= 2) - return EC_ERROR_PARAM_COUNT; - if (!parse_bool(argv[2], &val)) - return EC_ERROR_PARAM2; - rv = set_chg_ctrl_mode(val ? CHARGE_CONTROL_DISCHARGE : - CHARGE_CONTROL_NORMAL); - if (rv) - return rv; -#ifdef CONFIG_CHARGER_DISCHARGE_ON_AC_CUSTOM - rv = board_discharge_on_ac(val); -#else - rv = charger_discharge_on_ac(val); -#endif /* CONFIG_CHARGER_DISCHARGE_ON_AC_CUSTOM */ - if (rv) - return rv; -#endif /* CONFIG_CHARGER_DISCHARGE_ON_AC */ - } else if (!strcasecmp(argv[1], "debug")) { - if (argc <= 2) - return EC_ERROR_PARAM_COUNT; - if (!parse_bool(argv[2], &debugging)) - return EC_ERROR_PARAM2; - } else { - return EC_ERROR_PARAM1; - } - } - - dump_charge_state(); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(chgstate, command_chgstate, - "[idle|discharge|debug on|off]", - "Get/set charge state machine status"); - -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER -static int command_chgdualdebug(int argc, char **argv) -{ - int val; - char *e; - - if (argc > 1) { - if (argv[1][0] == 'c') { - if (argc <= 2) - return EC_ERROR_PARAM_COUNT; - - if (!strcasecmp(argv[2], "auto")) { - val = -1; - } else { - val = strtoi(argv[2], &e, 0); - if (*e || val < 0) - return EC_ERROR_PARAM2; - } - - manual_ac_current_base = val; - charge_wakeup(); - } else if (argv[1][0] == 'd') { - if (argc <= 2) - return EC_ERROR_PARAM_COUNT; - - if (!strcasecmp(argv[2], "auto")) { - manual_noac_enabled = 0; - } else { - val = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - manual_noac_current_base = val; - manual_noac_enabled = 1; - } - charge_wakeup(); - } else { - return EC_ERROR_PARAM1; - } - } else { - ccprintf("Base/Lid: %d%s/%d mA\n", - prev_current_base, prev_allow_charge_base ? "+" : "", - prev_current_lid); - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(chgdualdebug, command_chgdualdebug, - "[charge (auto|)|discharge (auto|)]", - "Manually control dual-battery charging algorithm."); -#endif - -#ifdef CONFIG_CHARGE_STATE_DEBUG -int charge_get_charge_state_debug(int param, uint32_t *value) -{ - switch (param) { - case CS_PARAM_DEBUG_CTL_MODE: - *value = chg_ctl_mode; - break; - case CS_PARAM_DEBUG_MANUAL_CURRENT: - *value = manual_current; - break; - case CS_PARAM_DEBUG_MANUAL_VOLTAGE: - *value = manual_voltage; - break; - case CS_PARAM_DEBUG_SEEMS_DEAD: - *value = battery_seems_to_be_dead; - break; - case CS_PARAM_DEBUG_SEEMS_DISCONNECTED: - *value = battery_seems_to_be_disconnected; - break; - case CS_PARAM_DEBUG_BATT_REMOVED: - *value = battery_was_removed; - break; - default: - *value = 0; - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} -#endif diff --git a/common/charger.c b/common/charger.c deleted file mode 100644 index 7ee80a9c23..0000000000 --- a/common/charger.c +++ /dev/null @@ -1,211 +0,0 @@ -/* Copyright 2013 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 functions for battery charging. - */ - -#include "battery_smart.h" -#include "charge_state_v2.h" -#include "charger.h" -#include "common.h" -#include "console.h" -#include "dptf.h" -#include "host_command.h" -#include "printf.h" -#include "util.h" -#include "hooks.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_CHARGER, outstr) -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -/* DPTF current limit, -1 = none */ -static int dptf_limit_ma = -1; - -void dptf_set_charging_current_limit(int ma) -{ - dptf_limit_ma = ma >= 0 ? ma : -1; -} - -int dptf_get_charging_current_limit(void) -{ - return dptf_limit_ma; -} - -static void dptf_disable_hook(void) -{ - /* Before get to Sx, EC should take control of charger from DPTF */ - dptf_limit_ma = -1; -} -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, dptf_disable_hook, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, dptf_disable_hook, HOOK_PRIO_DEFAULT); - -int charger_closest_voltage(int voltage) -{ - const struct charger_info *info = charger_get_info(); - - /* - * If the requested voltage is non-zero but below our minimum, - * return the minimum. See crosbug.com/p/8662. - */ - if (voltage > 0 && voltage < info->voltage_min) - return info->voltage_min; - - /* Clip to max */ - if (voltage > info->voltage_max) - return info->voltage_max; - - /* Otherwise round down to nearest voltage step */ - return voltage - (voltage % info->voltage_step); -} - -int charger_closest_current(int current) -{ - const struct charger_info * const info = charger_get_info(); - - /* Apply DPTF limit if necessary */ - if (dptf_limit_ma >= 0 && current > dptf_limit_ma) - current = dptf_limit_ma; - - /* - * If the requested current is non-zero but below our minimum, - * return the minimum. See crosbug.com/p/8662. - */ - if (current > 0 && current < info->current_min) - return info->current_min; - - /* Clip to max */ - if (current > info->current_max) - return info->current_max; - - /* Otherwise round down to nearest current step */ - return current - (current % info->current_step); -} - -void charger_get_params(struct charger_params *chg) -{ - memset(chg, 0, sizeof(*chg)); - - if (charger_get_current(&chg->current)) - chg->flags |= CHG_FLAG_BAD_CURRENT; - - if (charger_get_voltage(&chg->voltage)) - chg->flags |= CHG_FLAG_BAD_VOLTAGE; - - if (charger_get_input_current(&chg->input_current)) - chg->flags |= CHG_FLAG_BAD_INPUT_CURRENT; - - if (charger_get_status(&chg->status)) - chg->flags |= CHG_FLAG_BAD_STATUS; - - if (charger_get_option(&chg->option)) - chg->flags |= CHG_FLAG_BAD_OPTION; -} - -static void print_item_name(const char *name) -{ - ccprintf(" %-8s", name); -} - -static int check_print_error(int rv) -{ - if (rv == EC_SUCCESS) - return 1; - ccputs(rv == EC_ERROR_UNIMPLEMENTED ? "(unsupported)\n" : "(error)\n"); - return 0; -} - -void print_charger_debug(void) -{ - int d; - const struct charger_info *info = charger_get_info(); - - /* info */ - print_item_name("Name:"); - ccprintf("%s\n", info->name); - - /* option */ - print_item_name("Option:"); - if (check_print_error(charger_get_option(&d))) - ccprintf("%pb (0x%04x)\n", BINARY_VALUE(d, 16), d); - - /* manufacturer id */ - print_item_name("Man id:"); - if (check_print_error(charger_manufacturer_id(&d))) - ccprintf("0x%04x\n", d); - - /* device id */ - print_item_name("Dev id:"); - if (check_print_error(charger_device_id(&d))) - ccprintf("0x%04x\n", d); - - /* charge voltage limit */ - print_item_name("V_batt:"); - if (check_print_error(charger_get_voltage(&d))) - ccprintf("%5d (%4d - %5d, %3d)\n", d, - info->voltage_min, info->voltage_max, - info->voltage_step); - - /* charge current limit */ - print_item_name("I_batt:"); - if (check_print_error(charger_get_current(&d))) - ccprintf("%5d (%4d - %5d, %3d)\n", d, - info->current_min, info->current_max, - info->current_step); - - /* input current limit */ - print_item_name("I_in:"); - if (check_print_error(charger_get_input_current(&d))) - ccprintf("%5d (%4d - %5d, %3d)\n", d, - info->input_current_min, info->input_current_max, - info->input_current_step); - - /* dptf current limit */ - print_item_name("I_dptf:"); - if (dptf_limit_ma >= 0) - ccprintf("%5d\n", dptf_limit_ma); - else - ccputs("disabled\n"); -} - -static int command_charger(int argc, char **argv) -{ - int d; - char *e; - - if (argc != 3) { - print_charger_debug(); - return EC_SUCCESS; - } - - if (strcasecmp(argv[1], "input") == 0) { - d = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - return charger_set_input_current(d); - } else if (strcasecmp(argv[1], "current") == 0) { - d = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - chgstate_set_manual_current(d); - return charger_set_current(d); - } else if (strcasecmp(argv[1], "voltage") == 0) { - d = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - chgstate_set_manual_voltage(d); - return charger_set_voltage(d); - } else if (strcasecmp(argv[1], "dptf") == 0) { - d = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - dptf_limit_ma = d; - return EC_SUCCESS; - } else - return EC_ERROR_PARAM1; -} - -DECLARE_CONSOLE_COMMAND(charger, command_charger, - "[input | current | voltage | dptf] [newval]", - "Get or set charger param(s)"); diff --git a/common/charger_profile_override.c b/common/charger_profile_override.c deleted file mode 100644 index 2b691b9a5a..0000000000 --- a/common/charger_profile_override.c +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright 2016 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. - * - * Charger profile override for fast charging - */ - -#include "charger_profile_override.h" -#include "console.h" -#include "ec_commands.h" -#include "util.h" - -#ifdef CONFIG_CMD_CHARGER_PROFILE_OVERRIDE_TEST -static int fast_charge_test_on; -static int test_flag_temp; -static int test_flag_vtg; -static int test_temp_c; -static int test_vtg_mV = -1; -#endif - -static int fast_charging_allowed = 1; - -int charger_profile_override_common(struct charge_state_data *curr, - const struct fast_charge_params *fast_chg_params, - const struct fast_charge_profile **prev_chg_prof_info, - int batt_vtg_max) -{ - int i, voltage_range; - /* temp in 0.1 deg C */ - int temp_c = curr->batt.temperature - 2731; - int temp_ranges = fast_chg_params->total_temp_ranges; - const struct fast_charge_profile *chg_profile_info = - fast_chg_params->chg_profile_info; - -#ifdef CONFIG_CMD_CHARGER_PROFILE_OVERRIDE_TEST - if (fast_charge_test_on && test_vtg_mV != -1) { - temp_c = TEMPC_TENTHS_OF_DEG(test_temp_c); - curr->batt.voltage = test_vtg_mV; - - if (test_flag_temp) - curr->batt.flags |= BATT_FLAG_BAD_TEMPERATURE; - else - curr->batt.flags &= BATT_FLAG_BAD_TEMPERATURE; - - if (test_flag_vtg) - curr->batt.flags |= BATT_FLAG_BAD_VOLTAGE; - else - curr->batt.flags &= BATT_FLAG_BAD_VOLTAGE; - } -#endif - - /* - * Determine temperature range. - * If temp reading was bad, use last range. - */ - if (!(curr->batt.flags & BATT_FLAG_BAD_TEMPERATURE)) { - while (chg_profile_info && temp_ranges) { - if (temp_c <= chg_profile_info->temp_c) { - *prev_chg_prof_info = chg_profile_info; - break; - } - chg_profile_info++; - temp_ranges--; - } - - /* Invalid charge profile selected */ - if (!chg_profile_info || !temp_ranges) - return -1; - } - - /* - * If the battery voltage reading is bad or the battery voltage is - * greater than or equal to the lower limit or the battery voltage is - * not in the charger profile voltage range, consider battery has high - * voltage range so that we charge at lower current limit. - */ - voltage_range = CONFIG_CHARGER_PROFILE_VOLTAGE_RANGES - 1; - - if (!(curr->batt.flags & BATT_FLAG_BAD_VOLTAGE)) { - for (i = 0; i < CONFIG_CHARGER_PROFILE_VOLTAGE_RANGES - 1; - i++) { - if (curr->batt.voltage < - fast_chg_params->voltage_mV[i]) { - voltage_range = i; - break; - } - } - } - - /* - * If we are not charging or we aren't using fast charging profiles, - * then do not override desired current and voltage. - */ - if (curr->state != ST_CHARGE || !fast_charging_allowed) - return 0; - - /* - * Okay, impose our custom will: - */ - curr->requested_current = - (*prev_chg_prof_info)->current_mA[voltage_range]; - curr->requested_voltage = curr->requested_current ? batt_vtg_max : 0; - -#ifdef CONFIG_CMD_CHARGER_PROFILE_OVERRIDE_TEST - if (fast_charge_test_on) - ccprintf("Fast charge profile i=%dmA, v=%dmV\n", - curr->requested_current, curr->requested_voltage); -#endif - - return 0; -} - -/* Customs options controllable by host command. */ -#define PARAM_FASTCHARGE (CS_PARAM_CUSTOM_PROFILE_MIN + 0) - -enum ec_status charger_profile_override_get_param(uint32_t param, - uint32_t *value) -{ - if (param == PARAM_FASTCHARGE) { - *value = fast_charging_allowed; - return EC_RES_SUCCESS; - } - return EC_RES_INVALID_PARAM; -} - -enum ec_status charger_profile_override_set_param(uint32_t param, - uint32_t value) -{ - if (param == PARAM_FASTCHARGE) { - fast_charging_allowed = value; - return EC_RES_SUCCESS; - } - return EC_RES_INVALID_PARAM; -} - -#ifdef CONFIG_CMD_CHARGER_PROFILE_OVERRIDE -static int command_fastcharge(int argc, char **argv) -{ - if (argc > 1 && !parse_bool(argv[1], &fast_charging_allowed)) - return EC_ERROR_PARAM1; - - ccprintf("fastcharge %s\n", fast_charging_allowed ? "on" : "off"); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(fastcharge, command_fastcharge, - "[on|off]", - "Get or set fast charging profile"); -#endif - -/* - * Manipulate the temperature and voltage values and check if the correct - * fast charging profile is selected. - */ -#ifdef CONFIG_CMD_CHARGER_PROFILE_OVERRIDE_TEST -static int command_fastcharge_test(int argc, char **argv) -{ - char *e; - int test_on; - - if (argc > 1 && !parse_bool(argv[1], &test_on)) - return EC_ERROR_PARAM2; - - /* Check if only tuurn printf message on / off */ - if (argc == 2) { - fast_charge_test_on = test_on; - test_vtg_mV = -1; - - return EC_SUCCESS; - } - - /* Validate the input parameters */ - if ((test_on && argc != 6) || !test_on) - return EC_ERROR_PARAM_COUNT; - - test_flag_temp = strtoi(argv[2], &e, 0); - if (*e || test_flag_temp > 1 || test_flag_temp < 0) - return EC_ERROR_PARAM3; - - test_flag_vtg = strtoi(argv[3], &e, 0); - if (*e || test_flag_vtg > 1 || test_flag_vtg < 0) - return EC_ERROR_PARAM4; - - test_temp_c = strtoi(argv[4], &e, 0); - if (*e) - return EC_ERROR_PARAM5; - - test_vtg_mV = strtoi(argv[5], &e, 0); - if (*e || test_vtg_mV < 0) { - test_vtg_mV = -1; - return EC_ERROR_PARAM6; - } - - fast_charge_test_on = 1; - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(fastchgtest, command_fastcharge_test, - "off | on tempflag[1|0] vtgflag[1|0] temp_c vtg_mV", - "Check if fastcharge profile works"); -#endif diff --git a/common/i2c_master.c b/common/i2c_master.c index db26aaf0ee..340c20bb7e 100644 --- a/common/i2c_master.c +++ b/common/i2c_master.c @@ -7,7 +7,6 @@ #include "battery.h" #include "clock.h" -#include "charge_state.h" #include "console.h" #include "crc8.h" #include "host_command.h" diff --git a/common/lightbar.c b/common/lightbar.c index 814ef3b2cc..e535f5c20d 100644 --- a/common/lightbar.c +++ b/common/lightbar.c @@ -10,7 +10,6 @@ #include "simulation.h" #else #include "battery.h" -#include "charge_state.h" #include "common.h" #include "console.h" #include "ec_commands.h" diff --git a/include/charge_ramp.h b/include/charge_ramp.h deleted file mode 100644 index c4082fdbf2..0000000000 --- a/include/charge_ramp.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright 2015 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. - */ - -/* Charge input current limit ramp header for Chrome EC */ - -#ifndef __CROS_EC_CHARGE_RAMP_H -#define __CROS_EC_CHARGE_RAMP_H - -#include "timer.h" - -/* Charge ramp state used for checking VBUS */ -enum chg_ramp_vbus_state { - CHG_RAMP_VBUS_RAMPING, - CHG_RAMP_VBUS_STABLE -}; - -/** - * Check if VBUS is too low - * - * @param port Charge ramp port - * @param ramp_state Current ramp state - * - * @return VBUS is sagging low - */ -int board_is_vbus_too_low(int port, enum chg_ramp_vbus_state ramp_state); - -/** - * Check if ramping is allowed for given supplier - * - * @supplier Supplier to check - * - * @return Ramping is allowed for given supplier - */ -int chg_ramp_allowed(int supplier); - -/** - * Get the maximum current limit that we are allowed to ramp to - * - * @supplier Active supplier type - * @sup_curr Input current limit based on supplier - * - * @return Maximum current in mA - */ -int chg_ramp_max(int supplier, int sup_curr); - -/** - * Get the input current limit set by ramp module - * - * Active input current limit (mA) - */ -int chg_ramp_get_current_limit(void); - -/** - * Return if charge ramping has reached stable state - * - * @return 1 if stable, 0 otherwise - */ -int chg_ramp_is_stable(void); - -/** - * Return if charge ramping has reached detected state - * - * @return 1 if detected, 0 otherwise - */ -int chg_ramp_is_detected(void); - -#ifdef HAS_TASK_CHG_RAMP -/** - * Notify charge ramp module of supplier type change on a port. If port - * is CHARGE_PORT_NONE, the call indicates the last charge supplier went - * away. - * - * @port Active charging port - * @supplier Active charging supplier - * @current Minimum input current limit - * @registration_time Timestamp of when the supplier is registered - * @voltage Negotiated charge voltage. - */ -void chg_ramp_charge_supplier_change(int port, int supplier, int current, - timestamp_t registration_time, int voltage); - -#else -static inline void chg_ramp_charge_supplier_change( - int port, int supplier, timestamp_t registration_time) { } -#endif - -#endif /* __CROS_EC_CHARGE_RAMP_H */ diff --git a/include/charge_state.h b/include/charge_state.h deleted file mode 100644 index 66fa84aa3c..0000000000 --- a/include/charge_state.h +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright 2014 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. - */ -#ifndef __CROS_EC_CHARGE_STATE_H -#define __CROS_EC_CHARGE_STATE_H - -#include "common.h" -#include "timer.h" - -/* Stuff that's common to all charger implementations can go here. */ - -/* Seconds to spend trying to wake a non-responsive battery */ -#define PRECHARGE_TIMEOUT CONFIG_BATTERY_PRECHARGE_TIMEOUT - -/* Power state task polling periods in usec */ -#define CHARGE_POLL_PERIOD_VERY_LONG MINUTE -#define CHARGE_POLL_PERIOD_LONG (MSEC * 500) -#define CHARGE_POLL_PERIOD_CHARGE (MSEC * 250) -#define CHARGE_POLL_PERIOD_SHORT (MSEC * 100) -#define CHARGE_MIN_SLEEP_USEC (MSEC * 50) -/* If a board hasn't provided a max sleep, use 1 minute as default */ -#ifndef CHARGE_MAX_SLEEP_USEC -#define CHARGE_MAX_SLEEP_USEC MINUTE -#endif - -/* Power states */ -enum charge_state { - /* Meta-state; unchanged from previous time through task loop */ - PWR_STATE_UNCHANGE = 0, - /* Initializing charge state machine at boot */ - PWR_STATE_INIT, - /* Re-initializing charge state machine */ - PWR_STATE_REINIT, - /* Just transitioned from init to idle */ - PWR_STATE_IDLE0, - /* Idle; AC present */ - PWR_STATE_IDLE, - /* Discharging */ - PWR_STATE_DISCHARGE, - /* Discharging and fully charged */ - PWR_STATE_DISCHARGE_FULL, - /* Charging */ - PWR_STATE_CHARGE, - /* Charging, almost fully charged */ - PWR_STATE_CHARGE_NEAR_FULL, - /* Charging state machine error */ - PWR_STATE_ERROR -}; - -/* Charge state flags */ -/* Forcing idle state */ -#define CHARGE_FLAG_FORCE_IDLE BIT(0) -/* External (AC) power is present */ -#define CHARGE_FLAG_EXTERNAL_POWER BIT(1) -/* Battery is responsive */ -#define CHARGE_FLAG_BATT_RESPONSIVE BIT(2) - -/* Debugging constants, in the same order as enum charge_state. This string - * table was moved here to sync with enum above. - */ -#define CHARGE_STATE_NAME_TABLE { \ - "unchange", \ - "init", \ - "reinit", \ - "idle0", \ - "idle", \ - "discharge", \ - "discharge_full", \ - "charge", \ - "charge_near_full", \ - "error" \ - } - /* End of CHARGE_STATE_NAME_TABLE macro */ - - -/** - * Return current charge state. - */ -enum charge_state charge_get_state(void); - -/** - * Return non-zero if battery is so low we want to keep AP off. - */ -int charge_keep_power_off(void); - -/** - * Return current charge state flags (CHARGE_FLAG_*) - */ -uint32_t charge_get_flags(void); - -#if defined(CONFIG_CHARGER) -/** - * Return current battery charge percentage. - */ -int charge_get_percent(void); -#elif defined(CONFIG_BATTERY) -/** - * Return current battery charge if not using charge manager sub-system. - */ -int board_get_battery_soc(void); -#endif - -/** - * Return current display charge in 10ths of a percent (e.g. 1000 = 100.0%) - */ -int charge_get_display_charge(void); - -/** - * Check if board is consuming full input current - * - * This returns true if the battery charge percentage is between 2% and 95% - * exclusive. - * - * @return Board is consuming full input current - */ -int charge_is_consuming_full_input_current(void); - -/** - * Return non-zero if discharging and battery so low we should shut down. - */ -int charge_want_shutdown(void); - -/** - * Return non-zero if the battery level is too low to allow power on, even if - * a charger is attached. - * - * @param power_button_pressed True if the power-up attempt is caused by a - * power button press. - */ -int charge_prevent_power_on(int power_button_pressed); - -/** - * Get the last polled battery/charger temperature. - * - * @param idx Sensor index to read. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int charge_get_battery_temp(int idx, int *temp_ptr); - -/** - * Get the pointer to the battery parameters we saved in charge state. - * - * Use this carefully. Other threads can modify data while you are reading. - */ -const struct batt_params *charger_current_battery_params(void); - - -/* Config Charger */ -#include "charge_state_v2.h" - -#endif /* __CROS_EC_CHARGE_STATE_H */ diff --git a/include/charge_state_v2.h b/include/charge_state_v2.h deleted file mode 100644 index c958c0ed7c..0000000000 --- a/include/charge_state_v2.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright 2014 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. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "charger.h" -#include "chipset.h" -#include "ec_ec_comm_master.h" -#include "timer.h" - -#ifndef __CROS_EC_CHARGE_STATE_V2_H -#define __CROS_EC_CHARGE_STATE_V2_H - -#if defined(CONFIG_I2C_VIRTUAL_BATTERY) && defined(CONFIG_BATTERY_SMART) -#define VIRTUAL_BATTERY_ADDR_FLAGS BATTERY_ADDR_FLAGS -#endif -/* - * The values exported by charge_get_state() and charge_get_flags() are used - * only to control the LEDs (with one not-quite-correct exception). For V2 - * we use a different set of states internally. - */ -enum charge_state_v2 { - ST_IDLE = 0, - ST_DISCHARGE, - ST_CHARGE, - ST_PRECHARGE, - - NUM_STATES_V2 -}; - -struct charge_state_data { - timestamp_t ts; - int ac; - int batt_is_charging; - struct charger_params chg; - struct batt_params batt; - enum charge_state_v2 state; - int requested_voltage; - int requested_current; - int desired_input_current; -#ifdef CONFIG_CHARGER_OTG - int output_current; -#endif -#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER - int input_voltage; -#endif -}; - -/** - * Set the output current limit and voltage. This is used to provide power from - * the charger chip ("OTG" mode). - * - * @param ma Maximum current to provide in mA (0 to disable output). - * @param mv Voltage in mV (ignored if ma == 0). - * @return EC_SUCCESS or error - */ -int charge_set_output_current_limit(int ma, int mv); - -/** - * Set the charge input current limit. This value is stored and sent every - * time AC is applied. - * - * @param ma New input current limit in mA - * @param mv Negotiated charge voltage in mV. - * @return EC_SUCCESS or error - */ -int charge_set_input_current_limit(int ma, int mv); - -/* - * Expose charge/battery related state - * - * @param param command to get corresponding data - * @param value the corresponding data - * @return EC_SUCCESS or error - */ -#ifdef CONFIG_CHARGE_STATE_DEBUG -int charge_get_charge_state_debug(int param, uint32_t *value); -#endif /* CONFIG_CHARGE_STATE_DEBUG */ - -/** - * Set the desired manual charge current when in idle mode. - * - * @param curr_ma: Charge current in mA. - */ -void chgstate_set_manual_current(int curr_ma); - -/** - * Set the desired manual charge voltage when in idle mode. - * - * @param volt_mv: Charge voltage in mV. - */ -void chgstate_set_manual_voltage(int volt_mv); - -/** - * Board-specific routine to indicate if the base is connected. - */ -int board_is_base_connected(void); - -/** - * Board-specific routine to enable power distribution between lid and base - * (current can flow both ways). - */ -void board_enable_base_power(int enable); - -/** - * Board-specific routine to reset the base (in case it is unresponsive, e.g. - * if we told it to hibernate). - */ -void board_base_reset(void); - -/** - * Callback with which boards determine action on critical low battery - * - * The default implementation is provided in charge_state_v2.c. Overwrite it - * to customize it. - * - * @param curr Pointer to struct charge_state_data - * @return Action to take. - */ -enum critical_shutdown board_critical_shutdown_check( - struct charge_state_data *curr); - -/** - * Callback to set battery level for shutdown - * - * A board can implement this to customize shutdown battery level at runtime. - * - * @return battery level for shutdown - */ -uint8_t board_set_battery_level_shutdown(void); - -#endif /* __CROS_EC_CHARGE_STATE_V2_H */ diff --git a/include/charger.h b/include/charger.h deleted file mode 100644 index 342f6a7b48..0000000000 --- a/include/charger.h +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright 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. - */ - -/* Charger/battery debug command module for Chrome EC */ - -#ifndef __CROS_EC_CHARGER_H -#define __CROS_EC_CHARGER_H - -#include "common.h" - -/* Charger information - * voltage unit: mV - * current unit: mA - */ -struct charger_info { - const char *name; - uint16_t voltage_max; - uint16_t voltage_min; - uint16_t voltage_step; - uint16_t current_max; - uint16_t current_min; - uint16_t current_step; - uint16_t input_current_max; - uint16_t input_current_min; - uint16_t input_current_step; -}; - -/* - * Parameters common to all chargers. Current is in mA, voltage in mV. - * The status and option values are charger-specific. - */ -struct charger_params { - int current; - int voltage; - int input_current; - int status; - int option; - int flags; -}; - -/* Get the current charger_params. Failures are reported in .flags */ -void charger_get_params(struct charger_params *chg); - -/* Bits to indicate which fields of struct charger_params could not be read */ -#define CHG_FLAG_BAD_CURRENT 0x00000001 -#define CHG_FLAG_BAD_VOLTAGE 0x00000002 -#define CHG_FLAG_BAD_INPUT_CURRENT 0x00000004 -#define CHG_FLAG_BAD_STATUS 0x00000008 -#define CHG_FLAG_BAD_OPTION 0x00000010 -/* All of the above CHG_FLAG_BAD_* bits */ -#define CHG_FLAG_BAD_ANY 0x0000001f - -/* Power state machine post init */ -int charger_post_init(void); - -/* Get charger information. */ -const struct charger_info *charger_get_info(void); - -/* Get smart battery charger status. Supported flags may vary. */ -int charger_get_status(int *status); - -/* Set smart battery charger mode. Supported modes may vary. */ -int charger_set_mode(int mode); - -/** - * For chargers that are able to supply output power for OTG dongle, this - * function enables or disables power output. - */ -int charger_enable_otg_power(int enabled); - -/** - * Sets OTG current limit and voltage (independent of whether OTG power is - * currently enabled). - * - * Depending on the charger and use case, one needs to be careful about - * changing the current/voltage while OTG power is enabled, and it might be wise - * to reset the value before enabling OTG power to ensure one does not provide - * excessive voltage to a device. - * - * @param output_current Requested current limit in mA, driver should - * round the value up. - * @param output_voltage Requested voltage in mV, driver should round the - * the value down. - * - * @return EC_SUCCESS on success, an error otherwise. - */ -int charger_set_otg_current_voltage(int output_current, int output_voltage); - -/** - * Is the charger sourcing VBUS / OTG power? - * - * @param port The Type-C port number. - * @return 1 if sourcing VBUS, 0 if not. - */ -int charger_is_sourcing_otg_power(int port); - -/** - * Return the closest match the charger can supply to the requested current. - * - * @param current Requested current in mA. - * - * @return Current the charger will actually supply if is requested. - */ -int charger_closest_current(int current); - -/** - * Return the closest match the charger can supply to the requested voltage. - * - * @param voltage Requested voltage in mV. - * - * @return Voltage the charger will actually supply if is requested. - */ -int charger_closest_voltage(int voltage); - -/* Get/set charge current limit in mA */ -int charger_get_current(int *current); -int charger_set_current(int current); - -/* Get/set charge voltage limit in mV */ -int charger_get_voltage(int *voltage); -int charger_set_voltage(int voltage); - -/* Discharge battery when on AC power. */ -int charger_discharge_on_ac(int enable); - -/* Get the VBUS voltage (mV) from the charger */ -int charger_get_vbus_voltage(int port); - -/* Custom board function to discharge battery when on AC power */ -int board_discharge_on_ac(int enable); - -/* - * Read the current total system power in uW (usually from PSYS). - * Can be negative if the PSYS output is not currently enabled (e.g. AP is off). - */ -int charger_get_system_power(void); - -/* Other parameters that may be charger-specific, but are common so far. */ - -/* Set desired input current value */ -int charger_set_input_current(int input_current); - -/* - * Get actual input current value. - * Actual input current may be less than the desired input current set - * due to current ratings of the wall adapter. - */ -int charger_get_input_current(int *input_current); - -int charger_manufacturer_id(int *id); -int charger_device_id(int *id); -int charger_get_option(int *option); -int charger_set_option(int option); -int charger_set_hw_ramp(int enable); - -/* Print all charger info for debugging purposes */ -void print_charger_debug(void); - -#endif /* __CROS_EC_CHARGER_H */ - diff --git a/include/charger_detect.h b/include/charger_detect.h deleted file mode 100644 index ae2001e418..0000000000 --- a/include/charger_detect.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright 2016 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. - */ -/* Detect what adapter is connected */ - -#ifndef __CROS_CHARGER_DETECT_H -#define __CROS_CHARGER_DETECT_H - -/* - * Get attached device type. - * - * @return CHARGE_SUPPLIER_BC12_* or 0 if the device type was not detected - */ -int charger_detect_get_device_type(void); - -#endif /* __CROS_CHARGER_DETECT_H */ diff --git a/include/charger_profile_override.h b/include/charger_profile_override.h deleted file mode 100644 index 091eb11946..0000000000 --- a/include/charger_profile_override.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright 2016 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. - * - * Charger profile override for fast charging - */ - -#ifndef __CROS_EC_CHARGER_PROFILE_OVERRIDE_H -#define __CROS_EC_CHARGER_PROFILE_OVERRIDE_H - -#include "charge_state_v2.h" - -#define TEMPC_TENTHS_OF_DEG(c) ((c) * 10) - -#define CHARGER_PROF_TEMP_C_LAST_RANGE 0xFFFF - -#define CHARGER_PROF_VOLTAGE_MV_LAST_RANGE 0xFFFF - -/* Charge profile override info */ -struct fast_charge_profile { - /* temperature in 10ths of a degree C */ - const int temp_c; - /* charge current for respective battery voltage ranges in mA. */ - const int current_mA[CONFIG_CHARGER_PROFILE_VOLTAGE_RANGES]; -}; - -/* Charge profile override parameters */ -struct fast_charge_params { - /* Total temperature ranges of the charge profile */ - const int total_temp_ranges; - /* Default temperature range of the charge profile */ - const int default_temp_range_profile; - /* - * Battery voltage ranges in mV. - * It is assumed that these values are added in ascending order in the - * board battery file. - */ - const int voltage_mV[CONFIG_CHARGER_PROFILE_VOLTAGE_RANGES]; - const struct fast_charge_profile *chg_profile_info; -}; - -/** - * Optional customization of charger profile override for fast charging. - * - * On input, the struct reflects the default behavior. The function can make - * changes to the state, requested_voltage, or requested_current. - * - * @param curr Charge state machine data. - * - * @return - * >0 Desired time in usec for this poll period. - * 0 Use the default poll period (which varies with the state). - * <0 An error occurred. The poll time will be shorter than usual. - * Too many errors in a row may trigger some corrective action. - */ -int charger_profile_override(struct charge_state_data *curr); - -/** - * Common code of charger profile override for fast charging. - * - * @param curr Charge state machine data. - * @param fast_chg_params Fast charge profile parameters. - * @param prev_chg_prof_info Previous charge profile info. - * @param batt_vtg_max Maximum battery voltage. - * - * @return - * >0 Desired time in usec for this poll period. - * 0 Use the default poll period (which varies with the state). - * <0 An error occurred. The poll time will be shorter than usual. - * Too many errors in a row may trigger some corrective action. - */ -int charger_profile_override_common(struct charge_state_data *curr, - const struct fast_charge_params *fast_chg_params, - const struct fast_charge_profile **prev_chg_prof_info, - int batt_vtg_max); - -/* - * Access to custom profile params through host commands. - * What this does is up to the implementation. - */ -enum ec_status charger_profile_override_get_param(uint32_t param, - uint32_t *value); -enum ec_status charger_profile_override_set_param(uint32_t param, - uint32_t value); - -#endif /* __CROS_EC_CHARGER_PROFILE_OVERRIDE_H */ -- cgit v1.2.1