summaryrefslogtreecommitdiff
path: root/chip/stm32
diff options
context:
space:
mode:
authorBossen WU <bossen.wu@stmicro.corp-partner.google.com>2021-06-21 17:43:52 +0800
committerCommit Bot <commit-bot@chromium.org>2021-07-01 10:01:38 +0000
commit7c30c183c161fc4285d191864ed6a631f5f8e8b0 (patch)
tree8025686114f6514702693fcf18f026925c9f6344 /chip/stm32
parent167c755d3a4b492cb5fe1759551f9eb1b7177733 (diff)
downloadchrome-ec-7c30c183c161fc4285d191864ed6a631f5f8e8b0.tar.gz
stm32: add stm32l431 ec in chip/stm32 : adc
stm32l431 related driver: adc-stm32l4.c adc_chip.h The stm32l476g-eval is the only board which would be impacted. BRANCH=main BUG=b:188117811 TEST=make buildall Signed-off-by: Bossen WU <bossen.wu@stmicro.corp-partner.google.com> Change-Id: I0ce73ee9ab02e1cfd20a178628d935d24a1907ce Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2975521 Reviewed-by: Eric Yilun Lin <yllin@google.com>
Diffstat (limited to 'chip/stm32')
-rw-r--r--chip/stm32/adc-stm32l4.c235
-rw-r--r--chip/stm32/adc_chip.h24
2 files changed, 258 insertions, 1 deletions
diff --git a/chip/stm32/adc-stm32l4.c b/chip/stm32/adc-stm32l4.c
new file mode 100644
index 0000000000..8c6e737588
--- /dev/null
+++ b/chip/stm32/adc-stm32l4.c
@@ -0,0 +1,235 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "dma.h"
+#include "hooks.h"
+#include "hwtimer.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+struct mutex adc_lock;
+
+struct adc_profile_t {
+ /* Register values. */
+ uint32_t cfgr1_reg;
+ uint32_t cfgr2_reg;
+ uint32_t smpr_reg; /* Default Sampling Rate */
+ uint32_t ier_reg;
+ /* DMA config. */
+ const struct dma_option *dma_option;
+ /* Size of DMA buffer, in units of ADC_CH_COUNT. */
+ int dma_buffer_size;
+};
+
+#ifdef CONFIG_ADC_PROFILE_SINGLE
+#ifndef CONFIG_ADC_SAMPLE_TIME
+#define CONFIG_ADC_SAMPLE_TIME STM32_ADC_SMPR_12_5_CY
+#endif
+#endif
+
+#if defined(CHIP_FAMILY_STM32L4)
+#define ADC_CALIBRATION_TIMEOUT_US 100000U
+#define ADC_ENABLE_TIMEOUT_US 200000U
+#define ADC_CONVERSION_TIMEOUT_US 200000U
+
+#define NUMBER_OF_ADC_CHANNEL 2
+uint8_t adc1_initialized;
+#endif
+
+#ifdef CONFIG_ADC_PROFILE_FAST_CONTINUOUS
+
+#ifndef CONFIG_ADC_SAMPLE_TIME
+#define CONFIG_ADC_SAMPLE_TIME STM32_ADC_SMPR_1_5_CY
+#endif
+
+static const struct dma_option dma_continuous = {
+ STM32_DMAC_ADC, (void *)&STM32_ADC_DR,
+ STM32_DMA_CCR_MSIZE_32_BIT | STM32_DMA_CCR_PSIZE_32_BIT |
+ STM32_DMA_CCR_CIRC,
+};
+
+static const struct adc_profile_t profile = {
+ /* Sample all channels continuously using DMA */
+ .cfgr1_reg = STM32_ADC_CFGR1_OVRMOD |
+ STM32_ADC_CFGR1_CONT |
+ STM32_ADC_CFGR1_DMACFG,
+ .cfgr2_reg = 0,
+ .smpr_reg = CONFIG_ADC_SAMPLE_TIME,
+ /* Fire interrupt at end of sequence. */
+ .ier_reg = STM32_ADC_IER_EOSEQIE,
+ .dma_option = &dma_continuous,
+ /* Double-buffer our samples. */
+ .dma_buffer_size = 2,
+};
+#endif
+
+static void adc_init(const struct adc_t *adc)
+{
+ /*
+ * If clock is already enabled, and ADC module is enabled
+ * then this is a warm reboot and ADC is already initialized.
+ */
+
+ if (STM32_RCC_AHB2ENR & STM32_RCC_AHB2ENR_ADCEN &&
+ (STM32_ADC1_CR & STM32_ADC1_CR_ADEN))
+ return;
+
+ /* Enable ADC clock */
+ clock_enable_module(MODULE_ADC, 1);
+
+ /* set ADC clock to 20MHz */
+ STM32_ADC1_CCR &= ~0x003C0000;
+ STM32_ADC1_CCR |= 0x00080000;
+
+ STM32_RCC_AHB2ENR |= STM32_RCC_HB2_GPIOA;
+ STM32_RCC_AHB2ENR |= STM32_RCC_HB2_GPIOB;
+
+ /* Set ADC data resolution */
+ STM32_ADC1_CFGR &= ~STM32_ADC1_CFGR_CONT;
+ /* Set ADC conversion data alignment */
+ STM32_ADC1_CFGR &= ~STM32_ADC1_CFGR_ALIGN;
+ /* Set ADC delayed conversion mode */
+ STM32_ADC1_CFGR &= ~STM32_ADC1_CFGR_AUTDLY;
+}
+
+static void adc_configure(int ain_id, int ain_rank,
+ enum stm32_adc_smpr sample_rate)
+{
+ /* Select Sampling time and channel to convert */
+ if (ain_id <= 10) {
+ STM32_ADC1_SMPR1 &= ~(7 << ((ain_id - 1) * 3));
+ STM32_ADC1_SMPR1 |= (sample_rate << ((ain_id - 1) * 3));
+ } else {
+ STM32_ADC1_SMPR2 &= ~(7 << ((ain_id - 11) * 3));
+ STM32_ADC1_SMPR2 |= (sample_rate << ((ain_id - 11) * 3));
+ }
+
+ /* Setup Rank */
+ STM32_ADC1_JSQR &= ~(0x03);
+ STM32_ADC1_JSQR |= NUMBER_OF_ADC_CHANNEL - 1;
+
+ STM32_ADC1_JSQR &= ~(0x1F << (((ain_rank - 1) * 6) + 8));
+ STM32_ADC1_JSQR |= (ain_id << (((ain_rank - 1) * 6) + 8));
+
+ /* Disable DMA */
+ STM32_ADC1_CFGR &= ~STM32_ADC1_CFGR_DMAEN;
+}
+
+int adc_read_channel(enum adc_channel ch)
+{
+ const struct adc_t *adc = adc_channels + ch;
+
+ int value = 0;
+ uint32_t wait_loop_index;
+
+ mutex_lock(&adc_lock);
+
+ if (adc1_initialized == 0) {
+ adc_init(adc);
+
+ /* Configure Injected Channel N */
+ for (uint8_t i = 0; i < NUMBER_OF_ADC_CHANNEL; i++) {
+ const struct adc_t *adc = adc_channels + i;
+
+ adc_configure(adc->channel, adc->rank,
+ adc->sample_rate);
+ }
+
+ if ((STM32_ADC1_CR & STM32_ADC1_CR_ADEN) !=
+ STM32_ADC1_CR_ADEN) {
+ /* Disable ADC deep power down (enabled by default after
+ * reset state)
+ */
+ STM32_ADC1_CR &= ~STM32_ADC1_CR_DEEPPWD;
+ /* Enable ADC internal voltage regulator */
+ STM32_ADC1_CR |= STM32_ADC1_CR_ADVREGEN;
+ }
+
+ /*
+ * Delay for ADC internal voltage regulator stabilization.
+ * Compute number of CPU cycles to wait for, from delay in us.
+ *
+ * Note: Variable divided by 2 to compensate partially
+ * CPU processing cycles (depends on compilation optimization).
+ *
+ * Note: If system core clock frequency is below 200kHz, wait
+ * time is only a few CPU processing cycles.
+ */
+ wait_loop_index = ((20 * (80000000 / (100000 * 2))) / 10);
+ while (wait_loop_index-- != 0)
+ ;
+
+ /* Run ADC self calibration */
+ STM32_ADC1_CR |= STM32_ADC1_CR_ADCAL;
+
+ /* wait for the end of calibration */
+ wait_loop_index = ((ADC_CALIBRATION_TIMEOUT_US *
+ (CPU_CLOCK / (100000 * 2))) / 10);
+ while (STM32_ADC1_CR & STM32_ADC1_CR_ADCAL) {
+ if (wait_loop_index-- == 0)
+ break;
+ }
+
+ /* Enable ADC */
+ STM32_ADC1_ISR |= STM32_ADC1_ISR_ADRDY;
+ STM32_ADC1_CR |= STM32_ADC1_CR_ADEN;
+ wait_loop_index = ((ADC_ENABLE_TIMEOUT_US *
+ (CPU_CLOCK / (100000 * 2))) / 10);
+ while (!(STM32_ADC1_ISR & STM32_ADC1_ISR_ADRDY)) {
+ wait_loop_index--;
+ if (wait_loop_index == 0)
+ break;
+ }
+
+ adc1_initialized = 1;
+ }
+
+ /* Start injected conversion */
+ STM32_ADC1_CR |= BIT(3); /* JADSTART */
+
+ /* Wait for end of injected conversion */
+ wait_loop_index = ((ADC_CONVERSION_TIMEOUT_US *
+ (CPU_CLOCK / (100000 * 2))) / 10);
+ while (!(STM32_ADC1_ISR & BIT(6))) {
+ if (wait_loop_index-- == 0)
+ break;
+ }
+
+ /* Clear JEOS bit */
+ STM32_ADC1_ISR |= BIT(6);
+
+ /* read converted value */
+ if (adc->rank == 1)
+ value = STM32_ADC1_JDR1;
+ if (adc->rank == 2)
+ value = STM32_ADC1_JDR2;
+
+ mutex_unlock(&adc_lock);
+
+ return value * adc->factor_mul / adc->factor_div + adc->shift;
+}
+
+void adc_disable(void)
+{
+ /* Disable ADC */
+ /* Do not Set ADDIS when ADC is disabled */
+ adc1_initialized = 0;
+
+ if (STM32_ADC1_CR & STM32_ADC1_CR_ADEN)
+ STM32_ADC1_CR |= STM32_ADC1_CR_ADDIS;
+
+ /*
+ * Note that the ADC is not in OFF state immediately.
+ * Once the ADC is effectively put into OFF state,
+ * STM32_ADC_CR_ADDIS bit will be cleared by hardware.
+ */
+}
diff --git a/chip/stm32/adc_chip.h b/chip/stm32/adc_chip.h
index 413653e4d7..0d6ae7fe51 100644
--- a/chip/stm32/adc_chip.h
+++ b/chip/stm32/adc_chip.h
@@ -10,6 +10,20 @@
#include "stdint.h"
+#ifdef CHIP_FAMILY_STM32L4
+enum stm32_adc_smpr {
+ STM32_ADC_SMPR_DEFAULT = 0,
+ STM32_ADC_SMPR_2_5_CY,
+ STM32_ADC_SMPR_6_5_CY,
+ STM32_ADC_SMPR_12_5_CY,
+ STM32_ADC_SMPR_24_5_CY,
+ STM32_ADC_SMPR_47_5_CY,
+ STM32_ADC_SMPR_92_5_CY,
+ STM32_ADC_SMPR_247_5_CY,
+ STM32_ADC_SMPR_640_5_CY,
+ STM32_ADC_SMPR_COUNT,
+};
+#else
enum stm32_adc_smpr {
STM32_ADC_SMPR_DEFAULT = 0,
STM32_ADC_SMPR_1_5_CY,
@@ -22,6 +36,7 @@ enum stm32_adc_smpr {
STM32_ADC_SMPR_239_5_CY,
STM32_ADC_SMPR_COUNT,
};
+#endif
/* Data structure to define ADC channels. */
struct adc_t {
@@ -30,7 +45,11 @@ struct adc_t {
int factor_div;
int shift;
int channel;
-#ifdef CHIP_FAMILY_STM32F0
+#ifdef CHIP_FAMILY_STM32L4
+ int rank;
+#endif
+
+#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4)
enum stm32_adc_smpr sample_rate; /* Sampling Rate of the channel */
#endif
};
@@ -52,4 +71,7 @@ void adc_disable(void);
/* Just plain id mapping for code readability */
#define STM32_AIN(x) (x)
+/* Add for ADCs with RANK */
+#define STM32_RANK(x) (x)
+
#endif /* __CROS_EC_ADC_CHIP_H */