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

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

commit bed51ede9bc0e423ccb931a7943874812398a9d0
Author: dechao_gong <[email protected]>
AuthorDate: Thu Oct 22 10:03:37 2026 +0800

    arch/arm/rtl8730e: add CA32 ADC driver on /dev/adc0
    
    Wire the shared Ameba ADC driver up on the AmebaSmart CA32 and register
    the converter at /dev/adc0.  The chip has ten channels, of which CH0-CH5
    are external and bound to the fixed pads PA0-PA5.  PA0 and PA1 are not
    bonded out on the RTL8730EAM/EAH packages, so the board lists CH2-CH5.
    
    Chip specifics go in ameba_adc_chip.h, as for the other Ameba chips:
    
      - The pads reach the converter through the cap-touch function (pinmux
        function 18), and the CTC clock is gated together with the ADC one.
      - ADC_Read() keeps only the low 16 bits of the global data register
        here, so the channel id is in [15:12] and the 12-bit sample in
        [11:0].  The shared driver defaults assume [19:16] and 16 bits, so
        let a chip header override AMEBA_ADC_GET_CHNO and AMEBA_ADC_GET_DATA.
      - PAD_InputCtrl() is a header-only inline in the SDK on this chip, so
        the ROM has no symbol for it.  Let a chip header supply its own via
        AMEBA_ADC_PAD_INPUTCTRL.
    
    ADC_Init() reads the vref calibration byte from the OTP, which needs two
    more things the port did not have:
    
      - SYSCFG_RLVersion(), which IPC_SEMTake()/IPC_SEMFree() use to pick
        their semaphore register layout.  The SDK only ships it inside an
        object that cannot be linked alone, so mirror its logic.
      - DelayUs().  The ROM version busy-waits with DelayNop() and only
        knows the LP and NP cores.  On the CA32 (CPUID 2) the
        RBSS_UDELAY_FLAG == 0 fallback indexes its Clk[]/Div[] tables out of
        bounds, so the divisor is stack garbage.  OTP_Read8() polls with
        DelayUs(5), and the first ADC_Init() spun for between 11 and 33
        seconds, delaying the NSH prompt by as much after every reset.  Use
        up_udelay() instead, which is bounded by CONFIG_BOARD_LOOPSPERMSEC.
    
    Signed-off-by: dechao_gong <[email protected]>
    Assisted-by: Claude <[email protected]>
---
 arch/arm/include/rtl8730e/irq.h                    |   1 +
 arch/arm/src/common/ameba/ameba_adc.c              |  27 ++++-
 arch/arm/src/rtl8730e/CMakeLists.txt               |  37 +++++-
 arch/arm/src/rtl8730e/Make.defs                    |   8 +-
 arch/arm/src/rtl8730e/ameba_adc_chip.h             | 124 +++++++++++++++++++++
 arch/arm/src/rtl8730e/ameba_board.mk               |  14 ++-
 arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c       |  43 +++++++
 .../rtl8730e/rtl8730e_evb/configs/adc/defconfig    |  64 +++++++++++
 boards/arm/rtl8730e/rtl8730e_evb/scripts/Make.defs |   2 +-
 .../arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt   |   6 +
 boards/arm/rtl8730e/rtl8730e_evb/src/Makefile      |   6 +-
 .../src/{rtl8730e_evb.h => rtl8730e_adc.c}         | 100 +++++++++--------
 .../rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c   |  11 ++
 .../arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h   |   4 +
 14 files changed, 384 insertions(+), 63 deletions(-)

diff --git a/arch/arm/include/rtl8730e/irq.h b/arch/arm/include/rtl8730e/irq.h
index 00c639e181e..d0132e46a36 100644
--- a/arch/arm/include/rtl8730e/irq.h
+++ b/arch/arm/include/rtl8730e/irq.h
@@ -43,6 +43,7 @@
 
 #define RTL8730E_IRQ_TIMER2     34   /* GIC SPI 2:  TIM2 (LP basic timer) */
 #define RTL8730E_IRQ_TIMER3     35   /* GIC SPI 3:  TIM3 (LP basic timer) */
+#define RTL8730E_IRQ_ADC        46   /* GIC SPI 14: ADC */
 #define RTL8730E_IRQ_IPC_AP     56   /* GIC SPI 24: CA32 AP-IPC (WHC WiFi) */
 #define RTL8730E_IRQ_UART0      82   /* GIC SPI 50: UART0 */
 #define RTL8730E_IRQ_UART1      83   /* GIC SPI 51: UART1 */
