diff options
author | Ting Shen <phoenixshen@google.com> | 2021-07-20 17:18:25 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-08-13 10:20:33 +0000 |
commit | f00ea7bb8f9d7f835981d969294fef0f5015c3f7 (patch) | |
tree | bddf8ff550f9a968ff3d8c3a638ebcb28f319de0 | |
parent | ff052aedbd21a41b52921c8c33b22eef03c03352 (diff) | |
download | chrome-ec-f00ea7bb8f9d7f835981d969294fef0f5015c3f7.tar.gz |
rt1718s: implement adc read
Cherry uses the VBUS1 adc channel in RT1718S to check the VBUS voltage
on port 1. Thus add this function for Cherry.
BUG=b:196001868
TEST=1) manually check the readings of ADC_VBUS1
2) Combined with board/ side changes, `ectool usbpdpower` shows
correct value
BRANCH=main
Signed-off-by: Ting Shen <phoenixshen@google.com>
Change-Id: I243f28b2bd4e8541257afcacb50a024a72e301fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3040801
Reviewed-by: Sue Chen <sue.chen@quanta.corp-partner.google.com>
Reviewed-by: Eric Yilun Lin <yllin@google.com>
Tested-by: Sue Chen <sue.chen@quanta.corp-partner.google.com>
Tested-by: Ting Shen <phoenixshen@chromium.org>
Commit-Queue: Ting Shen <phoenixshen@chromium.org>
-rw-r--r-- | driver/tcpm/rt1718s.c | 100 | ||||
-rw-r--r-- | driver/tcpm/rt1718s.h | 25 |
2 files changed, 119 insertions, 6 deletions
diff --git a/driver/tcpm/rt1718s.c b/driver/tcpm/rt1718s.c index 631d98a522..96a08785c2 100644 --- a/driver/tcpm/rt1718s.c +++ b/driver/tcpm/rt1718s.c @@ -25,26 +25,42 @@ #define RT1718S_SW_RESET_DELAY_MS 2 /* i2c_write function which won't wake TCPC from low power mode. */ -int rt1718s_write8(int port, int reg, int val) +static int rt1718s_write(int port, int reg, int val, int len) { if (reg > 0xFF) { return i2c_write_offset16( tcpc_config[port].i2c_info.port, tcpc_config[port].i2c_info.addr_flags, - reg, val, 1); + reg, val, len); + } else if (len == 1) { + return tcpc_write(port, reg, val); + } else { + return tcpc_write16(port, reg, val); } - return tcpc_write(port, reg, val); } -int rt1718s_read8(int port, int reg, int *val) +static int rt1718s_read(int port, int reg, int *val, int len) { if (reg > 0xFF) { return i2c_read_offset16( tcpc_config[port].i2c_info.port, tcpc_config[port].i2c_info.addr_flags, - reg, val, 1); + reg, val, len); + } else if (len == 1) { + return tcpc_read(port, reg, val); + } else { + return tcpc_read16(port, reg, val); } - return tcpc_read(port, reg, val); +} + +int rt1718s_write8(int port, int reg, int val) +{ + return rt1718s_write(port, reg, val, 1); +} + +int rt1718s_read8(int port, int reg, int *val) +{ + return rt1718s_read(port, reg, val, 1); } int rt1718s_update_bits8(int port, int reg, int mask, int val) @@ -61,6 +77,17 @@ int rt1718s_update_bits8(int port, int reg, int mask, int val) return rt1718s_write8(port, reg, reg_val); } +int rt1718s_write16(int port, int reg, int val) +{ + return rt1718s_write(port, reg, val, 2); +} + +int rt1718s_read16(int port, int reg, int *val) +{ + return rt1718s_read(port, reg, val, 2); +} + + static int rt1718s_sw_reset(int port) { int rv; @@ -385,6 +412,67 @@ static int rt1718s_enter_low_power_mode(int port) } #endif +int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val) +{ + static struct mutex adc_lock; + int rv; + const int max_wait_times = 30; + + if (in_interrupt_context()) { + CPRINTS("Err: use ADC in IRQ"); + return EC_ERROR_INVAL; + } + + mutex_lock(&adc_lock); + + /* Start ADC conversation */ + rv = rt1718s_write16(port, RT1718S_ADC_CTRL_01, BIT(channel)); + if (rv) + goto out; + + /* + * The expected conversion time is 85.3us * number of enabled channels. + * Polling for 3ms should be long enough. + */ + for (int i = 0; i < max_wait_times; i++) { + int adc_done; + + usleep(100); + rv = rt1718s_read8(port, RT1718S_RT_INT6, &adc_done); + if (rv) + goto out; + if (adc_done & RT1718S_RT_INT6_INT_ADC_DONE) + break; + if (i == max_wait_times - 1) { + CPRINTS("conversion fail channel=%d", channel); + rv = EC_ERROR_TIMEOUT; + goto out; + } + } + + /* Read ADC data */ + rv = rt1718s_read16(port, RT1718S_ADC_CHX_VOL_L(channel), adc_val); + if (rv) + goto out; + + /* + * The resolution of VBUS1 ADC is 12.5mV, + * other channels are 4mV. + */ + if (channel == RT1718S_ADC_VBUS1) + *adc_val = *adc_val * 125 / 10; + else + *adc_val *= 4; + +out: + /* Cleanup: disable adc and clear interrupt. Error ignored. */ + rt1718s_write16(port, RT1718S_ADC_CTRL_01, 0); + rt1718s_write8(port, RT1718S_RT_INT6, RT1718S_RT_INT6_INT_ADC_DONE); + + mutex_unlock(&adc_lock); + return rv; +} + /* RT1718S is a TCPCI compatible port controller */ const struct tcpm_drv rt1718s_tcpm_drv = { .init = &rt1718s_init, diff --git a/driver/tcpm/rt1718s.h b/driver/tcpm/rt1718s.h index fd1547cf25..9aed749440 100644 --- a/driver/tcpm/rt1718s.h +++ b/driver/tcpm/rt1718s.h @@ -59,6 +59,7 @@ #define RT1718S_RT_INT6_INT_BC12_SNK_DONE BIT(7) #define RT1718S_RT_INT6_INT_HVDCP_CHK_DONE BIT(6) #define RT1718S_RT_INT6_INT_BC12_TA_CHG BIT(5) +#define RT1718S_RT_INT6_INT_ADC_DONE BIT(0) #define RT1718S_RT_ST6 0xA4 #define RT1718S_RT_ST6_BC12_SNK_DONE BIT(7) @@ -156,12 +157,36 @@ #define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_DCP 0x20 #define RT1718S_RT2_BC12_SRC_FUNC_WAIT_VBUS_ON BIT(0) +#define RT1718S_ADC_CTRL_01 0xF2A0 +#define RT1718S_ADC_CTRL_02 0xF2A1 +#define RT1718S_ADC_CHX_VOL_L(ch) (0xF2A6 + (ch) * 2) +#define RT1718S_ADC_CHX_VOL_H(ch) (0xF2A7 + (ch) * 2) + extern const struct tcpm_drv rt1718s_tcpm_drv; extern const struct bc12_drv rt1718s_bc12_drv; int rt1718s_write8(int port, int reg, int val); int rt1718s_read8(int port, int reg, int *val); int rt1718s_update_bits8(int port, int reg, int mask, int val); +int rt1718s_write16(int port, int reg, int val); +int rt1718s_read16(int port, int reg, int *val); __override_proto int board_rt1718s_init(int port); +enum rt1718s_adc_channel { + RT1718S_ADC_VBUS1 = 0, + RT1718S_ADC_VBUS2, + RT1718S_ADC_VDC, + RT1718S_ADC_VBUS_CURRENT, + RT1718S_ADC_CC1, + RT1718S_ADC_CC2, + RT1718S_ADC_SBU1, + RT1718S_ADC_SBU2, + RT1718S_ADC_DP, + RT1718S_ADC_DM, + RT1718S_ADC_CH10, + RT1718S_ADC_CH11, +}; + +int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val); + #endif /* __CROS_EC_USB_PD_TCPM_MT6370_H */ |