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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3adaf8e0437 arm/nrf54l: add TWIM support
3adaf8e0437 is described below

commit 3adaf8e043719aa8d60cf86586f75473713b8202
Author: raiden00pl <[email protected]>
AuthorDate: Sun Sep 20 16:23:54 2026 +0200

    arm/nrf54l: add TWIM support
    
    arm/nrf54l: add TWIM support
    
    Assisted-by: Codex:GPT-6
    Signed-off-by: raiden00pl <[email protected]>
---
 Documentation/platforms/arm/nrf54l/index.rst |  20 +-
 arch/arm/src/nrf54l/CMakeLists.txt           |   3 +
 arch/arm/src/nrf54l/Kconfig                  |  86 ++-
 arch/arm/src/nrf54l/Make.defs                |   4 +
 arch/arm/src/nrf54l/hardware/nrf54l_twi.h    | 214 +++++++
 arch/arm/src/nrf54l/nrf54l_i2c.c             | 894 +++++++++++++++++++++++++++
 arch/arm/src/nrf54l/nrf54l_i2c.h             |  75 +++
 7 files changed, 1288 insertions(+), 8 deletions(-)

diff --git a/Documentation/platforms/arm/nrf54l/index.rst 
b/Documentation/platforms/arm/nrf54l/index.rst
index b7318e976f9..b685cc74e74 100644
--- a/Documentation/platforms/arm/nrf54l/index.rst
+++ b/Documentation/platforms/arm/nrf54l/index.rst
@@ -24,7 +24,7 @@ RRAMC       Yes     Progmem erase/write interface
 SAADC       Yes
 SPIM        Yes
 TIMER       Yes
-TWIM        No
+TWIM        Yes
 UARTE       Yes     No hardware flow control
 USBHS       No
 WDT         No
@@ -110,7 +110,7 @@ and optional command/data callbacks declared in 
``nrf54l_spi.h``.
 The driver supports 8-bit transfers, modes 0 through 3 and configurable
 bit order. SPI4 supports up to 32 MHz; other instances support up to 8 MHz.
 ``SPI_SETFREQUENCY()`` returns the clock selected using the hardware divider.
-SPI and UART cannot use the same SERIAL instance concurrently.
+SPI, I2C and UART cannot use the same SERIAL instance concurrently.
 
 TIMER
 -----
@@ -119,6 +119,22 @@ TIMER0 through TIMER6 correspond to TIMER20, TIMER21, 
TIMER22, TIMER23,
 TIMER24, TIMER00 and TIMER10. The timer lower-half driver uses a 1 MHz
 counter clock on each instance.
 
+TWIM
+----
+
+I2C0 through I2C3 correspond to TWIM20, TWIM21, TWIM22 and TWIM30.
+nRF54LM20 also provides I2C4 and I2C5 using TWIM23 and TWIM24. Each bus
+requires ``BOARD_I2Cn_SCL_PIN`` and ``BOARD_I2Cn_SDA_PIN`` definitions.
+UART and I2C cannot use the same SERIAL instance concurrently.
+
+The driver supports 7-bit addressing at 100, 250 and 400 kHz, including
+write/read transfers with a repeated START and two-part continued writes.
+Other message chains requiring an uninterrupted bus return ``-ENOTSUP``.
+Continued writes use a per-bus buffer sized by
+``CONFIG_NRF54L_I2C_MASTER_COPY_BUF_SIZE``. A combined write exceeding this
+size returns ``-E2BIG`` before starting the transaction.
+Bus reset is not supported.
+
 UARTE
 -----
 
diff --git a/arch/arm/src/nrf54l/CMakeLists.txt 
b/arch/arm/src/nrf54l/CMakeLists.txt
index 0cbf364e664..cb33809d1a5 100644
--- a/arch/arm/src/nrf54l/CMakeLists.txt
+++ b/arch/arm/src/nrf54l/CMakeLists.txt
@@ -46,6 +46,9 @@ endif()
 if(CONFIG_NRF54L_UART)
   list(APPEND SRCS nrf54l_serial.c)
 endif()
+if(CONFIG_NRF54L_I2C_MASTER)
+  list(APPEND SRCS nrf54l_i2c.c)
+endif()
 if(CONFIG_NRF54L_SPI_MASTER)
   list(APPEND SRCS nrf54l_spi.c)
 endif()
diff --git a/arch/arm/src/nrf54l/Kconfig b/arch/arm/src/nrf54l/Kconfig
index 81e5ce4277b..f562280d332 100644
--- a/arch/arm/src/nrf54l/Kconfig
+++ b/arch/arm/src/nrf54l/Kconfig
@@ -25,6 +25,11 @@ endchoice # nRF54L Chip Selection
 
 # Peripheral Selection
 
+config NRF54L_I2C_MASTER
+       bool
+       default n
+       select I2C
+
 config NRF54L_SPI_MASTER
        bool
        default n
@@ -49,28 +54,64 @@ config NRF54L_GPIOTE
        bool "GPIOTE (GPIO interrupts)"
        default n
 
+config NRF54L_I2C0_MASTER
+       bool "I2C0 Master (TWIM20)"
+       default n
+       depends on !NRF54L_UART0
+       select NRF54L_I2C_MASTER
+
+config NRF54L_I2C1_MASTER
+       bool "I2C1 Master (TWIM21)"
+       default n
+       depends on !NRF54L_UART1
+       select NRF54L_I2C_MASTER
+
+config NRF54L_I2C2_MASTER
+       bool "I2C2 Master (TWIM22)"
+       default n
+       depends on !NRF54L_UART2
+       select NRF54L_I2C_MASTER
+
+config NRF54L_I2C3_MASTER
+       bool "I2C3 Master (TWIM30)"
+       default n
+       depends on !NRF54L_UART3
+       select NRF54L_I2C_MASTER
+
+config NRF54L_I2C4_MASTER
+       bool "I2C4 Master (TWIM23)"
+       default n
+       depends on !ARCH_CHIP_NRF54L15 && !NRF54L_UART5
+       select NRF54L_I2C_MASTER
+
+config NRF54L_I2C5_MASTER
+       bool "I2C5 Master (TWIM24)"
+       default n
+       depends on !ARCH_CHIP_NRF54L15 && !NRF54L_UART6
+       select NRF54L_I2C_MASTER
+
 config NRF54L_SPI0_MASTER
        bool "SPI0 Master (SPIM20)"
        default n
-       depends on !NRF54L_UART0
+       depends on !NRF54L_UART0 && !NRF54L_I2C0_MASTER
        select NRF54L_SPI_MASTER
 
 config NRF54L_SPI1_MASTER
        bool "SPI1 Master (SPIM21)"
        default n
