You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/05/22 15:10:12 UTC

[incubator-nuttx] branch master updated: arm/tlsr82: optimize the adc driver.

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 200109fd28 arm/tlsr82: optimize the adc driver.
200109fd28 is described below

commit 200109fd2869cfbbe558f9b7f8571e5c32ee8db4
Author: wangbowen6 <wa...@xiaomi.com>
AuthorDate: Wed May 18 22:53:27 2022 +0800

    arm/tlsr82: optimize the adc driver.
    
    1. Add vbat mode for chip internal voltage sample;
    2. Add adc channel config;
    3. Using DFIFO2 to get the sample value, follow telink sdk.
    4. Add calibration function and config;
    
    Signed-off-by: wangbowen6 <wa...@xiaomi.com>
---
 arch/arm/src/tlsr82/Kconfig                        |  44 ++
 arch/arm/src/tlsr82/hardware/tlsr82_adc.h          |  40 ++
 arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h        |  83 +++
 arch/arm/src/tlsr82/tlsr82_adc.c                   | 622 +++++++++++++++------
 arch/arm/src/tlsr82/tlsr82_adc.h                   |  16 +
 arch/arm/src/tlsr82/tlsr82_timer.h                 |  14 +
 .../tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c   |  39 +-
 7 files changed, 681 insertions(+), 177 deletions(-)

diff --git a/arch/arm/src/tlsr82/Kconfig b/arch/arm/src/tlsr82/Kconfig
index fb740c18f2..1adae2580f 100644
--- a/arch/arm/src/tlsr82/Kconfig
+++ b/arch/arm/src/tlsr82/Kconfig
@@ -314,6 +314,50 @@ menuconfig TLSR82_ADC
 	bool "ADC Configuration"
 	default n
 
+if TLSR82_ADC
+
+config TLSR82_ADC_CALI
+	bool "TLSR82 Adc calibration enable"
+	default n
+	---help---
+		When enable the adc calibration, adc driver will read the calibration
+		parameters stored in the falsh during initialization and use these
+		parameters to calibrate the sample value.
+
+config TLSR82_ADC_CALI_PARA_ADDR
+	hex
+	default 0x3fff8 if TLSR82_ADC_CALI
+	---help---
+		This is the adc calibration parameters address, this address must be
+		equal to the address defined in production tools.
+
+config TLSR82_ADC_CHAN0
+  bool "TLSR82 Adc channel 0 enable"
+  default n
+
+config TLSR82_ADC_CHAN1
+  bool "TLSR82 Adc channel 1 enable"
+  default n
+
+config TLSR82_ADC_CHAN2
+  bool "TLSR82 Adc channel 2 enable"
+  default n
+
+config TLSR82_ADC_VBAT
+  bool "TLSR82 Adc channel Vbat enable"
+  default n
+
+config TLSR82_ADC_FILT_NUM
+	int "TLSR82 Adc filter average number"
+	default 4
+	---help---
+		This number determines the average number during sampling, driver will
+		remove max and min sample values and calculate the average of the
+		remaining values as the last sample value.
+		Note: This number must be multiple of 4.
+
+endif
+
 menuconfig TLSR82_LPCOMP
 	bool "LPCOMP Configuration"
 	default n
diff --git a/arch/arm/src/tlsr82/hardware/tlsr82_adc.h b/arch/arm/src/tlsr82/hardware/tlsr82_adc.h
index c384916fda..950e3c1ad9 100644
--- a/arch/arm/src/tlsr82/hardware/tlsr82_adc.h
+++ b/arch/arm/src/tlsr82/hardware/tlsr82_adc.h
@@ -62,6 +62,46 @@
 #define ADC_VREF_1P2V                      (0x2 << ADC_VREF_SHIFT)
 #define ADC_VREF_RSVD2                     (0x3 << ADC_VREF_SHIFT)
 
+/* ADC analog input positive and negative channel definition */
+
+#define ADC_CHAN_POS_SHIFT                 4
+#define ADC_CHAN_POS_MASK                  (0xf << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_NOINPUT               (0  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B0                    (1  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B1                    (2  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B2                    (3  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B3                    (4  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B4                    (5  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B5                    (6  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B6                    (7  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B7                    (8  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_C4                    (9  << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_C5                    (10 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_PGA0                  (11 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_PGA1                  (12 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_TEMSENSOR             (13 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_TEMSENSOR_EE          (14 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_VBAT                  (15 << ADC_CHAN_POS_SHIFT)
+
+#define ADC_CHAN_NEG_SHIFT                 0
+#define ADC_CHAN_NEG_MASK                  (0xf << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_NOINPUT               (0  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B0                    (1  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B1                    (2  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B2                    (3  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B3                    (4  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B4                    (5  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B5                    (6  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B6                    (7  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B7                    (8  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_C4                    (9  << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_C5                    (10 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_PGA0                  (11 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_PGA1                  (12 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_TEMSENSOR             (13 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_TEMSENSOR_EE          (14 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_GND                   (15 << ADC_CHAN_NEG_SHIFT)
+
 /* ADC Mode, Resolution definition */
 
 #define ADC_MODE_RES_SHIFT                 0
