diff options
-rw-r--r-- | board/samus_pd/board.c | 162 | ||||
-rw-r--r-- | board/samus_pd/board.h | 4 | ||||
-rw-r--r-- | common/charge_manager.c | 20 | ||||
-rw-r--r-- | common/charge_state_v2.c | 45 | ||||
-rw-r--r-- | common/lightbar.c | 13 | ||||
-rw-r--r-- | include/charge_manager.h | 1 |
6 files changed, 201 insertions, 44 deletions
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c index 65e9f03bf7..8359d770f2 100644 --- a/board/samus_pd/board.c +++ b/board/samus_pd/board.c @@ -34,6 +34,11 @@ static enum power_state ps; /* Battery state of charge */ static int batt_soc; +static int fake_state_of_charge = -1; /* use real soc by default */ + +/* Last charge port override when charging turned off due to full battery */ +static int chg_override_port = OVERRIDE_OFF; +static int chg_is_cutoff; /* PD MCU status and host event status for host command */ static struct ec_response_pd_status pd_status; @@ -59,19 +64,20 @@ BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT); static void pericom_port0_reenable_interrupts(void) { + CPRINTS("VBUS p0 %d", gpio_get_level(GPIO_USB_C0_VBUS_WAKE)); pi3usb9281_enable_interrupts(0); } DECLARE_DEFERRED(pericom_port0_reenable_interrupts); static void pericom_port1_reenable_interrupts(void) { + CPRINTS("VBUS p1 %d", gpio_get_level(GPIO_USB_C1_VBUS_WAKE)); pi3usb9281_enable_interrupts(1); } DECLARE_DEFERRED(pericom_port1_reenable_interrupts); void vbus0_evt(enum gpio_signal signal) { - ccprintf("VBUS %d, %d!\n", signal, gpio_get_level(signal)); /* * Re-enable interrupts on pericom charger detector since the * chip may periodically reset itself, and come back up with @@ -84,7 +90,6 @@ void vbus0_evt(enum gpio_signal signal) void vbus1_evt(enum gpio_signal signal) { - ccprintf("VBUS %d, %d!\n", signal, gpio_get_level(signal)); /* * Re-enable interrupts on pericom charger detector since the * chip may periodically reset itself, and come back up with @@ -210,41 +215,96 @@ void usb1_evt(enum gpio_signal signal) wake_usb_charger_task(1); } -void pch_evt(enum gpio_signal signal) +/* When battery is full, cutoff charging by disabling AC input current */ +static void check_charging_cutoff(void) +{ + int port; + + /* Only check if charging needs to be turned off when not in S0 */ + if (ps == POWER_S0) + return; + + port = charge_manager_get_active_charge_port(); + + /* + * If battery is full disable charging, if battery is not full, restore + * charge port. + */ + if (!chg_is_cutoff && port != CHARGE_PORT_NONE && batt_soc == 100) { + charge_manager_set_override(OVERRIDE_DONT_CHARGE); + chg_is_cutoff = 1; + } else if (chg_is_cutoff && batt_soc < 100) { + charge_manager_set_override(chg_override_port); + chg_is_cutoff = 0; + } +} +DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, check_charging_cutoff, HOOK_PRIO_DEFAULT); + +static void chipset_s5_to_s3(void) { - /* Determine new chipset state, trigger corresponding hook */ + ps = POWER_S3; + hook_notify(HOOK_CHIPSET_STARTUP); +} + +static void chipset_s3_to_s0(void) +{ + /* Disable deep sleep and restore charge override port */ + disable_sleep(SLEEP_MASK_AP_RUN); + charge_manager_set_override(chg_override_port); + chg_is_cutoff = 0; + + ps = POWER_S0; + hook_notify(HOOK_CHIPSET_RESUME); +} + +static void chipset_s3_to_s5(void) +{ + ps = POWER_S5; + hook_notify(HOOK_CHIPSET_SHUTDOWN); +} + +static void chipset_s0_to_s3(void) +{ + /* Enable deep sleep and store charge override port */ + enable_sleep(SLEEP_MASK_AP_RUN); + chg_override_port = charge_manager_get_override(); + + ps = POWER_S3; + hook_notify(HOOK_CHIPSET_SUSPEND); +} + +static void pch_evt_deferred(void) +{ + /* Determine new chipset state, trigger corresponding transition */ switch (ps) { case POWER_S5: - if (gpio_get_level(GPIO_PCH_SLP_S5_L)) { - /* S5 -> S3 */ - hook_notify(HOOK_CHIPSET_STARTUP); - ps = POWER_S3; - } + if (gpio_get_level(GPIO_PCH_SLP_S5_L)) + chipset_s5_to_s3(); + if (gpio_get_level(GPIO_PCH_SLP_S3_L)) + chipset_s3_to_s0(); break; case POWER_S3: - if (gpio_get_level(GPIO_PCH_SLP_S3_L)) { - /* S3 -> S0: disable deep sleep */ - disable_sleep(SLEEP_MASK_AP_RUN); - hook_notify(HOOK_CHIPSET_RESUME); - ps = POWER_S0; - } else if (!gpio_get_level(GPIO_PCH_SLP_S5_L)) { - /* S3 -> S5 */ - hook_notify(HOOK_CHIPSET_SHUTDOWN); - ps = POWER_S5; - } + if (gpio_get_level(GPIO_PCH_SLP_S3_L)) + chipset_s3_to_s0(); + else if (!gpio_get_level(GPIO_PCH_SLP_S5_L)) + chipset_s3_to_s5(); break; case POWER_S0: - if (!gpio_get_level(GPIO_PCH_SLP_S3_L)) { - /* S0 -> S3: enable deep sleep */ - enable_sleep(SLEEP_MASK_AP_RUN); - hook_notify(HOOK_CHIPSET_SUSPEND); - ps = POWER_S3; - } + if (!gpio_get_level(GPIO_PCH_SLP_S3_L)) + chipset_s0_to_s3(); + if (!gpio_get_level(GPIO_PCH_SLP_S5_L)) + chipset_s3_to_s5(); break; default: break; } } +DECLARE_DEFERRED(pch_evt_deferred); + +void pch_evt(enum gpio_signal signal) +{ + hook_call_deferred(pch_evt_deferred, 0); +} void board_config_pre_init(void) { @@ -483,6 +543,7 @@ void board_flip_usb_mux(int port) void board_update_battery_soc(int soc) { batt_soc = soc; + check_charging_cutoff(); } int board_get_battery_soc(void) @@ -521,8 +582,10 @@ static void pd_send_ec_int(void) */ int board_set_active_charge_port(int charge_port) { - if (charge_port >= 0 && charge_port < PD_PORT_COUNT && - pd_get_role(charge_port) != PD_ROLE_SINK) { + /* charge port is a realy physical port */ + int is_real_port = (charge_port >= 0 && charge_port < PD_PORT_COUNT); + + if (is_real_port && pd_get_role(charge_port) != PD_ROLE_SINK) { CPRINTS("Skip enable p%d", charge_port); return EC_ERROR_INVAL; } @@ -531,6 +594,17 @@ int board_set_active_charge_port(int charge_port) gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, !(charge_port == 0)); gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, !(charge_port == 1)); + /* + * If new charge port when charge is cutoff, then user must have + * plugged in a new dedicated charger. This resets the charge + * override port and clears the charge cutoff flag. + */ + if (chg_is_cutoff && is_real_port) { + chg_override_port = OVERRIDE_OFF; + chg_is_cutoff = 0; + } + check_charging_cutoff(); + CPRINTS("New chg p%d", charge_port); return EC_SUCCESS; } @@ -602,6 +676,36 @@ DECLARE_CONSOLE_COMMAND(pdevent, command_pd_host_event, "Send PD host event", NULL); +static int command_battfake(int argc, char **argv) +{ + char *e; + int v; + + if (argc == 2) { + v = strtoi(argv[1], &e, 0); + if (*e || v < -1 || v > 100) + return EC_ERROR_PARAM1; + + fake_state_of_charge = v; + } + + if (fake_state_of_charge < 0) { + ccprintf("Using real batt level\n"); + } else { + ccprintf("Using fake batt level %d%%\n", + fake_state_of_charge); + } + + /* Send EC int to get batt info from EC */ + pd_send_ec_int(); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(battfake, command_battfake, + "percent (-1 = use real level)", + "Set fake battery level", + NULL); + /****************************************************************************/ /* Host commands */ static int ec_status_host_cmd(struct host_cmd_handler_args *args) @@ -609,7 +713,9 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args) const struct ec_params_pd_status *p = args->params; struct ec_response_pd_status *r = args->response; - board_update_battery_soc(p->batt_soc); + /* if not using fake soc, then update battery soc */ + board_update_battery_soc(fake_state_of_charge < 0 ? + p->batt_soc : fake_state_of_charge); *r = pd_status; diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h index ea660d1f84..adbb4f02df 100644 --- a/board/samus_pd/board.h +++ b/board/samus_pd/board.h @@ -66,9 +66,9 @@ */ #define CONFIG_SYSTEM_UNLOCKED -/* 10 deferrable tasks on this board */ +/* Maximum number of deferrable functions */ #undef DEFERRABLE_MAX_COUNT -#define DEFERRABLE_MAX_COUNT 8 +#define DEFERRABLE_MAX_COUNT 9 #ifndef __ASSEMBLER__ diff --git a/common/charge_manager.c b/common/charge_manager.c index 651cf3af5e..4b400f137c 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -347,6 +347,8 @@ int charge_manager_set_override(int port) ASSERT(port >= OVERRIDE_DONT_CHARGE && port < PD_PORT_COUNT); + CPRINTS("Charge Override: %d", port); + /* Supersede any pending delayed overrides. */ if (delayed_override_port != OVERRIDE_OFF) { if (delayed_override_port != port) @@ -387,6 +389,17 @@ int charge_manager_set_override(int port) return retval; } +/** + * Get the override port. OVERRIDE_OFF if no override port. + * OVERRIDE_DONT_CHARGE if override is set for no port. + * + * @return override port + */ +int charge_manager_get_override(void) +{ + return override_port; +} + int charge_manager_get_active_charge_port(void) { return charge_port; @@ -508,16 +521,19 @@ DECLARE_HOST_COMMAND(EC_CMD_PD_CHARGE_PORT_OVERRIDE, static int command_charge_port_override(int argc, char **argv) { int port = OVERRIDE_OFF; + int ret = EC_SUCCESS; char *e; if (argc >= 2) { port = strtoi(argv[1], &e, 0); if (*e || port < OVERRIDE_DONT_CHARGE || port >= PD_PORT_COUNT) return EC_ERROR_PARAM1; + ret = charge_manager_set_override(port); } - ccprintf("Set override: %d\n", port); - return charge_manager_set_override(port); + ccprintf("Override: %d\n", (argc >= 2 && ret == EC_SUCCESS) ? + port : override_port); + return ret; } DECLARE_CONSOLE_COMMAND(chgoverride, command_charge_port_override, "[port | -1 | -2]", diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index de7cfea731..051113c0e2 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -39,7 +39,8 @@ */ static const struct battery_info *batt_info; static struct charge_state_data curr; -static int prev_ac, prev_charge; +static int prev_ac, prev_charge, prev_full; +static int is_full; /* battery not accepting current */ static int state_machine_force_idle; static int manual_mode; /* volt/curr are no longer maintained by charger */ static unsigned int user_current_limit = -1U; @@ -275,14 +276,16 @@ static void show_charging_progress(void) } if (rv) - CPRINTS("Battery %d%% / ??h:?? %s", + CPRINTS("Battery %d%% / ??h:?? %s%s", curr.batt.state_of_charge, - to_full ? "to full" : "to empty"); + to_full ? "to full" : "to empty", + is_full ? ", not accepting current" : ""); else - CPRINTS("Battery %d%% / %dh:%d %s", + CPRINTS("Battery %d%% / %dh:%d %s%s", curr.batt.state_of_charge, minutes / 60, minutes % 60, - to_full ? "to full" : "to empty"); + to_full ? "to full" : "to empty", + is_full ? ", not accepting current" : ""); if (debugging) { ccprintf("battery:\n"); @@ -294,6 +297,26 @@ static void show_charging_progress(void) } } +/* Calculate if battery is full based on whether it is accepting charge */ +static int calc_is_full(void) +{ + static int 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. @@ -732,11 +755,17 @@ wait_for_it: notify_host_of_low_battery(); /* And the EC console */ - if (!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - curr.batt.state_of_charge != prev_charge) { + is_full = calc_is_full(); + if ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && + curr.batt.state_of_charge != prev_charge) || + (is_full != prev_full)) { show_charging_progress(); prev_charge = curr.batt.state_of_charge; +#ifdef HAS_TASK_PDCMD + host_command_pd_send_status(); +#endif } + prev_full = is_full; /* Turn charger off if it's not needed */ if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) { @@ -882,7 +911,7 @@ int charge_get_percent(void) * to the battery, that'll be zero, which is probably as good as * anything. */ - return curr.batt.state_of_charge; + return is_full ? 100 : curr.batt.state_of_charge; } int charge_temp_sensor_get_val(int idx, int *temp_ptr) diff --git a/common/lightbar.c b/common/lightbar.c index bc43a6080e..ab9bfa8985 100644 --- a/common/lightbar.c +++ b/common/lightbar.c @@ -80,7 +80,7 @@ static const struct lightbar_params_v1 default_params = { .tap_display_time = 3 * SECOND, /* total sequence time */ .tap_pct_red = 10, /* below this is red */ - .tap_pct_green = 97, /* above this is green */ + .tap_pct_green = 94, /* above this is green */ .tap_seg_min_on = 35, /* min intensity (%) for "on" */ .tap_seg_max_on = 100, /* max intensity (%) for "on" */ .tap_seg_osc = 50, /* amplitude for charging osc */ @@ -876,8 +876,9 @@ static uint32_t sequence_TAP_inner(int dir) f_mult = f_mult * gate[i] / FP_SCALE; - /* Pulse when charging */ - if (st.battery_is_charging) { + /* Pulse when charging and not yet full */ + if (st.battery_is_charging && + st.battery_percent <= st.p.tap_pct_green) { int scale = (FP_SCALE - f_osc * cycle_010(w++) / FP_SCALE); f_mult = f_mult * scale / FP_SCALE; @@ -906,6 +907,7 @@ static int force_dir = -1; /* Return 0 (left or none) or 1 (right) */ static int get_tap_direction(void) { + static int last_dir; int dir = 0; if (force_dir >= 0) @@ -914,10 +916,13 @@ static int get_tap_direction(void) else pd_exchange_status(&dir); #endif - if (dir != 1) + if (dir < 0) + dir = last_dir; + else if (dir != 1) dir = 0; CPRINTS("LB tap direction %d", dir); + last_dir = dir; return dir; } diff --git a/include/charge_manager.h b/include/charge_manager.h index d1ee472a50..0b1de3186d 100644 --- a/include/charge_manager.h +++ b/include/charge_manager.h @@ -31,6 +31,7 @@ void charge_manager_set_ceil(int port, int ceil); /* Select an 'override port', which is always the preferred charge port */ int charge_manager_set_override(int port); +int charge_manager_get_override(void); /* Returns the current active charge port, as determined by charge manager */ int charge_manager_get_active_charge_port(void); |