diff options
author | Scott Chao <scott_chao@wistron.corp-partner.google.com> | 2021-08-16 11:00:21 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-01 21:23:59 +0000 |
commit | f5ba5ec8361d7dadefb3860a05bf80e4ad230a44 (patch) | |
tree | cf094b2d197e40bca8dad511f55940081ced04b1 | |
parent | 36986a9efbd475c249d4045573b20f9d1a8ba2f1 (diff) | |
download | chrome-ec-f5ba5ec8361d7dadefb3860a05bf80e4ad230a44.tar.gz |
primus: control prochot
BUG=b:198722634
BRANCH=none
TEST=make -j BOARD=primus
TEST=verified by power team
Signed-off-by: Scott Chao <scott_chao@wistron.corp-partner.google.com>
Change-Id: I777f803b91f0449317f0185a6ca77348de3835bc
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3096806
Reviewed-by: caveh jalali <caveh@chromium.org>
Commit-Queue: caveh jalali <caveh@chromium.org>
-rw-r--r-- | board/primus/board.h | 1 | ||||
-rw-r--r-- | board/primus/build.mk | 3 | ||||
-rw-r--r-- | board/primus/ec.tasklist | 1 | ||||
-rw-r--r-- | board/primus/prochot.c | 209 | ||||
-rw-r--r-- | board/primus/sensors.c | 7 |
5 files changed, 220 insertions, 1 deletions
diff --git a/board/primus/board.h b/board/primus/board.h index 96562ec7a4..dc16251b93 100644 --- a/board/primus/board.h +++ b/board/primus/board.h @@ -159,6 +159,7 @@ enum adc_channel { ADC_TEMP_SENSOR_3_CHARGER, ADC_TEMP_SENSOR_4_MEMORY, ADC_TEMP_SENSOR_5_USBC, + ADC_IADPT, ADC_CH_COUNT }; diff --git a/board/primus/build.mk b/board/primus/build.mk index d6fe9b4808..9dab971565 100644 --- a/board/primus/build.mk +++ b/board/primus/build.mk @@ -20,7 +20,8 @@ board-y+=fw_config.o board-y+=i2c.o board-y+=keyboard.o board-y+=led.o -board-y+=pwm.o +board-y+=prochot.o board-y+=ps2.o +board-y+=pwm.o board-y+=sensors.o board-y+=usbc_config.o diff --git a/board/primus/ec.tasklist b/board/primus/ec.tasklist index c0a5194e89..83415ffceb 100644 --- a/board/primus/ec.tasklist +++ b/board/primus/ec.tasklist @@ -26,4 +26,5 @@ TASK_ALWAYS(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \ TASK_ALWAYS(PD_INT_C0, pd_interrupt_handler_task, 0, TASK_STACK_SIZE) \ TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, TASK_STACK_SIZE) \ + TASK_NOTEST(PROCHOT, prochot_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_NOTEST(LOGOLED, logoled_task, NULL, LARGER_TASK_STACK_SIZE) diff --git a/board/primus/prochot.c b/board/primus/prochot.c new file mode 100644 index 0000000000..335e2708e4 --- /dev/null +++ b/board/primus/prochot.c @@ -0,0 +1,209 @@ +/* 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 BATT_MAX_CONTINUE_DISCHARGE_WATT 66 +#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; +}; + +static struct batt_para batt_params; + +static int cal_sys_watt(void) +{ + int Vacpacn; + int V_iadpt; + int IDPM; + int W_adpt; + + /* Read ADC_IADPT from BQ25720 */ + V_iadpt = adc_read_channel(ADC_IADPT); + + /* Calculate V(ACP-ACN) + * We select IADPT_FAIN as 40 for more precise + */ + Vacpacn = V_iadpt * 1000 / 40; + + /* Calculate the input current */ + IDPM = Vacpacn / CONFIG_CHARGER_SENSE_RESISTOR_AC; + + /* Current multiplied by 20v to calculate actual adapter wattage */ + W_adpt = IDPM * 20 / 97 * 100; + + return W_adpt; +} + +static int get_batt_parameter(void) +{ + int battery_voltage_mv; + int battery_current_ma; + int battery_design_voltage_mv; + int battery_design_capacity_mAh; + int rv = 0; + + batt_params.flags = 0; + + if (sb_read(SB_VOLTAGE, &battery_voltage_mv)) + 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_ma)) + batt_params.flags |= BATT_FLAG_BAD_CURRENT; + else + battery_current_ma = (int16_t)battery_current_ma; + + /* calculate battery wattage and convert to mW */ + batt_params.battery_continuous_discharge_mw = + (battery_voltage_mv * battery_current_ma) / 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; + + 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 void assert_prochot(void) +{ + int adapter_wattage; + int adpt_mw; + int reg; + int total_W; + + /* no AC, don't assert PROCHOT */ + if (!extpower_is_present()) { + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + return; + } + + /* Set 0x12 bit4=1 */ + if (charger_get_option(®)) + CPRINTS("Failed to read bq25720"); + else { + /* only execute if get_option succeeded. */ + reg |= BQ25710_CHARGE_OPTION_0_IADP_GAIN; + if (charger_set_option(reg)) + 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(); + + 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 > (adapter_wattage * 105/100)) + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + else if (total_W < (adapter_wattage * 90/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 * + 90/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 > (ADT_RATING_W * 105/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) * 95/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(); + } +} diff --git a/board/primus/sensors.c b/board/primus/sensors.c index 33ea302a2a..d297912772 100644 --- a/board/primus/sensors.c +++ b/board/primus/sensors.c @@ -47,6 +47,13 @@ const struct adc_t adc_channels[] = { .factor_div = ADC_READ_MAX + 1, .shift = 0, }, + [ADC_IADPT] = { + .name = "CHARGER_IADPT", + .input_ch = NPCX_ADC_CH3, + .factor_mul = ADC_MAX_VOLT, + .factor_div = ADC_READ_MAX + 1, + .shift = 0, + }, }; BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); |