diff --git a/arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h b/arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h
new file mode 100644
index 0000000000..df78568c3b
--- /dev/null
+++ b/arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_TLSR82_HARDWARE_TLSR82_DFIFO_H
+#define __ARCH_ARM_SRC_TLSR82_HARDWARE_TLSR82_DFIFO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/tlsr82/chip.h>
+
+#include "hardware/tlsr82_register.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* DFIFO = DMA FIFO */
+
+/* DFIFO0 ~ DFIFO2 address and size register definition */
+
+#define DFIFO0_ADDR_REG            REG_ADDR16(0xb00)
+#define DFIFO0_SIZE_REG            REG_ADDR8(0xb02)
+#define DFIFO0_ADDRHI_REG          REG_ADDR8(0xb03)
+
+#define DFIFO1_ADDR_REG            REG_ADDR16(0xb04)
+#define DFIFO1_SIZE_REG            REG_ADDR8(0xb06)
+#define DFIFO1_ADDRHI_REG          REG_ADDR8(0xb07)
+
+#define DFIFO2_ADDR_REG            REG_ADDR16(0xb08)
+#define DFIFO2_SIZE_REG            REG_ADDR8(0xb0a)
+#define DFIFO2_ADDRHI_REG          REG_ADDR8(0xb0b)
+
+#define DFIFO_ADC_ADDR_REG         DFIFO2_ADDR_REG
+#define DFIFO_ADC_SIZE_REG         DFIFO2_SIZE_REG
+#define DFIFO_ADC_ADDRHI_REG       DFIFO0_ADDRHI_REG
+
+/* DFIFO mode register definition */
+
+#define DFIFO_MODE_REG             REG_ADDR8(0xb10)
+
+/* DFIFO read and write buffer register definition */
+
+#define DFIFO0_RPTR_REG            REG_ADDR16(0xb14)
+#define DFIFO0_WPTR_REG            REG_ADDR16(0xb16)
+
+#define DFIFO1_RPTR_REG            REG_ADDR16(0xb18)
+#define DFIFO1_WPTR_REG            REG_ADDR16(0xb1a)
+
+#define DFIFO2_RPTR_REG            REG_ADDR16(0xb1c)
+#define DFIFO2_WPTR_REG            REG_ADDR16(0xb1e)
+
+/* DFIFO mode bit definition */
+
+#define DFIFO_MODE_DFIFO0_IN       BIT(0)
+#define DFIFO_MODE_DFIFO1_IN       BIT(1)
+#define DFIFO_MODE_DFIFO2_IN       BIT(2)
+#define DFIFO_MODE_DFIFO0_OUT      BIT(3)
+#define DFIFO_MODE_DFIFO0_L_INT    BIT(4)
+#define DFIFO_MODE_DFIFO0_H_INT    BIT(5)
+#define DFIFO_MODE_DFIFO1_H_INT    BIT(6)
+#define DFIFO_MODE_DFIFO2_H_INT    BIT(7)
+
+#endif /* __ARCH_ARM_SRC_TLSR82_HARDWARE_TLSR82_DFIFO_H */
diff --git a/arch/arm/src/tlsr82/tlsr82_adc.c b/arch/arm/src/tlsr82/tlsr82_adc.c
index 9a43a21a1f..229e97fdf6 100644
--- a/arch/arm/src/tlsr82/tlsr82_adc.c
+++ b/arch/arm/src/tlsr82/tlsr82_adc.c
@@ -37,6 +37,9 @@
 #include "tlsr82_adc.h"
 #include "tlsr82_gpio.h"
 #include "tlsr82_analog.h"
+#include "tlsr82_flash.h"
+#include "tlsr82_timer.h"
+#include "hardware/tlsr82_dfifo.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -52,6 +55,23 @@
 #  define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
