summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-09-23 10:05:10 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-09-25 18:15:41 +0000
commit9c62920f96e844760aeef403da9d19f08060fd29 (patch)
tree4bb6197132a813e4c21b44902b5c09b6a9eca647
parentfb5ff7b1bb59174ea140d18cb84ce1d6599337c1 (diff)
downloadchrome-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.c10
-rw-r--r--chip/stm32/adc-stm32f0.c17
-rw-r--r--chip/stm32/registers.h3
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)