-       depends on !NRF54L_UART1
+       depends on !NRF54L_UART1 && !NRF54L_I2C1_MASTER
        select NRF54L_SPI_MASTER
 
 config NRF54L_SPI2_MASTER
        bool "SPI2 Master (SPIM22)"
        default n
-       depends on !NRF54L_UART2
+       depends on !NRF54L_UART2 && !NRF54L_I2C2_MASTER
        select NRF54L_SPI_MASTER
 
 config NRF54L_SPI3_MASTER
        bool "SPI3 Master (SPIM30)"
        default n
-       depends on !NRF54L_UART3
+       depends on !NRF54L_UART3 && !NRF54L_I2C3_MASTER
        select NRF54L_SPI_MASTER
 
 config NRF54L_SPI4_MASTER
@@ -82,13 +123,13 @@ config NRF54L_SPI4_MASTER
 config NRF54L_SPI5_MASTER
        bool "SPI5 Master (SPIM23)"
        default n
-       depends on !ARCH_CHIP_NRF54L15 && !NRF54L_UART5
+       depends on !ARCH_CHIP_NRF54L15 && !NRF54L_UART5 && !NRF54L_I2C4_MASTER
        select NRF54L_SPI_MASTER
 
 config NRF54L_SPI6_MASTER
        bool "SPI6 Master (SPIM24)"
        default n
-       depends on !ARCH_CHIP_NRF54L15 && !NRF54L_UART6
+       depends on !ARCH_CHIP_NRF54L15 && !NRF54L_UART6 && !NRF54L_I2C5_MASTER
        select NRF54L_SPI_MASTER
 
 config NRF54L_UART0
@@ -496,6 +537,39 @@ endif # NRF54L_SPI_MASTER
 
 endmenu # SPI Configuration
 
+menu "I2C Master Configuration"
+
+if NRF54L_I2C_MASTER
+
+config NRF54L_I2C_MASTER_DISABLE_NOSTART
+       bool "Disable the I2C Master NOSTART flag support"
+       default n
+       ---help---
+               Disable combining two write messages into one DMA buffer.
+
+config NRF54L_I2C_MASTER_COPY_BUF_SIZE
+       int "Static buffer size for NOSTART flag support"
+       depends on !NRF54L_I2C_MASTER_DISABLE_NOSTART
+       default 4
+       range 1 65535
+       ---help---
+               Size of the per-bus buffer used to combine two continued write
+               messages. Their combined length must fit in this buffer; larger
+               transfers return E2BIG before starting the transaction.
+
+config NRF54L_I2C_MASTER_TIMEOUT
+       int "I2C transfer timeout (milliseconds)"
+       default 1000
+       range 1 60000
+       ---help---
+               Send STOP if the transfer does not finish within this interval.
+               Completion still waits for STOPPED before releasing DMA buffers;
+               a device holding the bus can delay this cleanup.
+
+endif # NRF54L_I2C_MASTER
+
+endmenu # I2C Master Configuration
+
 menuconfig NRF54L_SOFTDEVICE_CONTROLLER
        bool "SoftDevice Controller"
        depends on ALLOW_BSDNORDIC_COMPONENTS
diff --git a/arch/arm/src/nrf54l/Make.defs b/arch/arm/src/nrf54l/Make.defs
index 85565492eca..ba6fb4d5c8e 100644
--- a/arch/arm/src/nrf54l/Make.defs
+++ b/arch/arm/src/nrf54l/Make.defs
@@ -46,6 +46,10 @@ ifeq ($(CONFIG_NRF54L_UART),y)
 CHIP_CSRCS += nrf54l_serial.c
 endif
 
+ifeq ($(CONFIG_NRF54L_I2C_MASTER),y)
+CHIP_CSRCS += nrf54l_i2c.c
+endif
+
 ifeq ($(CONFIG_NRF54L_SPI_MASTER),y)
 CHIP_CSRCS += nrf54l_spi.c
 endif