+/* Default reference voltage 1175 mV */
+
+#define ADC_DEFAULT_VREF     1175
+
+#define ADC_FILT_NUM         CONFIG_TLSR82_ADC_FILT_NUM
+
+#if (ADC_FILT_NUM & 0x3) != 0
+#  error "The filter number must be multiple of 4 !"
+#endif
+
+/* ADC Channel type definition */
+
+#define ADC_CHAN_TYPE_NONE   0
+#define ADC_CHAN_TYPE_BASE   1
+#define ADC_CHAN_TYPE_VBAT   2
+#define ADC_CHAN_TYPE_TEMP   3
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -60,22 +80,26 @@
 
 struct adc_info_s
 {
-  uint32_t   vref;        /* The reference voltage (mV) */
-  bool       calied;      /* Calibration finished or not */
-  bool       registered;  /* Have registered a adc device */
-  bool       configed;    /* Adc has been configured or not */
-  const bool cali;        /* Calibration enable/disable, default enable */
+  uint32_t   base_vref;    /* The reference voltage (mV) or gain for base/gpio mode */
+  int        base_off;     /* The offset for base/gpio mode two-point calibration */
+  uint32_t   vbat_vref;    /* The reference voltage (mV) for vbat mode */
+  bool       base_two;     /* Base/Gpio mode two-point calibration or not */
+  bool       registered;   /* Have registered a adc device */
+  bool       configed;     /* Adc has been configured or not */
+  uint8_t    channel;      /* Adc current channel */
+  uint8_t    channeltype;  /* Adc current channel type */
 };
 
 /* ADC Private Data */
 
 struct adc_chan_s
 {
-  uint32_t                     ref;     /* Reference count */
-  struct adc_info_s           *info;    /* Adc information */
-  const uint8_t                channel; /* Channel number */
-  const uint32_t               pinset;  /* GPIO pin number */
-  const struct adc_callback_s *cb;      /* Upper driver callback */
+  uint32_t                     ref;          /* Reference count */
+  struct adc_info_s           *info;         /* Adc information */
+  const uint8_t                channeltype;  /* Channel number */
+  const uint8_t                channel;      /* Channel number */
+  const uint32_t               pinset;       /* GPIO pin number */
+  const struct adc_callback_s *cb;           /* Upper driver callback */
 };
 
 /****************************************************************************
@@ -85,8 +109,7 @@ struct adc_chan_s
 static void tlsr82_adc_reset(void);
 static void tlsr82_adc_power_ctrl(bool enable);
 static void tlsr82_adc_clk_ctrl(bool enable);
-static void tlsr82_adc_set_sampleclk(uint32_t clk);
-static void tlsr82_adc_config(uint32_t cfg);
+static void tlsr82_adc_config(struct adc_chan_s *priv);
 static void tlsr82_adc_pin_config(uint32_t pinset);
 static void tlsr82_adc_chan_config(uint32_t pinset);
 
@@ -104,14 +127,18 @@ static void adc_read_work(struct adc_dev_s *dev);
  * Private Data
  ****************************************************************************/
 
-/* ADC information */
+/* ADC module information */
 
-static struct adc_info_s g_adc_chan0_info =
+static struct adc_info_s g_adc_module0_info =
 {
-  .vref       = 1175,  /* Default reference voltage is 1175mV (1.2V) */
-  .registered = false,
-  .configed   = false,
-  .cali       = true,  /* Default calibration switch is enable */
+  .base_vref    = ADC_DEFAULT_VREF,
+  .base_off     = 0,
+  .vbat_vref    = ADC_DEFAULT_VREF,
+  .base_two     = false,
+  .registered   = false,
+  .configed     = false,
+  .channel      = ADC_CHAN_NONE,
+  .channeltype  = ADC_CHAN_TYPE_NONE,
 };
 
 /* ADC interface operations */
@@ -126,21 +153,151 @@ static const struct adc_ops_s g_adcops =
   .ao_ioctl       = adc_ioctl,
 };
 
+/* ADC normal channel, for gpio sample */
+
+#ifdef CONFIG_TLSR82_ADC_CHAN0
 static struct adc_chan_s g_adc_chan0 =
 {
-  .info    = &g_adc_chan0_info,
-  .channel = 0,
-  .pinset  = GPIO_PIN_PB2,
+  .info        = &g_adc_module0_info,
+  .channeltype = ADC_CHAN_TYPE_BASE,
+  .channel     = ADC_CHAN_0,
+  .pinset      = GPIO_PIN_PB2,
 };
 
 static struct adc_dev_s g_adc_chan0_dev =
 {
-  .ad_ops      = &g_adcops,
-  .ad_priv     = &g_adc_chan0,
+  .ad_ops  = &g_adcops,
+  .ad_priv = &g_adc_chan0,
+};
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN1
+static struct adc_chan_s g_adc_chan1 =
+{
+  .info        = &g_adc_module0_info,
+  .channeltype = ADC_CHAN_TYPE_BASE,
+  .channel     = ADC_CHAN_1,
+  .pinset      = GPIO_PIN_PB3,
+};
+
+static struct adc_dev_s g_adc_chan1_dev =
+{
+  .ad_ops  = &g_adcops,
+  .ad_priv = &g_adc_chan1,
+};
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN2
+static struct adc_chan_s g_adc_chan2 =
+{
+  .info        = &g_adc_module0_info,
+  .channeltype = ADC_CHAN_TYPE_BASE,
+  .channel     = ADC_CHAN_2,
+  .pinset      = GPIO_PIN_PB5,
+};
+
+static struct adc_dev_s g_adc_chan2_dev =
+{
+  .ad_ops  = &g_adcops,
+  .ad_priv = &g_adc_chan2,
 };