diff --git a/arch/arm/src/common/ameba/ameba_adc.c 
b/arch/arm/src/common/ameba/ameba_adc.c
index 9ba17598e26..c3cf08b52cf 100644
--- a/arch/arm/src/common/ameba/ameba_adc.c
+++ b/arch/arm/src/common/ameba/ameba_adc.c
@@ -92,10 +92,19 @@
 #define AMEBA_ADC_CLKDIV_24         0x3  /* ADC_CLK_DIV_24      */
 #define AMEBA_PAD_NOPULL            0x0  /* GPIO_PuPd_NOPULL    */
 
-/* 16-bit conversion word layout: channel id in [19:16], data in [15:0]. */
+/* Conversion word layout as returned by ADC_Read(): channel id in [19:16],
+ * data in [15:0] on most chips.  A chip whose ADC_ID_AND_DATA() keeps fewer
+ * bits (amebasmart: id in [15:12], data in [11:0]) overrides both macros in
+ * its ameba_adc_chip.h.
+ */
 
-#define AMEBA_ADC_GET_CHNO(x)       (((x) >> 16) & 0x0f)
-#define AMEBA_ADC_GET_DATA(x)       ((x) & 0xffff)
+#ifndef AMEBA_ADC_GET_CHNO
+#  define AMEBA_ADC_GET_CHNO(x)     (((x) >> 16) & 0x0f)
+#endif
+
+#ifndef AMEBA_ADC_GET_DATA
+#  define AMEBA_ADC_GET_DATA(x)     ((x) & 0xffff)
+#endif
 
 /****************************************************************************
  * Private Types
@@ -188,7 +197,17 @@ extern void RCC_PeriphClockCmd(uint32_t periph, uint32_t 
clock,
 extern void Pinmux_Config(uint8_t pin, uint32_t func);
 extern void PAD_PullCtrl(uint8_t pin, uint8_t pulltype);
 extern void PAD_SleepPullCtrl(uint8_t pin, uint8_t pulltype);
+
+/* PAD_InputCtrl() is a ROM function on some chips and a header-only inline
+ * on others (amebasmart), so a chip that has no linkable symbol defines
+ * AMEBA_ADC_PAD_INPUTCTRL in its ameba_adc_chip.h to supply its own.
+ */
+
+#ifndef AMEBA_ADC_PAD_INPUTCTRL
 extern void PAD_InputCtrl(uint8_t pin, uint32_t newstate);
+#  define AMEBA_ADC_PAD_INPUTCTRL(pin, state) PAD_InputCtrl(pin, state)
+#endif
+
 extern void ADC_StructInit(struct ameba_adc_init_s *init);
 extern void ADC_Init(struct ameba_adc_init_s *init);
 extern void ADC_Cmd(uint32_t newstate);
@@ -477,7 +496,7 @@ int ameba_adc_register(const char *path, const uint8_t 
*channels,
           Pinmux_Config(pins[i], AMEBA_ADC_PINMUX_FID);
           PAD_PullCtrl(pins[i], AMEBA_PAD_NOPULL);
           PAD_SleepPullCtrl(pins[i], AMEBA_PAD_NOPULL);
-          PAD_InputCtrl(pins[i], AMEBA_DISABLE);
+          AMEBA_ADC_PAD_INPUTCTRL(pins[i], AMEBA_DISABLE);
         }
     }
 
diff --git a/arch/arm/src/rtl8730e/CMakeLists.txt 
b/arch/arm/src/rtl8730e/CMakeLists.txt
index 61723ef22b6..e4cbade7b2f 100644
--- a/arch/arm/src/rtl8730e/CMakeLists.txt
+++ b/arch/arm/src/rtl8730e/CMakeLists.txt
@@ -130,6 +130,20 @@ if(CONFIG_AMEBA_WDG)
   endif()
 endif()
 
+if(CONFIG_AMEBA_ADC)
+  list(APPEND SRCS ${AMEBA_COMMON}/ameba_adc.c)
+  if(NOT CONFIG_RTL8730E_FLASH_FS
+     AND NOT CONFIG_AMEBA_GPIO
+     AND NOT CONFIG_AMEBA_UART
+     AND NOT CONFIG_AMEBA_I2C
+     AND NOT CONFIG_AMEBA_SPI
+     AND NOT CONFIG_AMEBA_PWM
+     AND NOT CONFIG_AMEBA_TIMER
+     AND NOT CONFIG_AMEBA_WDG)
+    list(APPEND SRCS rtl8730e_flash_stubs.c)
+  endif()
+endif()
+
 target_include_directories(arch PRIVATE ${AMEBA_COMMON})
 target_sources(arch PRIVATE ${SRCS})
 