diff --git a/arch/arm/src/nrf54l/hardware/nrf54l_twi.h 
b/arch/arm/src/nrf54l/hardware/nrf54l_twi.h
new file mode 100644
index 00000000000..c65dea3965f
--- /dev/null
+++ b/arch/arm/src/nrf54l/hardware/nrf54l_twi.h
@@ -0,0 +1,214 @@
+/****************************************************************************
+ * arch/arm/src/nrf54l/hardware/nrf54l_twi.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_NRF54L_HARDWARE_NRF54L_TWI_H
+#define __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_TWI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf54l_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets for TWI master (TWIM) ***********************************/
+
+#define NRF54L_TWIM_TASKS_STOP_OFFSET                       0x0004             
/* Stop TWIM transaction */
+#define NRF54L_TWIM_TASKS_SUSPEND_OFFSET                    0x000c             
/* Suspend TWIM transaction */
+#define NRF54L_TWIM_TASKS_RESUME_OFFSET                     0x0010             
/* Resume TWIM transaction */
+#define NRF54L_TWIM_TASKS_DMA_RX_START_OFFSET               0x0028             
/* Start receive sequence */
+#define NRF54L_TWIM_TASKS_DMA_RX_STOP_OFFSET                0x002c             
/* Stop RX DMA */
+#define NRF54L_TWIM_TASKS_DMA_RX_ENABLEMATCH_OFFSET(n)      (0x0030 + 4 * (n)) 
/* Enable RX match event n */
+#define NRF54L_TWIM_TASKS_DMA_RX_DISABLEMATCH_OFFSET(n)     (0x0040 + 4 * (n)) 
/* Disable RX match event n */
+#define NRF54L_TWIM_TASKS_DMA_TX_START_OFFSET               0x0050             
/* Start transmit sequence */
+#define NRF54L_TWIM_TASKS_DMA_TX_STOP_OFFSET                0x0054             
/* Stop TX DMA */
+#define NRF54L_TWIM_SUBSCRIBE_STOP_OFFSET                   0x0084             
/* Subscribe to STOP task */
+#define NRF54L_TWIM_SUBSCRIBE_SUSPEND_OFFSET                0x008c             
/* Subscribe to SUSPEND task */
+#define NRF54L_TWIM_SUBSCRIBE_RESUME_OFFSET                 0x0090             
/* Subscribe to RESUME task */
+#define NRF54L_TWIM_SUBSCRIBE_DMA_RX_START_OFFSET           0x00a8             
/* Subscribe to RX START task */
+#define NRF54L_TWIM_SUBSCRIBE_DMA_RX_STOP_OFFSET            0x00ac             
/* Subscribe to RX STOP task */
+#define NRF54L_TWIM_SUBSCRIBE_DMA_RX_ENABLEMATCH_OFFSET(n)  (0x00b0 + 4 * (n)) 
/* Subscribe to RX ENABLEMATCH task n */
+#define NRF54L_TWIM_SUBSCRIBE_DMA_RX_DISABLEMATCH_OFFSET(n) (0x00c0 + 4 * (n)) 
/* Subscribe to RX DISABLEMATCH task n */
+#define NRF54L_TWIM_SUBSCRIBE_DMA_TX_START_OFFSET           0x00d0             
/* Subscribe to TX START task */
+#define NRF54L_TWIM_SUBSCRIBE_DMA_TX_STOP_OFFSET            0x00d4             
/* Subscribe to TX STOP task */
+#define NRF54L_TWIM_EVENTS_STOPPED_OFFSET                   0x0104             
/* TWIM stopped */
+#define NRF54L_TWIM_EVENTS_ERROR_OFFSET                     0x0114             
/* TWIM error */
+#define NRF54L_TWIM_EVENTS_SUSPENDED_OFFSET                 0x0128             
/* TWIM suspended */
+#define NRF54L_TWIM_EVENTS_LASTRX_OFFSET                    0x0134             
/* Starting to receive the last byte */
+#define NRF54L_TWIM_EVENTS_LASTTX_OFFSET                    0x0138             
/* Starting to transmit the last byte */
+#define NRF54L_TWIM_EVENTS_DMA_RX_END_OFFSET                0x014c             
/* RX DMA buffer completed */
+#define NRF54L_TWIM_EVENTS_DMA_RX_READY_OFFSET              0x0150             
/* RX DMA buffer prepared */
+#define NRF54L_TWIM_EVENTS_DMA_RX_BUSERROR_OFFSET           0x0154             
/* RX DMA bus error */
+#define NRF54L_TWIM_EVENTS_DMA_RX_MATCH_OFFSET(n)           (0x0158 + 4 * (n)) 
/* RX data matched candidate n */
+#define NRF54L_TWIM_EVENTS_DMA_TX_END_OFFSET                0x0168             
/* TX DMA buffer completed */
+#define NRF54L_TWIM_EVENTS_DMA_TX_READY_OFFSET              0x016c             
/* TX DMA buffer prepared */
+#define NRF54L_TWIM_EVENTS_DMA_TX_BUSERROR_OFFSET           0x0170             
/* TX DMA bus error */
+#define NRF54L_TWIM_PUBLISH_STOPPED_OFFSET                  0x0184             
/* Publish STOPPED event */
+#define NRF54L_TWIM_PUBLISH_ERROR_OFFSET                    0x0194             
/* Publish ERROR event */
+#define NRF54L_TWIM_PUBLISH_SUSPENDED_OFFSET                0x01a8             
/* Publish SUSPENDED event */
+#define NRF54L_TWIM_PUBLISH_LASTRX_OFFSET                   0x01b4             
/* Publish LASTRX event */
+#define NRF54L_TWIM_PUBLISH_LASTTX_OFFSET                   0x01b8             
/* Publish LASTTX event */
+#define NRF54L_TWIM_PUBLISH_DMA_RX_END_OFFSET               0x01cc             
/* Publish RX END event */
+#define NRF54L_TWIM_PUBLISH_DMA_RX_READY_OFFSET             0x01d0             
/* Publish RX READY event */
+#define NRF54L_TWIM_PUBLISH_DMA_RX_BUSERROR_OFFSET          0x01d4             
/* Publish RX BUSERROR event */
+#define NRF54L_TWIM_PUBLISH_DMA_RX_MATCH_OFFSET(n)          (0x01d8 + 4 * (n)) 
/* Publish RX MATCH event n */
+#define NRF54L_TWIM_PUBLISH_DMA_TX_END_OFFSET               0x01e8             
/* Publish TX END event */
+#define NRF54L_TWIM_PUBLISH_DMA_TX_READY_OFFSET             0x01ec             
/* Publish TX READY event */
+#define NRF54L_TWIM_PUBLISH_DMA_TX_BUSERROR_OFFSET          0x01f0             
/* Publish TX BUSERROR event */
+#define NRF54L_TWIM_SHORTS_OFFSET                           0x0200             
/* Shortcuts between local events and tasks */
+#define NRF54L_TWIM_INTEN_OFFSET                            0x0300             
/* Enable or disable interrupt */
+#define NRF54L_TWIM_INTENSET_OFFSET                         0x0304             
/* Enable interrupt */
+#define NRF54L_TWIM_INTENCLR_OFFSET                         0x0308             
/* Disable interrupt */
+#define NRF54L_TWIM_ERRORSRC_OFFSET                         0x04c4             
/* Error source */
+#define NRF54L_TWIM_ENABLE_OFFSET                           0x0500             
/* Enable TWIM */
+#define NRF54L_TWIM_PSELSCL_OFFSET                          0x0600             
/* Pin select for SCL signal */
+#define NRF54L_TWIM_PSELSDA_OFFSET                          0x0604             
/* Pin select for SDA signal */
+#define NRF54L_TWIM_FREQUENCY_OFFSET                        0x0524             
/* TWIM frequency */
+#define NRF54L_TWIM_DMA_RX_PTR_OFFSET                       0x0704             
/* RX buffer address */
+#define NRF54L_TWIM_DMA_RX_MAXCNT_OFFSET                    0x0708             
/* RX buffer size */
+#define NRF54L_TWIM_DMA_RX_AMOUNT_OFFSET                    0x070c             
/* Number of received bytes */
+#define NRF54L_TWIM_DMA_RX_LIST_OFFSET                      0x0714             
/* RX list type */
+#define NRF54L_TWIM_DMA_RX_TERMINATEONBUSERROR_OFFSET       0x071c             
/* Terminate RX DMA on bus error */
+#define NRF54L_TWIM_DMA_RX_BUSERRORADDRESS_OFFSET           0x0720             
/* Address of last RX DMA bus error */
+#define NRF54L_TWIM_DMA_RX_MATCH_CONFIG_OFFSET              0x0724             
/* RX DMA match configuration */
+#define NRF54L_TWIM_DMA_RX_MATCH_CANDIDATE_OFFSET(n)        (0x0728 + 4 * (n)) 
/* RX DMA match candidate n */
+#define NRF54L_TWIM_DMA_TX_PTR_OFFSET                       0x073c             
/* TX buffer address */
+#define NRF54L_TWIM_DMA_TX_MAXCNT_OFFSET                    0x0740             
/* TX buffer size */
+#define NRF54L_TWIM_DMA_TX_AMOUNT_OFFSET                    0x0744             
/* Number of transmitted bytes */
+#define NRF54L_TWIM_DMA_TX_LIST_OFFSET                      0x074c             
/* TX list type */
+#define NRF54L_TWIM_DMA_TX_TERMINATEONBUSERROR_OFFSET       0x0754             
/* Terminate TX DMA on bus error */
+#define NRF54L_TWIM_DMA_TX_BUSERRORADDRESS_OFFSET           0x0758             
/* Address of last TX DMA bus error */
+#define NRF54L_TWIM_ADDRESS_OFFSET                          0x0588             
/* TWIM address */
+
+/* Register Bitfield Definitions for TWIM ***********************************/
+
+/* SHORTS Register */
+
+#define TWIM_SHORTS_LASTTX_STARTRX          (1 << 7)   /* Bit 7: Shortcut 
between event LASTTX and task STARTRX */
+#define TWIM_SHORTS_LASTTX_SUSPEND          (1 << 8)   /* Bit 8: Shortcut 
between event LASTTX and task SUSPEND */
+#define TWIM_SHORTS_LASTTX_STOP             (1 << 9)   /* Bit 9: Shortcut 
between event LASTTX and task STOP */
+#define TWIM_SHORTS_LASTRX_STARTTX          (1 << 10)  /* Bit 10: Shortcut 
between event LASTRX and task STARTTX */
+#define TWIM_SHORTS_LASTRX_STOP             (1 << 12)  /* Bit 12: Shortcut 
between event LASTRX and task STOP */
+
+/* INTEN/INTENSET/INTENCLR Register */
+
+#define TWIM_INT_STOPPED                    (1 << 1)   /* Bit 1: Interrupt for 
event STOPPED */
+#define TWIM_INT_ERROR                      (1 << 5)   /* Bit 5: ERROR */
+#define TWIM_INT_SUSPENDED                  (1 << 10)  /* Bit 10: SUSPENDED */
+#define TWIM_INT_LASTRX                     (1 << 13)  /* Bit 13: LASTRX */
+#define TWIM_INT_LASTTX                     (1 << 14)  /* Bit 14: LASTTX */
+#define TWIM_INT_DMA_RX_END                 (1 << 19)
+#define TWIM_INT_DMA_RX_READY               (1 << 20)
+#define TWIM_INT_DMA_RX_BUSERROR            (1 << 21)
+#define TWIM_INT_DMA_RX_MATCH(n)            (1 << (22 + (n)))
+#define TWIM_INT_DMA_TX_END                 (1 << 26)
+#define TWIM_INT_DMA_TX_READY               (1 << 27)
+#define TWIM_INT_DMA_TX_BUSERROR            (1 << 28)
+
+/* ERRORSRC Register */
+
+#define TWIM_ERRORSRC_OVERRUN               (1 << 0)   /* Bit 0: Overrun error 
*/
+#define TWIM_ERRORSRC_ANACK                 (1 << 1)   /* Bit 1: NACK received 
after sending the address */
+#define TWIM_ERRORSRC_DNACK                 (1 << 2)   /* Bit 2: NACK received 
after sending a data byte */
+
+/* ENABLE Register */
+
+#define TWIM_ENABLE_DIS                     (0)        /* Disable TWIM */
+#define TWIM_ENABLE_EN                      (0x6 << 0) /* Enable TWIM */
+
+/* PSELSCL Register */
+
+#define TWIM_PSELSCL_PIN_SHIFT              (0)        /* Bits 0-4: SCL pin 
number */
+#define TWIM_PSELSCL_PIN_MASK               (0x1f << TWIM_PSELSCL_PIN_SHIFT)
+#define TWIM_PSELSCL_PORT_SHIFT             (5)        /* Bits 5-7: SCL port 
number */
+#define TWIM_PSELSCL_PORT_MASK              (0x7 << TWIM_PSELSCL_PORT_SHIFT)
+#define TWIM_PSELSCL_CONNECTED              (0 << 31)  /* Bit 31: Connection */
+#define TWIM_PSELSCL_DISCONNECTED           (1 << 31)
+#define TWIM_PSELSCL_RESET                  (0xffffffff)
+
+/* PSELSDA Register */
+
+#define TWIM_PSELSDA_PIN_SHIFT              (0)        /* Bits 0-4: SDA pin 
number */
+#define TWIM_PSELSDA_PIN_MASK               (0x1f << TWIM_PSELSDA_PIN_SHIFT)
+#define TWIM_PSELSDA_PORT_SHIFT             (5)        /* Bits 5-7: SDA port 
number */
+#define TWIM_PSELSDA_PORT_MASK              (0x7 << TWIM_PSELSDA_PORT_SHIFT)
+#define TWIM_PSELSDA_CONNECTED              (0 << 31)  /* Bit 31: Connection */
+#define TWIM_PSELSDA_DISCONNECTED           (1 << 31)
+#define TWIM_PSELSDA_RESET                  (0xffffffff)
+
+/* FREQUENCY Register */
+
+#define TWIM_FREQUENCY_100KBPS              (0x01980000) /* 100 kbps */
+#define TWIM_FREQUENCY_250KBPS              (0x04000000) /* 250 kbps */
+#define TWIM_FREQUENCY_400KBPS              (0x06400000) /* 400 kbps */
+#define TWIM_FREQUENCY_1000KBPS             (0x0ff00000) /* 1000 kbps */
+
+/* RXDMAXCNT Register */
+
+#define TWIM_RXDMAXCNT_SHIFT                (0)        /* Bits 0-15: Maximum 
number of bytes in receive buffer */
+#define TWIM_RXDMAXCNT_MASK                 (0xffff << TWIM_RXDMAXCNT_SHIFT)
+
+/* RXDAMOUNT Register */
+
+#define TWIM_RXDAMOUNT_SHIFT                (0)        /* Bits 0-15: Number of 
bytes transferred in the last transaction */
+#define TWIM_RXDAMOUNT_MASK                 (0xffff << TWIM_RXDAMOUNT_SHIFT)
+
+/* TXDMAXCNT Register */
+
+#define TWIM_TXDMAXCNT_SHIFT                (0)        /* Bits 0-15: Maximum 
number of bytes in transmit buffer */
+#define TWIM_TXDMAXCNT_MASK                 (0xffff << TWIM_TXDMAXCNT_SHIFT)
+
+/* TXDAMOUNT Register */
+
+#define TWIM_TXDAMOUNT_SHIFT                (0)        /* Bits 0-15: Number of 
bytes transferred in the last transaction */
+#define TWIM_TXDAMOUNT_MASK                 (0xffff << TWIM_TXDAMOUNT_SHIFT)
+
+/* ADDRESS Register */
+
+#define TWIM_ADDRESS_SHIFT                  (0)        /* Bits 0-6: Address 
used in the TWI transfer */
+#define TWIM_ADDRESS_MASK                   (0x7f << TWIM_ADDRESS_SHIFT)
+
+/* DPPI subscribe and publish registers */
+
+#define TWIM_DPPI_CHIDX_SHIFT               (0)
+#define TWIM_DPPI_CHIDX_MASK                (0xff << TWIM_DPPI_CHIDX_SHIFT)
+#define TWIM_DPPI_EN                        (1 << 31)
+
+/* DMA registers */
+
+#define TWIM_DMA_LIST_DISABLED              (0)
+#define TWIM_DMA_LIST_ARRAYLIST             (1)
+#define TWIM_DMA_TERMINATEONBUSERROR        (1)
+#define TWIM_DMA_MATCH_ENABLE(n)            (1 << (n))
+#define TWIM_DMA_MATCH_ONESHOT(n)           (1 << (16 + (n)))
+#define TWIM_DMA_MATCH_CANDIDATE_MASK       (0xff)
+
+/* Pattern matcher shortcuts */
+
+#define TWIM_SHORTS_MATCH_ENABLE(n)         (1 << (21 + (n)))
+#define TWIM_SHORTS_MATCH_DISABLE(n)        (1 << (25 + (n)))
+
+#endif /* __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_TWI_H */
diff --git a/arch/arm/src/nrf54l/nrf54l_i2c.c b/arch/arm/src/nrf54l/nrf54l_i2c.c
new file mode 100644
index 00000000000..1b668c78e6d
--- /dev/null
+++ b/arch/arm/src/nrf54l/nrf54l_i2c.c
@@ -0,0 +1,894 @@
+/****************************************************************************
+ * arch/arm/src/nrf54l/nrf54l_i2c.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/debug.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/mutex.h>
+#include <nuttx/kmalloc.h>
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "nrf54l_gpio.h"
+#include "nrf54l_i2c.h"
+
+#include "hardware/nrf54l_twi.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* I2C Device Private Data */
+
+struct nrf54l_i2c_priv_s
+{
+  const struct i2c_ops_s *ops;      /* Standard I2C operations */
+  uint32_t                base;     /* TWI base address */
+  uint32_t                scl_pin;  /* SCL pin configuration */
+  uint32_t                sda_pin;  /* SDA pin configuration */
+  int                     refs;     /* Reference count */
+  int                     status;   /* I2C transfer status */
+#ifndef CONFIG_I2C_POLLED
+  uint32_t                irq;      /* TWI interrupt */
+#endif
+  uint8_t                 msgc;     /* Message count */
+  struct i2c_msg_s       *msgv;     /* Message list */
+  uint8_t                *ptr;      /* Current message buffer */
+#ifdef CONFIG_NRF54L_I2C_MASTER_COPY_BUF_SIZE
+  /* Static buffer used for continued messages */
+
+  uint8_t                 copy_buf[CONFIG_NRF54L_I2C_MASTER_COPY_BUF_SIZE];
+#endif
+  uint32_t                freq;      /* Current I2C frequency */
+  int                     dcnt;      /* Current message length */
+  uint16_t                flags;     /* Current message flags */
+  uint16_t                addr;      /* Current I2C address */
+  mutex_t                 lock;      /* Mutual exclusion mutex */
+#ifndef CONFIG_I2C_POLLED
+  sem_t                   sem_isr;   /* Interrupt wait semaphore */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline void nrf54l_i2c_putreg(struct nrf54l_i2c_priv_s *priv,
+                                     uint32_t offset,
+                                     uint32_t value);
+static inline uint32_t nrf54l_i2c_getreg(struct nrf54l_i2c_priv_s *priv,
+                                         uint32_t offset);
+static int nrf54l_i2c_transfer(struct i2c_master_s *dev,
+                               struct i2c_msg_s *msgs,
+                               int count);
+#ifdef CONFIG_I2C_RESET
+static int nrf54l_i2c_reset(struct i2c_master_s *dev);
+#endif
+#ifndef CONFIG_I2C_POLLED
+static int nrf54l_i2c_isr(int irq, void *context, void *arg);
+#endif
+static int nrf54l_i2c_deinit(struct nrf54l_i2c_priv_s *priv);
+static int nrf54l_i2c_init(struct nrf54l_i2c_priv_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C operations */
+
+static const struct i2c_ops_s g_nrf54l_i2c_ops =
+{
+  .transfer = nrf54l_i2c_transfer
+#ifdef CONFIG_I2C_RESET
+  , .reset  = nrf54l_i2c_reset
+#endif
+};
+
+/* I2C0 (TWIM20) device */
+
+#ifdef CONFIG_NRF54L_I2C0_MASTER
+
+static struct nrf54l_i2c_priv_s g_nrf54l_i2c0_priv =
+{
+  .ops     = &g_nrf54l_i2c_ops,
+  .base    = NRF54L_TWIM20_BASE,
+  .scl_pin = BOARD_I2C0_SCL_PIN,
+  .sda_pin = BOARD_I2C0_SDA_PIN,
+  .refs    = 0,
+  .lock    = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+  .irq     = NRF54L_IRQ_SERIAL20,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/* I2C1 (TWIM21) device */
+
+#ifdef CONFIG_NRF54L_I2C1_MASTER
+static struct nrf54l_i2c_priv_s g_nrf54l_i2c1_priv =
+{
+  .ops     = &g_nrf54l_i2c_ops,
+  .base    = NRF54L_TWIM21_BASE,
+  .scl_pin = BOARD_I2C1_SCL_PIN,
+  .sda_pin = BOARD_I2C1_SDA_PIN,
+  .refs    = 0,
+  .lock    = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+  .irq     = NRF54L_IRQ_SERIAL21,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/* I2C2 (TWIM22) device */
+
+#ifdef CONFIG_NRF54L_I2C2_MASTER
+static struct nrf54l_i2c_priv_s g_nrf54l_i2c2_priv =
+{
+  .ops     = &g_nrf54l_i2c_ops,
+  .base    = NRF54L_TWIM22_BASE,
+  .scl_pin = BOARD_I2C2_SCL_PIN,
+  .sda_pin = BOARD_I2C2_SDA_PIN,
+  .refs    = 0,
+  .lock    = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+  .irq     = NRF54L_IRQ_SERIAL22,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/* I2C3 (TWIM30) device */
+
+#ifdef CONFIG_NRF54L_I2C3_MASTER
+static struct nrf54l_i2c_priv_s g_nrf54l_i2c3_priv =
+{
+  .ops     = &g_nrf54l_i2c_ops,
+  .base    = NRF54L_TWIM30_BASE,
+  .scl_pin = BOARD_I2C3_SCL_PIN,
+  .sda_pin = BOARD_I2C3_SDA_PIN,
+  .refs    = 0,
+  .lock    = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+  .irq     = NRF54L_IRQ_SERIAL30,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/* I2C4 (TWIM23) device */
+
+#ifdef CONFIG_NRF54L_I2C4_MASTER
+static struct nrf54l_i2c_priv_s g_nrf54l_i2c4_priv =
+{
+  .ops     = &g_nrf54l_i2c_ops,
+  .base    = NRF54L_TWIM23_BASE,
+  .scl_pin = BOARD_I2C4_SCL_PIN,
+  .sda_pin = BOARD_I2C4_SDA_PIN,
+  .refs    = 0,
+  .lock    = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+  .irq     = NRF54L_IRQ_SERIAL23,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/* I2C5 (TWIM24) device */
+
+#ifdef CONFIG_NRF54L_I2C5_MASTER
+static struct nrf54l_i2c_priv_s g_nrf54l_i2c5_priv =
+{
+  .ops     = &g_nrf54l_i2c_ops,
+  .base    = NRF54L_TWIM24_BASE,
+  .scl_pin = BOARD_I2C5_SCL_PIN,
+  .sda_pin = BOARD_I2C5_SDA_PIN,
+  .refs    = 0,
+  .lock    = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+  .irq     = NRF54L_IRQ_SERIAL24,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf54l_i2c_putreg
+ *
+ * Description:
+ *   Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void nrf54l_i2c_putreg(struct nrf54l_i2c_priv_s *priv,
+                                     uint32_t offset,
+                                     uint32_t value)
+{
+  putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf54l_i2c_getreg
+ *
+ * Description:
+ *   Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf54l_i2c_getreg(struct nrf54l_i2c_priv_s *priv,
+                                         uint32_t offset)
+{
+  return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf54l_i2c_transfer
+ *
+ * Description:
+ *   Generic I2C transfer function
+ *
+ ****************************************************************************/
+
+static int nrf54l_i2c_transfer(struct i2c_master_s *dev,
+                               struct i2c_msg_s *msgs,
+                               int count)
+{
+  struct nrf54l_i2c_priv_s *priv = (struct nrf54l_i2c_priv_s *)dev;
+  uint32_t regval = 0;
+  int      ret = OK;
+#ifndef CONFIG_NRF54L_I2C_MASTER_DISABLE_NOSTART
+  uint8_t *pack_buf = NULL;
+#endif
+
+  ret = nxmutex_lock(&priv->lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Reset ptr and dcnt */
+
+  priv->dcnt = 0;
+  priv->ptr = NULL;
+
+  priv->msgv = msgs;
+  priv->msgc = count;
+
+  /* Reset I2C transfer status */
+
+  priv->status = OK;
+
+  i2cinfo("I2C TRANSFER count=%d\n", count);
+
+  /* Do we need change I2C bus frequency ? */
+
+  if (priv->msgv->frequency != priv->freq)
+    {
+      /* Get TWI frequency */
+
+      switch (priv->msgv->frequency)
+        {
+          case 100000:
+            {
+              regval = TWIM_FREQUENCY_100KBPS;
+              break;
+            }
+
+          case 250000:
+            {
+              regval = TWIM_FREQUENCY_250KBPS;
+              break;
+            }
+
+          case 400000:
+            {
+              regval = TWIM_FREQUENCY_400KBPS;
+              break;
+            }
+
+          default:
+            {
+              ret = -EINVAL;
+              goto errout;
+            }
+        }
+
+      /* Write TWI frequency */
+
+      nrf54l_i2c_putreg(priv, NRF54L_TWIM_FREQUENCY_OFFSET, regval);
+
+      /* Save the new I2C frequency */
+
+      priv->freq = priv->msgv->frequency;
+    }
+
+  /* I2C transfer */
+
+  do
+    {
+      /* Get current message data */
+
+      priv->ptr   = priv->msgv->buffer;
+      priv->dcnt  = priv->msgv->length;
+      priv->flags = priv->msgv->flags;
+      priv->addr  = priv->msgv->addr;
+
+      i2cinfo("ptr=%p dcnt=%d flags=%d addr=%d\n",
+              priv->ptr, priv->dcnt, priv->flags, priv->addr);
+
+      /* Write TWI address */
+
+      regval = priv->addr;
+      nrf54l_i2c_putreg(priv, NRF54L_TWIM_ADDRESS_OFFSET, regval);
+
+      if ((priv->flags & I2C_M_READ) == 0)
+        {
+#ifndef CONFIG_NRF54L_I2C_MASTER_DISABLE_NOSTART
+          /* Check if we need to combine messages */
+
+          if (priv->msgc > 1)
+            {
+              if (priv->msgv[1].flags & I2C_M_NOSTART)
+                {
+                  /* More than 2 messages not supported */
+
+                  DEBUGASSERT(priv->msgc < 3);
+
+                  /* Combine buffers */
+
+                  if ((priv->msgv[0].length +
+                       priv->msgv[1].length) <=
+                      CONFIG_NRF54L_I2C_MASTER_COPY_BUF_SIZE)
+                    {
+                      pack_buf = priv->copy_buf;
+                    }
+                  else
+                    {
+                      pack_buf = kmm_malloc(priv->msgv[0].length +
+                                            priv->msgv[1].length);
+                      if (pack_buf == NULL)
+                        {
+                          return -ENOMEM;
+                        }
+                    }
+
+                  /* Combine messages */
+
+                  memcpy(pack_buf, priv->msgv[0].buffer,
+                         priv->msgv[0].length);
+                  memcpy(pack_buf + priv->msgv[0].length,
+                         priv->msgv[1].buffer, priv->msgv[1].length);
+
+                  /* Use new buffer to transmit data */
+
+                  priv->ptr  = pack_buf;
+                  priv->dcnt = priv->msgv[0].length + priv->msgv[1].length;
+
+                  /* Next message */
+
+                  priv->msgc -= 1;
+                  priv->msgv += 1;
+                }
+            }
+#else
+          if (priv->msgc > 1)
+            {
+              if (priv->msgv[1].flags & I2C_M_NOSTART)
+                {
+                  /* Not supported */
+
+                  DEBUGPANIC();
+                }
+            }
+#endif
+
+          /* Write TXD data pointer. Zero-length transfers (used for bus
+           * scanning) never access the buffer, so any pointer is valid.
+           */
+
+          regval = (uintptr_t)priv->ptr;
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_DMA_TX_PTR_OFFSET, regval);
+
+          /* Write number of bytes in TXD buffer */
+
+          regval = priv->dcnt;
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_DMA_TX_MAXCNT_OFFSET, regval);
+
+          /* Shortcut from LASTTX to STOP */
+
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_SHORTS_OFFSET,
+                            TWIM_SHORTS_LASTTX_STOP);
+
+          /* Start TX sequence */
+
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_TASKS_DMA_TX_START_OFFSET, 1);
+        }
+      else
+        {
+          /* Write RXD data pointer. Zero-length transfers (used for bus
+           * scanning) never access the buffer, so any pointer is valid.
+           */
+
+          regval = (uintptr_t)priv->ptr;
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_DMA_RX_PTR_OFFSET, regval);
+
+          /* Write number of bytes in RXD buffer */
+
+          regval = priv->dcnt;
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_DMA_RX_MAXCNT_OFFSET, regval);
+
+          /* Shortcuts from LASTRX to STOP */
+
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_SHORTS_OFFSET,
+                            TWIM_SHORTS_LASTRX_STOP);
+
+          /* Start RX sequence */
+
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_TASKS_DMA_RX_START_OFFSET, 1);
+        }
+
+      /* Wait for stop event */
+
+#ifdef CONFIG_I2C_POLLED
+      while (1)
+        {
+          regval = nrf54l_i2c_getreg(priv,
+                                     NRF54L_TWIM_ERRORSRC_OFFSET) & 0x7;
+          if (regval != 0)
+            {
+              i2cerr("Error SRC: 0x%08" PRIx32 "\n", regval);
+              ret = -1;
+              nrf54l_i2c_putreg(priv,
+                                NRF54L_TWIM_ERRORSRC_OFFSET, 0x7);
+              goto errout;
+            }
+
+          if (nrf54l_i2c_getreg(priv,
+                                NRF54L_TWIM_EVENTS_STOPPED_OFFSET) == 1)
+            {
+              break;
+            }
+        }
+
+      /* Clear event */
+
+      nrf54l_i2c_putreg(priv, NRF54L_TWIM_EVENTS_STOPPED_OFFSET, 0);
+#else
+      nxsem_wait(&priv->sem_isr);
+
+      if (priv->status < 0)
+        {
+          ret = priv->status;
+          goto errout;
+        }
+#endif
+
+      /* Next message */
+
+      priv->msgc -= 1;
+      priv->msgv += 1;
+    }
+  while (priv->msgc > 0);
+
+errout:
+#ifndef CONFIG_NRF54L_I2C_MASTER_DISABLE_NOSTART
+  if (pack_buf != NULL && pack_buf != priv->copy_buf)
+    {
+      kmm_free(pack_buf);
+    }
+#endif
+
+  nxmutex_unlock(&priv->lock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf54l_i2c_reset
+ *
+ * Description:
+ *   Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_RESET
+static int nrf54l_i2c_reset(struct i2c_master_s *dev)
+{
+#error not implemented
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf54l_i2c_isr
+ *
+ * Description:
+ *   Common I2C interrupt service routine
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int nrf54l_i2c_isr(int irq, void *context, void *arg)
+{
+  struct nrf54l_i2c_priv_s *priv   = (struct nrf54l_i2c_priv_s *)arg;
+  uint32_t                 regval = 0;
+
+  /* Reset I2C status */
+
+  priv->status = OK;
+
+  if ((priv->flags & I2C_M_READ) == 0)
+    {
+      if (nrf54l_i2c_getreg(priv, NRF54L_TWIM_EVENTS_LASTTX_OFFSET) == 1)
+        {
+          i2cinfo("I2C LASTTX\n");
+
+          /* Clear event */
+
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_EVENTS_LASTTX_OFFSET, 0);
+
+          return OK;
+        }
+    }
+  else
+    {
+      if (nrf54l_i2c_getreg(priv, NRF54L_TWIM_EVENTS_LASTRX_OFFSET) == 1)
+        {
+          i2cinfo("I2C LASTRX\n");
+
+          /* Clear event */
+
+          nrf54l_i2c_putreg(priv, NRF54L_TWIM_EVENTS_LASTRX_OFFSET, 0);
+
+          return OK;
+        }
+    }
+
+  if (nrf54l_i2c_getreg(priv, NRF54L_TWIM_EVENTS_STOPPED_OFFSET) == 1)
+    {
+      i2cinfo("I2C STOPPED\n");
+
+      /* STOPPED event */
+
+      nxsem_post(&priv->sem_isr);
+
+      /* Clear event */
+
+      nrf54l_i2c_putreg(priv, NRF54L_TWIM_EVENTS_STOPPED_OFFSET, 0);
+    }
+
+  if (nrf54l_i2c_getreg(priv, NRF54L_TWIM_EVENTS_ERROR_OFFSET) == 1)
+    {
+      regval = nrf54l_i2c_getreg(priv, NRF54L_TWIM_ERRORSRC_OFFSET) & 0x7;
+
+      i2cerr("Error SRC: 0x%08" PRIx32 "\n", regval);
+
+      /* Set ERROR status */
+
+      if (regval & TWIM_ERRORSRC_OVERRUN)
+        {
+          /* Overrun error */
+
+          priv->status = -EIO;
+        }
+      else
+        {
+          /* NACK */
+
+          priv->status = -ENXIO;
+        }
+
+      /* ERROR event */
+
+      nxsem_post(&priv->sem_isr);
+
+      /* Clear event */
+
+      nrf54l_i2c_putreg(priv, NRF54L_TWIM_EVENTS_ERROR_OFFSET, 0);
+      nrf54l_i2c_putreg(priv, NRF54L_TWIM_ERRORSRC_OFFSET, 0x7);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf54l_i2c_init
+ *
+ * Description:
+ *   Setup the I2C hardware, ready for operation with defaults
+ *
+ ****************************************************************************/
+
+static int nrf54l_i2c_init(struct nrf54l_i2c_priv_s *priv)
+{
+  uint32_t regval = 0;
+  int pin         = 0;
+  int port        = 0;
+
+  /* Disable TWI interface */
+
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_ENABLE_OFFSET, TWIM_ENABLE_DIS);
+
+  /* Configure SCL and SDA pins */
+
+  nrf54l_gpio_config(priv->scl_pin);
+  nrf54l_gpio_config(priv->sda_pin);
+
+  /* Select SCL pin */
+
+  pin  = GPIO_PIN_DECODE(priv->scl_pin);
+  port = GPIO_PORT_DECODE(priv->scl_pin);
+
+  regval = (pin << TWIM_PSELSCL_PIN_SHIFT);
+  regval |= (port << TWIM_PSELSCL_PORT_SHIFT);
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_PSELSCL_OFFSET, regval);
+
+  /* Select SDA pin */
+
+  pin  = GPIO_PIN_DECODE(priv->sda_pin);
+  port = GPIO_PORT_DECODE(priv->sda_pin);
+
+  regval = (pin << TWIM_PSELSDA_PIN_SHIFT);
+  regval |= (port << TWIM_PSELSDA_PORT_SHIFT);
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_PSELSDA_OFFSET, regval);
+
+  /* Enable TWI interface */
+
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_ENABLE_OFFSET, TWIM_ENABLE_EN);
+
+#ifndef CONFIG_I2C_POLLED
+  /* Enable I2C interrupts */
+
+  regval = (TWIM_INT_STOPPED | TWIM_INT_ERROR);
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_INTEN_OFFSET, regval);
+
+  /* Attach error and event interrupts to the ISRs */
+
+  irq_attach(priv->irq, nrf54l_i2c_isr, priv);
+  up_enable_irq(priv->irq);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf54l_i2c_deinit
+ *
+ * Description:
+ *   Shutdown the I2C hardware
+ *
+ ****************************************************************************/
+
+static int nrf54l_i2c_deinit(struct nrf54l_i2c_priv_s *priv)
+{
+  /* Disable TWI interface */
+
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_ENABLE_OFFSET, TWIM_ENABLE_DIS);
+
+  /* Unconfigure GPIO pins */
+
+  nrf54l_gpio_unconfig(priv->scl_pin);
+  nrf54l_gpio_unconfig(priv->sda_pin);
+
+  /* Deatach TWI from GPIO */
+
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_PSELSCL_OFFSET, TWIM_PSELSCL_RESET);
+  nrf54l_i2c_putreg(priv, NRF54L_TWIM_PSELSDA_OFFSET, TWIM_PSELSDA_RESET);
+
+  /* Disable and detach interrupts */
+
+#ifndef CONFIG_I2C_POLLED
+  up_disable_irq(priv->irq);
+  irq_detach(priv->irq);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf54l_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize one I2C bus
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *nrf54l_i2cbus_initialize(int port)
+{
+  struct nrf54l_i2c_priv_s *priv = NULL;
+
+  i2cinfo("I2C INITIALIZE port=%d\n", port);
+
+  /* Get interface */
+
+  switch (port)
+    {
+#ifdef CONFIG_NRF54L_I2C0_MASTER
+      case 0:
+        {
+          priv = (struct nrf54l_i2c_priv_s *)&g_nrf54l_i2c0_priv;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF54L_I2C1_MASTER
+      case 1:
+        {
+          priv = (struct nrf54l_i2c_priv_s *)&g_nrf54l_i2c1_priv;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF54L_I2C2_MASTER
+      case 2:
+        {
+          priv = (struct nrf54l_i2c_priv_s *)&g_nrf54l_i2c2_priv;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF54L_I2C3_MASTER
+      case 3:
+        {
+          priv = (struct nrf54l_i2c_priv_s *)&g_nrf54l_i2c3_priv;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF54L_I2C4_MASTER
+      case 4:
+        {
+          priv = (struct nrf54l_i2c_priv_s *)&g_nrf54l_i2c4_priv;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF54L_I2C5_MASTER
+      case 5:
+        {
+          priv = (struct nrf54l_i2c_priv_s *)&g_nrf54l_i2c5_priv;
+          break;
+        }
+#endif
+
+      default:
+        {
+          return NULL;
+        }
+    }
+
+  /* Initialize private data for the first time, increment reference count,
+   * power-up hardware and configure GPIOs.
+   */
+
+  nxmutex_lock(&priv->lock);
+  if (priv->refs++ == 0)
+    {
+      /* Initialize I2C */
+
+      nrf54l_i2c_init(priv);
+    }
+
+  nxmutex_unlock(&priv->lock);
+  return (struct i2c_master_s *)priv;
+}
+
+/****************************************************************************
+ * Name: nrf54l_i2cbus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an I2C bus
+ *
+ ****************************************************************************/
+
+int nrf54l_i2cbus_uninitialize(struct i2c_master_s *dev)
+{
+  struct nrf54l_i2c_priv_s *priv = (struct nrf54l_i2c_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  /* Decrement reference count and check for underflow */
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  nxmutex_lock(&priv->lock);
+  if (--priv->refs)
+    {
+      nxmutex_unlock(&priv->lock);
+      return OK;
+    }
+
+  /* Disable power and other HW resource (GPIO's) */
+
+  nrf54l_i2c_deinit(priv);
+  nxmutex_unlock(&priv->lock);
+
+  return OK;
+}
diff --git a/arch/arm/src/nrf54l/nrf54l_i2c.h b/arch/arm/src/nrf54l/nrf54l_i2c.h
new file mode 100644
index 00000000000..782a0db2c1e
--- /dev/null
+++ b/arch/arm/src/nrf54l/nrf54l_i2c.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+ * arch/arm/src/nrf54l/nrf54l_i2c.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_NRF54L_NRF54L_I2C_H
+#define __ARCH_ARM_SRC_NRF54L_NRF54L_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include "chip.h"
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf54l_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize the selected I2C port. And return a unique instance of struct
+ *   struct i2c_master_s. This function may be called to obtain multiple
+ *   instances of the interface, each of which may be set up with a
+ *   different frequency and slave address.
+ *
+ * Input Parameters:
+ *   Port number (for hardware that has multiple TWI interfaces)
+ *
+ * Returned Value:
+ *   Valid I2C device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *nrf54l_i2cbus_initialize(int port);
+
+/****************************************************************************
+ * Name: nrf54l_i2cbus_uninitialize
+ *
+ * Description:
+ *   De-initialize the selected I2C port, and power down the device.
+ *
+ * Input Parameters:
+ *   Device structure as returned by the nrf54l_i2cbus_initialize()
+ *
+ * Returned Value:
+ *   OK on success, ERROR when internal reference count mismatch or dev
+ *   points to invalid hardware device.
+ *
+ ****************************************************************************/
+
+int nrf54l_i2cbus_uninitialize(struct i2c_master_s *dev);
+
+#endif /* __ARCH_ARM_SRC_NRF54L_NRF54L_I2C_H */

Reply via email to