+#endif
+
+/* ADC Bat channel, for chip battery sample */
+
+#ifdef CONFIG_TLSR82_ADC_VBAT
+static struct adc_chan_s g_adc_chanbat =
+{
+  .info        = &g_adc_module0_info,
+  .channeltype = ADC_CHAN_TYPE_VBAT,
+  .channel     = ADC_CHAN_VBAT,
+  .pinset      = GPIO_INVLD_CFG,
+};
+
+static struct adc_dev_s g_adc_chanbat_dev =
+{
+  .ad_ops  = &g_adcops,
+  .ad_priv = &g_adc_chanbat,
+};
+#endif
 
 static sem_t g_sem_excl = SEM_INITIALIZER(1);
 
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tlsr82_adc_dfifo_enable
+ *
+ * Description:
+ *   Enable the adc dfifo/dfifo2, the dfifo2 will copy the adc sample data
+ *   to the address in DFIFO_ADC_ADDR_REG.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void tlsr82_adc_dfifo_enable(void)
+{
+  DFIFO_MODE_REG |= DFIFO_MODE_DFIFO2_IN;
+}
+
+/****************************************************************************
+ * Name: tlsr82_adc_dfifo_disable
+ *
+ * Description:
+ *   Disable the adc dfifo/dfifo2
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void tlsr82_adc_dfifo_disable(void)
+{
+  DFIFO_MODE_REG &= ~DFIFO_MODE_DFIFO2_IN;
+}
+
+/****************************************************************************
+ * Name: tlsr82_adc_dfifo_config
+ *
+ * Description:
+ *   Config the data buffer, so DFIFO2 can copy sample value to buffer
+ *
+ * Input Parameters:
+ *   buffer - the buffer to store the adc sample data
+ *   size   - the buffer size, this size must be multiple of 4
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void tlsr82_adc_dfifo_config(uint8_t *buffer, size_t size)
+{
+  /* Config the data buffer, so DFIFO2 can copy sample value to buffer
+   * DFIFO buffer address : only need low 16 bit, beacause the high 16 bit
+   *                        must be 0x0084
+   * DFIFO buffer size    : DFIFO_ADC_SIZE_REG = n ==> 4 * (n + 1) size
+   *                        DFIFO_ADC_SIZE_REG = size / 4 - 1
+   */
+
+  DFIFO_ADC_ADDR_REG = (uint16_t)((uint32_t)buffer & 0xffff);
+  DFIFO_ADC_SIZE_REG = (size >> 2) - 1;
+
+  /* Clear the dfifo write pointer */
+
+  DFIFO2_WPTR_REG    = 0;
+}
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -224,19 +381,66 @@ static void tlsr82_adc_clk_ctrl(bool enable)
  * Name: tlsr82_adc_config
  *
  * Description:
- *   Config the adc, after this, the adc can start sample.
+ *   Config the adc to different mode, after this, the adc can start sample
+ *   the voltage in the gpio pin (Base mode) or the chip volatge (Vbat
+ *   channel mode).
+ *   Five configuration conditions:
+ *   1. Same channel, do not need do not need re-configuration;
+ *   2. adc module has not been configured, must configure it;
+ *   3. adc module has been configured, but current channel and configured
+ *      channel are both vbat channel, do not need re-configuration;
+ *   4. adc module has been configured, but current channel and configured
+ *      channel are both base channel, only configure the channel;
+ *   5. others, need re-configuration.
  *
  * Input Parameters:
- *   cfg  -  adc pinset
+ *   priv  - adc channel handler
  *
  * Returned Value:
  *   None
  *
  ****************************************************************************/
 