@@ -215,14 +229,18 @@ if(CONFIG_RTL8730E_FLASH_FS
    OR CONFIG_AMEBA_I2C
    OR CONFIG_AMEBA_SPI
    OR CONFIG_AMEBA_PWM
-   OR CONFIG_AMEBA_TIMER)
+   OR CONFIG_AMEBA_TIMER
+   OR CONFIG_AMEBA_ADC)
   set(AMEBA_FWLIB_SRCS
       ${AMEBA_SOC}/fwlib/ram_common/ameba_arch.c ${AMEBA_SOC}/swlib/log.c
       ${AMEBA_SOC}/swlib/sscanf_minimal.c)
 
-  # IPC layer is needed by both WiFi (WHC) and Flash FS (write-lock protocol).
-  # Include it once regardless of which feature(s) are enabled.
-  if(CONFIG_RTL8730E_FLASH_FS OR CONFIG_RTL8730E_WIFI)
+  # IPC layer is needed by WiFi (WHC), Flash FS (write-lock protocol) and the
+  # ADC (OTP reads take the cross-core IPC_SEM_OTP semaphore).  Include it once
+  # regardless of which feature(s) are enabled.
+  if(CONFIG_RTL8730E_FLASH_FS
+     OR CONFIG_RTL8730E_WIFI
+     OR CONFIG_AMEBA_ADC)
     list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_ipc_api.c
          ${AMEBA_SOC}/fwlib/ram_common/ameba_ipc_ram.c)
   endif()
@@ -251,6 +269,13 @@ if(CONFIG_RTL8730E_FLASH_FS
     list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_tim.c)
   endif()
 
+  # The AP ROM has no ADC; the whole fwlib ADC layer is RAM-side, and it reads
+  # its calibration data through OTP_Read8() from ameba_otp.c.
+  if(CONFIG_AMEBA_ADC)
+    list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_adc.c
+         ${AMEBA_SOC}/fwlib/ram_common/ameba_otp.c)
+  endif()
+
   # Silence SDK warnings, activate CA32 code paths.  No -mcmse (ARMv7-A).
   set(AMEBA_FWLIB_INC
       -Wno-int-conversion
@@ -293,6 +318,7 @@ if(CONFIG_AMEBA_GPIO
    OR CONFIG_AMEBA_PWM
    OR CONFIG_AMEBA_TIMER
    OR CONFIG_AMEBA_WDG
+   OR CONFIG_AMEBA_ADC
    OR CONFIG_RTL8730E_FLASH_FS)
   list(APPEND AMEBA_EXTRA_LIBS
        ${AMEBA_SOC}/project/${AMEBA_KM_PROJ}/lib/soc/lib_rom.a)
@@ -304,7 +330,8 @@ if(CONFIG_RTL8730E_FLASH_FS
    OR CONFIG_AMEBA_I2C
    OR CONFIG_AMEBA_SPI
    OR CONFIG_AMEBA_PWM
-   OR CONFIG_AMEBA_TIMER)
+   OR CONFIG_AMEBA_TIMER
+   OR CONFIG_AMEBA_ADC)
   list(APPEND AMEBA_EXTRA_LIBS ${AMEBA_FWLIB_A})
 endif()
 
diff --git a/arch/arm/src/rtl8730e/Make.defs b/arch/arm/src/rtl8730e/Make.defs
index c7d6353dbbd..aef5babb761 100644
--- a/arch/arm/src/rtl8730e/Make.defs
+++ b/arch/arm/src/rtl8730e/Make.defs
@@ -65,7 +65,7 @@ AMEBA_AP_SOC_LIB = 
$(TOPDIR)/arch/arm/src/common/ameba/ameba-rtos/component/soc/
 # rtl8730e_flash_stubs.c supplies the RAM-side symbols that lib_rom.a objects
 # expect (DiagPrintfNano, irq_enable, Pinmux_Config, etc.).  Compile them once
 # whenever any driver needing ROM is enabled.
