diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-09-23 10:05:10 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-09-25 18:15:41 +0000 |
commit | 9c62920f96e844760aeef403da9d19f08060fd29 (patch) | |
tree | 4bb6197132a813e4c21b44902b5c09b6a9eca647 | |
parent | fb5ff7b1bb59174ea140d18cb84ce1d6599337c1 (diff) | |
download | chrome-ec-9c62920f96e844760aeef403da9d19f08060fd29.tar.gz |
stm32f0: fix rare ADC initialization bug
Fix potential bug in ADC initialization. After setting ADEN bit to
enable ADC module, we must wait for ADRDY (ADC ready) bit before
continuing. This bug only affects a few chips, and only some of
the time.
BUG=chrome-os-partner:31978
BRANCH=none
TEST=Used a samus board where the PD MCU fails ADC initialization
quite often. Without this fix, if you reboot the PD MCU, it will
sometimes come up with all ADC's reading 0 and ADEN reading 0.
With this fix, it always boots with the ADC's working
Change-Id: Iba1d0e56006ba1ad6d9f0eee964a70ef2d0f8dcf
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/219522
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Vic Yang <victoryang@chromium.org>
-rw-r--r-- | board/zinger/hardware.c | 10 | ||||
-rw-r--r-- | chip/stm32/adc-stm32f0.c | 17 | ||||
-rw-r--r-- | chip/stm32/registers.h | 3 |
3 files changed, 21 insertions, 9 deletions
diff --git a/board/zinger/hardware.c b/board/zinger/hardware.c index fc0612eeb9..7e2cb013ea 100644 --- a/board/zinger/hardware.c +++ b/board/zinger/hardware.c @@ -104,13 +104,17 @@ static void adc_init(void) /* Only do the calibration if the ADC is off */ if (!(STM32_ADC_CR & 1)) { /* ADC calibration */ - STM32_ADC_CR = 1 << 31; /* set ADCAL = 1, ADC off */ + STM32_ADC_CR = STM32_ADC_CR_ADCAL; /* set ADCAL = 1, ADC off */ /* wait for the end of calibration */ - while (STM32_ADC_CR & (1 << 31)) + while (STM32_ADC_CR & STM32_ADC_CR_ADCAL) ; } + /* As per ST recommendation, ensure two cycles before setting ADEN */ + asm volatile("nop; nop;"); /* ADC enabled */ - STM32_ADC_CR = 1 << 0; + STM32_ADC_CR = STM32_ADC_ISR_ADRDY; + while (!(STM32_ADC_ISR & STM32_ADC_ISR_ADRDY)) + ; /* Single conversion, right aligned, 12-bit */ STM32_ADC_CFGR1 = 1 << 12; /* (1 << 15) => AUTOOFF */; /* clock is ADCCLK */ diff --git a/chip/stm32/adc-stm32f0.c b/chip/stm32/adc-stm32f0.c index 31c928fc6a..c29089048f 100644 --- a/chip/stm32/adc-stm32f0.c +++ b/chip/stm32/adc-stm32f0.c @@ -278,10 +278,10 @@ fail: static void adc_init(void) { /* - * If clock is already enabled, then this is a warm reboot and - * ADC is already initialized. + * If clock is already enabled, and ADC module is enabled + * then this is a warm reboot and ADC is already initialized. */ - if (STM32_RCC_APB2ENR & (1 << 9)) + if (STM32_RCC_APB2ENR & (1 << 9) && (STM32_ADC_CR & STM32_ADC_CR_ADEN)) return; /* Enable ADC clock */ @@ -289,13 +289,18 @@ static void adc_init(void) /* check HSI14 in RCC ? ON by default */ /* ADC calibration (done with ADEN = 0) */ - STM32_ADC_CR = 1 << 31; /* set ADCAL = 1, ADC off */ + STM32_ADC_CR = STM32_ADC_CR_ADCAL; /* set ADCAL = 1, ADC off */ /* wait for the end of calibration */ - while (STM32_ADC_CR & (1 << 31)) + while (STM32_ADC_CR & STM32_ADC_CR_ADCAL) ; + /* As per ST recommendation, ensure two cycles before setting ADEN */ + asm volatile("nop; nop;"); + /* ADC enabled */ - STM32_ADC_CR = 1 << 0; + STM32_ADC_CR = STM32_ADC_CR_ADEN; + while (!(STM32_ADC_ISR & STM32_ADC_ISR_ADRDY)) + ; /* Single conversion, right aligned, 12-bit */ STM32_ADC_CFGR1 = 1 << 12; /* (1 << 15) => AUTOOFF */; diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 9922aaad11..79c2e54934 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -887,8 +887,11 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_ADC_DR(x) REG32(STM32_ADC_BASE(x) + 0x4c) #elif defined(CHIP_FAMILY_STM32F0) #define STM32_ADC_ISR REG32(STM32_ADC1_BASE + 0x00) +#define STM32_ADC_ISR_ADRDY (1 << 0) #define STM32_ADC_IER REG32(STM32_ADC1_BASE + 0x04) #define STM32_ADC_CR REG32(STM32_ADC1_BASE + 0x08) +#define STM32_ADC_CR_ADEN (1 << 0) +#define STM32_ADC_CR_ADCAL (1 << 31) #define STM32_ADC_CFGR1 REG32(STM32_ADC1_BASE + 0x0C) #define STM32_ADC_CFGR2 REG32(STM32_ADC1_BASE + 0x10) #define STM32_ADC_SMPR REG32(STM32_ADC1_BASE + 0x14) |