-static void tlsr82_adc_config(uint32_t cfg)
+static void tlsr82_adc_config(struct adc_chan_s *priv)
 {
-  /* Follow the datasheet and sdk adc_vbat_init() to config the adc */
+  uint8_t channel     = priv->info->channel;
+  uint8_t channeltype = priv->info->channeltype;
+
+  ainfo("Current channel=%u, channeltype=%u\n", channel, channeltype);
+  ainfo("Input   channel=%u, channeltype=%u\n",
+        priv->channel, priv->channeltype);
+
+  DEBUGASSERT(priv != NULL && priv->channel != ADC_CHAN_NONE);
+
+  /* If current channel type is same as the priv channel type, do not
+   * need re-configure all the register.
+   */
+
+  if (channeltype == priv->channeltype)
+    {
+      if (channeltype == ADC_CHAN_TYPE_BASE && channel != priv->channel)
+        {
+          /* The channel type is base and the input channel (GPIO pin) is
+           * different, only need re-configure the adc input channel.
+           */
+
+          tlsr82_adc_chan_config(priv->pinset);
+          priv->info->channel = priv->channel;
+        }
+
+      return;
+    }
+
+  ainfo("Start config\n");
+
+  /* Follow the sdk code adc_base_init() and adc_vbat_channel_init()
+   * to config the adc, VBAT_CHAN mode is samiler to BASE mode, the
+   * differences are:
+   * 1. adc divider : VBAT_CHAN mode, 1/3
+   *                  BASE mode, 1
+   * 2. pre-scale   : VBAT_CHAN mode, 1
+   *                  BASE mode, 1/8
+   */
 
   /* Enable misc chanel and set totaol length for sampling state be 2 */
 
@@ -253,14 +457,34 @@ static void tlsr82_adc_config(uint32_t cfg)
   tlsr82_analog_write(ADC_SAMP1_REG, 240 & 0xff);
   tlsr82_analog_write(ADC_SAMP3_REG, ((240 >> 8) << 6) | (10 & 0xff));
 
-  /* Divider select OFF */
+  /* Divider select 1/3 or OFF */
 
-  tlsr82_analog_modify(ADC_DIVIDER_REG, ADC_DIVIDER_SEL_MASK,
-                       ADC_DIVIDER_SEL_OFF);
+#ifdef CONFIG_TLSR82_ADC_VBAT
+  if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+    {
+      tlsr82_analog_modify(ADC_DIVIDER_REG, ADC_DIVIDER_SEL_MASK,
+                           ADC_DIVIDER_SEL_1F3);
+    }
+  else
+#endif
+    {
+      tlsr82_analog_modify(ADC_DIVIDER_REG, ADC_DIVIDER_SEL_MASK,
+                           ADC_DIVIDER_SEL_OFF);
+    }
 
   /* Set the adc differential channel */
 
-  tlsr82_adc_chan_config(cfg);
+#ifdef CONFIG_TLSR82_ADC_VBAT
+  if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+    {
+      tlsr82_analog_write(ADC_CHAN_REG, ADC_CHAN_POS_VBAT |
+                                        ADC_CHAN_NEG_GND);
+    }
+  else
+#endif
+    {
+      tlsr82_adc_chan_config(priv->pinset);
+    }
 
   /* Enable the Different input mode */
 
@@ -286,8 +510,23 @@ static void tlsr82_adc_config(uint32_t cfg)
    * When pre-scaling is 1/8, the ADC_DIVIDER_REG_0xf9 <4> must be 1
    */
 
-  tlsr82_analog_modify(ADC_SCALE_REG, ADC_SCALE_MASK, ADC_SCALE_1F8);
-  tlsr82_analog_modify(ADC_DIVIDER_REG, 0, (0x1 << 4));
+#ifdef CONFIG_TLSR82_ADC_VBAT
+  if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+    {
+      tlsr82_analog_modify(ADC_SCALE_REG, ADC_SCALE_MASK, ADC_SCALE_1);
+      tlsr82_analog_modify(ADC_DIVIDER_REG, BIT_RNG(4, 5), 0);
+    }
+  else
+#endif
+    {
+      tlsr82_analog_modify(ADC_SCALE_REG, ADC_SCALE_MASK, ADC_SCALE_1F8);
+      tlsr82_analog_modify(ADC_DIVIDER_REG, BIT(4), BIT(4));
+    }
+
+  /* Set current channel and current type */
+
+  priv->info->channel     = priv->channel;
+  priv->info->channeltype = priv->channeltype;
 }
 
 /****************************************************************************
@@ -311,17 +550,13 @@ static void tlsr82_adc_pin_config(uint32_t pinset)
 
   GPIO_SET_AS_GPIO(GPIO_GET(GROUP, cfg), GPIO_GET(PIN, cfg));
 
-  /* Vbat mode pin config, disable input, enable output, output set high */
+  /* Base mode pin config, diable input, disable output, output set low */
 
   tlsr82_gpio_input_ctrl(cfg, false);
 
-  tlsr82_gpio_output_ctrl(cfg, true);
+  tlsr82_gpio_output_ctrl(cfg, false);
 
-  tlsr82_gpiowrite(cfg, true);
-
-  /* Base mode pin config, diable input, disable output, output set low */
-
-  /* nothing */
+  tlsr82_gpiowrite(cfg, false);
 }
 
 /****************************************************************************
@@ -364,53 +599,16 @@ static void tlsr82_adc_chan_config(uint32_t pinset)
       return;
     }
 
+  /* Config gpio */
+
+  tlsr82_adc_pin_config(pinset);
+
   /* Config the positive and negative input, here, the negative input
    * is always configured to GND (0x0f).
    */
 
-  tlsr82_analog_write(ADC_CHAN_REG, (pinadc << 4) | 0x0f);
-}
-
-/****************************************************************************
- * Name: read_efuse
- *
- * Description:
- *   Read Efuse data.
- *
- * Input Parameters:
- *   addr   - register address
- *   b_off  - bit offset
- *   b_size - bit size
- *
- * Returned Value:
- *  Efuse data.
- *
- ****************************************************************************/
-
-static uint32_t read_efuse(uint32_t addr, uint32_t b_off, uint32_t b_size)
-{
-  uint32_t data;
-  uint32_t regval;
-  uint32_t shift = 32 - b_size;
-  uint32_t mask = UINT32_MAX >> shift;
-  uint32_t res = b_off % 32;
-  uint32_t regaddr = addr + (b_off / 32 * 4);
-
-  regval = getreg32(regaddr);
-  data = regval >> res;
-  if (res <= shift)
-    {
-      data &= mask;
-    }
-  else
-    {
-      shift = 32 - res;
-
-      regval = getreg32(regaddr + 4);
-      data |= (regval & (mask >> shift)) << shift;
-    }
-
-  return data;
+  tlsr82_analog_write(ADC_CHAN_REG, (pinadc << ADC_CHAN_POS_SHIFT) |
+                                    ADC_CHAN_NEG_GND);
 }
 
 /****************************************************************************
@@ -490,49 +688,79 @@ static void adc_dump(const char *msg)
 
 static uint16_t adc_read(void)
 {
-  volatile uint8_t adc_misc_data_l;
-  volatile uint8_t adc_misc_data_h;
-  volatile uint16_t adc_misc_data;
-
-  /* Stop the adc sample */
+  volatile uint16_t data_buf[ADC_FILT_NUM];
+  uint16_t tmp;
+  uint16_t max = 0;
+  uint16_t min = UINT16_MAX;
+  uint32_t sum = 0;
+  uint32_t currtime;
+  int i;
 