-ifneq ($(filter y,$(CONFIG_AMEBA_GPIO) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_AMEBA_SPI) $(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER) $(CONFIG_AMEBA_WDG) $(CONFIG_RTL8730E_FLASH_FS)),)
+ifneq ($(filter y,$(CONFIG_AMEBA_GPIO) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_AMEBA_SPI) $(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER) $(CONFIG_AMEBA_WDG) $(CONFIG_AMEBA_ADC) 
$(CONFIG_RTL8730E_FLASH_FS)),)
 CHIP_CSRCS += rtl8730e_flash_stubs.c
 EXTRA_LIBS += $(AMEBA_AP_SOC_LIB)$(DELIM)lib_rom.a
 
@@ -99,6 +99,10 @@ ifeq ($(CONFIG_AMEBA_WDG),y)
 CHIP_CSRCS += ameba_wdg.c
 endif
 
+ifeq ($(CONFIG_AMEBA_ADC),y)
+CHIP_CSRCS += ameba_adc.c
+endif
+
 # WiFi (WHC host, CA32 side).
 ifeq ($(CONFIG_RTL8730E_WIFI),y)
 CHIP_CSRCS += rtl8730e_wifi_init.c
@@ -129,7 +133,7 @@ endif
 
 # fwlib archive is needed whenever any driver uses RAM-side SDK tables
 # (flash MTD, UART, I2C, ...).  Link it once for all such configs.
-ifneq ($(filter y,$(CONFIG_RTL8730E_FLASH_FS) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_AMEBA_SPI) $(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER)),)
+ifneq ($(filter y,$(CONFIG_RTL8730E_FLASH_FS) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_AMEBA_SPI) $(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER) $(CONFIG_AMEBA_ADC)),)
 
 # Prebuilt staging area (within the board tree, gitignored).
 AMEBA_PREBUILT      = $(BOARD_DIR)$(DELIM)prebuilt
diff --git a/arch/arm/src/rtl8730e/ameba_adc_chip.h 
b/arch/arm/src/rtl8730e/ameba_adc_chip.h
new file mode 100644
index 00000000000..19a745fbfbd
--- /dev/null
+++ b/arch/arm/src/rtl8730e/ameba_adc_chip.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * arch/arm/src/rtl8730e/ameba_adc_chip.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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_RTL8730E_AMEBA_ADC_CHIP_H
+#define __ARCH_ARM_SRC_RTL8730E_AMEBA_ADC_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Per-chip ADC wiring for RTL8730E (AmebaSmart, Cortex-A32), read out of the
+ * SoC ameba_adc.h, sysreg_lsys.h, ameba_pinmux.h and the CA32 section of
+ * ameba_vector_table.h.  The shared driver
+ * (arch/arm/src/common/ameba/ameba_adc.c) drives the converter through the
+ * SDK fwlib API, so no register base appears here.
+ *
+ * Channels: ADC_CH_NUM is 10.  CH0..CH5 are external and bound to fixed pads
+ * PA0..PA5 (ADC_CHx_PIN); the remaining channels are internal and have no
+ * pad.  On the RTL8730EAM/EAH packages PA0 and PA1 are not bonded out, so
+ * only CH2..CH5 (PA2..PA5) are usable there.
+ *
+ * Pad mux: the pads reach the ADC through the cap-touch function
+ * (PINMUX_FUNCTION_CAPTOUCH, FUNC_ID18, "TOUCHn_ADCn" in the pinmux table).
+ * PINMUX_FUNCTION_AUXIN is 16 here, which is FUNC_ID16 = SPK, so it must
+ * not be used.  The ADC and the cap-touch controller share these pads, and
+ * the SDK enables the cap-touch (CTC) clock together with the ADC clock, so
+ * AMEBA_ADC_AUXCLK_* gate APBPeriph_CTC as well.
+ *
+ * Conversion word: ADC_Read() keeps only the low 16 bits of the global data
+ * register on this chip, so the channel id is in [15:12] and the 12-bit
+ * sample in [11:0].  Other chips keep 20 bits (id in [19:16]); the shared
+ * driver's defaults assume that, hence the overrides below.
+ */
+
+#define AMEBA_ADC_NCHAN           10    /* ADC_CH_NUM: CH0..CH5 ext pads       
*/
+#define AMEBA_ADC_MAXLIST         16    /* Channel-switch list depth (Cvlist)  
*/
+#define AMEBA_ADC_PINMUX_FID      18    /* PINMUX_FUNCTION_CAPTOUCH            
 */
