diff options
author | Will Tsai <will_tsai@wistron.corp-partner.google.com> | 2021-10-04 18:59:13 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-15 19:13:28 +0000 |
commit | 0899b717501b72f3ba88c3ee4e749ec60ad90819 (patch) | |
tree | 593bfc83662883b3a3ed26cf9804e415a2d0b0ac | |
parent | 0398923c16ee19fd31e1a43ace6d2c29a026c854 (diff) | |
download | chrome-ec-0899b717501b72f3ba88c3ee4e749ec60ad90819.tar.gz |
brya: add control prochot feature
BUG=b:198689488
BRANCH=none
TEST=make -j BOARD=gimble
Signed-off-by: Will Tsai <will_tsai@wistron.corp-partner.google.com>
Change-Id: I4be2dc8505baffaa8b7d0c9b6949711aca370778
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3201831
Tested-by: Scott Chao <scott_chao@wistron.corp-partner.google.com>
Commit-Queue: Boris Mittelberg <bmbm@google.com>
Reviewed-by: Boris Mittelberg <bmbm@google.com>
-rw-r--r-- | baseboard/brya/baseboard.h | 10 | ||||
-rw-r--r-- | baseboard/brya/build.mk | 1 | ||||
-rw-r--r-- | baseboard/brya/prochot.c | 253 |
3 files changed, 264 insertions, 0 deletions
diff --git a/baseboard/brya/baseboard.h b/baseboard/brya/baseboard.h index 757b504d16..dbee995546 100644 --- a/baseboard/brya/baseboard.h +++ b/baseboard/brya/baseboard.h @@ -144,6 +144,16 @@ #define CONFIG_PWM +/* Prochot assertion/deassertion ratios*/ +#define PROCHOT_ADAPTER_WATT_RATIO 97 +#define PROCHOT_ASSERTION_BATTERY_RATIO 95 +#define PROCHOT_DEASSERTION_BATTERY_RATIO 85 +#define PROCHOT_ASSERTION_PD_RATIO 105 +#define PROCHOT_DEASSERTION_PD_BATTERY_RATIO 95 +#define PROCHOT_ASSERTION_ADAPTER_RATIO 105 +#define PROCHOT_DEASSERTION_ADAPTER_RATIO 90 +#define PROCHOT_DEASSERTION_ADAPTER_BATT_RATIO 90 + /* Enable I2C Support */ #define CONFIG_I2C #define CONFIG_I2C_CONTROLLER diff --git a/baseboard/brya/build.mk b/baseboard/brya/build.mk index ca983f26ac..2ed0186242 100644 --- a/baseboard/brya/build.mk +++ b/baseboard/brya/build.mk @@ -10,4 +10,5 @@ baseboard-y= baseboard-y+=baseboard.o baseboard-y+=battery_presence.o baseboard-y+=cbi.o +baseboard-$(HAS_TASK_PROCHOT)+=prochot.o baseboard-y+=usb_pd_policy.o diff --git a/baseboard/brya/prochot.c b/baseboard/brya/prochot.c new file mode 100644 index 0000000000..39512cf5c6 --- /dev/null +++ b/baseboard/brya/prochot.c @@ -0,0 +1,253 @@ +/* Copyright 2021 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 "adc.h" +#include "battery.h" +#include "battery_smart.h" +#include "charge_manager.h" +#include "charger.h" +#include "console.h" +#include "driver/charger/bq25710.h" +#include "hooks.h" +#include "i2c.h" +#include "math_util.h" +#include "task.h" + +/* Console output macros */ +#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) + +#define ADT_RATING_W (PD_MAX_POWER_MW / 1000) +#define PROCHOT_EVENT_200MS_TICK TASK_EVENT_CUSTOM_BIT(0) + +struct batt_para { + int battery_continuous_discharge_mw; + int battery_design_mWh; + int flags; + int state_of_charge; +}; + +struct batt_para batt_params; + +static int cal_sys_watt(void) +{ + int adapter_voltage_mv; + int IDPM; + int Vacpacn; + int V_iadpt; + int W_adpt; + + Vacpacn = adc_read_channel(ADC_IADPT); + + /* the ratio selectable through IADPT_GAIN bit. */ + V_iadpt = Vacpacn * 1000 / 40; + + IDPM = V_iadpt / CONFIG_CHARGER_SENSE_RESISTOR_AC; + + adapter_voltage_mv = charge_manager_get_charger_voltage(); + + W_adpt = IDPM * adapter_voltage_mv / PROCHOT_ADAPTER_WATT_RATIO * 100; + + return W_adpt; +} + +static int get_batt_parameter(void) +{ + int battery_voltage; + int battery_current; + int battery_design_voltage_mv; + int battery_design_capacity_mAh; + int rv = 0; + + batt_params.flags = 0; + + /* read battery voltage */ + if (sb_read(SB_VOLTAGE, &battery_voltage)) + batt_params.flags |= BATT_FLAG_BAD_VOLTAGE; + + /* Battery_current sometimes return a very huge number + * and cause prochot keep toggling so add (int16_t) to guard it. + */ + if (sb_read(SB_CURRENT, &battery_current)) + batt_params.flags |= BATT_FLAG_BAD_CURRENT; + else + battery_current = (int16_t)battery_current; + + /* calculate battery wattage and convert to mW */ + batt_params.battery_continuous_discharge_mw = + (battery_voltage * battery_current) / 1000; + + rv |= sb_read(SB_DESIGN_VOLTAGE, &battery_design_voltage_mv); + rv |= sb_read(SB_DESIGN_CAPACITY, &battery_design_capacity_mAh); + batt_params.battery_design_mWh = (battery_design_voltage_mv * + battery_design_capacity_mAh) / 1000; + + if (sb_read(SB_RELATIVE_STATE_OF_CHARGE, &batt_params.state_of_charge)) + batt_params.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; + + return (batt_params.flags || rv); +} + +static int get_chg_watt(void) +{ + int adapter_current_ma; + int adapter_voltage_mv; + int adapter_wattage; + + /* Get adapter wattage */ + adapter_current_ma = charge_manager_get_charger_current(); + adapter_voltage_mv = charge_manager_get_charger_voltage(); + adapter_wattage = adapter_current_ma * adapter_voltage_mv / 1000 / 1000; + + return adapter_wattage; +} + +static int set_register_charge_option(void) +{ + int reg; + int rv; + + rv = i2c_read16(I2C_PORT_CHARGER, BQ25710_SMBUS_ADDR1_FLAGS, + BQ25710_REG_CHARGE_OPTION_0, ®); + if (rv == EC_SUCCESS) { + reg |= BQ25710_CHARGE_OPTION_0_IADP_GAIN; + /* if AC only, disable IDPM, + * because it will cause charger keep asserting PROCHOT + */ + if (!battery_hw_present()) + reg &= ~BQ25710_CHARGE_OPTION_0_EN_IDPM; + else + reg |= BQ25710_CHARGE_OPTION_0_EN_IDPM; + } else { + CPRINTS("Failed to read bq25720"); + return rv; + } + + return i2c_write16(I2C_PORT_CHARGER, BQ25710_SMBUS_ADDR1_FLAGS, + BQ25710_REG_CHARGE_OPTION_0, reg); +} + +static void assert_prochot(void) +{ + int adapter_wattage; + int adpt_mw; + int total_W; + + /* Set 0x12 bit4=1 */ + if (set_register_charge_option()) { + CPRINTS("Failed to set bq25720"); + return; + } + + /* Calculate actual system W */ + adpt_mw = cal_sys_watt(); + + /* Read battery info + * if any flag is set, skip this cycle and hope + * the next cycle succeeds + */ + if (get_batt_parameter()) + return; + + /* When battery is discharging, the battery current will be negative */ + if (batt_params.battery_continuous_discharge_mw < 0) { + total_W = adpt_mw + + ABS(batt_params.battery_continuous_discharge_mw); + } else { + /* we won't assert prochot when battery is charging. */ + total_W = adpt_mw; + } + total_W /= 1000; + + /* Get adapter wattage */ + adapter_wattage = get_chg_watt(); + + /* + * no AC, don't assert PROCHOT. + * If AC exists, PROCHOT will only be asserted when the battery + * is physical present and the battery wattage is over 95% of + * the max continue discharge current of battery spec. + * When the battery wattage is lower than 85% of the max + * continue discharge current of battery spec, PROCHOT will be + * deasserted. + */ + if (!extpower_is_present()) { + if (!battery_hw_present()) { + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + } else { + batt_params.battery_continuous_discharge_mw = + ABS(batt_params.battery_continuous_discharge_mw); + if ((batt_params.battery_continuous_discharge_mw / + 1000) > BATT_MAX_CONTINUE_DISCHARGE_WATT * + PROCHOT_ASSERTION_BATTERY_RATIO / 100) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + else if ((batt_params.battery_continuous_discharge_mw + / 1000) < BATT_MAX_CONTINUE_DISCHARGE_WATT * + PROCHOT_DEASSERTION_BATTERY_RATIO / 100) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + } + return; + } + + if (adapter_wattage >= ADT_RATING_W) { + /* if adapter >= 60W */ + /* if no battery or battery < 10% */ + if (!battery_hw_present() || + batt_params.state_of_charge <= 10) { + if (total_W > ADT_RATING_W * + PROCHOT_ASSERTION_PD_RATIO / 100) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + else if (total_W <= ADT_RATING_W) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + } else { + /* AC + battery */ + if (total_W > (ADT_RATING_W + + BATT_MAX_CONTINUE_DISCHARGE_WATT)) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + else if (total_W < (ADT_RATING_W + + BATT_MAX_CONTINUE_DISCHARGE_WATT) * + PROCHOT_DEASSERTION_PD_BATTERY_RATIO / 100) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + } + } else { + /* if adapter < 60W */ + /* if no battery or battery < 10% */ + if (!battery_hw_present() || + batt_params.state_of_charge <= 10) { + if (total_W > (adapter_wattage * + PROCHOT_ASSERTION_ADAPTER_RATIO / 100)) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + else if (total_W <= (adapter_wattage * + PROCHOT_DEASSERTION_ADAPTER_RATIO / 100)) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + } else { + /* AC + battery */ + if (total_W > (adapter_wattage + + BATT_MAX_CONTINUE_DISCHARGE_WATT)) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + else if (total_W < (adapter_wattage + + (BATT_MAX_CONTINUE_DISCHARGE_WATT * + PROCHOT_DEASSERTION_ADAPTER_BATT_RATIO / 100))) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + } + } +} + +/* Called by hook task every 200 ms */ +static void control_prochot_tick(void) +{ + task_set_event(TASK_ID_PROCHOT, PROCHOT_EVENT_200MS_TICK); +} +DECLARE_HOOK(HOOK_TICK, control_prochot_tick, HOOK_PRIO_DEFAULT); + +void prochot_task(void *u) +{ + uint32_t evt; + + while (1) { + evt = task_wait_event(-1); + + if (evt & PROCHOT_EVENT_200MS_TICK) + assert_prochot(); + } +} |