-  tlsr82_analog_modify(ADC_CTRL1_REG, ADC_CTRL1_SAMP_MASK,
-                       ADC_CTRL1_SAMP_OFF);
+  /* Clear the data buffer and config */
 
-  /* Get adc sample value */
+  memset((void *)data_buf, 0, ADC_FILT_NUM);
 
-  adc_misc_data_l = tlsr82_analog_read(ADC_DATAL_REG);
-  adc_misc_data_h = tlsr82_analog_read(ADC_DATAH_REG);
+  tlsr82_adc_dfifo_config((uint8_t *)data_buf, ADC_FILT_NUM);
 
-  /* Restart the adc sample */
+  /* Enable DFIFO 2 */
 
-  tlsr82_analog_modify(ADC_CTRL1_REG, ADC_CTRL1_SAMP_MASK,
-                       ADC_CTRL1_SAMP_ON);
+  tlsr82_adc_dfifo_enable();
 
-  /* Combine the adc sample value and process */
+  /* Wait at least 2 sample cycle, frequency = 96k, T = 10.4us */
 
-  adc_misc_data = (adc_misc_data_h << 8 | adc_misc_data_l);
+  currtime = tlsr82_time();
+  while (!tlsr82_time_exceed(currtime, 25));
 
-  if (adc_misc_data & BIT(13))
+  for (i = 0; i < ADC_FILT_NUM; i++)
     {
+      while (data_buf[i] == 0 && !tlsr82_time_exceed(currtime, 25));
+      currtime = tlsr82_time();
+
       /* Bit13 is the sign bit, bit13 = 1 indicates the data
-       * is negative.
+       * is negative but we only get the low 13bit data.
        */
 
-      adc_misc_data = 0;
-    }
-  else
-    {
-      /* Only get the low 13bit data */
+      tmp = data_buf[i];
+      if (tmp & BIT(13))
+        {
+          tmp = 0;
+        }
+      else
+        {
+          tmp &= 0x1fff;
+        }
+
+      sum += tmp;
+
+      if (tmp > max)
+        {
+          max = tmp;
+        }
 
-      adc_misc_data &= 0x1fff;
+      if (tmp < min)
+        {
+          min = tmp;
+        }
+
+      ainfo("data_buf[%d]=%u\n", i, tmp);
     }
 
-  return adc_misc_data;
+  /* Disable DFIFO 2 */
+
+  tlsr82_adc_dfifo_disable();
+
+  ainfo("sum=%lu, max=%u, min=%u, filt_num=%d\n",
+        sum, max, min, ADC_FILT_NUM);
+
+  /* Remove max, min value and get the average value */
+
+  tmp = (sum - min - max) / (ADC_FILT_NUM - 2);
+
+  return tmp;
 }
 
 /****************************************************************************
- * Name: adc_calibrate
+ * Name: tlsr82_adc_calibrate
  *
  * Description:
  *   ADC calibration.
@@ -545,85 +773,80 @@ static uint16_t adc_read(void)
  *
  ****************************************************************************/
 
-#if 0
-
-static void adc_calibrate(void)
+#ifdef CONFIG_TLSR82_ADC_CALI
+static void tlsr82_adc_calibrate(struct adc_chan_s *priv)
 {
-  uint16_t cali_val;
-  uint16_t adc;
-  uint16_t adc_max = 0;
-  uint16_t adc_min = UINT16_MAX;
-  uint32_t adc_sum = 0;
-  uint32_t regval;
+  uint8_t cali_data[7];
 
-  regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_VER_OFF, ADC_CAL_VER_LEN);
-  if (regval == 1)
-    {
-      ainfo("Calibrate based on efuse data\n");
-
-      regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_DATA_OFF,
-                          ADC_CAL_DATA_LEN);
-      cali_val = regval + ADC_CAL_DATA_COMP;
-    }
-  else
-    {
-      ainfo("Calibrate based on GND voltage\n");
+  uint32_t base_vref;
+  uint32_t vbat_vref;
 
-      /* Enable Vdef */
+  memset((void *)cali_data, 0, sizeof(cali_data));
+  tlsr82_flash_read_data(CONFIG_TLSR82_ADC_CALI_PARA_ADDR, cali_data,
+                         sizeof(cali_data));
 
-      rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
-                            I2C_ADC1_DEF, I2C_ADC1_DEF_MSB,
-                            I2C_ADC1_DEF_LSB, 1);
+  ainfo("Calibration data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+        cali_data[0], cali_data[1], cali_data[2], cali_data[3],
+        cali_data[4], cali_data[5], cali_data[6]);
 