+#define AMEBA_ADC_IRQ             46    /* ADC_IRQ (unused by this polling 
drv) */
+
+/* sizeof(fwlib ADC_InitTypeDef): OpMode/CvlistLen/Cvlist[16]/ClkDiv/
+ * RxThresholdLevel/SpecialCh (21 bytes), ChanInType (u32, 4-aligned at 24),
+ * ChIDEn -> 32 bytes.
+ */
+
+#define AMEBA_ADC_INIT_SIZE       32
+
+/* APBPeriph_ADC / APBPeriph_ADC_CLOCK: bit 20 / bit 15 of the LSYS block,
+ * with the bit30 group selector clear.  APBPeriph_CTC / _CTC_CLOCK are bit
+ * 21 / bit 14.
+ */
+
+#define AMEBA_ADC_APBPERIPH       ((uint32_t)1 << 20)
+#define AMEBA_ADC_APBPERIPH_CLK   ((uint32_t)1 << 15)
+#define AMEBA_ADC_AUXCLK_PERIPH   ((uint32_t)1 << 21)
+#define AMEBA_ADC_AUXCLK_CLK      ((uint32_t)1 << 14)
+
+/* ADC_InitTypeDef has a ClkDiv field at offset 18 on this chip. */
+
+#define AMEBA_ADC_HAS_CLKDIV      1
+
+/* Conversion word layout, see above. */
+
+#define AMEBA_ADC_GET_CHNO(x)     (((x) >> 12) & 0x0f)
+#define AMEBA_ADC_GET_DATA(x)     ((x) & 0x0fff)
+
+/* PAD_InputCtrl() is a header-only inline in the SDK on this chip, so the
+ * ROM has no symbol for it.  It gates the digital input path of the ADC/CTC
+ * pads (PA0..PA8) with one bit per pad in REG_LSYS_DUMMY_094 of the LSYS
+ * block (SYSTEM_CTRL_BASE for the CA32 is 0x42008000, offset 0x2f8).
+ */
+
+#define RTL8730E_ADC_PADIN_REG    0x420082f8
+#define RTL8730E_ADC_PADIN_MAXPAD 8     /* _PA_8 */
+
+static inline void rtl8730e_adc_padinput(uint8_t pin, uint32_t enable)
+{
+  volatile uint32_t *reg = (volatile uint32_t *)RTL8730E_ADC_PADIN_REG;
+
+  if (pin > RTL8730E_ADC_PADIN_MAXPAD)
+    {
+      return;
+    }
+
+  if (enable)
+    {
+      *reg |= (uint32_t)1 << pin;
+    }
+  else
+    {
+      *reg &= ~((uint32_t)1 << pin);
+    }
+}
+
+#define AMEBA_ADC_PAD_INPUTCTRL(pin, state) \
+  rtl8730e_adc_padinput(pin, state)
+
+#endif /* __ARCH_ARM_SRC_RTL8730E_AMEBA_ADC_CHIP_H */
diff --git a/arch/arm/src/rtl8730e/ameba_board.mk 
b/arch/arm/src/rtl8730e/ameba_board.mk
index dcd4b0fbcdd..bc461d4c02d 100644
--- a/arch/arm/src/rtl8730e/ameba_board.mk
+++ b/arch/arm/src/rtl8730e/ameba_board.mk
@@ -54,9 +54,10 @@ AMEBA_FWLIB_SRCS = 
$(AMEBA_SOC)/fwlib/ram_common/ameba_arch.c \
                    $(AMEBA_SOC)/swlib/log.c \
                    $(AMEBA_SOC)/swlib/sscanf_minimal.c
 
-# IPC layer is needed by both WiFi (WHC) and Flash FS (write-lock protocol).
-# Include it once regardless of which feature(s) are enabled.
-ifneq ($(filter y,$(CONFIG_RTL8730E_WIFI) $(CONFIG_RTL8730E_FLASH_FS)),)
+# IPC layer is needed by WiFi (WHC), Flash FS (write-lock protocol) and the
+# ADC (OTP reads take the cross-core IPC_SEM_OTP semaphore).  Include it
+# once regardless of which feature(s) are enabled.
+ifneq ($(filter y,$(CONFIG_RTL8730E_WIFI) $(CONFIG_RTL8730E_FLASH_FS) 
$(CONFIG_AMEBA_ADC)),)
 AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_ipc_api.c \
                     $(AMEBA_SOC)/fwlib/ram_common/ameba_ipc_ram.c
 endif
@@ -97,6 +98,13 @@ ifneq ($(filter y,$(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER)),)
 AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_tim.c
 endif
 
