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 4e6ad4fb56c32136c277992726ee09b3ad2584ae
Author: dechao_gong <[email protected]>
AuthorDate: Thu Oct 8 13:44:44 2026 +0800

    arch/arm/rtl8730e: add I2C master driver support
    
    Expose the RTL8730E I2C controllers through the shared Ameba I2C driver
    (arch/arm/src/common/ameba/ameba_i2c.c) by adding the chip-specific
    glue, build wiring and a board bus table.  The change is gated by
    CONFIG_AMEBA_I2C (default disabled).
    
    Chip glue (ameba_i2c_chip.h) supplies the three controller register
    bases, the APB function/clock masks -- amebasmart encodes these in
    bit 25/26/27 with the group selector bit30=0, unlike the (bit30 |
    bit10/11) layout of the KM4-based parts -- and the pad-mux code.
    amebasmart has a single generic PINMUX_FUNCTION_I2C shared by every I2C
    pad instead of per-signal SCL/SDA crossbar codes, and its
    I2C_InitTypeDef omits the DMA request-level fields, so
    AMEBA_I2C_HAS_DMA_FIELDS stays undefined.  The whole I2C fwlib lives in
    ram_common/ameba_i2c.c rather than lib_rom.a, so it is compiled into
    libameba_fwlib.a when I2C is enabled.
    
    The shared driver gains an optional per-controller IP-clock hook,
    AMEBA_I2C_IPCLK_FN(bus).  amebasmart needs it because its
    I2C_StructInit() fills in a 10 MHz placeholder rather than the real
    reference clock (the other Ameba parts fill in a correct XTAL_ClkGet()
    / PLL_GetHBUSClk() / HPERI_ClkGet()), which makes I2C_SetSpeed()
    miscompute the SCL counts.  The hook resolves the rate at run time: the
    two HS controllers sit on HS_AHB, i.e. NP_PLL divided by
    REG_LSYS_CKD_GRP0.CKD_HBUS, so it is a PLL/board setting and not a
    constant -- an EVB measured CKD_HBUS=8 (div9, 88.9 MHz) while the SDK's
    own I2CCLK_TABLE claims a flat 100 MHz and the register reset value
    would imply 80 MHz.  The LP-domain I2C0 keeps its fixed 20 MHz.  Chips
    that leave the macro undefined use the fwlib default and are
    unaffected; regression-tested on pke8721daf:i2c.
    
    All three controllers are registered: /dev/i2c0 on PA9/PA10, /dev/i2c1
    on PA3/PA4 and /dev/i2c2 on PB10/PB11.  Pad choice is constrained on
    this chip -- a pad reaches exactly one controller (SDA fixed per
    controller, SCL the next pad up), and the pads inside the analogue
    audio ranges (PA20-PA29, PA30-PB2, PB3-PB6) are driven by the codec and
    leave the bus stuck idle.  Both rules are noted in the table's
    comment.
    
    Also add a weak DiagVprintf stub: the I2C fwlib logs through RTK_LOGx()
    -> rtk_log_write(), and unlike DiagPrintf that symbol is not in the AP
    ROM symbol table.  It is weak so the strong definition in
    rtl8730e_wifi_stubs.c still wins when WiFi is enabled; both route to
    vprintf.
    
    Hardware-verified on an RTL8730E EVB against a second board running an
    I2C slave: register read, write, write/read round-trip, multi-byte dump
    and a full address scan, on all three buses at 100 kHz.
    
    Signed-off-by: dechao_gong <[email protected]>
    Assisted-by: Claude <[email protected]>
---
 arch/arm/src/common/ameba/Kconfig                  |   7 +-
 arch/arm/src/common/ameba/ameba_i2c.c              |  20 +++
 arch/arm/src/common/ameba/ameba_i2c.h              |   4 +-
 arch/arm/src/rtl8730e/CMakeLists.txt               |  19 ++-
 arch/arm/src/rtl8730e/Make.defs                    |  10 +-
 arch/arm/src/rtl8730e/ameba_board.mk               |   7 +
 arch/arm/src/rtl8730e/ameba_i2c_chip.h             | 143 +++++++++++++++++++++
 arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c       |  12 ++
 .../rtl8730e/rtl8730e_evb/configs/i2c/defconfig    |  63 +++++++++
 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 +-
 .../rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c   |  11 ++
 .../arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h   |   4 +
 .../src/{rtl8730e_evb.h => rtl8730e_i2c.c}         |  82 ++++++++----
 15 files changed, 364 insertions(+), 32 deletions(-)