-      /* Start sampling */
+  /* Calibration parameters format follow the telink sdk code */
 
-      adc_samplecfg(ADC_CAL_CHANNEL);
+  /* Base/gpio mode calibration parameters read */
 
-      /* Enable internal connect GND (for calibration). */
+  if (cali_data[4] <= 0x7f && cali_data[5] != 0xff &&
+      cali_data[6] != 0xff)
+    {
+      /* Two-point calibration exist, the base_vref as the gain to use
+       * Method of calculating two-point gpio calibration Flash_gain
+       * and Flash_offset:
+       * gain   = (data[6] << 8) + data[5] + 1000 mv
+       * offset = data[4] - 20 mv
+       */
 
-      rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
-                            I2C_ADC1_ENCAL_GND, I2C_ADC1_ENCAL_GND_MSB,
-                            I2C_ADC1_ENCAL_GND_LSB, 1);
+      priv->info->base_vref = (cali_data[6] << 8) + cali_data[5] + 1000;
+      priv->info->base_off  = (int)cali_data[4] - 20;
+      priv->info->base_two  = true;
+    }
+  else
+    {
+      /* One-point calibration exist
+       * Method of calculating calibration Flash_gpio_vref value:
+       * vref = 1175 + data[0] - 255 + data[1] mV
+       *      = 920 + data[0] + data[1] mV
+       */
 
-      for (int i = 1; i < ADC_CAL_CNT_MAX ; i++)
+      base_vref = 920 + cali_data[0] + cali_data[1];
+      if (base_vref >= 1047 && base_vref <= 1302)
         {
-          adc_set_calibration(0);
-          adc = adc_read();
-
-          adc_sum += adc;
-          adc_max  = MAX(adc, adc_max);
-          adc_min  = MIN(adc, adc_min);
+          priv->info->base_vref = base_vref;
         }
 
-      cali_val = (adc_sum - adc_max - adc_min) / (ADC_CAL_CNT_MAX - 2);
-
-      /* Disable internal connect GND (for calibration). */
-
-      rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
-                            I2C_ADC1_ENCAL_GND,
-                            I2C_ADC1_ENCAL_GND_MSB,
-                            I2C_ADC1_ENCAL_GND_LSB, 0);
+      priv->info->base_two = false;
     }
 
-  ainfo("calibration value: %" PRIu16 "\n", cali_val);
-
-  /* Set final calibration parameters */
+  /* Vbat mode calibration parameters read */
 
-  adc_set_calibration(cali_val);
-
-  /* Set calibration digital parameters */
-
-  regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_VOL_OFF, ADC_CAL_VOL_LEN);
-  if (regval & BIT(ADC_CAL_VOL_LEN - 1))
+  if (cali_data[2] != 0xff || cali_data[3] != 0xff)
     {
-      g_cal_digit = 2000 - (regval & ~(BIT(ADC_CAL_VOL_LEN - 1)));
-    }
-  else
-    {
-      g_cal_digit = 2000 + regval;
+      /* One-point calibration exist
+       * Method of calculating calibration Flash_vbat_vref value:
+       * vref = 1175 + data[2] - 255 + data[3] mV
+       *      = 920 + data[2] + data[3] mV
+       */
+
+      vbat_vref = 920 + cali_data[2] + cali_data[3];
+      if (vbat_vref >= 1047 && vbat_vref <= 1302)
+        {
+          priv->info->vbat_vref = vbat_vref;
+        }
     }
-}
 
+    ainfo("Calibration paramters:\n");
+    ainfo("  base two-point: gain=%d, offset=%d\n",
+          priv->info->base_vref, priv->info->base_off);
+    ainfo("  base one-point: vref=%lu\n", priv->info->base_vref);
+    ainfo("  vbat one-point: vref=%lu\n", priv->info->vbat_vref);
+}
 #endif
 
 /****************************************************************************
@@ -654,7 +877,9 @@ static void adc_read_work(struct adc_dev_s *dev)
       return;
     }
 
-  tlsr82_adc_chan_config(priv->pinset);
+  /* Config the adc */
+
+  tlsr82_adc_config(priv);
 
   /* Dump adc register for debug */
 
@@ -667,9 +892,27 @@ static void adc_read_work(struct adc_dev_s *dev)
    * negative input be gnd, so the actual adc resolution is 13bit.
    */
 
-  adc = (value * priv->info->vref * 8) >> 13;
+#ifdef CONFIG_TLSR82_ADC_VBAT
+  if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+    {
+      /* Vbat channel mode, divider = 1/3, scale = 1 ==> factor = 3 */
+
+      adc = (value * priv->info->vbat_vref * 3) >> 13;
+    }
+  else
+#endif
+    {
+      /* Base/gpio mode, divider = 1, scale = 1/8 ==> factor = 8 */
+
+      adc = (value * priv->info->base_vref * 8) >> 13;
+
+      if (priv->info->base_two)
+        {
+          adc += priv->info->base_off;
+        }
+    }
 