+# The AP ROM has no ADC; the whole fwlib ADC layer is RAM-side, and it
+# reads its calibration data through OTP_Read8() from ameba_otp.c.
+ifeq ($(CONFIG_AMEBA_ADC),y)
+AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_adc.c
+AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_otp.c
+endif
+
 # Include paths scoped to the fwlib compile only (never leaked to NuttX core).
 # -DCONFIG_ARM_CORE_CA32 activates the CA32 code paths in ameba_flash_ram.c.
 # No -mcmse (that is Cortex-M33 TrustZone; CA32 is ARMv7-A non-secure EL1).
diff --git a/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c 
b/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c
index dd9083673f6..47399fc8869 100644
--- a/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c
+++ b/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c
@@ -349,6 +349,49 @@ void Pinmux_Config(uint32_t pinname, uint32_t pinfunc)
   _Pinmux_Config(pinname, pinfunc);
 }
 
+/* DelayUs: the ROM version busy-waits with DelayNop() and only knows the LP
+ * (CPUID 0) and NP (CPUID 1) cores.  On the CA32 (CPUID 2) the
+ * RBSS_UDELAY_FLAG == 0 fallback indexes its Clk[]/Div[] tables out of
+ * bounds, so the divisor is stack garbage and a DelayUs(5) can spin for
+ * ~38 billion iterations.  OTP_Read8() polls with DelayUs(5), so the first
+ * ADC_Init() (vref calibration read) stalled boot for ~33 seconds.  Use the
+ * NuttX delay instead, which is bounded by CONFIG_BOARD_LOOPSPERMSEC.
+ */
+
+void DelayUs(uint32_t us)
+{
+  up_udelay(us);
+}
+
+/* SYSCFG_RLVersion: silicon cut (A=0, B=1, C=2, D=3).  The SDK only ships
+ * it inside lib_chipinfo.a's ameba_rom_patch.o, which also carries dozens of
+ * unrelated functions and cannot be linked in alone, so mirror its logic: a
+ * select code 0xa written to [31:28] of LSYS REG_LSYS_SCAN_CTRL (0x274)
+ * exposes the cut in [19:16] on readback; the register is then restored.
+ * The result is cached, as in the original.  IPC_SEMTake()/IPC_SEMFree()
+ * (OTP reads) pick their semaphore register layout from this value.
+ */
+
+uint32_t SYSCFG_RLVersion(void)
+{
+  static uint8_t cut = 0xff;
+
+  if (cut == 0xff)
+    {
+      volatile uint32_t *reg = (volatile uint32_t *)0x42008274u;
+      uint32_t base = *reg & ~0xf0000000u;
+      uint32_t val;
+
+      *reg = base | 0xa0000000u;
+      val  = *reg;
+      *reg = base;
+
+      cut = (val >> 16) & 0xf;
+    }
+
+  return cut;
+}
+
 /****************************************************************************
  * Name: rtl8730e_flash_init_para
  *
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/configs/adc/defconfig 
b/boards/arm/rtl8730e/rtl8730e_evb/configs/adc/defconfig
new file mode 100644
index 00000000000..6fa0ab80ecd
--- /dev/null
+++ b/boards/arm/rtl8730e/rtl8730e_evb/configs/adc/defconfig
@@ -0,0 +1,64 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_NSH_DISABLE_MB is not set
+# CONFIG_NSH_DISABLE_MH is not set
+# CONFIG_NSH_DISABLE_MW is not set
+CONFIG_ALARM_ARCH=y
+CONFIG_AMEBA_ADC=y
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="rtl8730e_evb"
+CONFIG_ARCH_BOARD_RTL8730E_EVB=y
+CONFIG_ARCH_CHIP="rtl8730e"
+CONFIG_ARCH_CHIP_RTL8730E=y
+CONFIG_ARCH_CHIP_RTL8730E_CA32=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_LOWVECTORS=y
+CONFIG_ARM_PSCI=y
+CONFIG_BOARD_LOOPSPERMSEC=393693
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEFAULT_TASK_STACKSIZE=4096
+CONFIG_EXAMPLES_ADC=y
+CONFIG_EXAMPLES_ADC_NSAMPLES=1
+CONFIG_EXAMPLES_ADC_SWTRIG=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FLASH_SIZE=1048576
+CONFIG_FLASH_START=0x60300000
+CONFIG_FLASH_VSTART=0x60300000
+CONFIG_FS_PROCFS=y
+CONFIG_FS_TMPFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=4096
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_LIBC_MEMFD_ERROR=y
+CONFIG_MM_DEFAULT_ALIGNMENT=64
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_PRIORITY_INHERITANCE=y
+CONFIG_RAM_SIZE=3145728
+CONFIG_RAM_START=0x60400000
+CONFIG_RAM_VSTART=0x60400000
+CONFIG_RAW_BINARY=y
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=192
+CONFIG_SMP=y
+CONFIG_SMP_NCPUS=2
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=25
+CONFIG_START_MONTH=4
+CONFIG_START_YEAR=2023
+CONFIG_SYSTEM_NSH=y
+CONFIG_USEC_PER_TICK=1000
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/scripts/Make.defs 
b/boards/arm/rtl8730e/rtl8730e_evb/scripts/Make.defs
index cd0e93042c0..88090db7424 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/scripts/Make.defs
+++ b/boards/arm/rtl8730e/rtl8730e_evb/scripts/Make.defs
@@ -62,7 +62,7 @@ include 
$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)rtl8730e$(DELIM)ameba
 # lib_rom.a and the RTK toolchain's libgcc.a are compiled without VFP ABI
 # flags; suppress the harmless mismatch so the linker does not abort on it
 # whenever libameba_fwlib.a is in the link (GPIO, WiFi, or flash-FS config).
-ifneq ($(filter y,$(CONFIG_AMEBA_GPIO) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_AMEBA_SPI) $(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER) $(CONFIG_AMEBA_WDG) $(CONFIG_RTL8730E_WIFI) 
$(CONFIG_RTL8730E_FLASH_FS)),)
+ifneq ($(filter y,$(CONFIG_AMEBA_GPIO) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_AMEBA_SPI) $(CONFIG_AMEBA_PWM) 
$(CONFIG_AMEBA_TIMER) $(CONFIG_AMEBA_WDG) $(CONFIG_AMEBA_ADC) 
$(CONFIG_RTL8730E_WIFI) $(CONFIG_RTL8730E_FLASH_FS)),)
 LDFLAGS += --no-warn-mismatch
 endif
 
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt 
b/boards/arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt
index 4eaf77767f5..1bdd8a58a35 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt
@@ -63,6 +63,12 @@ if(CONFIG_AMEBA_WDG)
                              PRIVATE ${NUTTX_DIR}/arch/arm/src/common/ameba)
 endif()
 
+if(CONFIG_AMEBA_ADC)
+  list(APPEND SRCS rtl8730e_adc.c)
+  target_include_directories(board
+                             PRIVATE ${NUTTX_DIR}/arch/arm/src/common/ameba)
+endif()
+
 if(CONFIG_LIBC_FDT)
   target_include_directories(board
                              PRIVATE ${NUTTX_DIR}/libs/libc/fdt/dtc/libfdt)
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/Makefile 
b/boards/arm/rtl8730e/rtl8730e_evb/src/Makefile
index b6b8cc8cc54..619b895ea93 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/Makefile
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/Makefile
@@ -34,7 +34,7 @@ ifeq ($(CONFIG_LIBC_FDT),y)
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)fdt$(DELIM)dtc$(DELIM)libfdt
 endif
 
-ifneq 
($(CONFIG_RTL8730E_FLASH_FS)$(CONFIG_AMEBA_GPIO)$(CONFIG_AMEBA_UART)$(CONFIG_AMEBA_I2C)$(CONFIG_AMEBA_SPI)$(CONFIG_AMEBA_PWM)$(CONFIG_AMEBA_TIMER)$(CONFIG_AMEBA_WDG),)
+ifneq 
($(CONFIG_RTL8730E_FLASH_FS)$(CONFIG_AMEBA_GPIO)$(CONFIG_AMEBA_UART)$(CONFIG_AMEBA_I2C)$(CONFIG_AMEBA_SPI)$(CONFIG_AMEBA_PWM)$(CONFIG_AMEBA_TIMER)$(CONFIG_AMEBA_WDG)$(CONFIG_AMEBA_ADC),)
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
 endif
 
@@ -66,4 +66,8 @@ ifeq ($(CONFIG_AMEBA_WDG),y)
 CSRCS += rtl8730e_wdg.c
 endif
 
+ifeq ($(CONFIG_AMEBA_ADC),y)
+CSRCS += rtl8730e_adc.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h 
b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_adc.c
similarity index 51%
copy from boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
copy to boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_adc.c
index 28de502f7cc..960b166431c 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_adc.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
+ * boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_adc.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,70 +20,76 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM_RTL8730E_RTL8730E_EVB_SRC_RTL8730E_EVB_H
-#define __BOARDS_ARM_RTL8730E_RTL8730E_EVB_SRC_RTL8730E_EVB_H
-
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
 
-#include <stdint.h>
+#include <sys/param.h>
+#include <syslog.h>
+#include <errno.h>
 
-/****************************************************************************
- * Public Types
- ****************************************************************************/
+#include "ameba_gpio.h"
+#include "ameba_adc.h"
+#include "rtl8730e_evb.h"
 
 /****************************************************************************
- * Public Data
+ * Private Data
  ****************************************************************************/
 