diff --git a/arch/arm/src/common/ameba/Kconfig 
b/arch/arm/src/common/ameba/Kconfig
index d34a65e2b6d..e2b6fa06fc1 100644
--- a/arch/arm/src/common/ameba/Kconfig
+++ b/arch/arm/src/common/ameba/Kconfig
@@ -61,9 +61,10 @@ config AMEBA_I2C
        select I2C
        select I2C_DRIVER
        ---help---
-               Expose the Ameba I2C controllers (I2C0/I2C1) as NuttX I2C master
-               buses at /dev/i2cN.  The board selects which controller is used 
and
-               its SCL/SDA pads in its bring-up code.
+               Expose the Ameba I2C controllers as NuttX I2C master buses at
+               /dev/i2cN (two controllers on most parts, three on amebasmart).
+               The board selects which controller is used and its SCL/SDA pads 
in
+               its bring-up code.
 
                The driver (arch/arm/src/common/ameba/ameba_i2c.c) sits on the 
SDK
                fwlib register layer and drives the DesignWare I2C block in 
polling
diff --git a/arch/arm/src/common/ameba/ameba_i2c.c 
b/arch/arm/src/common/ameba/ameba_i2c.c
index 66ac13c3509..82b72668b44 100644
--- a/arch/arm/src/common/ameba/ameba_i2c.c
+++ b/arch/arm/src/common/ameba/ameba_i2c.c
@@ -172,6 +172,9 @@ struct ameba_i2c_dev_s
   uint8_t   sdapin;            /* SDA pad (AMEBA_PA()/AMEBA_PB() encoding) */
   uint8_t   sclfid;            /* Pin mux function code for the SCL pad */
   uint8_t   sdafid;            /* Pin mux function code for the SDA pad */
+#ifdef AMEBA_I2C_IPCLK_FN
+  uint32_t  ipclk;             /* I2C IP reference clock (Hz) */
+#endif
   mutex_t   lock;              /* Serializes bus access */
 };
 
@@ -233,6 +236,12 @@ static const uint32_t  g_i2c_clk[AMEBA_NI2C]   = 
AMEBA_I2C_APBPERIPH_CLK;
 static const uint8_t   g_i2c_sclfid[AMEBA_NI2C] = AMEBA_I2C_SCLFID;
 static const uint8_t   g_i2c_sdafid[AMEBA_NI2C] = AMEBA_I2C_SDAFID;
 
