diff options
author | Diana Z <dzigterman@chromium.org> | 2020-03-19 11:57:17 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-23 19:11:26 +0000 |
commit | 07909845a4d6f7a2d91bc3438622d28298702729 (patch) | |
tree | 03eb710afb39d7cdf4781101d4a7cec13a3913ab | |
parent | 0b7596910e056841dd0c9c885a1075b3fb7f8956 (diff) | |
download | chrome-ec-07909845a4d6f7a2d91bc3438622d28298702729.tar.gz |
SM5803: OTG, charger detect, and interrupt functionality
This commit adds the OTG functions for sourcing Vbus, adds functions for
charger detect, and corrects the interrupt handler to call into a
deferred function to handle i2c querries.
BUG=b:146651778,b:148289370
BRANCH=None
TEST=builds
Signed-off-by: Diana Z <dzigterman@chromium.org>
Change-Id: I66851b9fb339bce2026b184e93edca143cad340b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2110531
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r-- | driver/charger/sm5803.c | 157 | ||||
-rw-r--r-- | driver/charger/sm5803.h | 27 |
2 files changed, 178 insertions, 6 deletions
diff --git a/driver/charger/sm5803.c b/driver/charger/sm5803.c index 2cb1d2a524..6f5f409406 100644 --- a/driver/charger/sm5803.c +++ b/driver/charger/sm5803.c @@ -4,9 +4,11 @@ * * Silicon Mitus SM5803 Buck-Boost Charger */ +#include "atomic.h" #include "battery_smart.h" #include "charger.h" #include "gpio.h" +#include "hooks.h" #include "i2c.h" #include "sm5803.h" #include "throttle_ap.h" @@ -33,6 +35,9 @@ static const struct charger_info sm5803_charger_info = { .input_current_step = INPUT_I_STEP, }; +static uint32_t irq_pending; /* Bitmask of chips with interrupts pending */ + +static int sm5803_is_sourcing_otg_power(int chgnum, int port); static inline enum ec_error_list chg_read8(int chgnum, int offset, int *value) { @@ -111,6 +116,56 @@ enum ec_error_list sm5803_set_gpio0_level(int chgnum, int level) return rv; } +enum ec_error_list sm5803_configure_chg_det_od(int chgnum, int enable) +{ + enum ec_error_list rv; + int reg; + + rv = main_read8(chgnum, SM5803_REG_GPIO0_CTRL, ®); + if (rv) + return rv; + + if (enable) + reg |= SM5803_CHG_DET_OPEN_DRAIN_EN; + else + reg &= ~SM5803_CHG_DET_OPEN_DRAIN_EN; + + rv = main_write8(chgnum, SM5803_REG_GPIO0_CTRL, reg); + return rv; +} + +enum ec_error_list sm5803_get_chg_det(int chgnum, int *chg_det) +{ + enum ec_error_list rv; + int reg; + + rv = main_read8(chgnum, SM5803_REG_STATUS1, ®); + if (rv) + return rv; + + *chg_det = (reg & SM5803_STATUS1_CHG_DET) != 0; + + return EC_SUCCESS; +} + +enum ec_error_list sm5803_set_vbus_disch(int chgnum, int enable) +{ + enum ec_error_list rv; + int reg; + + rv = main_read8(chgnum, SM5803_REG_PORTS_CTRL, ®); + if (rv) + return rv; + + if (enable) + reg |= SM5803_PORTS_VBUS_DISCH; + else + reg &= ~SM5803_PORTS_VBUS_DISCH; + + rv = main_write8(chgnum, SM5803_REG_PORTS_CTRL, reg); + return rv; +} + static void sm5803_init(int chgnum) { enum ec_error_list rv; @@ -145,8 +200,8 @@ static enum ec_error_list sm5803_post_init(int chgnum) } /* - * Process interrupt registers and report any Vbus changes. Pull PROCHOT low if - * charger has gotten too hot. + * Process interrupt registers and report any Vbus changes. Alert the AP if the + * charger has become too hot. */ void sm5803_handle_interrupt(int chgnum) { @@ -167,8 +222,8 @@ void sm5803_handle_interrupt(int chgnum) throttle_ap(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_THERMAL); } - if (int_reg & SM5803_INT2_VBUS) { - /* TODO(b/146651778): Check whether we're sourcing Vbus */ + if ((int_reg & SM5803_INT2_VBUS) && + !sm5803_is_sourcing_otg_power(chgnum, chgnum)) { rv = meas_read8(chgnum, SM5803_REG_VBUS_MEAS_MSB, &vbus_reg); if (vbus_reg <= SM5803_VBUS_LOW_LEVEL) usb_charger_vbus_change(chgnum, 0); @@ -180,6 +235,23 @@ void sm5803_handle_interrupt(int chgnum) } } +static void sm5803_irq_deferred(void) +{ + int i; + uint32_t pending = atomic_read_clear(&irq_pending); + + for (i = 0; i < CHARGER_NUM; i++) + if (BIT(i) & pending) + sm5803_handle_interrupt(i); +} +DECLARE_DEFERRED(sm5803_irq_deferred); + +void sm5803_interrupt(int chgnum) +{ + atomic_or(&irq_pending, BIT(chgnum)); + hook_call_deferred(&sm5803_irq_deferred_data, 0); +} + static const struct charger_info *sm5803_get_info(int chgnum) { return &sm5803_charger_info; @@ -390,6 +462,80 @@ static enum ec_error_list sm5803_set_option(int chgnum, int option) return rv; } +static enum ec_error_list sm5803_set_otg_current_voltage(int chgnum, + int output_current, + int output_voltage) +{ + enum ec_error_list rv; + int reg; + + reg = (output_current / SM5803_CLS_CURRENT_STEP) & + SM5803_DISCH_CONF5_CLS_LIMIT; + rv = chg_write8(chgnum, SM5803_REG_DISCH_CONF5, reg); + if (rv) + return rv; + + reg = SM5803_VOLTAGE_TO_REG(output_voltage); + rv = chg_write8(chgnum, SM5803_REG_VPWR_MSB, (reg >> 3)); + rv |= chg_write8(chgnum, SM5803_REG_DISCH_CONF2, + reg & SM5803_DISCH_CONF5_VPWR_LSB); + + return rv; +} + +static enum ec_error_list sm5803_enable_otg_power(int chgnum, int enabled) +{ + enum ec_error_list rv; + int reg; + + if (enabled) { + rv = chg_read8(chgnum, SM5803_REG_ANA_EN1, ®); + if (rv) + return rv; + + /* Enable current limit */ + reg &= ~SM5803_ANA_EN1_CLS_DISABLE; + rv = chg_write8(chgnum, SM5803_REG_ANA_EN1, reg); + } + + rv = chg_read8(chgnum, SM5803_REG_FLOW1, ®); + if (rv) + return rv; + + /* + * Enable: CHG_EN - turns on buck-boost + * VBUSIN_DISCH_EN - enable discharge on Vbus + * DIRECTCHG_SOURCE_EN - enable current loop (for designs with + * no external Vbus FET) + * + * Disable: disable above, note this SHOULD NOT be done while the port + * is charging, as turning off CHG_EN will disable charging + * as well + */ + if (enabled) + reg |= (SM5803_FLOW1_CHG_EN | SM5803_FLOW1_VBUSIN_DISCHG_EN | + SM5803_FLOW1_DIRECTCHG_SRC_EN); + else + reg &= ~(SM5803_FLOW1_CHG_EN | SM5803_FLOW1_VBUSIN_DISCHG_EN | + SM5803_FLOW1_DIRECTCHG_SRC_EN); + + rv = chg_write8(chgnum, SM5803_REG_FLOW1, reg); + return rv; +} + +static int sm5803_is_sourcing_otg_power(int chgnum, int port) +{ + enum ec_error_list rv; + int reg; + + rv = chg_read8(chgnum, SM5803_REG_FLOW1, ®); + if (rv) + return 0; + + reg &= (SM5803_FLOW1_CHG_EN | SM5803_FLOW1_VBUSIN_DISCHG_EN); + return reg == (SM5803_FLOW1_CHG_EN | SM5803_FLOW1_VBUSIN_DISCHG_EN); +} + const struct charger_drv sm5803_drv = { .init = &sm5803_init, .post_init = &sm5803_post_init, @@ -405,4 +551,7 @@ const struct charger_drv sm5803_drv = { .get_input_current = &sm5803_get_input_current, .get_option = &sm5803_get_option, .set_option = &sm5803_set_option, + .set_otg_current_voltage = &sm5803_set_otg_current_voltage, + .enable_otg_power = &sm5803_enable_otg_power, + .is_sourcing_otg_power = &sm5803_is_sourcing_otg_power, }; diff --git a/driver/charger/sm5803.h b/driver/charger/sm5803.h index 86e2fa43c2..8b96ac8f94 100644 --- a/driver/charger/sm5803.h +++ b/driver/charger/sm5803.h @@ -153,6 +153,9 @@ enum sm5803_gpio0_modes { #define SM5803_FLOW3_FW_SWITCH_PAUSE BIT(2) #define SM5803_FLOW3_SOFT_DISABLE_EN BIT(3) +#define SM5803_REG_ANA_EN1 0x21 +#define SM5803_ANA_EN1_CLS_DISABLE BIT(7) + /* * Input current limit is CHG_ILIM_RAW *100 mA */ @@ -163,6 +166,21 @@ enum sm5803_gpio0_modes { #define SM5803_CURRENT_TO_REG(c) (c / SM5803_CURRENT_STEP) /* + * Output voltage uses the same equation as Vsys + * Lower saturation value is 3 V, upper 20.5 V + */ +#define SM5803_REG_VPWR_MSB 0x30 +#define SM5803_REG_DISCH_CONF2 0x31 +#define SM5803_DISCH_CONF5_VPWR_LSB GENMASK(2, 0) + +/* + * Output current limit is CLS_LIMIT * 50 mA and saturates to 3.2 A + */ +#define SM5803_REG_DISCH_CONF5 0x34 +#define SM5803_DISCH_CONF5_CLS_LIMIT GENMASK(6, 0) +#define SM5803_CLS_CURRENT_STEP 50 + +/* * Vsys is 11 bits, with the lower 3 bits in the LSB register. * The pre-regulation value is 2.72 V + Vsys_prereg * 10 mV * Lower saturation value is 3V, upper is 20V @@ -204,12 +222,17 @@ enum sm5803_gpio0_modes { #define INPUT_I_MIN 0 #define INPUT_I_STEP SM5803_CURRENT_STEP -/* Expose functions to control charger's GPIO */ +/* Expose functions to control charger's GPIO and CHG_DET configuration */ enum ec_error_list sm5803_configure_gpio0(int chgnum, enum sm5803_gpio0_modes mode); enum ec_error_list sm5803_set_gpio0_level(int chgnum, int level); +enum ec_error_list sm5803_configure_chg_det_od(int chgnum, int enable); +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); -void sm5803_handle_interrupt(int chgnum); +void sm5803_interrupt(int chgnum); extern const struct charger_drv sm5803_drv; |