summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Tsai <will_tsai@wistron.corp-partner.google.com>2021-10-04 18:59:13 +0800
committerCommit Bot <commit-bot@chromium.org>2021-10-15 19:13:28 +0000
commit0899b717501b72f3ba88c3ee4e749ec60ad90819 (patch)
tree593bfc83662883b3a3ed26cf9804e415a2d0b0ac
parent0398923c16ee19fd31e1a43ace6d2c29a026c854 (diff)
downloadchrome-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.h10
-rw-r--r--baseboard/brya/build.mk1
-rw-r--r--baseboard/brya/prochot.c253
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, &reg);
+ 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();
+ }
+}