-  /* Calibration */
+  /* Put adc value to the adc buffer */
 
   priv->cb->au_receive(dev, priv->channel, adc);
 
@@ -793,11 +1036,18 @@ static int adc_setup(struct adc_dev_s *dev)
 
   tlsr82_adc_clk_ctrl(true);
 
-  /* Config ADC hardware (Calibration and gpio) */
+  /* Read the calibration parameters */
 
-  ainfo("pin: 0x%" PRIx32 "\n", priv->pinset);
+#ifdef CONFIG_TLSR82_ADC_CALI
+  tlsr82_adc_calibrate(priv);
+#endif
+
+  /* Config ADC hardware */
 
-  tlsr82_adc_config(priv->pinset);
+  ainfo("pin: 0x%" PRIx32 ", channel: %" PRIu8 "\n",
+        priv->pinset, priv->channel);
+
+  tlsr82_adc_config(priv);
 
   /* The ADC device is ready */
 
@@ -944,9 +1194,29 @@ int tlsr82_adc_init(const char *devpath, int miror)
 
   switch (miror)
     {
-      case 0:
+#ifdef CONFIG_TLSR82_ADC_CHAN0
+      case ADC_CHAN_0:
         dev = &g_adc_chan0_dev;
         break;
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN1
+      case ADC_CHAN_1:
+        dev = &g_adc_chan1_dev;
+        break;
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN2
+      case ADC_CHAN_2:
+        dev = &g_adc_chan2_dev;
+        break;
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_VBAT
+      case ADC_CHAN_VBAT:
+        dev = &g_adc_chanbat_dev;
+        break;
+#endif
 
       default:
         {
diff --git a/arch/arm/src/tlsr82/tlsr82_adc.h b/arch/arm/src/tlsr82/tlsr82_adc.h
index ea42fe60ad..d7dbafad63 100644
--- a/arch/arm/src/tlsr82/tlsr82_adc.h
+++ b/arch/arm/src/tlsr82/tlsr82_adc.h
@@ -29,6 +29,22 @@
 
 #include "hardware/tlsr82_adc.h"
 
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ADC_CHAN_0               0
+#define ADC_CHAN_1               1
+#define ADC_CHAN_2               2
+#define ADC_CHAN_3               3
+#define ADC_CHAN_4               4
+#define ADC_CHAN_5               5
+#define ADC_CHAN_6               6
+#define ADC_CHAN_7               7
+#define ADC_CHAN_TEMP            253
+#define ADC_CHAN_VBAT            254
+#define ADC_CHAN_NONE            255
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
diff --git a/arch/arm/src/tlsr82/tlsr82_timer.h b/arch/arm/src/tlsr82/tlsr82_timer.h
index 6bd50649e3..3fe0f87b22 100644
--- a/arch/arm/src/tlsr82/tlsr82_timer.h
+++ b/arch/arm/src/tlsr82/tlsr82_timer.h
@@ -120,6 +120,20 @@ struct tlsr82_timer_ops_s
   int  (*checkint)(struct tlsr82_timer_dev_s *dev);
 };
 
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+static inline uint32_t tlsr82_time(void)
+{
+  return SYSTIMER_TICK_REG;
+}
+
+static inline bool tlsr82_time_exceed(uint32_t start, uint32_t us)
+{
+  return ((uint32_t)(tlsr82_time() - start) > us * 16);
+}
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
diff --git a/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c b/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c
index f74afe662c..10e3c4b5e4 100644
--- a/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c
+++ b/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c
@@ -134,7 +134,9 @@ int tlsr8278_bringup(void)
 #endif /* CONFIG_TLSR82_PWM */
 
 #ifdef CONFIG_TLSR82_ADC
-  ret = tlsr82_adc_init("/dev/adc0", 0);
+
+#ifdef CONFIG_TLSR82_ADC_CHAN0
+  ret = tlsr82_adc_init("/dev/adc0", ADC_CHAN_0);
   if (ret < 0)
     {
       syslog(LOG_ERR,
@@ -142,6 +144,41 @@ int tlsr8278_bringup(void)
              ret);
       return ret;
     }
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN1
+  ret = tlsr82_adc_init("/dev/adc1", ADC_CHAN_1);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to initialize adc1 driver: %d\n",
+             ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN2
+  ret = tlsr82_adc_init("/dev/adc2", ADC_CHAN_2);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to initialize adc2 driver: %d\n",
+             ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_VBAT
+  ret = tlsr82_adc_init("/dev/adcvbat", ADC_CHAN_VBAT);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to initialize adcbat driver: %d\n",
+             ret);
+      return ret;
+    }
+#endif
+
 #endif /* CONFIG_TLSR82_ADC */
 
 #ifdef CONFIG_TLSR82_FLASH