-#ifndef __ASSEMBLY__
+/* Channels sampled on /dev/adc0 and the analog pad each is wired to.  The
+ * external channels CH0..CH5 are bound to the fixed pads PA0..PA5 (the chip
+ * pin-mux table names them TOUCHn_ADCn).  PA0 and PA1 are not bonded out on
+ * the RTL8730EAM/EAH packages, so this board lists CH2..CH5 only; the same
+ * four are present on every package.
+ *
+ * PA3/PA4 are also I2C1 pads and PA4/PA5 are UART1 or PWM pads, so a config
+ * registering those too must drop the clashing channel here.  The pads are
+ * shared with the cap-touch controller and the DMIC, which this port does
+ * not use.
+ */
+
+static const uint8_t g_adc_channels[] =
+{
+  2,                 /* ADC_CH2 */
+  3,                 /* ADC_CH3 */
+  4,                 /* ADC_CH4 */
+  5,                 /* ADC_CH5 */
+};
+
+static const uint8_t g_adc_pins[] =
+{
+  AMEBA_PA(2),       /* CH2 -> PA2 */
+  AMEBA_PA(3),       /* CH3 -> PA3 */
+  AMEBA_PA(4),       /* CH4 -> PA4 */
+  AMEBA_PA(5),       /* CH5 -> PA5 */
+};
 
 /****************************************************************************
- * Public Functions Definitions
+ * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: rtl8730e_bringup
+ * Name: rtl8730e_adc_initialize
  *
  * Description:
- *   Bring up board features
+ *   Register the board's ADC channels at /dev/adc0.
  *
  ****************************************************************************/
 
