This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new f8c5b91522 arm64/imx9: Add LPI2C driver
f8c5b91522 is described below
commit f8c5b91522daf98140390e048d0268d247b3c8f8
Author: Ville Juven <[email protected]>
AuthorDate: Wed Mar 27 17:13:08 2024 +0200
arm64/imx9: Add LPI2C driver
---
arch/arm64/Kconfig | 1 +
arch/arm64/src/imx9/Kconfig | 249 ++
arch/arm64/src/imx9/Make.defs | 4 +
arch/arm64/src/imx9/hardware/imx9_lpi2c.h | 622 +++++
arch/arm64/src/imx9/imx9_lpi2c.c | 2579 ++++++++++++++++++++
.../arm64/src/imx9/imx9_lpi2c.h | 56 +-
boards/arm64/imx9/imx93-evk/configs/nsh/defconfig | 6 +
boards/arm64/imx9/imx93-evk/include/board.h | 12 +
boards/arm64/imx9/imx93-evk/src/Makefile | 4 +
boards/arm64/imx9/imx93-evk/src/imx93-evk.h | 12 +
boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c | 3 +
boards/arm64/imx9/imx93-evk/src/imx9_bringup.c | 10 +
.../imx93-evk/src/{imx9_bringup.c => imx9_i2c.c} | 43 +-
13 files changed, 3554 insertions(+), 47 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 37b632f9ae..b9fc7bdb06 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -94,6 +94,7 @@ config ARCH_CHIP_IMX8
config ARCH_CHIP_IMX9
bool "NXP i.MX9 Platform (ARMv8.2a)"
select ARCH_HAVE_ADDRENV
+ select ARCH_HAVE_I2CRESET
select ARCH_HAVE_IRQTRIGGER
select ARCH_NEED_ADDRENV_MAPPING
---help---
diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig
index 9ab957be01..9368c961c1 100644
--- a/arch/arm64/src/imx9/Kconfig
+++ b/arch/arm64/src/imx9/Kconfig
@@ -218,8 +218,257 @@ config IMX9_GPIO_IRQ
bool "GPIO Interrupt Support"
default n
+config IMX9_LPI2C
+ bool "LPI2C support"
+ default n
+
config IMX9_PLL
bool "PLL setup support (WIP)"
default n
+menu "LPI2C Peripherals"
+
+menuconfig IMX9_LPI2C1
+ bool "LPI2C1"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C1
+
+config IMX9_LPI2C1_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C1_DMA
+ bool "Enable DMA for I2C1"
+ default n
+ depends on IMX9_LPI2C_DMA
+
+config IMX9_LPI2C1_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C1_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C1
+
+menuconfig IMX9_LPI2C2
+ bool "LPI2C2"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C2
+
+config IMX9_LPI2C2_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C2_DMA
+ bool "Enable DMA for I2C2"
+ default n
+ depends on IMX9_LPI2C_DMA
+
+config IMX9_LPI2C2_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C2_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C2
+
+menuconfig IMX9_LPI2C3
+ bool "LPI2C3"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C3
+
+config IMX9_LPI2C3_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C3_DMA
+ bool "Enable DMA for I2C3"
+ default n
+ depends on IMX9_LPI2C_DMA
+
+config IMX9_LPI2C3_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C3_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C3
+
+menuconfig IMX9_LPI2C4
+ bool "LPI2C4"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C4
+
+config IMX9_LPI2C4_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C4_DMA
+ bool "Enable DMA for I2C4"
+ default n
+ depends on IMX9_LPI2C_DMA
+
+config IMX9_LPI2C4_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C4_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C4
+
+menuconfig IMX9_LPI2C5
+ bool "LPI2C5"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C5
+
+config IMX9_LPI2C5_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C5_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C5_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C5
+
+menuconfig IMX9_LPI2C6
+ bool "LPI2C6"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C6
+
+config IMX9_LPI2C6_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C6_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C6_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C6
+
+menuconfig IMX9_LPI2C7
+ bool "LPI2C7"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C7
+
+config IMX9_LPI2C7_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C7_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C7_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C7
+
+menuconfig IMX9_LPI2C8
+ bool "LPI2C8"
+ default n
+ select IMX9_LPI2C
+
+if IMX9_LPI2C8
+
+config IMX9_LPI2C8_BUSYIDLE
+ int "Bus idle timeout period in clock cycles"
+ default 0
+
+config IMX9_LPI2C8_FILTSCL
+ int "I2C master digital glitch filters for SCL input in clock cycles"
+ default 0
+
+config IMX9_LPI2C8_FILTSDA
+ int "I2C master digital glitch filters for SDA input in clock cycles"
+ default 0
+
+endif # IMX9_LPI2C8
+
+endmenu # LPI2C Peripherals
+menu "LPI2C Configuration"
+ depends on IMX9_LPI2C
+
+config IMX9_LPI2C_DMA
+ bool "I2C DMA Support"
+ default n
+ depends on IMX9_LPI2C && IMX9_EDMA && !I2C_POLLED
+ ---help---
+ This option enables the DMA for I2C transfers.
+ Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority
value
+ for the I2C dma streams, else the default priority level is set
to
+ medium.
+
+config IMX9_LPI2C_DMA_MAXMSG
+ int "Maximum number messages that will be DMAed"
+ default 8
+ depends on IMX9_LPI2C_DMA
+ ---help---
+ This option set the mumber of mesg that can be in a transfer.
+ It is used to allocate space for the 16 bit LPI2C commands
+ that will be DMA-ed to the LPI2C device.
+
+config IMX9_LPI2C_DYNTIMEO
+ bool "Use dynamic timeouts"
+ default n
+ depends on IMX9_LPI2C
+
+config IMX9_LPI2C_DYNTIMEO_USECPERBYTE
+ int "Timeout Microseconds per Byte"
+ default 500
+ depends on IMX9_LPI2C_DYNTIMEO
+
+config IMX9_LPI2C_DYNTIMEO_STARTSTOP
+ int "Timeout for Start/Stop (Milliseconds)"
+ default 1000
+ depends on IMX9_LPI2C_DYNTIMEO
+
+config IMX9_LPI2C_TIMEOSEC
+ int "Timeout seconds"
+ default 0
+ depends on IMX9_LPI2C
+
+config IMX9_LPI2C_TIMEOMS
+ int "Timeout Milliseconds"
+ default 500
+ depends on IMX9_LPI2C && !IMX9_LPI2C_DYNTIMEO
+
+config IMX9_LPI2C_TIMEOTICKS
+ int "Timeout for Done and Stop (ticks)"
+ default 500
+ depends on IMX9_LPI2C && !IMX9_LPI2C_DYNTIMEO
+
+endmenu # LPI2C Configuration
+
endif # ARCH_CHIP_IMX9
diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs
index 0d7427aec3..27a19cb357 100644
--- a/arch/arm64/src/imx9/Make.defs
+++ b/arch/arm64/src/imx9/Make.defs
@@ -46,3 +46,7 @@ endif
ifeq ($(CONFIG_IMX9_USBDEV),y)
CHIP_CSRCS += imx9_usbdev.c
endif
+
+ifeq ($(CONFIG_IMX9_LPI2C),y)
+ CHIP_CSRCS += imx9_lpi2c.c
+endif
diff --git a/arch/arm64/src/imx9/hardware/imx9_lpi2c.h
b/arch/arm64/src/imx9/hardware/imx9_lpi2c.h
new file mode 100644
index 0000000000..1c7e47aa88
--- /dev/null
+++ b/arch/arm64/src/imx9/hardware/imx9_lpi2c.h
@@ -0,0 +1,622 @@
+/****************************************************************************
+ * arch/arm64/src/imx9/hardware/imx9_lpi2c.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPI2C_H_
+#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPI2C_H_
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define IMX9_LPI2C_VERID_OFFSET 0x0000 /* Version ID Register
offset */
+#define IMX9_LPI2C_PARAM_OFFSET 0x0004 /* Parameter Register
offset */
+#define IMX9_LPI2C_MCR_OFFSET 0x0010 /* Master Control Register
offset */
+#define IMX9_LPI2C_MSR_OFFSET 0x0014 /* Master Status Register
offset */
+#define IMX9_LPI2C_MIER_OFFSET 0x0018 /* Master Interrupt Enable
Register offset */
+#define IMX9_LPI2C_MDER_OFFSET 0x001c /* Master DMA Enable
Register offset */
+#define IMX9_LPI2C_MCFGR0_OFFSET 0x0020 /* Master Config Register
0 offset */
+#define IMX9_LPI2C_MCFGR1_OFFSET 0x0024 /* Master Config Register
1 offset */
+#define IMX9_LPI2C_MCFGR2_OFFSET 0x0028 /* Master Config Register
2 offset */
+#define IMX9_LPI2C_MCFGR3_OFFSET 0x002c /* Master Config Register
3 offset */
+#define IMX9_LPI2C_MDMR_OFFSET 0x0040 /* Master Data Match
Register offset */
+#define IMX9_LPI2C_MCCR0_OFFSET 0x0048 /* Master Clock
Configuration Register 0 offset */
+#define IMX9_LPI2C_MCCR1_OFFSET 0x0050 /* Master Clock
Configuration Register 1 offset */
+#define IMX9_LPI2C_MFCR_OFFSET 0x0058 /* Master FIFO Control
Register offset */
+#define IMX9_LPI2C_MFSR_OFFSET 0x005C /* Master FIFO Status
Register offset */
+#define IMX9_LPI2C_MTDR_OFFSET 0x0060 /* Master Transmit Data
Register offset */
+#define IMX9_LPI2C_MRDR_OFFSET 0x0070 /* Master Receive Data
Register offset */
+#define IMX9_LPI2C_SCR_OFFSET 0x0110 /* Slave Control Register
offset */
+#define IMX9_LPI2C_SSR_OFFSET 0x0114 /* Slave Status Register
offset */
+#define IMX9_LPI2C_SIER_OFFSET 0x0118 /* Slave Interrupt Enable
Register offset */
+#define IMX9_LPI2C_SDER_OFFSET 0x011c /* Slave DMA Enable
Register offset */
+#define IMX9_LPI2C_SCFGR1_OFFSET 0x0124 /* Slave Config Register 1
offset */
+#define IMX9_LPI2C_SCFGR2_OFFSET 0x0128 /* Slave Config Register 2
offset */
+#define IMX9_LPI2C_SAMR_OFFSET 0x0140 /* Slave Address Match
Register offset */
+#define IMX9_LPI2C_SASR_OFFSET 0x0150 /* Slave Address Status
Register offset */
+#define IMX9_LPI2C_STAR_OFFSET 0x0154 /* Slave Transmit ACK
Register offset */
+#define IMX9_LPI2C_STDR_OFFSET 0x0160 /* Slave Transmit Data
Register offset */
+#define IMX9_LPI2C_SRDR_OFFSET 0x0170 /* Slave Receive Data
Register offset */
+
+/* Register addresses *******************************************************/
+
+/* LPI2C1 Registers */
+
+#define IMX9_LPI2C1_VERID (IMX9_LPI2C1_BASE +
IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */
+#define IMX9_LPI2C1_PARAM (IMX9_LPI2C1_BASE +
IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */
+#define IMX9_LPI2C1_MCR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */
+#define IMX9_LPI2C1_MSR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */
+#define IMX9_LPI2C1_MIER (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */
+#define IMX9_LPI2C1_MDER (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */
+#define IMX9_LPI2C1_MCFGR0 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */
+#define IMX9_LPI2C1_MCFGR1 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */
+#define IMX9_LPI2C1_MCFGR2 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */
+#define IMX9_LPI2C1_MCFGR3 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */
+#define IMX9_LPI2C1_MDMR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */
+#define IMX9_LPI2C1_MCCR0 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */
+#define IMX9_LPI2C1_MCCR1 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */
+#define IMX9_LPI2C1_MFCR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */
+#define IMX9_LPI2C1_MFSR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */
+#define IMX9_LPI2C1_MTDR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */
+#define IMX9_LPI2C1_MRDR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */
+#define IMX9_LPI2C1_SCR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */
+#define IMX9_LPI2C1_SSR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */
+#define IMX9_LPI2C1_SIER (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */
+#define IMX9_LPI2C1_SDER (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */
+#define IMX9_LPI2C1_SCFGR1 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */
+#define IMX9_LPI2C1_SCFGR2 (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */
+#define IMX9_LPI2C1_SAMR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */
+#define IMX9_LPI2C1_SASR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */
+#define IMX9_LPI2C1_STAR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */
+#define IMX9_LPI2C1_STDR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */
+#define IMX9_LPI2C1_SRDR (IMX9_LPI2C1_BASE +
IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */
+
+/* LPI2C2 Registers */
+
+#define IMX9_LPI2C2_VERID (IMX9_LPI2C2_BASE +
IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */
+#define IMX9_LPI2C2_PARAM (IMX9_LPI2C2_BASE +
IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */
+#define IMX9_LPI2C2_MCR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */
+#define IMX9_LPI2C2_MSR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */
+#define IMX9_LPI2C2_MIER (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */
+#define IMX9_LPI2C2_MDER (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */
+#define IMX9_LPI2C2_MCFGR0 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */
+#define IMX9_LPI2C2_MCFGR1 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */
+#define IMX9_LPI2C2_MCFGR2 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */
+#define IMX9_LPI2C2_MCFGR3 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */
+#define IMX9_LPI2C2_MDMR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */
+#define IMX9_LPI2C2_MCCR0 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */
+#define IMX9_LPI2C2_MCCR1 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */
+#define IMX9_LPI2C2_MFCR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */
+#define IMX9_LPI2C2_MFSR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */
+#define IMX9_LPI2C2_MTDR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */
+#define IMX9_LPI2C2_MRDR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */
+#define IMX9_LPI2C2_SCR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */
+#define IMX9_LPI2C2_SSR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */
+#define IMX9_LPI2C2_SIER (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */
+#define IMX9_LPI2C2_SDER (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */
+#define IMX9_LPI2C2_SCFGR1 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */
+#define IMX9_LPI2C2_SCFGR2 (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */
+#define IMX9_LPI2C2_SAMR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */
+#define IMX9_LPI2C2_SASR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */
+#define IMX9_LPI2C2_STAR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */
+#define IMX9_LPI2C2_STDR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */
+#define IMX9_LPI2C2_SRDR (IMX9_LPI2C2_BASE +
IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */
+
+/* LPI2C3 Registers */
+
+#define IMX9_LPI2C3_VERID (IMX9_LPI2C3_BASE +
IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */
+#define IMX9_LPI2C3_PARAM (IMX9_LPI2C3_BASE +
IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */
+#define IMX9_LPI2C3_MCR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */
+#define IMX9_LPI2C3_MSR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */
+#define IMX9_LPI2C3_MIER (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */
+#define IMX9_LPI2C3_MDER (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */
+#define IMX9_LPI2C3_MCFGR0 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */
+#define IMX9_LPI2C3_MCFGR1 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */
+#define IMX9_LPI2C3_MCFGR2 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */
+#define IMX9_LPI2C3_MCFGR3 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */
+#define IMX9_LPI2C3_MDMR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */
+#define IMX9_LPI2C3_MCCR0 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */
+#define IMX9_LPI2C3_MCCR1 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */
+#define IMX9_LPI2C3_MFCR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */
+#define IMX9_LPI2C3_MFSR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */
+#define IMX9_LPI2C3_MTDR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */
+#define IMX9_LPI2C3_MRDR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */
+#define IMX9_LPI2C3_SCR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */
+#define IMX9_LPI2C3_SSR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */
+#define IMX9_LPI2C3_SIER (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */
+#define IMX9_LPI2C3_SDER (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */
+#define IMX9_LPI2C3_SCFGR1 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */
+#define IMX9_LPI2C3_SCFGR2 (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */
+#define IMX9_LPI2C3_SAMR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */
+#define IMX9_LPI2C3_SASR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */
+#define IMX9_LPI2C3_STAR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */
+#define IMX9_LPI2C3_STDR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */
+#define IMX9_LPI2C3_SRDR (IMX9_LPI2C3_BASE +
IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */
+
+/* LPI2C4 Registers */
+
+#define IMX9_LPI2C4_VERID (IMX9_LPI2C4_BASE +
IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */
+#define IMX9_LPI2C4_PARAM (IMX9_LPI2C4_BASE +
IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */
+#define IMX9_LPI2C4_MCR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */
+#define IMX9_LPI2C4_MSR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */
+#define IMX9_LPI2C4_MIER (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */
+#define IMX9_LPI2C4_MDER (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */
+#define IMX9_LPI2C4_MCFGR0 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */
+#define IMX9_LPI2C4_MCFGR1 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */
+#define IMX9_LPI2C4_MCFGR2 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */
+#define IMX9_LPI2C4_MCFGR3 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */
+#define IMX9_LPI2C4_MDMR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */
+#define IMX9_LPI2C4_MCCR0 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */
+#define IMX9_LPI2C4_MCCR1 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */
+#define IMX9_LPI2C4_MFCR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */
+#define IMX9_LPI2C4_MFSR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */
+#define IMX9_LPI2C4_MTDR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */
+#define IMX9_LPI2C4_MRDR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */
+#define IMX9_LPI2C4_SCR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */
+#define IMX9_LPI2C4_SSR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */
+#define IMX9_LPI2C4_SIER (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */
+#define IMX9_LPI2C4_SDER (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */
+#define IMX9_LPI2C4_SCFGR1 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */
+#define IMX9_LPI2C4_SCFGR2 (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */
+#define IMX9_LPI2C4_SAMR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */
+#define IMX9_LPI2C4_SASR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */
+#define IMX9_LPI2C4_STAR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */
+#define IMX9_LPI2C4_STDR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */
+#define IMX9_LPI2C4_SRDR (IMX9_LPI2C4_BASE +
IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */
+
+/* Register bit definitions *************************************************/
+
+/* LPI2C Version ID Register */
+
+#define LPI2C_VERID_FEATURE_SHIFT (0)
+#define LPI2C_VERID_FEATURE_MASK (0xffff <<
LPI2C_VERID_FEATURE_SHIFT)
+#define LPI2C_VERID_MINOR_SHIFT (16)
+#define LPI2C_VERID_MINOR_MASK (0xff << LPI2C_VERID_MINOR_SHIFT)
+#define LPI2C_VERID_MAJOR_SHIFT (24)
+#define LPI2C_VERID_MAJOR_MASK (0xff << LPI2C_VERID_MAJOR_SHIFT)
+
+/* LPI2C Parameter Register */
+
+#define LPI2C_PARAM_MTXFIFO_MASK (0x0f) /* Config number of words
in master transmit fifo to 2^MTXFIFO (pow(2,MTXFIFO )) */
+# define LPI2C_PARAM_MTXFIFO_1_WORDS (0)
+# define LPI2C_PARAM_MTXFIFO_2_WORDS (1)
+# define LPI2C_PARAM_MTXFIFO_4_WORDS (2)
+# define LPI2C_PARAM_MTXFIFO_8_WORDS (3)
+# define LPI2C_PARAM_MTXFIFO_16_WORDS (4)
+# define LPI2C_PARAM_MTXFIFO_32_WORDS (5)
+# define LPI2C_PARAM_MTXFIFO_64_WORDS (6)
+# define LPI2C_PARAM_MTXFIFO_128_WORDS (7)
+# define LPI2C_PARAM_MTXFIFO_256_WORDS (8)
+# define LPI2C_PARAM_MTXFIFO_512_WORDS (9)
+# define LPI2C_PARAM_MTXFIFO_1024_WORDS (10)
+# define LPI2C_PARAM_MTXFIFO_2048_WORDS (11)
+# define LPI2C_PARAM_MTXFIFO_4096_WORDS (12)
+# define LPI2C_PARAM_MTXFIFO_8192_WORDS (13)
+# define LPI2C_PARAM_MTXFIFO_16384_WORDS (14)
+# define LPI2C_PARAM_MTXFIFO_32768_WORDS (15)
+
+#define LPI2C_PARAM_MRXFIFO_SHIFT (8)
+#define LPI2C_PARAM_MRXFIFO_MASK (0x0f <<
LPI2C_PARAM_MRXFIFO_SHIFT) /* Config number of words in master receive fifo
2^MRXFIFO (pow(2,MTRFIFO )) */
+# define LPI2C_PARAM_MRXFIFO_1_WORDS (0 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_2_WORDS (1 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_4_WORDS (2 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_8_WORDS (3 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_16_WORDS (4 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_32_WORDS (5 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_64_WORDS (6 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_128_WORDS (7 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_256_WORDS (8 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_512_WORDS (9 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_1024_WORDS (10 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_2048_WORDS (11 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_4096_WORDS (12 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_8192_WORDS (13 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_16384_WORDS (14 << LPI2C_PARAM_MRXFIFO_SHIFT)
+# define LPI2C_PARAM_MRXFIFO_32768_WORDS (15 << LPI2C_PARAM_MRXFIFO_SHIFT)
+
+/* LPI2C Master Control Register */
+
+#define LPI2C_MCR_MEN (1 << 0) /* Master Enable Bit */
+#define LPI2C_MCR_RST (1 << 1) /* Software Reset Bit */
+#define LPI2C_MCR_DOZEN (1 << 2) /* Doze Mode Enable Bit
*/
+#define LPI2C_MCR_DBGEN (1 << 3) /* Debug Enable Bit */
+ /* Bits 7-4 Reserved */
+#define LPI2C_MCR_RTF (1 << 8) /* Reset Transmit FIFO
Bit */
+#define LPI2C_MCR_RRF (1 << 9) /* Reset Receive FIFO
Bit */
+ /* Bits 31-10 Reserved */
+
+/* LPI2C Master Status Register */
+
+#define LPI2C_MSR_TDF (1 << 0) /* Transmit Data Flag
Bit */
+#define LPI2C_MSR_RDF (1 << 1) /* Receive Data Flag Bit
*/
+ /* Bits 7-2 Reserved */
+#define LPI2C_MSR_EPF (1 << 8) /* End Packet Flag Bit */
+#define LPI2C_MSR_SDF (1 << 9) /* STOP Detect Flag Bit
*/
+#define LPI2C_MSR_NDF (1 << 10) /* NACK Detect Flag Bit
*/
+#define LPI2C_MSR_ALF (1 << 11) /* Arbitration Lost Flag
Bit */
+#define LPI2C_MSR_FEF (1 << 12) /* FIFO Error Flag Bit */
+#define LPI2C_MSR_PLTF (1 << 13) /* Pin Low Timeout Flag
Bit */
+#define LPI2C_MSR_DMF (1 << 14) /* Data Match Flag Bit */
+ /* Bits 23-15 Reserved */
+#define LPI2C_MSR_MBF (1 << 24) /* Master Busy Flag Bit
*/
+#define LPI2C_MSR_BBF (1 << 25) /* Bus Busy Flag Bit */
+ /* Bits 31-26 Reserved */
+#define LPI2C_MSR_ERROR_MASK (LPI2C_MSR_NDF | LPI2C_MSR_ALF | \
+ LPI2C_MSR_FEF)
+
+/* LPI2C Master Interrupt Enable Register */
+
+#define LPI2C_MIER_TDIE (1 << 0) /* Transmit Data
Interrupt Enable Bit */
+#define LPI2C_MIER_RDIE (1 << 1) /* Receive Data
Interrupt Enable Bit */
+ /* Bits 7-2 Reserved */
+#define LPI2C_MIER_EPIE (1 << 8) /* End Packet Interrupt
Enable Bit */
+#define LPI2C_MIER_SDIE (1 << 9) /* STOP Detect Interrupt
Enable Bit */
+#define LPI2C_MIER_NDIE (1 << 10) /* NACK Detect Interrupt
Enable Bit */
+#define LPI2C_MIER_ALIE (1 << 11) /* Arbitration Lost
Interrupt Enable Bit */
+#define LPI2C_MIER_FEIE (1 << 12) /* FIFO Error Interrupt
Enable Bit */
+#define LPI2C_MIER_PLTIE (1 << 13) /* Pin Low Timeout
Interrupt Enable Bit */
+#define LPI2C_MIER_DMIE (1 << 14) /* Data Match Interrupt
Enable Bit */
+ /* Bits 31-15 Reserved */
+
+/* LPI2C Master DMA Enable Register */
+
+#define LPI2C_MDER_TDDE (1 << 0) /* Transmit Data DMA
Enable Bit */
+#define LPI2C_MDER_RDDE (1 << 1) /* Transmit Data DMA
Enable Bit */
+ /* Bits 31-2 Reserved */
+
+/* LPI2C Master Config Register 0 */
+
+#define LPI2C_MCFG0_HREN (1 << 0) /* Host Request Enable
Bit */
+#define LPI2C_MCFG0_HRPOL (1 << 1) /* Host Request Polarity
Bit */
+#define LPI2C_MCFG0_HRSEL (1 << 2) /* Host Request Select
Bit */
+ /* Bits 7-3 Reserved */
+#define LPI2C_MCFG0_CIRFIFO (1 << 8) /* Circular FIFO Enable
Bit */
+#define LPI2C_MCFG0_RDMO (1 << 9) /* Receive Data Match
Only Bit */
+ /* Bits 31-10 Reserved */
+
+/* LPI2C Master Config Register 1 */
+
+#define LPI2C_MCFGR1_PRESCALE_MASK (7 << 0) /* Clock Prescaler Bit
Mask */
+#define LPI2C_MCFGR1_PRESCALE(n) ((n) & LPI2C_MCFGR1_PRESCALE_MASK)
+# define LPI2C_MCFGR1_PRESCALE_1 (0)
+# define LPI2C_MCFGR1_PRESCALE_2 (1)
+# define LPI2C_MCFGR1_PRESCALE_4 (2)
+# define LPI2C_MCFGR1_PRESCALE_8 (3)
+# define LPI2C_MCFGR1_PRESCALE_16 (4)
+# define LPI2C_MCFGR1_PRESCALE_32 (5)
+# define LPI2C_MCFGR1_PRESCALE_64 (6)
+# define LPI2C_MCFGR1_PRESCALE_128 (7)
+#define LPI2C_MCFGR1_AUTOSTOP (1 << 8) /* Automatic STOP
Generation Bit */
+#define LPI2C_MCFGR1_IGNACK (1 << 9) /* Ignore NACK Bit */
+#define LPI2C_MCFGR1_TIMECFG (1 << 10) /* Timeout
Configuration Bit */
+ /* Bits 15-11 Reserved
*/
+#define LPI2C_MCFGR1_MATCFG_SHIFT (16)
+#define LPI2C_MCFGR1_MATCFG_MASK (7 << LPI2C_MCFGR1_MATCFG_SHIFT)
/* Match Configuration Bit Mask */
+#define LPI2C_MCFGR1_MATCFG(n) (((n) <<
LPI2C_MCFGR1_MATCFG_SHIFT) & LPI2C_MCFGR1_MATCFG_MASK)
+# define LPI2C_MCFGR1_MATCFG_DISABLE (0 << LPI2C_MCFGR1_MATCFG_SHIFT)
+ /* LPI2C_MCFG1_MATCFG =
001b Reserved */
+# define LPI2C_MCFGR1_MATCFG2 (2 << LPI2C_MCFGR1_MATCFG_SHIFT)
+# define LPI2C_MCFGR1_MATCFG3 (3 << LPI2C_MCFGR1_MATCFG_SHIFT)
+# define LPI2C_MCFGR1_MATCFG4 (4 << LPI2C_MCFGR1_MATCFG_SHIFT)
+# define LPI2C_MCFGR1_MATCFG5 (5 << LPI2C_MCFGR1_MATCFG_SHIFT)
+# define LPI2C_MCFGR1_MATCFG6 (6 << LPI2C_MCFGR1_MATCFG_SHIFT)
+# define LPI2C_MCFGR1_MATCFG7 (7 << LPI2C_MCFGR1_MATCFG_SHIFT)
+ /* Bits 23-19 Reserved */
+#define LPI2C_MCFGR1_PINCFG_SHIFT (24)
+#define LPI2C_MCFGR1_PINCFG_MASK (7 << LPI2C_MCFGR1_PINCFG_SHIFT)
/* Pin Configuration Bit Mask */
+#define LPI2C_MCFGR1_PINCFG(n) (((n) <<
LPI2C_MCFGR1_PINCFG_SHIFT) & LPI2C_MCFGR1_PINCFG_MASK)
+# define LPI2C_MCFGR1_PINCFG0 (0 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG1 (1 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG2 (2 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG3 (3 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG4 (4 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG5 (5 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG6 (6 << LPI2C_MCFGR1_PINCFG_SHIFT)
+# define LPI2C_MCFGR1_PINCFG7 (7 << LPI2C_MCFGR1_PINCFG_SHIFT)
+ /* Bits 31-27 Reserved */
+
+/* LPI2C Master Config Register 2 */
+
+#define LPI2C_MCFG2_BUSIDLE_MASK (0xfff << 0) /* Bus Idle Timeout
Period in Clock Cycles */
+#define LPI2C_MCFG2_BUSIDLE_DISABLE (0)
+#define LPI2C_MCFG2_BUSIDLE(n) ((n) & LPI2C_MCFG2_BUSIDLE_MASK)
+ /* Bits 15-12 Reserved */
+#define LPI2C_MCFG2_FILTSCL_SHIFT (16)
+#define LPI2C_MCFG2_FILTSCL_MASK (15 << LPI2C_MCFG2_FILTSCL_SHIFT)
/* Glitch Filter SCL */
+#define LPI2C_MCFG2_FILTSCL_DISABLE (0 << LPI2C_MCFG2_FILTSCL_SHIFT)
+#define LPI2C_MCFG2_FILTSCL_CYCLES(n) (((n) <<
LPI2C_MCFG2_FILTSCL_SHIFT) & LPI2C_MCFG2_FILTSCL_MASK)
+ /* Bits 23-20 Reserved */
+#define LPI2C_MCFG2_FILTSDA_SHIFT (24)
+#define LPI2C_MCFG2_FILTSDA_MASK (15 << LPI2C_MCFG2_FILTSDA_SHIFT)
/* Glitch Filter SDA */
+#define LPI2C_MCFG2_FILTSDA_DISABLE (0 << LPI2C_MCFG2_FILTSDA_SHIFT)
+#define LPI2C_MCFG2_FILTSDA_CYCLES(n) (((n) <<
LPI2C_MCFG2_FILTSDA_SHIFT) & LPI2C_MCFG2_FILTSDA_MASK)
+ /* Bits 31-28 Reserved */
+
+/* LPI2C Master Config Register 3 */
+
+ /* Bits 7-0 Reserved */
+#define LPI2C_MCFG3_PINLOW_SHIFT (8)
+#define LPI2C_MCFG3_PINLOW_MASK (0xfff <<
LPI2C_MCFG3_PINLOW_SHIFT) /* Configure The Pin Low Timeout in Clock Cycles */
+#define LPI2C_MCFG3_PINLOW_CYCLES(n) (((n) << LPI2C_MCFG3_PINLOW_SHIFT)
& LPI2C_MCFG3_PINLOW_MASK)
+ /* Bits 31-20 Reserved */
+
+/* LPI2C Master Data Match Register */
+
+#define LPI2C_MDMR_MATCH0_SHIFT (0)
+#define LPI2C_MDMR_MATCH0_MASK (0xff << LPI2C_MDMR_MATCH0_SHIFT)
/* Match 0 Value */
+#define LPI2C_MDMR_MATCH0(n) (((n) << LPI2C_MDMR_MATCH0_SHIFT)
& LPI2C_MDMR_MATCH0_MASK)
+ /* Bits 15-8 Reserved */
+#define LPI2C_MDMR_MATCH1_SHIFT (16)
+#define LPI2C_MDMR_MATCH1_MASK (0xff << LPI2C_MDMR_MATCH1_SHIFT)
/* Match 1 Value */
+#define LPI2C_MDMR_MATCH1(n) (((n) << LPI2C_MDMR_MATCH1_SHIFT)
& LPI2C_MDMR_MATCH1_MASK)
+ /* Bits 31-24 Reserved */
+
+/* LPI2C Master Clock Configuration Register 0 */
+
+#define LPI2C_MCCR0_CLKLO_SHIFT (0)
+#define LPI2C_MCCR0_CLKLO_MASK (0x3f << LPI2C_MCCR0_CLKLO_SHIFT)
/* Clock Low Period */
+#define LPI2C_MCCR0_CLKLO(n) (((n) << LPI2C_MCCR0_CLKLO_SHIFT)
& LPI2C_MCCR0_CLKLO_MASK)
+ /* Bits 7-6 Reserved */
+#define LPI2C_MCCR0_CLKHI_SHIFT (8)
+#define LPI2C_MCCR0_CLKHI_MASK (0x3f << LPI2C_MCCR0_CLKHI_SHIFT)
/* Clock High Period */
+#define LPI2C_MCCR0_CLKHI(n) (((n) << LPI2C_MCCR0_CLKHI_SHIFT)
& LPI2C_MCCR0_CLKHI_MASK)
+ /* Bits 15-14 Reserved */
+#define LPI2C_MCCR0_SETHOLD_SHIFT (16)
+#define LPI2C_MCCR0_SETHOLD_MASK (0x3f <<
LPI2C_MCCR0_SETHOLD_SHIFT) /* Setup Hold Delay */
+#define LPI2C_MCCR0_SETHOLD(n) (((n) <<
LPI2C_MCCR0_SETHOLD_SHIFT) & LPI2C_MCCR0_SETHOLD_MASK)
+ /* Bits 23-22 Reserved */
+#define LPI2C_MCCR0_DATAVD_SHIFT (24)
+#define LPI2C_MCCR0_DATAVD_MASK (0x3f << LPI2C_MCCR0_DATAVD_SHIFT)
/* Setup Hold Delay */
+#define LPI2C_MCCR0_DATAVD(n) (((n) << LPI2C_MCCR0_DATAVD_SHIFT)
& LPI2C_MCCR0_DATAVD_MASK)
+ /* Bits 31-30 Reserved */
+
+/* LPI2C Master Clock Configuration Register 1 */
+
+#define LPI2C_MCCR1_CLKLO_SHIFT (0)
+#define LPI2C_MCCR1_CLKLO_MASK (0x3f << LPI2C_MCCR1_CLKLO_SHIFT)
/* Clock Low Period */
+#define LPI2C_MCCR1_CLKLO(n) (((n) << LPI2C_MCCR1_CLKLO_SHIFT)
& LPI2C_MCCR1_CLKLO_MASK)
+ /* Bits 7-6 Reserved */
+#define LPI2C_MCCR1_CLKHI_SHIFT (8)
+#define LPI2C_MCCR1_CLKHI_MASK (0x3f << LPI2C_MCCR1_CLKHI_SHIFT)
/* Clock High Period */
+#define LPI2C_MCCR1_CLKHI(n) (((n) << LPI2C_MCCR1_CLKHI_SHIFT)
& LPI2C_MCCR1_CLKHI_MASK)
+ /* Bits 15-14 Reserved */
+#define LPI2C_MCCR1_SETHOLD_SHIFT (16)
+#define LPI2C_MCCR1_SETHOLD_MASK (0x3f <<
LPI2C_MCCR1_SETHOLD_SHIFT) /* Setup Hold Delay */
+#define LPI2C_MCCR1_SETHOLD(n) (((n) <<
LPI2C_MCCR1_SETHOLD_SHIFT) & LPI2C_MCCR1_SETHOLD_MASK)
+
+ /* Bits 23-22 Reserved */
+#define LPI2C_MCCR1_DATAVD_SHIFT (24)
+#define LPI2C_MCCR1_DATAVD_MASK (0x3f << LPI2C_MCCR1_DATAVD_SHIFT)
/* Setup Hold Delay */
+#define LPI2C_MCCR1_DATAVD(n) (((n) << LPI2C_MCCR1_DATAVD_SHIFT)
& LPI2C_MCCR1_DATAVD_MASK)
+
+ /* Bits 31-30 Reserved */
+
+/* LPI2C Master FIFO Control Register */
+
+#define LPI2C_MFCR_TXWATER_SHIFT (0)
+#define LPI2C_MFCR_TXWATER_MASK (3 << LPI2C_MFCR_TXWATER_SHIFT)
/* Transmit FIFO Watermark*/
+
+#define LPI2C_MFCR_TXWATER(n) (((n) << LPI2C_MFCR_TXWATER_SHIFT)
& LPI2C_MFCR_TXWATER_MASK) /* Transmit FIFO Watermark */
+
+ /* Bits 15-2 Reserved */
+#define LPI2C_MFCR_RXWATER_SHIFT (16)
+#define LPI2C_MFCR_RXWATER_MASK (3 << LPI2C_MFCR_RXWATER_SHIFT)
/* Receive FIFO Watermark */
+
+#define LPI2C_MFCR_RXWATER(n) (((n) << LPI2C_MFCR_RXWATER_SHIFT)
& LPI2C_MFCR_RXWATER_MASK) /* Transmit FIFO Watermark */
+
+ /* Bits 31-18 Reserved */
+
+/* LPI2C Master FIFO Status Register */
+
+#define LPI2C_MFSR_TXCOUNT_SHIFT (0)
+#define LPI2C_MFSR_TXCOUNT_MASK (3 << LPI2C_MFSR_TXCOUNT_SHIFT)
/* Transmit FIFO Count */
+
+ /* Bits 15-2 Reserved */
+#define LPI2C_MFSR_RXCOUNT_SHIFT (16)
+#define LPI2C_MFSR_RXCOUNT_MASK (3 << LPI2C_MFSR_RXCOUNT_SHIFT)
/* Receive FIFO Count */
+
+ /* Bits 31-18 Reserved */
+
+/* LPI2C Master Transmit Data Register */
+
+#define LPI2C_MTDR_DATA_SHIFT (0)
+#define LPI2C_MTDR_DATA_MASK (0xff << LPI2C_MTDR_DATA_SHIFT)
/* Transmit Data */
+#define LPI2C_MTDR_DATA(n) ((n) & LPI2C_MTDR_DATA_MASK)
+#define LPI2C_MTDR_CMD_SHIFT (8)
+#define LPI2C_MTDR_CMD_MASK (7 << LPI2C_MTDR_CMD_SHIFT) /*
Command Data */
+#define LPI2C_MTDR_CMD(n) (((n) << LPI2C_MTDR_CMD_SHIFT) &
LPI2C_MTDR_CMD_MASK)
+# define LPI2C_MTDR_CMD_TXD (0 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_RXD (1 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_STOP (2 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_RXD_DISC (3 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_START (4 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_START_NACK (5 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_START_HI (6 << LPI2C_MTDR_CMD_SHIFT)
+# define LPI2C_MTDR_CMD_START_HI_NACK (7 << LPI2C_MTDR_CMD_SHIFT)
+
+ /* Bits 31-11 Reserved */
+
+/* LPI2C Master Receive Data Register */
+
+#define LPI2C_MRDR_DATA_SHIFT (0)
+#define LPI2C_MRDR_DATA_MASK (0xff << LPI2C_MRDR_DATA_SHIFT)
/* Receive Data */
+
+ /* Bits 13-8 Reserved */
+#define LPI2C_MRDR_RXEMPTY_SHIFT (14)
+#define LPI2C_MRDR_RXEMPTY_MASK (1 << LPI2C_MRDR_RXEMPTY_SHIFT)
/* Rx Empty */
+
+ /* Bits 31-15 Reserved */
+
+/* LPI2C Slave Control Register */
+
+#define LPI2C_SCR_SEN (1 << 0) /* Slave Enable Bit */
+#define LPI2C_SCR_RST (1 << 1) /* Software Reset Bit */
+ /* Bits 3-2 Reserved */
+#define LPI2C_SCR_FILTEN (1 << 4) /* Filter Enable Bit */
+#define LPI2C_SCR_FILTDZ (1 << 5) /* Filter Doze Enable
Bit */
+ /* Bits 7-4 Reserved */
+#define LPI2C_SCR_RTF (1 << 8) /* Reset Transmit FIFO
Bit */
+#define LPI2C_SCR_RRF (1 << 9) /* Reset Receive FIFO
Bit */
+ /* Bits 31-10 Reserved */
+
+/* LPI2C Slave Status Register */
+
+#define LPI2C_SSR_TDF (1 << 0) /* Transmit Data Flag
Bit */
+#define LPI2C_SSR_RDF (1 << 1) /* Receive Data Flag Bit
*/
+#define LPI2C_SSR_AVF (1 << 2) /* Address Valid Flag
Bit */
+#define LPI2C_SSR_TAF (1 << 3) /* Transmit ACK Flag Bit
*/
+ /* Bits 7-4 Reserved */
+#define LPI2C_SSR_RSF (1 << 8) /* Repeated Start Flag
Bit */
+#define LPI2C_SSR_SDF (1 << 9) /* STOP Detect Flag Bit
*/
+#define LPI2C_SSR_BEF (1 << 10) /* Bit Error Flag Bit */
+#define LPI2C_SSR_FEF (1 << 11) /* FIFO Error Flag Bit */
+#define LPI2C_SSR_AM0F (1 << 12) /* Address Match 0 Flag
Bit */
+#define LPI2C_SSR_AM1F (1 << 13) /* Address Match 1 Flag
Bit */
+#define LPI2C_SSR_GCF (1 << 14) /* General Call Flag Bit
*/
+#define LPI2C_SSR_SARF (1 << 15) /* SMBus Alert Response
Flag Bit */
+ /* Bits 23-16 Reserved */
+#define LPI2C_MSR_SBF (1 << 24) /* Slave Busy Flag Bit */
+#define LPI2C_MSR_BBF (1 << 25) /* Bus Busy Flag Bit */
+ /* Bits 31-26 Reserved */
+
+/* LPI2C Slave Interrupt Enable Register */
+
+#define LPI2C_SIER_TDIE (1 << 0) /* Transmit Data
Interrupt Enable Bit */
+#define LPI2C_SIER_RDIE (1 << 1) /* Receive Data
Interrupt Enable Bit */
+#define LPI2C_SIER_AVIE (1 << 2) /* Address Valid
Interrupt Enable Bit */
+#define LPI2C_SIER_TAIE (1 << 3) /* Transmit ACK
Interrupt Enable Bit */
+ /* Bits 7-4 Reserved */
+#define LPI2C_SIER_RSIE (1 << 8) /* Repeated Start
Interrupt Enable Bit */
+#define LPI2C_SIER_SDIE (1 << 9) /* STOP Detect Interrupt
Enable Bit */
+#define LPI2C_SIER_BEIE (1 << 10) /* Bit Error Interrupt
Enable Bit */
+#define LPI2C_SIER_FEIE (1 << 11) /* FIFO Error Interrupt
Enable Bit */
+#define LPI2C_SIER_AM0IE (1 << 12) /* Address Match 0
Interrupt Enable Bit */
+#define LPI2C_SIER_AM1IE (1 << 13) /* Address Match 1
Interrupt Enable Bit */
+#define LPI2C_SIER_GCIE (1 << 14) /* General Call
Interrupt Enable Bit */
+#define LPI2C_SIER_SARIE (1 << 15) /* SMBus Alert Response
Interrupt Enable Bit */
+ /* Bits 31-16 Reserved */
+
+/* LPI2C Slave DMA Enable Register */
+
+#define LPI2C_SDER_TDDE (1 << 0) /* Transmit Data DMA
Enable Bit */
+#define LPI2C_SDER_RDDE (1 << 1) /* Transmit Data DMA
Enable Bit */
+#define LPI2C_SDER_AVDE (1 << 2) /* Address Valid DMA
Enable Bit */
+ /* Bits 31-3 Reserved */
+
+/* LPI2C Slave Configuration Register 1 */
+
+#define LPI2C_SCFGR1_ADRSTALL (1 << 0) /* Address SCL Stall */
+#define LPI2C_SCFGR1_RXSTALL (1 << 1) /* RX SCL Stall */
+#define LPI2C_SCFGR1_TXSTALL (1 << 2) /* TX Data SCL Stall */
+#define LPI2C_SCFGR1_ACKSTALL (1 << 3) /* ACK SCL Stall */
+ /* Bits 7-4 Reserved */
+#define LPI2C_SCFGR1_GCEN (1 << 8) /* General Call Enable */
+#define LPI2C_SCFGR1_SAEN (1 << 9) /* SMBus Alert Enable */
+#define LPI2C_SCFGR1_TXCFG (1 << 10) /* Transmit Flag
Configuration */
+#define LPI2C_SCFGR1_RXCFG (1 << 11) /* Receive Data
Configuration */
+#define LPI2C_SCFGR1_IFNACK (1 << 12) /* Ignore NACK */
+#define LPI2C_SCFGR1_HSMEN (1 << 13) /* High Speed Mode
Enable */
+ /* Bits 15-14 Reserved */
+#define LPI2C_SCFG1_ADDRCFG_SHIFT (16)
+#define LPI2C_SCFG1_ADDRCFG_MASK (7 << LPI2C_SCFG1_ADDRCFG_SHIFT)
/* Address Configuration Bit Mask */
+#define LPI2C_SCFG1_ADDRCFG(n) (((n) <<
LPI2C_SCFG1_ADDRCFG_SHIFT) & LPI2C_SCFG1_ADDRCFG_MASK)
+# define LPI2C_SCFG1_ADDRCFG0 (0 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG1 (2 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG2 (2 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG3 (3 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG4 (4 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG5 (5 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG6 (6 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+# define LPI2C_SCFG1_ADDRCFG7 (7 << LPI2C_SCFG1_ADDRCFG_SHIFT)
+ /* Bits 31-19 Reserved */
+
+/* LPI2C Slave Configuration Register 2 */
+
+#define LPI2C_SCFG2_CLKHOLD_MASK (15 << 0) /* Clock Hold Time */
+#define LPI2C_SCFG2_CLKHOLD(n) ((n) & LPI2C_SCFG2_CLKHOLD_MASK)
+ /* Bits 7-4 Reserved */
+#define LPI2C_SCFG2_DATAVD_SHIFT (8)
+#define LPI2C_SCFG2_DATAVD_MASK (0x3f << LPI2C_SCFG2_DATAVD_SHIFT)
/* Data Valid Delay */
+#define LPI2C_SCFG2_DATAVD(n) (((n) << LPI2C_SCFG2_DATAVD_SHIFT)
& LPI2C_SCFG2_DATAVD_MASK)
+ /* Bits 15-14 Reserved */
+#define LPI2C_SCFG2_FILTSCL_SHIFT (16)
+#define LPI2C_SCFG2_FILTSCL_MASK (15 << LPI2C_SCFG2_FILTSCL_SHIFT)
/* Glitch Filter SCL */
+#define LPI2C_SCFG2_FILTSCL_DISABLE (0 << LPI2C_SCFG2_FILTSCL_SHIFT)
+#define LPI2C_SCFG2_FILTSCL_CYCLES(n) (((n) <<
LPI2C_SCFG2_FILTSCL_SHIFT) & LPI2C_SCFG2_FILTSCL_MASK)
+ /* Bits 23-20 Reserved */
+#define LPI2C_SCFG2_FILTSDA_SHIFT (24)
+#define LPI2C_SCFG2_FILTSDA_MASK (15 << LPI2C_SCFG2_FILTSDA_SHIFT)
/* Glitch Filter SDA */
+#define LPI2C_SCFG2_FILTSDA_DISABLE (0 << LPI2C_SCFG2_FILTSDA_SHIFT)
+#define LPI2C_SCFG2_FILTSDA_CYCLES(n) (((n) <<
LPI2C_SCFG2_FILTSDA_SHIFT) & LPI2C_SCFG2_FILTSDA_MASK)
+ /* Bits 31-28 Reserved */
+
+/* LPI2C Slave Address Match Register */
+
+ /* Bit 0 Reserved */
+#define LPI2C_SAMR_ADDR0_SHIFT (1)
+#define LPI2C_SAMR_ADDR0_MASK (0x3ff << LPI2C_SAMR_ADDR0_SHIFT)
/* Address 0 Value */
+#define LPI2C_SAMR_ADDR0(n) (((n) << LPI2C_SAMR_ADDR0_SHIFT) &
LPI2C_SAMR_ADDR0_MASK)
+ /* Bits 16-11 Reserved */
+#define LPI2C_SAMR_ADDR1_SHIFT (17)
+#define LPI2C_SAMR_ADDR1_MASK (0x3ff << LPI2C_SAMR_ADDR1_SHIFT)
/* Address 1 Value */
+#define LPI2C_SAMR_ADDR1(n) (((n) << LPI2C_SAMR_ADDR1_SHIFT) &
LPI2C_SAMR_ADDR1_MASK)
+ /* Bits 31-27 Reserved */
+
+/* LPI2C Slave Address Status Register */
+
+#define LPI2C_SASR_RADDR_MASK (0x7ff << 0) /* Received Address */
+
+/* Bits 16-11
+ * Reserved
+ */
+
+#define LPI2C_SASR_ANV (1 << 14) /* Address Not Valid */
+ /* Bits 31-15 Reserved */
+
+/* LPI2C Slave Transmit ACK Register */
+
+#define LPI2C_STAR_TXNACK (1 << 0) /* Transmit NACK */
+ /* Bits 31-1 Reserved */
+
+/* LPI2C Slave Transmit Data Register */
+
+#define LPI2C_STDR_DATA_SHIFT (0)
+#define LPI2C_STDR_DATA_MASK (0xff << LPI2C_STDR_DATA_SHIFT)
/* Transmit Data */
+#define LPI2C_STDR_DATA(n) (((n) << LPI2C_STDR_DATA_SHIFT) &
LPI2C_STDR_DATA_MASK)
+ /* Bits 31-8 Reserved */
+
+/* LPI2C Slave Receive Data Register */
+
+#define LPI2C_SRDR_DATA_SHIFT (0)
+#define LPI2C_SRDR_DATA_MASK (0xff << LPI2C_SRDR_DATA_SHIFT)
/* Receive Data */
+#define LPI2C_SRDR_DATA(n) (((n) << LPI2C_SRDR_DATA_SHIFT) &
LPI2C_SRDR_DATA_MASK)
+ /* Bits 13-8 Reserved */
+#define LPI2C_STAR_SOF (1 << 14) /* RX Empty */
+#define LPI2C_STAR_RXEMPTY (1 << 15) /* Start Of Frame */
+ /* Bits 31-16 Reserved */
+
+#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPI2C_H_ */
diff --git a/arch/arm64/src/imx9/imx9_lpi2c.c b/arch/arm64/src/imx9/imx9_lpi2c.c
new file mode 100644
index 0000000000..c1122b1ddc
--- /dev/null
+++ b/arch/arm64/src/imx9/imx9_lpi2c.c
@@ -0,0 +1,2579 @@
+/****************************************************************************
+ * arch/arm64/src/imx9/imx9_lpi2c.c
+ *
+ * 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 <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+
+#include "arm64_internal.h"
+#include "imx9_ccm.h"
+#include "imx9_clockconfig.h"
+#include "imx9_gpio.h"
+#include "imx9_iomuxc.h"
+#include "imx9_lpi2c.h"
+
+#include "hardware/imx9_ccm.h"
+#include "hardware/imx9_pinmux.h"
+#include "hardware/imx9_lpi2c.h"
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+# include "chip.h"
+# include "imx9_edma.h"
+# include "hardware/imx9_dmamux.h"
+#endif
+
+/* At least one I2C peripheral must be enabled */
+
+#ifdef CONFIG_IMX9_LPI2C
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used.
+ * Instead, CPU-intensive polling will be used.
+ */
+
+/* Interrupt wait timeout in seconds and milliseconds */
+
+#if !defined(CONFIG_IMX9_LPI2C_TIMEOSEC) && \
+ !defined(CONFIG_IMX9_LPI2C_TIMEOMS)
+# define CONFIG_IMX9_LPI2C_TIMEOSEC 0
+# define CONFIG_IMX9_LPI2C_TIMEOMS 500 /* Default is 500 milliseconds */
+#elif !defined(CONFIG_IMX9_LPI2C_TIMEOSEC)
+# define CONFIG_IMX9_LPI2C_TIMEOSEC 0 /* User provided milliseconds */
+#elif !defined(CONFIG_IMX9_LPI2C_TIMEOMS)
+# define CONFIG_IMX9_LPI2C_TIMEOMS 0 /* User provided seconds */
+#endif
+
+/* Interrupt wait time timeout in system timer ticks */
+
+#ifndef CONFIG_IMX9_LPI2C_TIMEOTICKS
+# define CONFIG_IMX9_LPI2C_TIMEOTICKS \
+ (SEC2TICK(CONFIG_IMX9_LPI2C_TIMEOSEC) + \
+ MSEC2TICK(CONFIG_IMX9_LPI2C_TIMEOMS))
+#endif
+
+#ifndef CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP
+# define CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP \
+ TICK2USEC(CONFIG_IMX9_LPI2C_TIMEOTICKS)
+#endif
+
+/* Debug ********************************************************************/
+
+/* I2C event trace logic. NOTE: trace uses the internal, non-standard,
+ * low-level debug interface syslog() but does not require that any other
+ * debug is enabled.
+ */
+
+#ifndef CONFIG_I2C_TRACE
+# define imx9_lpi2c_tracereset(p)
+# define imx9_lpi2c_tracenew(p,s)
+# define imx9_lpi2c_traceevent(p,e,a)
+# define imx9_lpi2c_tracedump(p)
+#endif
+
+#ifndef CONFIG_I2C_NTRACE
+# define CONFIG_I2C_NTRACE 32
+#endif
+
+#ifdef CONFIG_I2C_SLAVE
+# error I2C slave logic is not supported yet for IMX9
+#endif
+
+#define LPI2C_MASTER 1
+#define LPI2C_SLAVE 2
+
+#define LPI2C_MSR_LIMITED_ERROR_MASK (LPI2C_MSR_ERROR_MASK & ~(LPI2C_MSR_FEF))
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Interrupt state */
+
+enum imx9_intstate_e
+{
+ INTSTATE_IDLE = 0, /* No I2C activity */
+ INTSTATE_WAITING, /* Waiting for completion of interrupt activity */
+ INTSTATE_DONE, /* Interrupt activity complete */
+};
+
+/* Trace events */
+
+enum imx9_trace_e
+{
+ I2CEVENT_NONE = 0, /* No events have occurred with this status */
+ I2CEVENT_SENDADDR, /* Start/Master bit set and address sent, param =
msgc */
+ I2CEVENT_SENDBYTE, /* Send byte, param = dcnt */
+ I2CEVENT_RCVBYTE, /* Read more dta, param = dcnt */
+ I2CEVENT_NOSTART, /* BTF on last byte with no restart, param = msgc */
+ I2CEVENT_STARTRESTART, /* Last byte sent, re-starting, param = msgc */
+ I2CEVENT_STOP, /* Last byte sten, send stop, param = 0 */
+ I2CEVENT_ERROR /* Error occurred, param = 0 */
+};
+
+/* Trace data */
+
+struct imx9_trace_s
+{
+ uint32_t status; /* I2C 32-bit SR2|SR1 status */
+ uint32_t count; /* Interrupt count when status change */
+ enum imx9_intstate_e event; /* Last event that occurred with this status */
+ uint32_t parm; /* Parameter associated with the event */
+ clock_t time; /* First of event or first status */
+};
+
+/* I2C Device hardware configuration */
+
+struct imx9_lpi2c_config_s
+{
+ uint32_t base; /* LPI2C base address */
+ uint8_t clk_root; /* LPI2C clock root */
+ uint8_t clk_gate; /* LPI2C clock gate */
+ uint16_t busy_idle; /* LPI2C Bus Idle Timeout */
+ uint8_t filtscl; /* Glitch Filter for SCL pin */
+ uint8_t filtsda; /* Glitch Filter for SDA pin */
+ iomux_cfg_t scl_pin; /* Peripheral configuration for SCL as SCL */
+ iomux_cfg_t sda_pin; /* Peripheral configuration for SDA as SDA */
+#if defined(CONFIG_I2C_RESET)
+ gpio_pinset_t reset_scl_pin; /* GPIO configuration for SCL as GPIO */
+ gpio_pinset_t reset_sda_pin; /* GPIO configuration for SDA as GPIO */
+#endif
+ uint8_t mode; /* Master or Slave mode */
+#ifndef CONFIG_I2C_POLLED
+ uint32_t irq; /* Event IRQ */
+#endif
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ uint32_t dma_rxreqsrc; /* DMA mux rx source */
+ uint32_t dma_txreqsrc; /* DMA mux tx source */
+#endif
+};
+
+/* I2C Device Private Data */
+
+struct imx9_lpi2c_priv_s
+{
+ /* Standard I2C operations */
+
+ const struct i2c_ops_s *ops;
+
+ /* Port configuration */
+
+ const struct imx9_lpi2c_config_s *config;
+
+ int refs; /* Reference count */
+ mutex_t lock; /* Mutual exclusion mutex */
+#ifndef CONFIG_I2C_POLLED
+ sem_t sem_isr; /* Interrupt wait semaphore */
+#endif
+ volatile uint8_t intstate; /* Interrupt handshake (see enum
imx9_intstate_e) */
+
+ uint8_t msgc; /* Message count */
+ struct i2c_msg_s *msgv; /* Message list */
+ uint8_t *ptr; /* Current message buffer */
+ uint32_t frequency; /* Current I2C frequency */
+ int dcnt; /* Current message length */
+ uint16_t flags; /* Current message flags */
+
+ /* I2C trace support */
+
+#ifdef CONFIG_I2C_TRACE
+ int tndx; /* Trace array index */
+ clock_t start_time; /* Time when the trace was started */
+
+ /* The actual trace data */
+
+ struct imx9_trace_s trace[CONFIG_I2C_NTRACE];
+#endif
+
+ uint32_t status; /* End of transfer SR2|SR1 status */
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ DMACH_HANDLE rxdma; /* rx DMA handle */
+ DMACH_HANDLE txdma; /* tx DMA handle */
+ uint16_t cmnds[CONFIG_IMX9_LPI2C_DMA_MAXMSG]; /* Commands */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline uint32_t
+imx9_lpi2c_getreg(struct imx9_lpi2c_priv_s *priv, uint16_t offset);
+static inline void imx9_lpi2c_putreg(struct imx9_lpi2c_priv_s *priv,
+ uint16_t offset, uint32_t value);
+static inline void imx9_lpi2c_modifyreg(struct imx9_lpi2c_priv_s *priv,
+ uint16_t offset, uint32_t clearbits,
+ uint32_t setbits);
+
+#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO
+static uint32_t imx9_lpi2c_toticks(int msgc, struct i2c_msg_s *msgs);
+#endif /* CONFIG_IMX9_LPI2C_DYNTIMEO */
+
+static inline int
+imx9_lpi2c_sem_waitdone(struct imx9_lpi2c_priv_s *priv);
+
+#ifdef CONFIG_I2C_TRACE
+static void imx9_lpi2c_tracereset(struct imx9_lpi2c_priv_s *priv);
+static void imx9_lpi2c_tracenew(struct imx9_lpi2c_priv_s *priv,
+ uint32_t status);
+static void imx9_lpi2c_traceevent(struct imx9_lpi2c_priv_s *priv,
+ enum imx9_trace_e event, uint32_t parm);
+static void imx9_lpi2c_tracedump(struct imx9_lpi2c_priv_s *priv);
+#endif /* CONFIG_I2C_TRACE */
+
+static void imx9_lpi2c_setclock(struct imx9_lpi2c_priv_s *priv,
+ uint32_t frequency);
+static inline void imx9_lpi2c_sendstart(struct imx9_lpi2c_priv_s *priv,
+ uint8_t address);
+static inline void imx9_lpi2c_sendstop(struct imx9_lpi2c_priv_s *priv);
+static inline uint32_t
+imx9_lpi2c_getstatus(struct imx9_lpi2c_priv_s *priv);
+
+static int imx9_lpi2c_isr_process(struct imx9_lpi2c_priv_s *priv);
+
+#ifndef CONFIG_I2C_POLLED
+static int imx9_lpi2c_isr(int irq, void *context, void *arg);
+#endif /* !CONFIG_I2C_POLLED */
+
+static void imx9_lpi2c_clock_enable(struct imx9_lpi2c_priv_s *priv);
+static void imx9_lpi2c_clock_disable(struct imx9_lpi2c_priv_s *priv);
+static int imx9_lpi2c_init(struct imx9_lpi2c_priv_s *priv);
+static int imx9_lpi2c_deinit(struct imx9_lpi2c_priv_s *priv);
+static int imx9_lpi2c_transfer(struct i2c_master_s *dev,
+ struct i2c_msg_s *msgs, int count);
+#ifdef CONFIG_I2C_RESET
+static int imx9_lpi2c_reset(struct i2c_master_s *dev);
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static void imx9_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done,
+ int result);
+static void imx9_txdma_callback(DMACH_HANDLE handle, void *arg, bool done,
+ int result);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Trace events strings */
+
+#ifdef CONFIG_I2C_TRACE
+static const char *g_trace_names[] =
+{
+ "NONE ",
+ "SENDADDR ",
+ "SENDBYTE ",
+ "RCVBYTE ",
+ "NOSTART ",
+ "START/RESTART ",
+ "STOP ",
+ "ERROR "
+};
+#endif
+
+/* I2C interface */
+
+static const struct i2c_ops_s imx9_lpi2c_ops =
+{
+ .transfer = imx9_lpi2c_transfer,
+#ifdef CONFIG_I2C_RESET
+ .reset = imx9_lpi2c_reset,
+#endif
+};
+
+/* I2C device structures */
+
+#ifdef CONFIG_IMX9_LPI2C1
+static const struct imx9_lpi2c_config_s imx9_lpi2c1_config =
+{
+ .base = IMX9_LPI2C1_BASE,
+ .clk_root = CCM_CR_LPI2C1,
+ .clk_gate = CCM_LPCG_LPI2C1,
+ .busy_idle = CONFIG_IMX9_LPI2C1_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C1_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C1_FILTSDA,
+ .scl_pin = MUX_LPI2C1_SCL,
+ .sda_pin = MUX_LPI2C1_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C1_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C1_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C1,
+#endif
+#ifdef CONFIG_IMX9_LPI2C1_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C1RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C1TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c1_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c1_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C2
+static const struct imx9_lpi2c_config_s imx9_lpi2c2_config =
+{
+ .base = IMX9_LPI2C2_BASE,
+ .clk_root = CCM_CR_LPI2C2,
+ .clk_gate = CCM_LPCG_LPI2C2,
+ .busy_idle = CONFIG_IMX9_LPI2C2_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C2_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C2_FILTSDA,
+ .scl_pin = MUX_LPI2C2_SCL,
+ .sda_pin = MUX_LPI2C2_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C2_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C2_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C2,
+#endif
+#ifdef CONFIG_IMX9_LPI2C2_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C2RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C2TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c2_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c2_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C3
+static const struct imx9_lpi2c_config_s imx9_lpi2c3_config =
+{
+ .base = IMX9_LPI2C3_BASE,
+ .clk_root = CCM_CR_LPI2C3,
+ .clk_gate = CCM_LPCG_LPI2C3,
+ .busy_idle = CONFIG_IMX9_LPI2C3_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C3_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C3_FILTSDA,
+ .scl_pin = MUX_LPI2C3_SCL,
+ .sda_pin = MUX_LPI2C3_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C3_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C3_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C3,
+#endif
+#ifdef CONFIG_IMX9_LPI2C3_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C3RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C3TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c3_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c3_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C4
+static const struct imx9_lpi2c_config_s imx9_lpi2c4_config =
+{
+ .base = IMX9_LPI2C4_BASE,
+ .clk_root = CCM_CR_LPI2C4,
+ .clk_gate = CCM_LPCG_LPI2C4,
+ .busy_idle = CONFIG_IMX9_LPI2C4_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C4_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C4_FILTSDA,
+ .scl_pin = MUX_LPI2C4_SCL,
+ .sda_pin = MUX_LPI2C4_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C4_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C4_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C4,
+#endif
+#ifdef CONFIG_IMX9_LPI2C4_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C4RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C4TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c4_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c4_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C5
+static const struct imx9_lpi2c_config_s imx9_lpi2c5_config =
+{
+ .base = IMX9_LPI2C5_BASE,
+ .clk_root = CCM_CR_LPI2C5,
+ .clk_gate = CCM_LPCG_LPI2C5,
+ .busy_idle = CONFIG_IMX9_LPI2C5_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C5_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C5_FILTSDA,
+ .scl_pin = MUX_LPI2C5_SCL,
+ .sda_pin = MUX_LPI2C5_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C5_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C5_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C5,
+#endif
+#ifdef CONFIG_IMX9_LPI2C5_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C5RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C5TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c5_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c5_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C6
+static const struct imx9_lpi2c_config_s imx9_lpi2c6_config =
+{
+ .base = IMX9_LPI2C6_BASE,
+ .clk_root = CCM_CR_LPI2C6,
+ .clk_gate = CCM_LPCG_LPI2C6,
+ .busy_idle = CONFIG_IMX9_LPI2C6_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C6_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C6_FILTSDA,
+ .scl_pin = MUX_LPI2C6_SCL,
+ .sda_pin = MUX_LPI2C6_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C6_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C6_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C6,
+#endif
+#ifdef CONFIG_IMX9_LPI2C6_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C6RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C6TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c6_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c6_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C7
+static const struct imx9_lpi2c_config_s imx9_lpi2c7_config =
+{
+ .base = IMX9_LPI2C7_BASE,
+ .clk_root = CCM_CR_LPI2C7,
+ .clk_gate = CCM_LPCG_LPI2C7,
+ .busy_idle = CONFIG_IMX9_LPI2C7_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C7_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C7_FILTSDA,
+ .scl_pin = MUX_LPI2C7_SCL,
+ .sda_pin = MUX_LPI2C7_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C7_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C7_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C7,
+#endif
+#ifdef CONFIG_IMX9_LPI2C7_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C7RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C7TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c7_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c7_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C8
+static const struct imx9_lpi2c_config_s imx9_lpi2c8_config =
+{
+ .base = IMX9_LPI2C8_BASE,
+ .clk_root = CCM_CR_LPI2C8,
+ .clk_gate = CCM_LPCG_LPI2C8,
+ .busy_idle = CONFIG_IMX9_LPI2C8_BUSYIDLE,
+ .filtscl = CONFIG_IMX9_LPI2C8_FILTSCL,
+ .filtsda = CONFIG_IMX9_LPI2C8_FILTSDA,
+ .scl_pin = MUX_LPI2C8_SCL,
+ .sda_pin = MUX_LPI2C8_SDA,
+#if defined(CONFIG_I2C_RESET)
+ .reset_scl_pin = GPIO_LPI2C8_SCL_RESET,
+ .reset_sda_pin = GPIO_LPI2C8_SDA_RESET,
+#endif
+#ifndef CONFIG_I2C_SLAVE
+ .mode = LPI2C_MASTER,
+#else
+ .mode = LPI2C_SLAVE,
+#endif
+#ifndef CONFIG_I2C_POLLED
+ .irq = IMX9_IRQ_LPI2C8,
+#endif
+#ifdef CONFIG_IMX9_LPI2C8_DMA
+ .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C8RX,
+ .dma_txreqsrc = DMA_REQUEST_MUXLPI2C8TX,
+#endif
+};
+
+static struct imx9_lpi2c_priv_s imx9_lpi2c8_priv =
+{
+ .ops = &imx9_lpi2c_ops,
+ .config = &imx9_lpi2c8_config,
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+ .sem_isr = SEM_INITIALIZER(0),
+#endif
+ .intstate = INTSTATE_IDLE,
+ .msgc = 0,
+ .msgv = NULL,
+ .ptr = NULL,
+ .dcnt = 0,
+ .flags = 0,
+ .status = 0
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_lpi2c_getreg
+ *
+ * Description:
+ * Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t
+imx9_lpi2c_getreg(struct imx9_lpi2c_priv_s *priv, uint16_t offset)
+{
+ return getreg32(priv->config->base + offset);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_putreg
+ *
+ * Description:
+ * Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void imx9_lpi2c_putreg(struct imx9_lpi2c_priv_s *priv,
+ uint16_t offset, uint32_t value)
+{
+ putreg32(value, priv->config->base + offset);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_modifyreg
+ *
+ * Description:
+ * Modify a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void imx9_lpi2c_modifyreg(struct imx9_lpi2c_priv_s *priv,
+ uint16_t offset, uint32_t clearbits,
+ uint32_t setbits)
+{
+ modifyreg32(priv->config->base + offset, clearbits, setbits);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_toticks
+ *
+ * Description:
+ * Return a micro-second delay based on the number of bytes left to be
+ * processed.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO
+static uint32_t imx9_lpi2c_toticks(int msgc, struct i2c_msg_s *msgs)
+{
+ int i;
+ size_t bytecount = 0;
+ uint32_t tick = 0;
+
+ /* Count the number of bytes left to process */
+
+ for (i = 0; i < msgc; i++)
+ {
+ bytecount += msgs[i].length;
+ }
+
+ /* Then return a number of microseconds based on a user provided scaling
+ * factor.
+ */
+
+ tick = USEC2TICK(CONFIG_IMX9_LPI2C_DYNTIMEO_USECPERBYTE * bytecount);
+ if (tick == 0)
+ {
+ tick = 1;
+ }
+
+ return tick;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_sem_waitdone
+ *
+ * Description:
+ * Wait for a transfer to complete
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static inline int
+imx9_lpi2c_sem_waitdone(struct imx9_lpi2c_priv_s *priv)
+{
+ irqstate_t flags;
+ uint32_t regval;
+ int ret;
+
+ flags = enter_critical_section();
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ if (priv->rxdma == NULL && priv->txdma == NULL)
+ {
+#endif
+ /* Clear the TX and RX FIFOs */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0,
+ LPI2C_MCR_RTF | LPI2C_MCR_RRF);
+
+ /* Enable Interrupts when master mode */
+
+ if (priv->config->mode == LPI2C_MASTER)
+ {
+ if ((priv->flags & I2C_M_READ) != 0)
+ {
+ regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE |
+ LPI2C_MIER_NDIE | LPI2C_MIER_ALIE |
+ LPI2C_MIER_SDIE;
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, regval);
+ }
+ else
+ {
+ regval = LPI2C_MIER_TDIE | LPI2C_MIER_NDIE |
+ LPI2C_MIER_ALIE | LPI2C_MIER_SDIE;
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, regval);
+ }
+ }
+
+#ifdef CONFIG_I2C_SLAVE
+ /* Enable Interrupts when slave mode */
+
+ else
+ {
+ /* REVISIT: Slave mode has not been implemented */
+ }
+#endif
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ }
+#endif
+
+ do
+ {
+ /* Wait until either the transfer is complete or the timeout expires */
+
+#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO
+ ret = nxsem_tickwait_uninterruptible(&priv->sem_isr,
+ imx9_lpi2c_toticks(priv->msgc, priv->msgv));
+#else
+ ret = nxsem_tickwait_uninterruptible(&priv->sem_isr,
+ CONFIG_IMX9_LPI2C_TIMEOTICKS);
+#endif
+ if (ret < 0)
+ {
+ /* Break out of the loop on irrecoverable errors. This would
+ * include timeouts and mystery errors reported by
+ * nxsem_tickwait_uninterruptible.
+ */
+
+ break;
+ }
+ }
+
+ /* Loop until the interrupt level transfer is complete. */
+
+ while (priv->intstate != INTSTATE_DONE);
+
+ /* Set the interrupt state back to IDLE */
+
+ priv->intstate = INTSTATE_IDLE;
+
+ /* Disable I2C interrupts */
+
+ if (priv->config->mode == LPI2C_MASTER)
+ {
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, 0);
+ }
+ else
+ {
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_SIER_OFFSET, 0);
+ }
+
+ leave_critical_section(flags);
+ return ret;
+}
+#else
+static inline int
+imx9_lpi2c_sem_waitdone(struct imx9_lpi2c_priv_s *priv)
+{
+ clock_t timeout;
+ clock_t start;
+ clock_t elapsed;
+ int ret;
+
+ /* Get the timeout value */
+
+#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO
+ timeout = imx9_lpi2c_toticks(priv->msgc, priv->msgv);
+#else
+ timeout = CONFIG_IMX9_LPI2C_TIMEOTICKS;
+#endif
+ start = clock_systime_ticks();
+
+ do
+ {
+ /* Calculate the elapsed time */
+
+ elapsed = clock_systime_ticks() - start;
+
+ /* Poll by simply calling the timer interrupt handler until it
+ * reports that it is done.
+ */
+
+ imx9_lpi2c_isr_process(priv);
+ }
+
+ /* Loop until the transfer is complete. */
+
+ while (priv->intstate != INTSTATE_DONE && elapsed < timeout);
+
+ i2cinfo("intstate: %d elapsed: %ld threshold: %ld status: %08x\n",
+ priv->intstate, (long)elapsed, (long)timeout, priv->status);
+
+ /* Set the interrupt state back to IDLE */
+
+ ret = priv->intstate == INTSTATE_DONE ? OK : -ETIMEDOUT;
+ priv->intstate = INTSTATE_IDLE;
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_sem_waitstop
+ *
+ * Description:
+ * Wait for a STOP to complete
+ *
+ ****************************************************************************/
+
+static inline void
+imx9_lpi2c_sem_waitstop(struct imx9_lpi2c_priv_s *priv)
+{
+ clock_t start;
+ clock_t elapsed;
+ clock_t timeout;
+ uint32_t regval;
+
+ /* Select a timeout */
+
+#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO
+ timeout = USEC2TICK(CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP);
+#else
+ timeout = CONFIG_IMX9_LPI2C_TIMEOTICKS;
+#endif
+
+ /* Wait as stop might still be in progress; but stop might also
+ * be set because of a timeout error: "The [STOP] bit is set and
+ * cleared by software, cleared by hardware when a Stop condition is
+ * detected, set by hardware when a timeout error is detected."
+ */
+
+ start = clock_systime_ticks();
+ do
+ {
+ /* Calculate the elapsed time */
+
+ elapsed = clock_systime_ticks() - start;
+
+ /* Check for STOP condition */
+
+ if (priv->config->mode == LPI2C_MASTER)
+ {
+ regval = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET);
+ if ((regval & LPI2C_MSR_SDF) == LPI2C_MSR_SDF)
+ {
+ return;
+ }
+ }
+
+ /* Enable Interrupts when slave mode */
+
+ else
+ {
+ regval = imx9_lpi2c_getreg(priv, IMX9_LPI2C_SSR_OFFSET);
+ if ((regval & LPI2C_SSR_SDF) == LPI2C_SSR_SDF)
+ {
+ return;
+ }
+ }
+
+ /* Check for NACK error */
+
+ if (priv->config->mode == LPI2C_MASTER)
+ {
+ regval = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET);
+ if ((regval & LPI2C_MSR_NDF) == LPI2C_MSR_NDF)
+ {
+ return;
+ }
+ }
+
+#ifdef CONFIG_I2C_SLAVE
+ /* Enable Interrupts when slave mode */
+
+ else
+ {
+ /* REVISIT: Slave mode has not been implemented */
+ }
+#endif
+ }
+
+ /* Loop until the stop is complete or a timeout occurs. */
+
+ while (elapsed < timeout);
+
+ /* If we get here then a timeout occurred with the STOP condition
+ * still pending.
+ */
+
+ i2cinfo("Timeout with Status Register: %" PRIx32 "\n", regval);
+}
+
+/****************************************************************************
+ * Name: imx9_rxdma_callback
+ *
+ * Description:
+ * This function performs the next I2C operation
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static void imx9_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done,
+ int result)
+{
+ struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)arg;
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET, 0,
+ LPI2C_MIER_SDIE);
+
+ if (result == OK)
+ {
+ if ((priv->flags & I2C_M_NOSTOP) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+ imx9_lpi2c_sendstop(priv);
+ }
+ }
+ else
+ {
+ uint32_t status = imx9_lpi2c_getstatus(priv);
+
+ if ((status & LPI2C_MSR_ERROR_MASK) != 0)
+ {
+ i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", status);
+
+ imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_txdma_callback
+ *
+ * Description:
+ * This function performs the next I2C operation
+ *
+ ****************************************************************************/
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static void imx9_txdma_callback(DMACH_HANDLE handle, void *arg, bool done,
+ int result)
+{
+ struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)arg;
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET, 0,
+ LPI2C_MIER_SDIE);
+
+ if (result == OK)
+ {
+ if ((priv->flags & I2C_M_NOSTOP) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+ imx9_lpi2c_sendstop(priv);
+ }
+ }
+ else
+ {
+ uint32_t status = imx9_lpi2c_getstatus(priv);
+
+ if ((status & LPI2C_MSR_ERROR_MASK) != 0)
+ {
+ i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", status);
+
+ imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_trace*
+ *
+ * Description:
+ * I2C trace instrumentation
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void imx9_lpi2c_traceclear(struct imx9_lpi2c_priv_s *priv)
+{
+ struct imx9_trace_s *trace = &priv->trace[priv->tndx];
+
+ trace->status = 0; /* I2C 32-bit SR2|SR1 status */
+ trace->count = 0; /* Interrupt count when status change */
+ trace->event = I2CEVENT_NONE; /* Last event that occurred with this status
*/
+ trace->parm = 0; /* Parameter associated with the event */
+ trace->time = 0; /* Time of first status or event */
+}
+
+static void imx9_lpi2c_tracereset(struct imx9_lpi2c_priv_s *priv)
+{
+ /* Reset the trace info for a new data collection */
+
+ priv->tndx = 0;
+ priv->start_time = clock_systime_ticks();
+ imx9_lpi2c_traceclear(priv);
+}
+
+static void imx9_lpi2c_tracenew(struct imx9_lpi2c_priv_s *priv,
+ uint32_t status)
+{
+ struct imx9_trace_s *trace = &priv->trace[priv->tndx];
+
+ /* Is the current entry uninitialized? Has the status changed? */
+
+ if (trace->count == 0 || status != trace->status)
+ {
+ /* Yes.. Was it the status changed? */
+
+ if (trace->count != 0)
+ {
+ /* Yes.. bump up the trace index (unless out of trace entries) */
+
+ if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
+ {
+ i2cerr("ERROR: Trace table overflow\n");
+ return;
+ }
+
+ priv->tndx++;
+ trace = &priv->trace[priv->tndx];
+ }
+
+ /* Initialize the new trace entry */
+
+ imx9_lpi2c_traceclear(priv);
+ trace->status = status;
+ trace->count = 1;
+ trace->time = clock_systime_ticks();
+ }
+ else
+ {
+ /* Just increment the count of times that we have seen this status */
+
+ trace->count++;
+ }
+}
+
+static void imx9_lpi2c_traceevent(struct imx9_lpi2c_priv_s *priv,
+ enum imx9_trace_e event, uint32_t parm)
+{
+ struct imx9_trace_s *trace;
+
+ if (event != I2CEVENT_NONE)
+ {
+ trace = &priv->trace[priv->tndx];
+
+ /* Initialize the new trace entry */
+
+ trace->event = event;
+ trace->parm = parm;
+
+ /* Bump up the trace index (unless we are out of trace entries) */
+
+ if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
+ {
+ i2cerr("ERROR: Trace table overflow\n");
+ return;
+ }
+
+ priv->tndx++;
+ imx9_lpi2c_traceclear(priv);
+ }
+}
+
+static void imx9_lpi2c_tracedump(struct imx9_lpi2c_priv_s *priv)
+{
+ struct imx9_trace_s *trace;
+ int i;
+
+ syslog(LOG_DEBUG, "Elapsed time: %ld\n",
+ (long)(clock_systime_ticks() - priv->start_time));
+
+ for (i = 0; i < priv->tndx; i++)
+ {
+ trace = &priv->trace[i];
+ syslog(LOG_DEBUG,
+ "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x "
+ "TIME: %d\n",
+ i + 1, trace->status, trace->count,
+ g_trace_names[trace->event],
+ trace->event, trace->parm, trace->time - priv->start_time);
+ }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: imx9_lpi2c_setclock
+ *
+ * Description:
+ * Set the I2C clock
+ *
+ ****************************************************************************/
+
+static void imx9_lpi2c_setclock(struct imx9_lpi2c_priv_s *priv,
+ uint32_t frequency)
+{
+ uint32_t src_freq = 0;
+ uint32_t regval;
+ uint32_t men;
+ uint32_t prescale = 0;
+ uint32_t best_prescale = 0;
+ uint32_t best_clk_hi = 0;
+ uint32_t abs_error = 0;
+ uint32_t best_error = 0xffffffff;
+ uint32_t clk_hi_cycle;
+ uint32_t computed_rate;
+ uint32_t count;
+
+ /* Has the I2C bus frequency changed? */
+
+ if (priv->config->mode == LPI2C_MASTER)
+ {
+ if (frequency != priv->frequency)
+ {
+ /* Disable the selected LPI2C peripheral to configure the new
+ * clock if it is enabled.
+ */
+
+ men = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MCR_OFFSET) &
+ LPI2C_MCR_MEN;
+ if (men)
+ {
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET,
+ LPI2C_MCR_MEN, 0);
+ }
+
+ /* Get the LPI2C clock source frequency */
+
+ imx9_get_rootclock(priv->config->clk_root, &src_freq);
+
+ /* LPI2C output frequency = (Source Clock (Hz)/ 2^prescale) /
+ * (CLKLO + 1 + CLKHI + 1 + ROUNDDOWN((2 + FILTSCL) / 2^prescale)
+ *
+ * Assume CLKLO = 2 * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI / 2
+ */
+
+ for (prescale = 1;
+ (prescale <= 128) && (best_error != 0);
+ prescale *= 2)
+ {
+ for (clk_hi_cycle = 1; clk_hi_cycle < 32; clk_hi_cycle++)
+ {
+ if (clk_hi_cycle == 1)
+ {
+ computed_rate = (src_freq / prescale) /
+ (6 + (2 / prescale));
+ }
+ else
+ {
+ computed_rate = (src_freq / prescale) /
+ ((3 * clk_hi_cycle + 2) +
+ (2 / prescale));
+ }
+
+ if (frequency > computed_rate)
+ {
+ abs_error = frequency - computed_rate;
+ }
+ else
+ {
+ abs_error = computed_rate - frequency;
+ }
+
+ if (abs_error < best_error)
+ {
+ best_prescale = prescale;
+ best_clk_hi = clk_hi_cycle;
+ best_error = abs_error;
+
+ if (abs_error == 0)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ regval = LPI2C_MCCR0_CLKHI(best_clk_hi);
+
+ if (best_clk_hi < 2)
+ {
+ regval |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) |
+ LPI2C_MCCR0_DATAVD(1);
+ }
+ else
+ {
+ regval |= LPI2C_MCCR0_CLKLO(2 * best_clk_hi) |
+ LPI2C_MCCR0_SETHOLD(best_clk_hi) |
+ LPI2C_MCCR0_DATAVD(best_clk_hi / 2);
+ }
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCCR0_OFFSET, regval);
+
+ for (count = 0; count < 8; count++)
+ {
+ if (best_prescale == (1 << count))
+ {
+ best_prescale = count;
+ break;
+ }
+ }
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET,
+ LPI2C_MCFGR1_PRESCALE_MASK,
+ LPI2C_MCFGR1_PRESCALE(best_prescale));
+
+ /* Re-enable LPI2C if it was enabled previously */
+
+ if (men)
+ {
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0,
+ LPI2C_MCR_MEN);
+ }
+
+ /* Save the new LPI2C frequency */
+
+ priv->frequency = frequency;
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_sendstart
+ *
+ * Description:
+ * Send the START conditions/force Master mode
+ *
+ ****************************************************************************/
+
+static inline void imx9_lpi2c_sendstart(struct imx9_lpi2c_priv_s *priv,
+ uint8_t address)
+{
+ uint32_t txcount = 0;
+ uint32_t status = 0;
+ uint8_t addr;
+
+ /* Generate START condition and send the address */
+
+ /* Disable AUTOSTOP and turn NAK Ignore off */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET,
+ LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP, 0);
+
+ do
+ {
+ txcount = (imx9_lpi2c_getreg(priv, IMX9_LPI2C_MFSR_OFFSET) &
+ LPI2C_MFSR_TXCOUNT_MASK) >> LPI2C_MFSR_TXCOUNT_SHIFT;
+ txcount = 4 - txcount;
+
+ status = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET);
+
+ if (status & LPI2C_MSR_ERROR_MASK)
+ {
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET,
+ status & LPI2C_MSR_ERROR_MASK);
+ }
+ }
+ while (txcount == 0);
+
+ if ((priv->flags & I2C_M_READ) != 0)
+ {
+ addr = I2C_READADDR8(address);
+ }
+ else
+ {
+ addr = I2C_WRITEADDR8(address);
+ }
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET,
+ (LPI2C_MTDR_CMD_START | LPI2C_MTDR_DATA(addr)));
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_sendstop
+ *
+ * Description:
+ * Send the STOP conditions
+ *
+ ****************************************************************************/
+
+static inline void imx9_lpi2c_sendstop(struct imx9_lpi2c_priv_s *priv)
+{
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET, LPI2C_MTDR_CMD_STOP);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_getstatus
+ *
+ * Description:
+ * Get 32-bit status
+ *
+ ****************************************************************************/
+
+static inline uint32_t
+imx9_lpi2c_getstatus(struct imx9_lpi2c_priv_s *priv)
+{
+ return imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_getenabledints
+ *
+ * Description:
+ * Get 32-bit status
+ *
+ ****************************************************************************/
+
+static inline uint32_t
+imx9_lpi2c_getenabledints(struct imx9_lpi2c_priv_s *priv)
+{
+ return imx9_lpi2c_getreg(priv, IMX9_LPI2C_MIER_OFFSET);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_isr_process
+ *
+ * Description:
+ * Common Interrupt Service Routine
+ *
+ ****************************************************************************/
+
+static int imx9_lpi2c_isr_process(struct imx9_lpi2c_priv_s *priv)
+{
+ uint32_t status = imx9_lpi2c_getstatus(priv);
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ uint32_t current_status = status;
+
+ if (priv->rxdma != NULL || priv->txdma != NULL)
+ {
+ /* Condition the status with only the enabled interrupts */
+
+ status &= imx9_lpi2c_getenabledints(priv);
+
+ /* Is there an Error condition */
+
+ if (current_status & LPI2C_MSR_LIMITED_ERROR_MASK)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
+
+ /* Return the full error status */
+
+ priv->status = current_status;
+ }
+
+ /* End of packet or Stop */
+
+ if ((status & (LPI2C_MSR_SDF | LPI2C_MSR_EPF)) != 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+
+ /* Acknowledge End of packet or Stop */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, status &
+ (LPI2C_MSR_SDF |
+ LPI2C_MSR_EPF));
+
+ /* Mark that this transaction stopped */
+
+ priv->msgv = NULL;
+ priv->msgc = 0;
+ priv->dcnt = -1;
+
+ if (priv->intstate == INTSTATE_WAITING)
+ {
+ /* inform the thread that transfer is complete
+ * and wake it up
+ */
+
+ imx9_dmach_stop(priv->txdma);
+ imx9_dmach_stop(priv->rxdma);
+
+ priv->intstate = INTSTATE_DONE;
+ nxsem_post(&priv->sem_isr);
+ }
+ }
+
+ /* Clear the error */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET,
+ (current_status & (LPI2C_MSR_NDF |
+ LPI2C_MSR_ALF |
+ LPI2C_MSR_FEF)));
+ return OK;
+ }
+
+#endif
+ /* Check for new trace setup */
+
+ imx9_lpi2c_tracenew(priv, status);
+
+ if ((status & LPI2C_MSR_LIMITED_ERROR_MASK) == 0)
+ {
+ /* Check if there is more bytes to send */
+
+ if (((priv->flags & I2C_M_READ) == 0) &&
+ (status & LPI2C_MSR_TDF) != 0)
+ {
+ if (priv->dcnt > 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt);
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET,
+ LPI2C_MTDR_CMD_TXD |
+ LPI2C_MTDR_DATA(*priv->ptr++));
+ priv->dcnt--;
+
+ /* Last byte of last message? */
+
+ if ((priv->msgc <= 0) && (priv->dcnt == 0))
+ {
+ if ((priv->flags & I2C_M_NOSTOP) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+
+ /* Do this once */
+
+ priv->flags |= I2C_M_NOSTOP;
+ imx9_lpi2c_sendstop(priv);
+ }
+ }
+ }
+ }
+
+ /* Check if there is more bytes to read */
+
+ else if (((priv->flags & I2C_M_READ) != 0) &&
+ (status & LPI2C_MSR_RDF) != 0)
+ {
+ /* Read a byte, if dcnt goes < 0, read dummy bytes to ack ISRs */
+
+ if (priv->dcnt > 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt);
+
+ /* No interrupts or context switches should occur in the
+ * following sequence. Otherwise, additional bytes may be
+ * sent by the device.
+ */
+
+ #ifdef CONFIG_I2C_POLLED
+ irqstate_t flags = enter_critical_section();
+ #endif
+
+ /* Receive a byte */
+
+ *priv->ptr++ = imx9_lpi2c_getreg(priv,
+ IMX9_LPI2C_MRDR_OFFSET) &
+ LPI2C_MRDR_DATA_MASK;
+ priv->dcnt--;
+
+ #ifdef CONFIG_I2C_POLLED
+ leave_critical_section(flags);
+ #endif
+ /* Last byte of last message? */
+
+ if ((priv->msgc <= 0) && (priv->dcnt == 0))
+ {
+ if ((priv->flags & I2C_M_NOSTOP) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+
+ /* Do this once */
+
+ priv->flags |= I2C_M_NOSTOP;
+ imx9_lpi2c_sendstop(priv);
+ }
+ }
+ }
+ else
+ {
+ /* Read and discard data */
+
+ imx9_lpi2c_getreg(priv, IMX9_LPI2C_MRDR_OFFSET);
+ }
+ }
+
+ /* Start the first or next message */
+
+ if (priv->dcnt <= 0 && (status & (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) == 0)
+ {
+ if (priv->msgc > 0 && priv->msgv != NULL)
+ {
+ priv->ptr = priv->msgv->buffer;
+ priv->dcnt = priv->msgv->length;
+ priv->flags = priv->msgv->flags;
+
+ if ((priv->flags & I2C_M_NOSTART) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STARTRESTART,
+ priv->msgc);
+
+ /* Do this once */
+
+ priv->flags |= I2C_M_NOSTART;
+
+ imx9_lpi2c_sendstart(priv, priv->msgv->addr);
+ }
+ else
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_NOSTART, priv->msgc);
+ }
+
+ priv->msgv++;
+ priv->msgc--;
+
+ if ((priv->flags & I2C_M_READ) != 0)
+ {
+#ifndef CONFIG_I2C_POLLED
+ /* Stop TX interrupt */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET,
+ LPI2C_MIER_TDIE, LPI2C_MIER_RDIE);
+#endif
+ /* Set LPI2C in read mode */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET,
+ LPI2C_MTDR_CMD_RXD |
+ LPI2C_MTDR_DATA((priv->dcnt - 1)));
+ }
+ else
+ {
+ /* Send the first byte from tx buffer */
+
+ imx9_lpi2c_traceevent(priv, I2CEVENT_SENDBYTE,
+ priv->dcnt);
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET,
+ LPI2C_MTDR_CMD_TXD |
+ LPI2C_MTDR_DATA(*priv->ptr++));
+ priv->dcnt--;
+
+ /* Last byte of last message? */
+
+ if ((priv->msgc <= 0) && (priv->dcnt == 0))
+ {
+ if ((priv->flags & I2C_M_NOSTOP) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+
+ /* Do this once */
+
+ priv->flags |= I2C_M_NOSTOP;
+ imx9_lpi2c_sendstop(priv);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
+
+ priv->status = status;
+
+ if ((priv->flags & I2C_M_NOSTOP) == 0)
+ {
+ imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
+
+ /* Do this once */
+
+ priv->flags |= I2C_M_NOSTOP;
+ imx9_lpi2c_sendstop(priv);
+ }
+
+ /* Clear the error */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET,
+ (status & (LPI2C_MSR_NDF | LPI2C_MSR_ALF |
+ LPI2C_MSR_FEF | LPI2C_MSR_EPF)));
+ }
+
+ /* Check for endof packet or Stop */
+
+ if ((status & (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) != 0)
+ {
+ /* Reset either or both */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, status &
+ (LPI2C_MSR_EPF | LPI2C_MSR_SDF));
+
+ /* Was it both End of packet and Stop */
+
+ if ((status & (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) ==
+ (LPI2C_MSR_EPF | LPI2C_MSR_SDF))
+ {
+#ifndef CONFIG_I2C_POLLED
+ if (priv->intstate == INTSTATE_WAITING)
+ {
+ /* inform the thread that transfer is complete
+ * and wake it up
+ */
+
+ priv->intstate = INTSTATE_DONE;
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET,
+ LPI2C_MIER_TDIE | LPI2C_MIER_RDIE |
+ LPI2C_MIER_NDIE | LPI2C_MIER_ALIE |
+ LPI2C_MIER_SDIE | LPI2C_MIER_EPIE, 0);
+ nxsem_post(&priv->sem_isr);
+ }
+#else
+ priv->intstate = INTSTATE_DONE;
+#endif
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_isr
+ *
+ * Description:
+ * Common I2C interrupt service routine
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int imx9_lpi2c_isr(int irq, void *context, void *arg)
+{
+ struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)arg;
+
+ DEBUGASSERT(priv != NULL);
+ return imx9_lpi2c_isr_process(priv);
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_clock_enable
+ *
+ * Description:
+ * Ungate LPI2C clock
+ *
+ ****************************************************************************/
+
+static void imx9_lpi2c_clock_enable(struct imx9_lpi2c_priv_s *priv)
+{
+ imx9_ccm_gate_on(priv->config->clk_gate, true);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_clock_disable
+ *
+ * Description:
+ * Gate LPI2C clock
+ *
+ ****************************************************************************/
+
+void imx9_lpi2c_clock_disable(struct imx9_lpi2c_priv_s *priv)
+{
+ imx9_ccm_gate_on(priv->config->clk_gate, false);
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_init
+ *
+ * Description:
+ * Setup the I2C hardware, ready for operation with defaults
+ *
+ ****************************************************************************/
+
+static int imx9_lpi2c_init(struct imx9_lpi2c_priv_s *priv)
+{
+ /* Power-up and configure GPIOs */
+
+ /* Configure pins */
+
+ imx9_iomux_configure(priv->config->scl_pin);
+ imx9_iomux_configure(priv->config->sda_pin);
+
+ /* Enable power and reset the peripheral */
+
+ imx9_lpi2c_clock_enable(priv);
+
+ /* Reset LPI2C before configuring it */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_RST);
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, 0);
+
+ /* Disable doze mode (Set DOZEN bit in 1 to disable) */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_DOZEN);
+
+ /* Disable host request */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR0_OFFSET,
+ LPI2C_MCFG0_HREN | LPI2C_MCFG0_HRSEL,
+ LPI2C_MCFG0_HRPOL);
+
+ /* Disable AUTOSTOP and turn NAK Ignore off */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET,
+ LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP, 0);
+
+ /* Set tx and rx watermarks */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MFCR_OFFSET,
+ LPI2C_MFCR_TXWATER(0) | LPI2C_MFCR_RXWATER(0));
+
+ /* Force a frequency update */
+
+ priv->frequency = 0;
+ imx9_lpi2c_setclock(priv, 100000);
+
+ /* Set scl, sda glitch filters and busy idle */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCFGR2_OFFSET,
+ LPI2C_MCFG2_BUSIDLE(priv->config->busy_idle) |
+ LPI2C_MCFG2_FILTSCL_CYCLES(priv->config->filtscl) |
+ LPI2C_MCFG2_FILTSDA_CYCLES(priv->config->filtsda));
+
+ /* Set pin low cycles to 0 (disable) */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCFGR3_OFFSET,
+ LPI2C_MCFG3_PINLOW_CYCLES(0));
+
+ /* Attach ISRs */
+
+#ifndef CONFIG_I2C_POLLED
+ irq_attach(priv->config->irq, imx9_lpi2c_isr, priv);
+ up_enable_irq(priv->config->irq);
+#endif
+
+ /* Enable I2C */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0, LPI2C_MCR_MEN);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_deinit
+ *
+ * Description:
+ * Shutdown the I2C hardware
+ *
+ ****************************************************************************/
+
+static int imx9_lpi2c_deinit(struct imx9_lpi2c_priv_s *priv)
+{
+ /* Disable I2C */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_MEN, 0);
+
+ /* Reset LPI2C */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_RST);
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, 0);
+
+ /* Disable and detach interrupts */
+
+#ifndef CONFIG_I2C_POLLED
+ up_disable_irq(priv->config->irq);
+ irq_detach(priv->config->irq);
+#endif
+
+ /* Disable clocking */
+
+ imx9_lpi2c_clock_disable(priv);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Device Driver Operations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_lpi2c_dma_command_configure
+ *
+ * Description:
+ * Create a command TCD
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static int imx9_lpi2c_dma_command_configure(struct imx9_lpi2c_priv_s *priv,
+ uint16_t *ccmd, uint32_t ncmd)
+{
+ struct imx9_edma_xfrconfig_s config;
+ memset(&config, 0, sizeof(config));
+
+ config.saddr = (uintptr_t) ccmd;
+ config.daddr = priv->config->base + IMX9_LPI2C_MTDR_OFFSET;
+ config.soff = sizeof(uint16_t);
+ config.doff = 0;
+ config.iter = 1;
+ config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
+ config.ssize = EDMA_16BIT;
+ config.dsize = EDMA_16BIT;
+ config.nbytes = sizeof(uint16_t) * ncmd;
+
+ up_clean_dcache((uintptr_t)config.saddr,
+ (uintptr_t)config.saddr + config.nbytes);
+
+ return imx9_dmach_xfrsetup(priv->txdma, &config);
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_dma_data_configure
+ *
+ * Description:
+ * Create a data TCD
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static int imx9_lpi2c_dma_data_configure(struct imx9_lpi2c_priv_s *priv,
+ struct i2c_msg_s *msg)
+{
+ DMACH_HANDLE dma;
+ struct imx9_edma_xfrconfig_s config;
+ memset(&config, 0, sizeof(config));
+
+ config.iter = msg->length;
+ config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
+ config.ssize = EDMA_8BIT;
+ config.dsize = EDMA_8BIT;
+ config.nbytes = sizeof(msg->buffer[0]);
+
+ if (msg->flags & I2C_M_READ)
+ {
+ dma = priv->rxdma;
+ config.saddr = priv->config->base + IMX9_LPI2C_MRDR_OFFSET;
+ config.daddr = (uintptr_t) msg->buffer;
+ config.soff = 0;
+ config.doff = sizeof(msg->buffer[0]);
+ up_invalidate_dcache((uintptr_t)msg->buffer,
+ (uintptr_t)msg->buffer + msg->length);
+ }
+ else
+ {
+ dma = priv->txdma;
+ config.saddr = (uintptr_t) msg->buffer;
+ config.daddr = priv->config->base + IMX9_LPI2C_MTDR_OFFSET;
+ config.soff = sizeof(msg->buffer[0]);
+ config.doff = 0;
+ up_clean_dcache((uintptr_t)msg->buffer,
+ (uintptr_t)msg->buffer + msg->length);
+ }
+
+ return imx9_dmach_xfrsetup(dma, &config) ? 0 : msg->length;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_form_command_list
+ *
+ * Description:
+ * Form the DMA command list
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static int imx9_lpi2c_form_command_list(struct imx9_lpi2c_priv_s *priv,
+ struct i2c_msg_s *msg, int ncmds)
+{
+ ssize_t length = 0;
+
+ if (priv->flags & I2C_M_NOSTART)
+ {
+ if (priv->flags & I2C_M_READ)
+ {
+ /* No start read operation */
+
+ priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD |
+ LPI2C_MTDR_DATA(msg->length - 1);
+ }
+ }
+ else
+ {
+ /* A start based read or write operation */
+
+ /* Create bus address with R/W */
+
+ uint16_t badd = (priv->flags & I2C_M_READ) ? I2C_READADDR8(msg->addr) :
+ I2C_WRITEADDR8(msg->addr);
+
+ priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_START | LPI2C_MTDR_DATA(badd);
+
+ if (badd & I2C_READBIT)
+ {
+ length = msg->length;
+ while (length)
+ {
+ if (length > 256u)
+ {
+ priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD |
+ LPI2C_MTDR_DATA(256u - 1);
+ length -= 256u;
+ }
+ else
+ {
+ priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD |
+ LPI2C_MTDR_DATA(length - 1);
+ length = 0;
+ }
+ }
+ }
+ }
+
+ return ncmds;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_dma_transfer
+ *
+ * Description:
+ * DMA based I2C transfer function
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+static int imx9_lpi2c_dma_transfer(struct imx9_lpi2c_priv_s *priv)
+{
+ int m;
+ int ntotcmds = 0;
+ int ncmds = 0;
+ uint16_t *ccmnd = NULL;
+
+ /* Disable Interrupts */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, 0);
+
+ /* Disable DMA */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MDER_OFFSET, LPI2C_MDER_TDDE |
+ LPI2C_MDER_RDDE, 0);
+
+ /* Enable AUTOSTOP and NAK Ignore */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET, 0,
+ LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP);
+
+ /* Form chains of TCDs to process the messages */
+
+ for (m = 0; m < priv->msgc; m++)
+ {
+ ncmds = 0;
+ priv->flags = priv->msgv[m].flags;
+
+ /* Form a command list */
+
+ ccmnd = &priv->cmnds[ntotcmds];
+
+ ncmds = imx9_lpi2c_form_command_list(priv, &priv->msgv[m], ntotcmds);
+
+ /* Have commands for this message ? */
+
+ if (ncmds != 0)
+ {
+ /* Build up a TCD with the command from this message */
+
+ imx9_lpi2c_dma_command_configure(priv, ccmnd, ncmds - ntotcmds);
+
+ ntotcmds += ncmds;
+
+ DEBUGASSERT(ntotcmds < CONFIG_IMX9_LPI2C_DMA_MAXMSG);
+
+ imx9_lpi2c_dma_data_configure(priv, &priv->msgv[m]);
+ }
+ }
+
+ /* Clear the TX and RX FIFOs */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0,
+ LPI2C_MCR_RTF | LPI2C_MCR_RRF);
+
+ /* Reset the Error bits */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, LPI2C_MSR_NDF |
+ LPI2C_MSR_ALF |
+ LPI2C_MSR_FEF);
+
+ /* Enable the Iterrupts */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET,
+ LPI2C_MIER_NDIE | LPI2C_MIER_ALIE |
+ LPI2C_MIER_PLTIE);
+
+ /* Start The DMA */
+
+ imx9_dmach_start(priv->rxdma, imx9_rxdma_callback, (void *)priv);
+ imx9_dmach_start(priv->txdma, imx9_txdma_callback, (void *)priv);
+
+ /* Enable the DMA Request */
+
+ imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MDER_OFFSET, 0,
+ LPI2C_MDER_TDDE | LPI2C_MDER_RDDE);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_lpi2c_transfer
+ *
+ * Description:
+ * Generic I2C transfer function
+ *
+ ****************************************************************************/
+
+static int imx9_lpi2c_transfer(struct i2c_master_s *dev,
+ struct i2c_msg_s *msgs, int count)
+{
+ struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev;
+ int ret;
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ int m;
+#endif
+
+ DEBUGASSERT(count > 0);
+
+ /* Ensure that address or flags don't change meanwhile */
+
+ ret = nxmutex_lock(&priv->lock);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Clear any pending error interrupts */
+
+ imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, 0xffffffff);
+
+ /* Old transfers are done */
+
+ /* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't
+ * overwrite stale data.
+ */
+
+ priv->dcnt = 0;
+ priv->ptr = NULL;
+
+ priv->msgv = msgs;
+ priv->msgc = count;
+ priv->flags = msgs->flags;
+
+ i2cinfo("Flags %x, len %ld\n", msgs->flags, msgs->length);
+
+ /* Reset I2C trace logic */
+
+ imx9_lpi2c_tracereset(priv);
+
+ /* Set I2C clock frequency */
+
+ imx9_lpi2c_setclock(priv, msgs->frequency);
+
+ priv->status = 0;
+
+ /* Signal the interrupt handler that we are waiting. NOTE: Interrupts
+ * are currently disabled but will be temporarily re-enabled below when
+ * nxsem_tickwait_uninterruptible() sleeps.
+ */
+
+ priv->intstate = INTSTATE_WAITING;
+
+ /* Wait for an ISR, if there was a timeout, fetch latest status to get
+ * the BUSY flag.
+ */
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ if (priv->rxdma || priv->txdma)
+ {
+ imx9_lpi2c_dma_transfer(priv);
+ }
+#endif
+
+ if (imx9_lpi2c_sem_waitdone(priv) < 0)
+ {
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ if (priv->rxdma != NULL)
+ {
+ imx9_dmach_stop(priv->rxdma);
+ }
+
+ if (priv->txdma != NULL)
+ {
+ imx9_dmach_stop(priv->txdma);
+ }
+
+#endif
+ ret = -ETIMEDOUT;
+ i2cerr("ERROR: Timed out: MSR: status: 0x0%" PRIx32 "\n",
+ priv->status);
+ }
+
+ /* Check for error status conditions */
+
+ else if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0)
+ {
+ /* I2C_SR1_ERRORMASK is the 'OR' of the following individual bits: */
+
+ if (priv->status & LPI2C_MSR_ALF)
+ {
+ /* Arbitration Lost (master mode) */
+
+ i2cerr("Arbitration lost\n");
+ ret = -EAGAIN;
+ }
+ else if (priv->status & LPI2C_MSR_NDF)
+ {
+ /* Acknowledge Failure */
+
+ i2cerr("Ack failure\n");
+ ret = -ENXIO;
+ }
+ else
+ {
+ /* FIFO Error */
+
+ i2cerr("Transfer without start condition\n");
+ ret = -EINVAL;
+ }
+ }
+
+ /* Dump the trace result */
+
+ imx9_lpi2c_tracedump(priv);
+
+ /* Ensure that any ISR happening after we finish can't overwrite any user
+ * data.
+ */
+
+ priv->dcnt = 0;
+ priv->ptr = NULL;
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ if (priv->rxdma)
+ {
+ for (m = 0; m < count; m++)
+ {
+ if (msgs[m].flags & I2C_M_READ)
+ {
+ up_invalidate_dcache((uintptr_t)msgs[m].buffer,
+ (uintptr_t)msgs[m].buffer +
+ msgs[m].length);
+ }
+ }
+ }
+#endif
+
+ nxmutex_unlock(&priv->lock);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: imx9_lpi2c_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 imx9_lpi2c_reset(struct i2c_master_s *dev)
+{
+ struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev;
+ unsigned int clock_count;
+ unsigned int stretch_count;
+ uint32_t scl_gpio;
+ uint32_t sda_gpio;
+ uint32_t frequency;
+ int ret;
+
+ DEBUGASSERT(dev);
+
+ /* Our caller must own a ref */
+
+ DEBUGASSERT(priv->refs > 0);
+
+ /* Lock out other clients */
+
+ ret = nxmutex_lock(&priv->lock);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = -EIO;
+
+ /* Save the current frequency */
+
+ frequency = priv->frequency;
+
+ /* De-init the port */
+
+ imx9_lpi2c_deinit(priv);
+
+ /* Use GPIO configuration to un-wedge the bus */
+
+ imx9_iomux_gpio(priv->config->scl_pin, true);
+ imx9_iomux_gpio(priv->config->sda_pin, true);
+
+ scl_gpio = priv->config->reset_scl_pin;
+ sda_gpio = priv->config->reset_sda_pin;
+
+ imx9_config_gpio(scl_gpio);
+ imx9_config_gpio(sda_gpio);
+
+ /* Let SDA go high */
+
+ imx9_gpio_write(sda_gpio, 1);
+
+ /* Clock the bus until any slaves currently driving it let it go. */
+
+ clock_count = 0;
+ while (!imx9_gpio_read(sda_gpio))
+ {
+ /* Give up if we have tried too hard */
+
+ if (clock_count++ > 10)
+ {
+ goto out;
+ }
+
+ /* Sniff to make sure that clock stretching has finished.
+ *
+ * If the bus never relaxes, the reset has failed.
+ */
+
+ stretch_count = 0;
+ while (!imx9_gpio_read(scl_gpio))
+ {
+ /* Give up if we have tried too hard */
+
+ if (stretch_count++ > 10)
+ {
+ goto out;
+ }
+
+ up_udelay(10);
+ }
+
+ /* Drive SCL low */
+
+ imx9_gpio_write(scl_gpio, 0);
+ up_udelay(10);
+
+ /* Drive SCL high again */
+
+ imx9_gpio_write(scl_gpio, 1);
+ up_udelay(10);
+ }
+
+ /* Generate a start followed by a stop to reset slave
+ * state machines.
+ */
+
+ imx9_gpio_write(sda_gpio, 0);
+ up_udelay(10);
+ imx9_gpio_write(scl_gpio, 0);
+ up_udelay(10);
+ imx9_gpio_write(scl_gpio, 1);
+ up_udelay(10);
+ imx9_gpio_write(sda_gpio, 1);
+ up_udelay(10);
+
+ /* Re-init the port */
+
+ imx9_lpi2c_init(priv);
+
+ /* Restore the frequency */
+
+ imx9_lpi2c_setclock(priv, frequency);
+ ret = OK;
+
+out:
+
+ /* Release the port for re-use by other clients */
+
+ nxmutex_unlock(&priv->lock);
+ return ret;
+}
+#endif /* CONFIG_I2C_RESET */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_i2cbus_initialize
+ *
+ * Description:
+ * Initialize one I2C bus
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *imx9_i2cbus_initialize(int port)
+{
+ struct imx9_lpi2c_priv_s * priv = NULL;
+ irqstate_t flags;
+
+ /* Get I2C private structure */
+
+ switch (port)
+ {
+#ifdef CONFIG_IMX9_LPI2C1
+ case 1:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c1_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C2
+ case 2:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c2_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C3
+ case 3:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c3_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C4
+ case 4:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c4_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C5
+ case 5:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c5_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C6
+ case 6:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c6_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C7
+ case 7:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c7_priv;
+ break;
+#endif
+#ifdef CONFIG_IMX9_LPI2C8
+ case 8:
+ priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c8_priv;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+ /* Initialize private data for the first time, increment reference count,
+ * power-up hardware and configure GPIOs.
+ */
+
+ flags = enter_critical_section();
+
+ if ((volatile int)priv->refs++ == 0)
+ {
+ imx9_lpi2c_init(priv);
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ if (priv->config->dma_txreqsrc != 0)
+ {
+ priv->txdma = imx9_dmach_alloc(priv->config->dma_txreqsrc, 0);
+ DEBUGASSERT(priv->txdma != NULL);
+ }
+
+ if (priv->config->dma_rxreqsrc != 0)
+ {
+ priv->rxdma = imx9_dmach_alloc(priv->config->dma_rxreqsrc, 0);
+ DEBUGASSERT(priv->rxdma != NULL);
+ }
+#endif
+ }
+
+ leave_critical_section(flags);
+
+ return (struct i2c_master_s *)priv;
+}
+
+/****************************************************************************
+ * Name: imx9_i2cbus_uninitialize
+ *
+ * Description:
+ * Uninitialize an I2C bus
+ *
+ ****************************************************************************/
+
+int imx9_i2cbus_uninitialize(struct i2c_master_s *dev)
+{
+ struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev;
+ irqstate_t flags;
+
+ DEBUGASSERT(dev);
+
+ /* Decrement reference count and check for underflow */
+
+ if (priv->refs == 0)
+ {
+ return ERROR;
+ }
+
+ flags = enter_critical_section();
+
+ if (--priv->refs > 0)
+ {
+ leave_critical_section(flags);
+ return OK;
+ }
+
+ leave_critical_section(flags);
+
+ /* Disable power and other HW resource (GPIO's) */
+
+#ifdef CONFIG_IMX9_LPI2C_DMA
+ if (priv->rxdma != NULL)
+ {
+ imx9_dmach_stop(priv->rxdma);
+ imx9_dmach_free(priv->rxdma);
+ priv->rxdma = NULL;
+ }
+
+ if (priv->txdma != NULL)
+ {
+ imx9_dmach_stop(priv->txdma);
+ imx9_dmach_free(priv->txdma);
+ priv->txdma = NULL;
+ }
+#endif
+
+ imx9_lpi2c_deinit(priv);
+
+ return OK;
+}
+
+#endif /* CONFIG_IMX9_LPI2C */
diff --git a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h
b/arch/arm64/src/imx9/imx9_lpi2c.h
similarity index 59%
copy from boards/arm64/imx9/imx93-evk/src/imx93-evk.h
copy to arch/arm64/src/imx9/imx9_lpi2c.h
index 4b9c0f3a46..d323871fa3 100644
--- a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h
+++ b/arch/arm64/src/imx9/imx9_lpi2c.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * boards/arm64/imx9/imx93-evk/src/imx93-evk.h
+ * arch/arm64/src/imx9/imx9_lpi2c.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -18,54 +18,54 @@
*
****************************************************************************/
-#ifndef __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H
-#define __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H
+#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_LPI2C_H
+#define __ARCH_ARM64_SRC_IMX9_IMX9_LPI2C_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
-
-#include <stdint.h>
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-#ifndef __ASSEMBLY__
+#include <nuttx/i2c/i2c_master.h>
/****************************************************************************
- * Public Functions Definitions
+ * Public Function Prototypes
****************************************************************************/
/****************************************************************************
- * Name: imx9_bringup
+ * Name: imx9_i2cbus_initialize
*
* Description:
- * Bring up board features
+ * 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 I2C interfaces)
+ *
+ * Returned Value:
+ * Valid I2C device structure reference on success; a NULL on failure
*
****************************************************************************/
-#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE)
-int imx9_bringup(void);
-#endif
+struct i2c_master_s *imx9_i2cbus_initialize(int port);
/****************************************************************************
- * Name: imx9_pwm_setup
+ * Name: imx9_i2cbus_uninitialize
*
* Description:
- * Initialize PWM outputs
+ * De-initialize the selected I2C port, and power down the device.
+ *
+ * Input Parameters:
+ * Device structure as returned by the imx9_i2cbus_initialize()
+ *
+ * Returned Value:
+ * OK on success, ERROR when internal reference count mismatch or dev
+ * points to invalid hardware device.
*
****************************************************************************/
-#if defined(CONFIG_PWM)
-int imx9_pwm_setup(void);
-#endif
+int imx9_i2cbus_uninitialize(struct i2c_master_s *dev);
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H */
+#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_LPI2C_H */
diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
index e1834dc8ed..64c7f53357 100644
--- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
+++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
@@ -28,9 +28,14 @@ CONFIG_FS_PROCFS=y
CONFIG_FS_ROMFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_I2C=y
+CONFIG_I2C_RESET=y
CONFIG_IDLETHREAD_STACKSIZE=8192
CONFIG_IMX9_FLEXIO1_PWM=y
CONFIG_IMX9_GPIO_IRQ=y
+CONFIG_IMX9_LPI2C1=y
+CONFIG_IMX9_LPI2C_DYNTIMEO=y
+CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP=10
CONFIG_IMX9_TPM3_PWM=y
CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003
CONFIG_IMX9_UART1=y
@@ -60,6 +65,7 @@ CONFIG_START_MONTH=3
CONFIG_START_YEAR=2022
CONFIG_SYMTAB_ORDEREDBYNAME=y
CONFIG_SYSTEM_CDCACM=y
+CONFIG_SYSTEM_I2CTOOL=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_SYSTEM=y
CONFIG_SYSTEM_TIME64=y
diff --git a/boards/arm64/imx9/imx93-evk/include/board.h
b/boards/arm64/imx9/imx93-evk/include/board.h
index bd78f1cf79..6cd4c26e56 100644
--- a/boards/arm64/imx9/imx93-evk/include/board.h
+++ b/boards/arm64/imx9/imx93-evk/include/board.h
@@ -31,6 +31,8 @@
* Pre-processor Definitions
****************************************************************************/
+#define IOMUX_LPI2C_DEFAULT (IOMUXC_PAD_OD_ENABLE | IOMUXC_PAD_FSEL_SFAST |
IOMUXC_PAD_DSE_X6)
+
/* FLEXIO to PWM pin muxings */
/* EVK signals
@@ -49,6 +51,16 @@
#define TPM3_PWM3_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO24_TPM3_CH3,
IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0)
+/* LPI2Cs */
+
+#define MUX_LPI2C1_SCL IOMUX_CFG(IOMUXC_PAD_I2C1_SCL_LPI2C1_SCL,
IOMUX_LPI2C_DEFAULT, IOMUXC_MUX_SION_ON)
+#define MUX_LPI2C1_SDA IOMUX_CFG(IOMUXC_PAD_I2C1_SDA_LPI2C1_SDA,
IOMUX_LPI2C_DEFAULT, IOMUXC_MUX_SION_ON)
+
+/* I2C reset functionality */
+
+#define GPIO_LPI2C1_SCL_RESET (GPIO_PORT1 | GPIO_PIN0 | GPIO_OUTPUT |
GPIO_OUTPUT_ONE)
+#define GPIO_LPI2C1_SDA_RESET (GPIO_PORT1 | GPIO_PIN1 | GPIO_OUTPUT |
GPIO_OUTPUT_ONE)
+
/****************************************************************************
* Public Data
****************************************************************************/
diff --git a/boards/arm64/imx9/imx93-evk/src/Makefile
b/boards/arm64/imx9/imx93-evk/src/Makefile
index fc2ce19a0c..564a2db926 100644
--- a/boards/arm64/imx9/imx93-evk/src/Makefile
+++ b/boards/arm64/imx9/imx93-evk/src/Makefile
@@ -30,4 +30,8 @@ ifeq ($(CONFIG_PWM),y)
CSRCS += imx9_pwm.c
endif
+ifeq ($(CONFIG_IMX9_LPI2C),y)
+CSRCS += imx9_i2c.c
+endif
+
include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h
b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h
index 4b9c0f3a46..1da0b3b88e 100644
--- a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h
+++ b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h
@@ -67,5 +67,17 @@ int imx9_bringup(void);
int imx9_pwm_setup(void);
#endif
+/****************************************************************************
+ * Name: imx9_i2c_setup
+ *
+ * Description:
+ * Initialize I2C devices and driver
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_I2C_DRIVER)
+int imx9_i2c_initialize(void);
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H */
diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c
b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c
index 7443f92ccd..876b9014de 100644
--- a/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c
+++ b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c
@@ -23,8 +23,11 @@
****************************************************************************/
#include <nuttx/config.h>
+
#include <stdint.h>
+
#include <nuttx/board.h>
+
#include "imx93-evk.h"
/****************************************************************************
diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
index fc30e67cff..6048509b67 100644
--- a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
+++ b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
@@ -67,6 +67,16 @@ int imx9_bringup(void)
}
#endif
+#if defined(CONFIG_I2C_DRIVER)
+ /* Configure I2C peripheral interfaces */
+
+ ret = imx9_i2c_initialize();
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "Failed to initialize I2C driver: %d\n", ret);
+ }
+#endif
+
UNUSED(ret);
return OK;
}
diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
b/boards/arm64/imx9/imx93-evk/src/imx9_i2c.c
similarity index 68%
copy from boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
copy to boards/arm64/imx9/imx93-evk/src/imx9_i2c.c
index fc30e67cff..ac30b5da2d 100644
--- a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
+++ b/boards/arm64/imx9/imx93-evk/src/imx9_i2c.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * boards/arm64/imx9/imx93-evk/src/imx9_bringup.c
+ * boards/arm64/imx9/imx93-evk/src/imx9_i2c.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -24,49 +24,54 @@
#include <nuttx/config.h>
+#include <debug.h>
+#include <errno.h>
#include <sys/types.h>
-#include <syslog.h>
-#include <nuttx/fs/fs.h>
+#include <nuttx/i2c/i2c_master.h>
-#include "imx93-evk.h"
+#include "imx9_lpi2c.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
- * Name: imx_bringup
+ * Name: board_i2c_init
*
* Description:
- * Bring up board features
+ * Configure the I2C driver.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; A negated errno value is returned
+ * to indicate the nature of any failure.
*
****************************************************************************/
-int imx9_bringup(void)
+int imx9_i2c_initialize(void)
{
- int ret;
+ int ret = OK;
-#ifdef CONFIG_FS_PROCFS
- /* Mount the procfs file system */
+#ifdef CONFIG_IMX9_LPI2C1
+ struct i2c_master_s *i2c;
- ret = nx_mount(NULL, "/proc", "procfs", 0, NULL);
- if (ret < 0)
+ i2c = imx9_i2cbus_initialize(1);
+ if (i2c == NULL)
{
- syslog(LOG_ERR, "ERROR: Failed to mount procfs at /proc: %d\n", ret);
+ i2cerr("ERROR: Failed to init I2C0 interface\n");
+ return -ENODEV;
}
#endif
-#ifdef CONFIG_PWM
- /* Configure PWM outputs */
-
- ret = imx9_pwm_setup();
+#ifdef CONFIG_I2C_DRIVER
+ ret = i2c_register(i2c, 0);
if (ret < 0)
{
- syslog(LOG_ERR, "ERROR: Failed initialize PWM outputs: %d\n", ret);
+ i2cerr("ERROR: Failed to register I2C0 driver: %d\n", ret);
+ imx9_i2cbus_uninitialize(i2c);
+ return ret;
}
#endif
- UNUSED(ret);
return OK;
}