From eba16b7ea42651e9e3d67cc643d67c870dd3fcc4 Mon Sep 17 00:00:00 2001 From: Philip Chen Date: Wed, 20 Feb 2019 16:57:49 -0800 Subject: bq25710: Add support for Vbus measurement by ADC This CL factors out some existing ADC code to bq25710_adc_start() and then use it to implement charger_get_vbus_voltage(). BUG=b:124968142 BRANCH=none TEST=verify VBUS measurement via 'ectool usbpdpower' Change-Id: Ifd3108d459bef02acd20d6a6959fd586fc3a9ca6 Signed-off-by: Philip Chen Reviewed-on: https://chromium-review.googlesource.com/1479876 Commit-Ready: ChromeOS CL Exonerator Bot Reviewed-by: Aseda Aboagye Reviewed-by: Scott Collyer --- driver/charger/bq25710.c | 111 ++++++++++++++++++++++++++++++++--------------- driver/charger/bq25710.h | 7 +++ 2 files changed, 83 insertions(+), 35 deletions(-) (limited to 'driver') diff --git a/driver/charger/bq25710.c b/driver/charger/bq25710.c index 1738904954..bbb05032bc 100644 --- a/driver/charger/bq25710.c +++ b/driver/charger/bq25710.c @@ -60,7 +60,8 @@ static inline int raw_write16(int offset, int value) value); } -#ifdef CONFIG_CHARGE_RAMP_HW +#if defined(CONFIG_CHARGE_RAMP_HW) || \ + defined(CONFIG_USB_PD_VBUS_MEASURE_CHARGER) static int bq25710_get_low_power_mode(int *mode) { int rv; @@ -95,6 +96,50 @@ static int bq25710_set_low_power_mode(int enable) return EC_SUCCESS; } + +static int bq25710_adc_start(int adc_en_mask) +{ + int reg; + int mode; + int tries_left = 8; + + /* Save current mode to restore same state after ADC read */ + if (bq25710_get_low_power_mode(&mode)) + return EC_ERROR_UNKNOWN; + + /* Exit low power mode so ADC conversion takes typical time */ + if (bq25710_set_low_power_mode(0)) + return EC_ERROR_UNKNOWN; + + /* + * Turn on the ADC for one reading. Note that adc_en_mask + * maps to bit[7:0] in ADCOption register. + */ + reg = (adc_en_mask & BQ25710_ADC_OPTION_EN_ADC_ALL) | + BQ25710_ADC_OPTION_ADC_START; + if (raw_write16(BQ25710_REG_ADC_OPTION, reg)) + return EC_ERROR_UNKNOWN; + + /* + * Wait until the ADC operation completes. The spec says typical + * conversion time is 10 msec. If low power mode isn't exited first, + * then the conversion time jumps to ~60 msec. + */ + do { + msleep(2); + raw_read16(BQ25710_REG_ADC_OPTION, ®); + } while (--tries_left && (reg & BQ25710_ADC_OPTION_ADC_START)); + + /* ADC reading attempt complete, go back to low power mode */ + if (bq25710_set_low_power_mode(mode)) + return EC_ERROR_UNKNOWN; + + /* Could not complete read */ + if (reg & BQ25710_ADC_OPTION_ADC_START) + return EC_ERROR_TIMEOUT; + + return EC_SUCCESS; +} #endif /* Charger interfaces */ @@ -254,6 +299,30 @@ int charger_device_id(int *id) return raw_read16(BQ25710_REG_DEVICE_ADDRESS, id); } +#ifdef CONFIG_USB_PD_VBUS_MEASURE_CHARGER +int charger_get_vbus_voltage(int port) +{ + int reg, rv; + + rv = bq25710_adc_start(BQ25710_ADC_OPTION_EN_ADC_VBUS); + if (rv) + goto error; + + /* Read ADC value */ + rv = raw_read16(BQ25710_REG_ADC_VBUS_PSYS, ®); + if (rv) + goto error; + + /* LSB => 64mV */ + return (reg >> BQ25710_ADC_VBUS_STEP_BIT_OFFSET) * + BQ25710_ADC_VBUS_STEP_MV + BQ25710_ADC_VBUS_BASE_MV; + +error: + CPRINTF("Could not read VBUS ADC! Error: %d\n", rv); + return 0; +} +#endif + int charger_get_option(int *option) { /* There are 4 option registers, but we only need the first for now. */ @@ -339,43 +408,15 @@ int chg_ramp_is_stable(void) int chg_ramp_get_current_limit(void) { - int reg; - int mode; - int tries_left = 8; - - /* Save current mode to restore same state after ADC read */ - if (bq25710_get_low_power_mode(&mode)) - goto error; + int reg, rv; - /* Exit low power mode so ADC conversion takes typical time */ - if (bq25710_set_low_power_mode(0)) - goto error; - - /* Turn on the ADC for one reading */ - reg = BQ25710_ADC_OPTION_ADC_START | BQ25710_ADC_OPTION_EN_ADC_IIN; - if (raw_write16(BQ25710_REG_ADC_OPTION, reg)) - goto error; - - /* - * Wait until the ADC operation completes. The spec says typical - * conversion time is 10 msec. If low power mode isn't exited first, - * then the conversion time jumps to ~60 msec. - */ - do { - msleep(2); - raw_read16(BQ25710_REG_ADC_OPTION, ®); - } while (--tries_left && (reg & BQ25710_ADC_OPTION_ADC_START)); - - /* ADC reading attempt complete, go back to low power mode */ - if (bq25710_set_low_power_mode(mode)) - goto error; - - /* Could not complete read */ - if (reg & BQ25710_ADC_OPTION_ADC_START) + rv = bq25710_adc_start(BQ25710_ADC_OPTION_EN_ADC_IIN); + if (rv) goto error; /* Read ADC value */ - if (raw_read16(BQ25710_REG_ADC_CMPIN_IIN, ®)) + rv = raw_read16(BQ25710_REG_ADC_CMPIN_IIN, ®); + if (rv) goto error; /* LSB => 50mA */ @@ -383,7 +424,7 @@ int chg_ramp_get_current_limit(void) BQ25710_ADC_IIN_STEP_MA; error: - CPRINTF("Could not read input current limit ADC!\n"); + CPRINTF("Could not read input current limit ADC! Error: %d\n", rv); return 0; } #endif /* CONFIG_CHARGE_RAMP_HW */ diff --git a/driver/charger/bq25710.h b/driver/charger/bq25710.h index 902ea17d82..faccfdec0d 100644 --- a/driver/charger/bq25710.h +++ b/driver/charger/bq25710.h @@ -58,7 +58,14 @@ /* ADCOption Register */ #define BQ25710_ADC_OPTION_ADC_START (1 << 14) +#define BQ25710_ADC_OPTION_EN_ADC_VBUS (1 << 6) #define BQ25710_ADC_OPTION_EN_ADC_IIN (1 << 4) +#define BQ25710_ADC_OPTION_EN_ADC_ALL 0xFF + +/* ADCVBUS/PSYS Register */ +#define BQ25710_ADC_VBUS_STEP_MV 64 +#define BQ25710_ADC_VBUS_BASE_MV 3200 +#define BQ25710_ADC_VBUS_STEP_BIT_OFFSET 8 /* ADCIIN Register */ #define BQ25710_ADC_IIN_STEP_MA 50 -- cgit v1.2.1