summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/drawcia/board.c49
-rw-r--r--board/drawcia/usb_pd_policy.c4
-rw-r--r--board/waddledee/board.c43
-rw-r--r--board/waddledee/usb_pd_policy.c6
-rw-r--r--driver/charger/sm5803.c264
-rw-r--r--driver/charger/sm5803.h1
6 files changed, 180 insertions, 187 deletions
diff --git a/board/drawcia/board.c b/board/drawcia/board.c
index 497bd9b7b7..0ba3b5c0b0 100644
--- a/board/drawcia/board.c
+++ b/board/drawcia/board.c
@@ -508,61 +508,34 @@ void board_set_charge_limit(int port, int supplier, int charge_ma, int max_ma,
int board_set_active_charge_port(int port)
{
int is_valid_port = (port >= 0 && port < board_get_usb_pd_port_count());
- int p0_otg = 0, p1_otg = 0;
if (!is_valid_port && port != CHARGE_PORT_NONE)
return EC_ERROR_INVAL;
- /* TODO(b/147440290): charger functions should take chgnum */
- p0_otg = chg_chips[0].drv->is_sourcing_otg_power(0, 0);
-
- if (board_get_charger_chip_count() > 1)
- p1_otg = chg_chips[1].drv->is_sourcing_otg_power(1, 1);
-
if (port == CHARGE_PORT_NONE) {
CPRINTUSB("Disabling all charge ports");
- if (!p0_otg)
- chg_chips[0].drv->set_mode(0,
- CHARGE_FLAG_INHIBIT_CHARGE);
+ sm5803_vbus_sink_enable(CHARGER_PRIMARY, 0);
+
+ if (board_get_charger_chip_count() > 1)
+ sm5803_vbus_sink_enable(CHARGER_SECONDARY, 0);
- if (board_get_charger_chip_count() > 1) {
- if (!p1_otg)
- chg_chips[1].drv->set_mode(1,
- CHARGE_FLAG_INHIBIT_CHARGE);
- }
return EC_SUCCESS;
}
CPRINTUSB("New chg p%d", port);
/*
- * Charger task will take care of enabling charging on the new charge
- * port. Here, we ensure the other port is not charging by changing
- * CHG_EN
+ * Ensure other port is turned off, then enable new charge port
*/
if (port == 0) {
- if (p0_otg) {
- CPRINTUSB("Skip enable p%d", port);
- return EC_ERROR_INVAL;
- }
- if (board_get_charger_chip_count() > 1) {
- if (!p1_otg) {
- chg_chips[1].drv->set_mode(1,
- CHARGE_FLAG_INHIBIT_CHARGE);
- }
- }
+ if (board_get_charger_chip_count() > 1)
+ sm5803_vbus_sink_enable(CHARGER_SECONDARY, 0);
+ sm5803_vbus_sink_enable(CHARGER_PRIMARY, 1);
+
} else {
- if (board_get_charger_chip_count() > 1) {
- if (p1_otg) {
- CPRINTUSB("Skip enable p%d", port);
- return EC_ERROR_INVAL;
- }
- }
- if (!p0_otg) {
- chg_chips[0].drv->set_mode(0,
- CHARGE_FLAG_INHIBIT_CHARGE);
- }
+ sm5803_vbus_sink_enable(CHARGER_PRIMARY, 0);
+ sm5803_vbus_sink_enable(CHARGER_SECONDARY, 1);
}
return EC_SUCCESS;
diff --git a/board/drawcia/usb_pd_policy.c b/board/drawcia/usb_pd_policy.c
index f9ff88c26c..58b442a0ac 100644
--- a/board/drawcia/usb_pd_policy.c
+++ b/board/drawcia/usb_pd_policy.c
@@ -52,8 +52,8 @@ int pd_set_power_supply_ready(int port)
{
enum ec_error_list rv;
- /* Disable charging */
- rv = chg_chips[port].drv->set_mode(port, CHARGE_FLAG_INHIBIT_CHARGE);
+ /* Disable sinking */
+ rv = sm5803_vbus_sink_enable(port, 0);
if (rv)
return rv;
diff --git a/board/waddledee/board.c b/board/waddledee/board.c
index 341f00ea4a..6e455d2ca1 100644
--- a/board/waddledee/board.c
+++ b/board/waddledee/board.c
@@ -331,25 +331,18 @@ void board_set_charge_limit(int port, int supplier, int charge_ma, int max_ma,
int board_set_active_charge_port(int port)
{
- int is_valid_port = (port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT);
- int p0_otg, p1_otg;
+ int is_valid_port = (port >= 0 && port < board_get_usb_pd_port_count());
if (!is_valid_port && port != CHARGE_PORT_NONE)
return EC_ERROR_INVAL;
- /* TODO(b/147440290): charger functions should take chgnum */
- p0_otg = chg_chips[0].drv->is_sourcing_otg_power(0, 0);
- p1_otg = chg_chips[1].drv->is_sourcing_otg_power(1, 1);
-
if (port == CHARGE_PORT_NONE) {
CPRINTUSB("Disabling all charge ports");
- if (!p0_otg)
- chg_chips[0].drv->set_mode(0,
- CHARGE_FLAG_INHIBIT_CHARGE);
- if (!p1_otg)
- chg_chips[1].drv->set_mode(1,
- CHARGE_FLAG_INHIBIT_CHARGE);
+ sm5803_vbus_sink_enable(CHARGER_PRIMARY, 0);
+
+ if (board_get_charger_chip_count() > 1)
+ sm5803_vbus_sink_enable(CHARGER_SECONDARY, 0);
return EC_SUCCESS;
}
@@ -357,28 +350,16 @@ int board_set_active_charge_port(int port)
CPRINTUSB("New chg p%d", port);
/*
- * Charger task will take care of enabling charging on the new charge
- * port. Here, we ensure the other port is not charging by changing
- * CHG_EN
+ * Ensure other port is turned off, then enable new charge port
*/
if (port == 0) {
- if (p0_otg) {
- CPRINTUSB("Skip enable p%d", port);
- return EC_ERROR_INVAL;
- }
- if (!p1_otg) {
- chg_chips[1].drv->set_mode(1,
- CHARGE_FLAG_INHIBIT_CHARGE);
- }
+ if (board_get_charger_chip_count() > 1)
+ sm5803_vbus_sink_enable(CHARGER_SECONDARY, 0);
+ sm5803_vbus_sink_enable(CHARGER_PRIMARY, 1);
+
} else {
- if (p1_otg) {
- CPRINTUSB("Skip enable p%d", port);
- return EC_ERROR_INVAL;
- }
- if (!p0_otg) {
- chg_chips[0].drv->set_mode(0,
- CHARGE_FLAG_INHIBIT_CHARGE);
- }
+ sm5803_vbus_sink_enable(CHARGER_PRIMARY, 0);
+ sm5803_vbus_sink_enable(CHARGER_SECONDARY, 1);
}
return EC_SUCCESS;
diff --git a/board/waddledee/usb_pd_policy.c b/board/waddledee/usb_pd_policy.c
index 0fc682b28e..58b442a0ac 100644
--- a/board/waddledee/usb_pd_policy.c
+++ b/board/waddledee/usb_pd_policy.c
@@ -26,7 +26,7 @@ void pd_power_supply_reset(int port)
{
int prev_en;
- if (port < 0 || port >= CONFIG_USB_PD_PORT_MAX_COUNT)
+ if (port < 0 || port >= board_get_usb_pd_port_count())
return;
/* TODO(b/147440290): charger functions should take chgnum */
@@ -52,8 +52,8 @@ int pd_set_power_supply_ready(int port)
{
enum ec_error_list rv;
- /* Disable charging */
- rv = chg_chips[port].drv->set_mode(port, CHARGE_FLAG_INHIBIT_CHARGE);
+ /* Disable sinking */
+ rv = sm5803_vbus_sink_enable(port, 0);
if (rv)
return rv;
diff --git a/driver/charger/sm5803.c b/driver/charger/sm5803.c
index 072fc2ca14..63ad62ab16 100644
--- a/driver/charger/sm5803.c
+++ b/driver/charger/sm5803.c
@@ -47,6 +47,7 @@ static const struct charger_info sm5803_charger_info = {
static uint32_t irq_pending; /* Bitmask of chips with interrupts pending */
static struct mutex flow1_access_lock[CHARGER_NUM];
+static struct mutex flow2_access_lock[CHARGER_NUM];
static int charger_vbus[CHARGER_NUM];
@@ -153,6 +154,23 @@ static enum ec_error_list sm5803_flow1_update(int chgnum, const uint8_t mask,
return rv;
}
+static enum ec_error_list sm5803_flow2_update(int chgnum, const uint8_t mask,
+ const enum mask_update_action action)
+{
+ int rv;
+
+ mutex_lock(&flow2_access_lock[chgnum]);
+
+ rv = i2c_update8(chg_chips[chgnum].i2c_port,
+ chg_chips[chgnum].i2c_addr_flags,
+ SM5803_REG_FLOW2,
+ mask, action);
+
+ mutex_unlock(&flow2_access_lock[chgnum]);
+
+ return rv;
+}
+
int sm5803_is_vbus_present(int chgnum)
{
return charger_vbus[chgnum];
@@ -248,6 +266,81 @@ enum ec_error_list sm5803_set_vbus_disch(int chgnum, int enable)
return rv;
}
+enum ec_error_list sm5803_vbus_sink_enable(int chgnum, int enable)
+{
+ enum ec_error_list rv;
+ int regval;
+
+ rv = sm5803_get_dev_id(chgnum, &dev_id);
+ if (rv)
+ return rv;
+
+ if (enable) {
+ if (chgnum == CHARGER_PRIMARY) {
+ /* Magic for new silicon */
+ if (dev_id >= 3) {
+ rv |= main_write8(chgnum, 0x1F, 0x1);
+ rv |= test_write8(chgnum, 0x44, 0x2);
+ rv |= main_write8(chgnum, 0x1F, 0);
+ }
+ rv = sm5803_flow2_update(chgnum,
+ SM5803_FLOW2_AUTO_ENABLED,
+ MASK_SET);
+ } else {
+ if (dev_id >= 3) {
+ /* Touch of magic on the primary charger */
+ rv |= main_write8(CHARGER_PRIMARY, 0x1F, 0x1);
+ rv |= test_write8(CHARGER_PRIMARY, 0x44, 0x20);
+ rv |= main_write8(CHARGER_PRIMARY, 0x1F, 0x0);
+
+ /*
+ * Enable linear, pre-charge, and linear fast
+ * charge for primary charger.
+ */
+ rv = chg_read8(CHARGER_PRIMARY,
+ SM5803_REG_FLOW3, &regval);
+ regval |= BIT(6) | BIT(5) | BIT(4);
+ rv |= chg_write8(CHARGER_PRIMARY,
+ SM5803_REG_FLOW3, regval);
+
+ /* Enable linear mode on the primary IC */
+ rv |= sm5803_flow1_update(CHARGER_PRIMARY,
+ SM5803_FLOW1_LINEAR_CHARGE_EN,
+ MASK_SET);
+ }
+ }
+
+ /* Last but not least, enable sinking */
+ rv |= sm5803_flow1_update(chgnum, CHARGER_MODE_SINK, MASK_SET);
+ } else {
+ if (chgnum == CHARGER_PRIMARY)
+ rv |= sm5803_flow2_update(chgnum,
+ SM5803_FLOW2_AUTO_ENABLED,
+ MASK_CLR);
+
+ if (chgnum == CHARGER_SECONDARY) {
+ rv |= sm5803_flow1_update(CHARGER_PRIMARY,
+ SM5803_FLOW1_LINEAR_CHARGE_EN,
+ MASK_CLR);
+
+ rv = chg_read8(CHARGER_PRIMARY, SM5803_REG_FLOW3,
+ &regval);
+ regval &= ~(BIT(6) | BIT(5) | BIT(4));
+ rv |= chg_write8(CHARGER_PRIMARY, SM5803_REG_FLOW3,
+ regval);
+ }
+
+
+ /* Disable sink mode, unless currently sourcing out */
+ if (!sm5803_is_sourcing_otg_power(chgnum, chgnum))
+ rv |= sm5803_flow1_update(chgnum, CHARGER_MODE_SINK,
+ MASK_CLR);
+ }
+
+ return rv;
+
+}
+
static void sm5803_init(int chgnum)
{
enum ec_error_list rv;
@@ -439,6 +532,16 @@ static void sm5803_init(int chgnum)
reg &= ~SM5803_PHOT1_IBUS_PHOT_COMP_EN;
rv |= chg_write8(chgnum, SM5803_REG_PHOT1, reg);
+ if (chgnum != CHARGER_PRIMARY) {
+ /*
+ * Enable the IBAT_CHG adc in order to calculate
+ * system resistance.
+ */
+ rv |= meas_read8(chgnum, SM5803_REG_GPADC_CONFIG1, &reg);
+ reg |= SM5803_GPADCC1_IBAT_CHG_EN;
+ rv |= meas_write8(chgnum, SM5803_REG_GPADC_CONFIG1, reg);
+ }
+
/* Set default input current */
reg = SM5803_CURRENT_TO_REG(CONFIG_CHARGER_INPUT_CURRENT)
& SM5803_CHG_ILIM_RAW;
@@ -465,28 +568,42 @@ static void sm5803_init(int chgnum)
*/
rv |= chg_write8(chgnum, SM5803_REG_FLOW2, SM5803_FLOW2_HOST_MODE_EN);
- /* Setup the proper precharge thresholds. */
- batt_info = battery_get_info();
- cells = batt_info->voltage_max / 4;
- pre_term = batt_info->voltage_min / cells;
- pre_term /= 100; /* Convert to decivolts. */
- pre_term = CLAMP(pre_term, SM5803_VBAT_PRE_TERM_MIN_DV,
- SM5803_VBAT_PRE_TERM_MAX_DV);
- pre_term -= SM5803_VBAT_PRE_TERM_MIN_DV; /* Convert to regval */
+ if (chgnum == CHARGER_PRIMARY) {
+ int ibat_eoc_ma;
+
+ /* Set end of fast charge threshold */
+ batt_info = battery_get_info();
+ ibat_eoc_ma = batt_info->precharge_current - 50;
+ ibat_eoc_ma /= 100;
+ ibat_eoc_ma = CLAMP(ibat_eoc_ma, 0, SM5803_CONF5_IBAT_EOC_TH);
+ rv |= chg_read8(chgnum, SM5803_REG_FAST_CONF5, &reg);
+ reg &= ~SM5803_CONF5_IBAT_EOC_TH;
+ reg |= ibat_eoc_ma;
+ rv |= chg_write8(CHARGER_PRIMARY, SM5803_REG_FAST_CONF5, reg);
+
+ /* Setup the proper precharge thresholds. */
+ cells = batt_info->voltage_max / 4;
+ pre_term = batt_info->voltage_min / cells;
+ pre_term /= 100; /* Convert to decivolts. */
+ pre_term = CLAMP(pre_term, SM5803_VBAT_PRE_TERM_MIN_DV,
+ SM5803_VBAT_PRE_TERM_MAX_DV);
+ pre_term -= SM5803_VBAT_PRE_TERM_MIN_DV; /* Convert to regval */
+
+ rv |= chg_read8(chgnum, SM5803_REG_PRE_FAST_CONF_REG1, &reg);
+ reg &= ~SM5803_VBAT_PRE_TERM;
+ reg |= pre_term << SM5803_VBAT_PRE_TERM_SHIFT;
+ rv |= chg_write8(chgnum, SM5803_REG_PRE_FAST_CONF_REG1, reg);
- rv |= chg_read8(chgnum, SM5803_REG_PRE_FAST_CONF_REG1, &reg);
- reg &= ~SM5803_VBAT_PRE_TERM;
- reg |= pre_term << SM5803_VBAT_PRE_TERM_SHIFT;
- rv |= chg_write8(chgnum, SM5803_REG_PRE_FAST_CONF_REG1, reg);
-
- /*
- * Set up precharge current
- * Note it is preferred to under-shoot the precharge current requested
- * Upper bits of this register are read/write 1 to clear
- */
- reg = SM5803_CURRENT_TO_REG(batt_info->precharge_current);
- reg = MIN(reg, SM5803_PRECHG_ICHG_PRE_SET);
- rv |= chg_write8(chgnum, SM5803_REG_PRECHG, reg);
+ /*
+ * Set up precharge current
+ * Note it is preferred to under-shoot the precharge current
+ * requested. Upper bits of this register are read/write 1 to
+ * clear
+ */
+ reg = SM5803_CURRENT_TO_REG(batt_info->precharge_current);
+ reg = MIN(reg, SM5803_PRECHG_ICHG_PRE_SET);
+ rv |= chg_write8(chgnum, SM5803_REG_PRECHG, reg);
+ }
if (rv)
CPRINTS("%s %d: Failed initialization", CHARGER_NAME, chgnum);
@@ -633,47 +750,14 @@ static enum ec_error_list sm5803_get_status(int chgnum, int *status)
static enum ec_error_list sm5803_set_mode(int chgnum, int mode)
{
- enum ec_error_list rv;
- int flow2_reg;
- int dev_id;
-
- rv = sm5803_get_dev_id(chgnum, &dev_id);
-
- /* New silicon version requires a new procedure to start charging. */
- if ((dev_id >= 3) && (!(mode & CHARGE_FLAG_INHIBIT_CHARGE))) {
- /* Enable Test Page */
- rv |= main_write8(chgnum, 0x1F, 0x1);
- /* magic */
- rv |= test_write8(chgnum, 0x44, 0x2);
- rv |= test_write8(chgnum, 0x48, 0x4);
- /* Disable Test Page */
- rv |= main_write8(chgnum, 0x1F, 0);
- }
-
- rv |= chg_read8(chgnum, SM5803_REG_FLOW2, &flow2_reg);
- if (rv)
- return rv;
+ enum ec_error_list rv = EC_SUCCESS;
- /*
- * Note: Charge may be enabled while OTG is enabled, but charge inhibit
- * should also turn off OTG. Battery charging flags should only be set
- * when battery is present.
- */
if (mode & CHARGE_FLAG_INHIBIT_CHARGE) {
- rv |= sm5803_flow1_update(chgnum, 0xFF, MASK_CLR);
- flow2_reg &= ~SM5803_FLOW2_AUTO_ENABLED;
- } else {
- /*
- * TODO(b/163511546): SM5803: Consolidate flow control changes
- *
- * Should be a part of an initial sink enable function
- */
- rv |= sm5803_flow1_update(chgnum, CHARGER_MODE_SINK, MASK_SET);
- flow2_reg |= SM5803_FLOW2_AUTO_ENABLED;
+ rv = sm5803_flow1_update(chgnum, 0xFF, MASK_CLR);
+ rv |= sm5803_flow2_update(chgnum, SM5803_FLOW2_AUTO_ENABLED,
+ MASK_CLR);
}
- rv |= chg_write8(chgnum, SM5803_REG_FLOW2, flow2_reg);
-
return rv;
}
@@ -920,26 +1004,18 @@ static enum ec_error_list sm5803_enable_otg_power(int chgnum, int enabled)
}
/*
- * Enable: CHG_EN - turns on buck-boost
- * VBUSIN_DISCH_EN - enable discharge on Vbus
+ * Enable: SOURCE_MODE - enable sourcing out
* DIRECTCHG_SOURCE_EN - enable current loop (for designs with
* no external Vbus FET)
*
- * Disable: disable bits above except CHG_EN, which should only be
- * disabled through set_mode.
+ * Disable: disable bits above
*/
if (enabled)
rv = sm5803_flow1_update(chgnum, CHARGER_MODE_SOURCE |
SM5803_FLOW1_DIRECTCHG_SRC_EN,
MASK_SET);
else
- /*
- * TODO(b/163511546): SM5803: Consolidate flow control changes
- *
- * May be able to disable mode entirely if PD task usage remains
- * consistent.
- */
- rv = sm5803_flow1_update(chgnum, BIT(1) |
+ rv = sm5803_flow1_update(chgnum, CHARGER_MODE_SOURCE |
SM5803_FLOW1_DIRECTCHG_SRC_EN,
MASK_CLR);
@@ -955,8 +1031,11 @@ static int sm5803_is_sourcing_otg_power(int chgnum, int port)
if (rv)
return 0;
- reg &= SM5803_FLOW1_MODE;
- return reg == CHARGER_MODE_SOURCE;
+ /*
+ * Note: In linear mode, MB charger will read a reserved mode when
+ * sourcing, so bit 1 is the most reliable way to detect sourcing.
+ */
+ return (reg & BIT(1));
}
static enum ec_error_list sm5803_set_vsys_compensation(int chgnum,
@@ -967,53 +1046,12 @@ static enum ec_error_list sm5803_set_vsys_compensation(int chgnum,
int rv;
int regval;
- const struct battery_info *batt_info;
- int ibat_eoc_ma;
int r;
- /*
- * Enable linear, pre-charge, and linear fast charge for primary
- * charger.
- *
- * TODO(b/163511546): Move this into a sink enable function.
- */
- rv = chg_read8(CHARGER_PRIMARY, SM5803_REG_FLOW3, &regval);
- regval |= BIT(6) | BIT(5) | BIT(4);
- rv |= chg_write8(CHARGER_PRIMARY, SM5803_REG_FLOW3, regval);
-
- /* Set end of fast charge threshold */
- batt_info = battery_get_info();
- ibat_eoc_ma = batt_info->precharge_current - 50;
- ibat_eoc_ma /= 100;
- ibat_eoc_ma = CLAMP(ibat_eoc_ma, 0, SM5803_CONF5_IBAT_EOC_TH);
- rv |= chg_read8(CHARGER_PRIMARY, SM5803_REG_FAST_CONF5, &regval);
- regval &= ~SM5803_CONF5_IBAT_EOC_TH;
- regval |= ibat_eoc_ma;
- rv |= chg_write8(CHARGER_PRIMARY, SM5803_REG_FAST_CONF5, regval);
-
- /* Enable test address and do some magic.*/
- rv |= main_write8(CHARGER_PRIMARY, 0x1F, 0x1);
- rv |= test_write8(CHARGER_PRIMARY, 0x44, 0x20);
- rv |= test_write8(CHARGER_PRIMARY, 0x48, 0x4);
- rv |= main_write8(CHARGER_PRIMARY, 0x1F, 0x0);
-
- /* Enable linear mode on the primary charger IC */
- rv |= sm5803_flow1_update(CHARGER_PRIMARY,
- SM5803_FLOW1_LINEAR_CHARGE_EN,
- MASK_SET);
-
- /* Start pre-regulation on auxiliary charger. */
- rv |= chg_write8(chgnum, SM5803_REG_FLOW1, CHARGER_MODE_SINK);
-
- /* Enable the IBAT_CHG adc in order to calculate system resistance. */
- rv |= meas_read8(chgnum, SM5803_REG_GPADC_CONFIG1, &regval);
- regval |= SM5803_GPADCC1_IBAT_CHG_EN;
- rv |= meas_write8(chgnum, SM5803_REG_GPADC_CONFIG1, regval);
-
/* Set IR drop compensation */
r = ocpc->combined_rsys_rbatt_mo * 100 / 167; /* 1.67mOhm steps */
r = MAX(0, r);
- rv |= chg_write8(chgnum, SM5803_REG_IR_COMP2, r & 0x7F);
+ rv = chg_write8(chgnum, SM5803_REG_IR_COMP2, r & 0x7F);
rv |= chg_read8(chgnum, SM5803_REG_IR_COMP1, &regval);
regval &= ~SM5803_IR_COMP_RES_SET_MSB;
r = r >> 8; /* Bits 9:8 */
diff --git a/driver/charger/sm5803.h b/driver/charger/sm5803.h
index d16f000323..75e4885cbc 100644
--- a/driver/charger/sm5803.h
+++ b/driver/charger/sm5803.h
@@ -315,6 +315,7 @@ enum ec_error_list sm5803_get_chg_det(int chgnum, int *chg_det);
/* Expose Vbus discharge function */
enum ec_error_list sm5803_set_vbus_disch(int chgnum, int enable);
+enum ec_error_list sm5803_vbus_sink_enable(int chgnum, int enable);
void sm5803_interrupt(int chgnum);