+/* A chip whose I2C_StructInit() does not already fill in a usable I2C IP
+ * reference clock supplies AMEBA_I2C_IPCLK_FN(bus) in its chip header; the
+ * value is resolved once per bus at registration time.  See the note at
+ * AMEBA_I2C_IPCLK_FN in the per-chip ameba_i2c_chip.h.
+ */
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -269,6 +278,14 @@ static void ameba_i2c_reconfigure(struct ameba_i2c_dev_s 
*priv,
 
   init.mstrestr = AMEBA_ENABLE;
 
+#ifdef AMEBA_I2C_IPCLK_FN
+  /* Correct the IP reference clock that I2C_SetSpeed() divides down to the
+   * SCL high/low counts; on this chip I2C_StructInit() left a placeholder.
+   */
+
+  init.ipclk = priv->ipclk;
+#endif
+
   if (frequency <= I2C_SPEED_STANDARD)
     {
       init.spdmod = AMEBA_I2C_SS_MODE;
@@ -585,6 +602,9 @@ int ameba_i2c_register(int bus, uint8_t sclpin, uint8_t 
sdapin)
   priv->sdapin  = sdapin;
   priv->sclfid  = g_i2c_sclfid[bus];
   priv->sdafid  = g_i2c_sdafid[bus];
+#ifdef AMEBA_I2C_IPCLK_FN
+  priv->ipclk   = AMEBA_I2C_IPCLK_FN(bus);
+#endif
   priv->address = 0xffff;
   nxmutex_init(&priv->lock);
 
diff --git a/arch/arm/src/common/ameba/ameba_i2c.h 
b/arch/arm/src/common/ameba/ameba_i2c.h
index 1c7435722f9..c071fba2637 100644
--- a/arch/arm/src/common/ameba/ameba_i2c.h
+++ b/arch/arm/src/common/ameba/ameba_i2c.h
@@ -43,6 +43,7 @@
 
 #define AMEBA_I2C0            0
 #define AMEBA_I2C1            1
+#define AMEBA_I2C2            2    /* amebasmart only */
 
 /****************************************************************************
  * Public Function Prototypes
@@ -64,7 +65,8 @@ extern "C"
  *   the NuttX I2C character driver at /dev/i2cN, where N is the bus number.
  *
  * Input Parameters:
- *   bus    - The controller index, AMEBA_I2C0 or AMEBA_I2C1.  Also used as
+ *   bus    - The controller index, AMEBA_I2C0 .. AMEBA_I2C2 depending on how
+ *            many controllers the chip exposes (AMEBA_NI2C).  Also used as
  *            the /dev/i2cN minor number.
  *   sclpin - The SCL pad, encoded with AMEBA_PA()/AMEBA_PB().
  *   sdapin - The SDA pad, encoded with AMEBA_PA()/AMEBA_PB().
diff --git a/arch/arm/src/rtl8730e/CMakeLists.txt 
b/arch/arm/src/rtl8730e/CMakeLists.txt
index 4a44a81d8e8..1fd353d181b 100644
--- a/arch/arm/src/rtl8730e/CMakeLists.txt
+++ b/arch/arm/src/rtl8730e/CMakeLists.txt
@@ -75,6 +75,15 @@ if(CONFIG_AMEBA_UART)
   endif()
 endif()
 
+if(CONFIG_AMEBA_I2C)
+  list(APPEND SRCS ${AMEBA_COMMON}/ameba_i2c.c)
+  if(NOT CONFIG_RTL8730E_FLASH_FS
+     AND NOT CONFIG_AMEBA_GPIO
+     AND NOT CONFIG_AMEBA_UART)
+    list(APPEND SRCS rtl8730e_flash_stubs.c)
+  endif()
+endif()
+
 target_include_directories(arch PRIVATE ${AMEBA_COMMON})
 target_sources(arch PRIVATE ${SRCS})
 
@@ -162,6 +171,11 @@ if(CONFIG_RTL8730E_FLASH_FS OR CONFIG_RTL8730E_WIFI)
     list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_hp/ameba_uart.c)
   endif()
 
+  # The whole amebasmart I2C fwlib lives in RAM, not in lib_rom.a.
+  if(CONFIG_AMEBA_I2C)
+    list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_i2c.c)
+  endif()
+
   # Silence SDK warnings, activate CA32 code paths.  No -mcmse (ARMv7-A).
   set(AMEBA_FWLIB_INC
       -Wno-int-conversion
@@ -199,13 +213,16 @@ set(AMEBA_EXTRA_LIBS)
 # Pinmux_Config, flash MTD primitives).
 if(CONFIG_AMEBA_GPIO
    OR CONFIG_AMEBA_UART
+   OR CONFIG_AMEBA_I2C
    OR CONFIG_RTL8730E_FLASH_FS)
   list(APPEND AMEBA_EXTRA_LIBS
        ${AMEBA_SOC}/project/${AMEBA_KM_PROJ}/lib/soc/lib_rom.a)
 endif()
 
 # fwlib archive linked whenever any driver needs its RAM-side tables/code.
-if(CONFIG_RTL8730E_FLASH_FS OR CONFIG_AMEBA_UART)
+if(CONFIG_RTL8730E_FLASH_FS
+   OR CONFIG_AMEBA_UART
+   OR CONFIG_AMEBA_I2C)
   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 7a20d2fff79..dc07873cfae 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_RTL8730E_FLASH_FS)),)
+ifneq ($(filter y,$(CONFIG_AMEBA_GPIO) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(CONFIG_RTL8730E_FLASH_FS)),)
 CHIP_CSRCS += rtl8730e_flash_stubs.c
 EXTRA_LIBS += $(AMEBA_AP_SOC_LIB)$(DELIM)lib_rom.a
 
@@ -79,6 +79,10 @@ ifeq ($(CONFIG_AMEBA_UART),y)
 CHIP_CSRCS += ameba_uart.c
 endif
 
+ifeq ($(CONFIG_AMEBA_I2C),y)
+CHIP_CSRCS += ameba_i2c.c
+endif
+
 # WiFi (WHC host, CA32 side).
 ifeq ($(CONFIG_RTL8730E_WIFI),y)
 CHIP_CSRCS += rtl8730e_wifi_init.c
@@ -108,8 +112,8 @@ CHIP_CSRCS += ameba_flash_mtd.c
 endif
 
 # fwlib archive is needed whenever any driver uses RAM-side SDK tables
-# (flash MTD, UART, ...).  Link it once for all such configs.
-ifneq ($(filter y,$(CONFIG_RTL8730E_FLASH_FS) $(CONFIG_AMEBA_UART)),)
+# (flash MTD, UART, I2C, ...).  Link it once for all such configs.
+ifneq ($(filter y,$(CONFIG_RTL8730E_FLASH_FS) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C)),)
 
 # Prebuilt staging area (within the board tree, gitignored).
 AMEBA_PREBUILT      = $(BOARD_DIR)$(DELIM)prebuilt
diff --git a/arch/arm/src/rtl8730e/ameba_board.mk 
b/arch/arm/src/rtl8730e/ameba_board.mk
index 432ed8b0135..4c16aae1da1 100644
--- a/arch/arm/src/rtl8730e/ameba_board.mk
+++ b/arch/arm/src/rtl8730e/ameba_board.mk
@@ -74,6 +74,13 @@ ifeq ($(CONFIG_AMEBA_UART),y)
 AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_hp/ameba_uart.c
 endif
 
+# The whole amebasmart I2C fwlib (I2C_StructInit/Init/MasterWrite/...) lives
+# in ram_common/ameba_i2c.c, not in lib_rom.a, so it must be compiled into
+# libameba_fwlib.a whenever I2C is enabled.
+ifeq ($(CONFIG_AMEBA_I2C),y)
+AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_i2c.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/ameba_i2c_chip.h 
b/arch/arm/src/rtl8730e/ameba_i2c_chip.h
new file mode 100644
index 00000000000..e1eb69fd60a
--- /dev/null
+++ b/arch/arm/src/rtl8730e/ameba_i2c_chip.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+ * arch/arm/src/rtl8730e/ameba_i2c_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_I2C_CHIP_H
+#define __ARCH_ARM_SRC_RTL8730E_AMEBA_I2C_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Per-chip I2C wiring for RTL8730E (amebasmart CA32).  The shared driver
+ * (arch/arm/src/common/ameba/ameba_i2c.c) includes this header to learn how
+ * many I2C controllers the chip exposes and, for each, its register base,
+ * peripheral-clock masks, pad-mux codes and IP clock.  It also learns the
+ * chip's I2C_InitTypeDef layout through AMEBA_I2C_HAS_DMA_FIELDS.
+ *
+ * Sources: component/soc/amebasmart/fwlib/include/hal_platform.h (bases),
+ * sysreg_lsys.h (APBPeriph masks), ameba_pinmux.h (pad-mux code),
+ * ameba_i2c.h (I2C_InitTypeDef) and hal/src/i2c_api.c (IP clocks).
+ */
+
+#define AMEBA_NI2C                3
+
+/* I2C register bases.  I2C0 lives in the LP (low-power) domain on the
+ * LP_APB bus; I2C1 and I2C2 are the HS (high-speed) controllers on APB4.
+ * These are the NON-secure aliases (the secure aliases I2C1_REG_BASE_S /
+ * I2C2_REG_BASE_S at 0x500ef000 / 0x500f0000 must not be used -- see the
+ * note in ameba_i2c.c); the LP I2C0 has no secure alias at all.
+ */
+
+#define AMEBA_I2C_BASES           \
+        { 0x4200f000ul, 0x400ef000ul, 0x400f0000ul }
+
+/* APBPeriph_I2Cx (function) and APBPeriph_I2Cx_CLOCK masks.  amebasmart
+ * encodes these in bit 25/26/27 with the group selector bit30 = 0, unlike
+ * the KM4-based Ameba parts which use (bit30 | bit10/11).  Equal for the
+ * function and clock arguments on this chip, but kept as two lists because
+ * RCC_PeriphClockCmd() takes them as distinct arguments.
+ */
+
+#define AMEBA_I2C_APBPERIPH       \
+        { ((uint32_t)1 << 25), \
+          ((uint32_t)1 << 26), \
+          ((uint32_t)1 << 27) }
+
+#define AMEBA_I2C_APBPERIPH_CLK   \
+        { ((uint32_t)1 << 25), \
+          ((uint32_t)1 << 26), \
+          ((uint32_t)1 << 27) }
+
+/* amebasmart has a single generic PINMUX_FUNCTION_I2C (7) shared by every
+ * I2C pad; there are no per-signal SCL/SDA crossbar codes as on the other
+ * Ameba parts, so both lists carry the same value for every controller.
+ */
+
+#define AMEBA_I2C_SCLFID          { 7, 7, 7 }  /* PINMUX_FUNCTION_I2C */
+#define AMEBA_I2C_SDAFID          { 7, 7, 7 }  /* PINMUX_FUNCTION_I2C */
+
+/* I2C IP (reference) clock in Hz, per controller.
+ *
+ * amebasmart needs this where the other Ameba parts do not.  Elsewhere
+ * I2C_StructInit() fills in a correct I2C0_1_IPCLK (XTAL_ClkGet() on
+ * amebadplus/amebagreen2, PLL_GetHBUSClk() on amebalite, HPERI_ClkGet() on
+ * RTL8720F); the amebasmart one hardcodes a 10 MHz placeholder, so without
+ * an override I2C_SetSpeed() miscomputes the SCL high/low counts and the
+ * bus runs at the wrong rate.  Chips that leave AMEBA_I2C_IPCLK undefined
+ * keep the fwlib default and are unaffected.
+ *
+ * The two HS controllers live on HS_AHB, which is NP_PLL (800 MHz) divided
+ * by REG_LSYS_CKD_GRP0.CKD_HBUS, so the rate is a board/PLL setting rather
+ * than a constant: this macro reads the divider instead of assuming it.
+ * (Measured on an EVB: CKD_HBUS = 8 -> div9 -> 88.9 MHz, while the SDK's
+ * own I2CCLK_TABLE in hal/src/i2c_api.c claims a flat 100 MHz and the
+ * register's reset value would give 80 MHz -- neither matches, which is
+ * why this is computed and not tabulated.)  The LP-domain I2C0 is fed from
+ * a fixed 20 MHz and is not affected by CKD_HBUS.
+ */
+
+#define AMEBA_I2C_NPPLL_HZ        800000000ul
+
+/* REG_LSYS_CKD_GRP0: SYSTEM_CTRL_BASE_LP (0x42008000) + 0x228.  CKD_HBUS is
+ * bits 12-15 and encodes 7 -> div8, 8 -> div9, otherwise div(value + 1).
+ */
+
+#define AMEBA_I2C_CKD_GRP0        (0x42008000ul + 0x228)
+#define AMEBA_I2C_CKD_HBUS_SHIFT  12
+#define AMEBA_I2C_CKD_HBUS_MASK   0xfu
+
+/* Resolved at run time, per controller: AMEBA_I2C_IPCLK_FN(bus) is called
+ * once when a bus is registered.  Controller 0 (LP domain) has a fixed
+ * 20 MHz reference; controllers 1 and 2 follow the HS_AHB divider.
+ */
+
+static inline uint32_t ameba_i2c_ipclk(int bus)
+{
+  uint32_t div;
+
+  if (bus == 0)
+    {
+      return 20000000ul;
+    }
+
+  div = (*(volatile uint32_t *)AMEBA_I2C_CKD_GRP0 >>
+         AMEBA_I2C_CKD_HBUS_SHIFT) & AMEBA_I2C_CKD_HBUS_MASK;
+  div = (div == 7) ? 8u : (div == 8) ? 9u : (div + 1u);
+
+  return AMEBA_I2C_NPPLL_HZ / div;
+}
+
+#define AMEBA_I2C_IPCLK_FN(bus)   ameba_i2c_ipclk(bus)
+
+/* The amebasmart I2C_InitTypeDef omits the DMA request-level fields. */
+
+#undef AMEBA_I2C_HAS_DMA_FIELDS
+
+#endif /* __ARCH_ARM_SRC_RTL8730E_AMEBA_I2C_CHIP_H */
diff --git a/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c 
b/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c
index e8338122e54..dd9083673f6 100644
--- a/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c
+++ b/arch/arm/src/rtl8730e/rtl8730e_flash_stubs.c
@@ -275,6 +275,18 @@ int DiagVprintfNano(const char *fmt, va_list ap)
   return vprintf(fmt, ap);
 }
 
+/* The full-size variant is reached from log.c rtk_log_write(), which the
+ * RTK_LOGx() macros in the I2C fwlib expand to.  DiagPrintf itself is a weak
+ * definition inside lib_rom.a, but DiagVprintf is not in the ROM symbol
+ * table, so it must be supplied here.  Weak, because rtl8730e_wifi_stubs.c
+ * defines it strongly when WiFi is enabled (both route to vprintf).
+ */
+
+__attribute__((weak)) int DiagVprintf(const char *fmt, va_list ap)
+{
+  return vprintf(fmt, ap);
+}
+
 /****************************************************************************
  * __km0_ipc_memory_start__
  *
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/configs/i2c/defconfig 
b/boards/arm/rtl8730e/rtl8730e_evb/configs/i2c/defconfig
new file mode 100644
index 00000000000..f73727af585
--- /dev/null
+++ b/boards/arm/rtl8730e/rtl8730e_evb/configs/i2c/defconfig
@@ -0,0 +1,63 @@
+#
+# 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_I2C=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_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_PREALLOC_TIMERS=4
+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_I2CTOOL=y
+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 2e8ad81df25..cb2de51e57f 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_RTL8730E_WIFI) $(CONFIG_RTL8730E_FLASH_FS)),)
+ifneq ($(filter y,$(CONFIG_AMEBA_GPIO) $(CONFIG_AMEBA_UART) 
$(CONFIG_AMEBA_I2C) $(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 afdebb491af..16c8fbdb465 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/CMakeLists.txt
@@ -33,6 +33,12 @@ if(CONFIG_AMEBA_UART)
                              PRIVATE ${NUTTX_DIR}/arch/arm/src/common/ameba)
 endif()
 
+if(CONFIG_AMEBA_I2C)
+  list(APPEND SRCS rtl8730e_i2c.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 013336f409b..36b7cbc795b 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),)
+ifneq 
($(CONFIG_RTL8730E_FLASH_FS)$(CONFIG_AMEBA_GPIO)$(CONFIG_AMEBA_UART)$(CONFIG_AMEBA_I2C),)
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
 endif
 
@@ -46,4 +46,8 @@ ifeq ($(CONFIG_AMEBA_UART),y)
 CSRCS += rtl8730e_uart.c
 endif
 
+ifeq ($(CONFIG_AMEBA_I2C),y)
+CSRCS += rtl8730e_i2c.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c 
b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c
index d54f4263ecc..94ac3b030b4 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_bringup.c
@@ -260,6 +260,17 @@ int rtl8730e_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_AMEBA_I2C
+  /* Register the board's I2C master buses at /dev/i2cN. */
+
+  ret = rtl8730e_i2c_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to initialize I2C: %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 38616432dc1..2324ede7fc0 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
@@ -65,5 +65,9 @@ int rtl8730e_gpio_initialize(void);
 int rtl8730e_uart_initialize(void);
 #endif
 
+#ifdef CONFIG_AMEBA_I2C
+int rtl8730e_i2c_initialize(void);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_ARM_RTL8730E_RTL8730E_EVB_SRC_RTL8730E_EVB_H */
diff --git a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h 
b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_i2c.c
similarity index 51%
copy from boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
copy to boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_i2c.c
index 38616432dc1..c6742932677 100644
--- a/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
+++ b/boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_i2c.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_evb.h
+ * boards/arm/rtl8730e/rtl8730e_evb/src/rtl8730e_i2c.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,50 +20,88 @@
  *
  ****************************************************************************/
 
-#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 "ameba_gpio.h"
+#include "ameba_i2c.h"
+#include "rtl8730e_evb.h"
+
+#ifdef CONFIG_AMEBA_I2C
 
 /****************************************************************************
- * Public Types
+ * Private Types
  ****************************************************************************/
 
+/* One entry per I2C bus exposed to NuttX at /dev/i2cN.  The SCL/SDA pads are
+ * examples used by the `i2c` config (system/i2c i2ctool) -- adjust them to
+ * match your board's wiring.  Unlike the GPIO or UART crossbars, an RTL8730E
+ * pad reaches exactly one I2C controller, so a pad can only be swapped for
+ * another from the same controller's set; see i2c_index_get() in the SDK's
+ * hal/src/i2c_api.c.  Pads the audio codec drives must not be used.
+ */
+
+struct rtl8730e_i2c_s
+{
+  int     bus;                  /* Controller index (AMEBA_I2C0..AMEBA_I2C2) */
+  uint8_t sclpin;               /* SCL pad (AMEBA_PA()/AMEBA_PB() encoding) */
+  uint8_t sdapin;               /* SDA pad (AMEBA_PA()/AMEBA_PB() encoding) */
+};
+
 /****************************************************************************
- * Public Data
+ * Private Data
  ****************************************************************************/
 
-#ifndef __ASSEMBLY__
+static const struct rtl8730e_i2c_s g_i2c_buses[] =
+{
+  {
+    AMEBA_I2C0, AMEBA_PA(10), AMEBA_PA(9)
+  },
+  {
+    AMEBA_I2C1, AMEBA_PA(4), AMEBA_PA(3)
+  },
+  {
+    AMEBA_I2C2, AMEBA_PB(11), AMEBA_PB(10)
+  },
+};
 
 /****************************************************************************
- * Public Functions Definitions
+ * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: rtl8730e_bringup
+ * Name: rtl8730e_i2c_initialize
  *
  * Description:
- *   Bring up board features
+ *   Register the board's I2C master buses at /dev/i2cN.
  *
  ****************************************************************************/
 
-#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE)
-int rtl8730e_bringup(void);
-#endif
+int rtl8730e_i2c_initialize(void)
+{
+  int ret;
+  int i;
 
-#ifdef CONFIG_AMEBA_GPIO
-int rtl8730e_gpio_initialize(void);
-#endif
+  for (i = 0; i < (int)nitems(g_i2c_buses); i++)
+    {
+      ret = ameba_i2c_register(g_i2c_buses[i].bus, g_i2c_buses[i].sclpin,
+                               g_i2c_buses[i].sdapin);
+      if (ret < 0)
+        {
+          syslog(LOG_ERR,
+                 "ERROR: ameba_i2c_register(/dev/i2c%d) failed: %d\n",
+                 g_i2c_buses[i].bus, ret);
+          return ret;
+        }
+    }
 
-#ifdef CONFIG_AMEBA_UART
-int rtl8730e_uart_initialize(void);
-#endif
+  return OK;
+}
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_RTL8730E_RTL8730E_EVB_SRC_RTL8730E_EVB_H */
+#endif /* CONFIG_AMEBA_I2C */

Reply via email to