-#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE)
-int rtl8730e_bringup(void);
-#endif
-
-#ifdef CONFIG_AMEBA_GPIO
-int rtl8730e_gpio_initialize(void);
-#endif
-
-#ifdef CONFIG_AMEBA_UART
-int rtl8730e_uart_initialize(void);
-#endif
-
-#ifdef CONFIG_AMEBA_I2C
-int rtl8730e_i2c_initialize(void);
-#endif
-
-#ifdef CONFIG_AMEBA_SPI
-int rtl8730e_spi_initialize(void);
-#endif
-
-#ifdef CONFIG_AMEBA_PWM
-int rtl8730e_pwm_initialize(void);
-#endif
-
-#ifdef CONFIG_AMEBA_TIMER
-int rtl8730e_timer_initialize(void);
-#endif
-
-#ifdef CONFIG_AMEBA_WDG
-int rtl8730e_wdg_initialize(void);
-#endif
-
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_RTL8730E_RTL8730E_EVB_SRC_RTL8730E_EVB_H */
+int rtl8730e_adc_initialize(void)
+{
+  int ret;
+
+  ret = ameba_adc_register("/dev/adc0", g_adc_channels, g_adc_pins,
+                           nitems(g_adc_channels));
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: ameba_adc_register(/dev/adc0) failed: %d\n", ret);
+      return ret;
+    }
+
+  return OK;
+}
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c 
b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c
index 49d9dac6d74..72e0fa0805a 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c
@@ -315,6 +315,17 @@ int rtl8730e_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_AMEBA_ADC
+  /* Register the board's ADC channels at /dev/adc0. */
+
+  ret = rtl8730e_adc_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to initialize ADC: %d\n", ret);
+    }
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h 
b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
index 28de502f7cc..a6b84bf8839 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
@@ -85,5 +85,9 @@ int rtl8730e_timer_initialize(void);
 int rtl8730e_wdg_initialize(void);
 #endif
 
+#ifdef CONFIG_AMEBA_ADC
+int rtl8730e_adc_initialize(void);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_ARM_RTL8730E_RTL8730E_EVB_SRC_RTL8730E_EVB_H */

Reply via email to