diff --git a/arch/arm/src/s32k1xx/Kconfig b/arch/arm/src/s32k1xx/Kconfig index a011e6002c..5da747b11b 100644 --- a/arch/arm/src/s32k1xx/Kconfig +++ b/arch/arm/src/s32k1xx/Kconfig @@ -641,6 +641,58 @@ config S32K1XX_LPSPI_HWPCS endmenu # LPSPI Configuration +menu "LPI2C Configuration" + depends on S32K1XX_LPI2C + +config S32K1XX_LPI2C_DMA + bool "I2C DMA Support" + default n + depends on S32K1XX_LPI2C && S32K1XX_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 S32K1XX_LPI2C_DMA_MAXMSG + int "Maximum number messages that will be DMAed" + default 8 + depends on S32K1XX_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 S32K1XX_LPI2C_DYNTIMEO + bool "Use dynamic timeouts" + default n + depends on S32K1XX_LPI2C + +config S32K1XX_LPI2C_DYNTIMEO_USECPERBYTE + int "Timeout Microseconds per Byte" + default 500 + depends on S32K1XX_LPI2C_DYNTIMEO + +config S32K1XX_LPI2C_DYNTIMEO_STARTSTOP + int "Timeout for Start/Stop (Milliseconds)" + default 1000 + depends on S32K1XX_LPI2C_DYNTIMEO + +config S32K1XX_LPI2C_TIMEOSEC + int "Timeout seconds" + default 0 + depends on S32K1XX_LPI2C + +config S32K1XX_LPI2C_TIMEOMS + int "Timeout Milliseconds" + default 500 + depends on S32K1XX_LPI2C && !S32K1XX_LPI2C_DYNTIMEO + +config S32K1XX_LPI2C_TIMEOTICKS + int "Timeout for Done and Stop (ticks)" + default 500 + depends on S32K1XX_LPI2C && !S32K1XX_LPI2C_DYNTIMEO + menu "LPI2C0 Master Configuration" depends on S32K1XX_LPI2C0 @@ -648,6 +700,11 @@ config LPI2C0_BUSYIDLE int "Bus idle timeout period in clock cycles" default 0 +config LPI2C0_DMA + bool "Enable DMA for I2C0" + default n + depends on S32K1XX_LPI2C_DMA + config LPI2C0_FILTSCL int "I2C master digital glitch filters for SCL input in clock cycles" default 0 @@ -678,6 +735,11 @@ endmenu # LPI2C0 Slave Configuration menu "LPI2C1 Master Configuration" depends on S32K1XX_LPI2C1 +config LPI2C1_DMA + bool "Enable DMA for I2C1" + default n + depends on S32K1XX_LPI2C_DMA + config LPI2C1_BUSYIDLE int "Bus idle timeout period in clock cycles" default 0 @@ -708,6 +770,7 @@ config LPI2C1_SLAVE_BUS the LPI2C master. These pins need to be defined in the board.h. endmenu # LPI2C1 Slave Configuration +endmenu # LPI2C Configuration menu "Ethernet Configuration" depends on S32K1XX_ENET diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_lpi2c.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_lpi2c.h index b9740b7ccc..dbdc70255a 100644 --- a/arch/arm/src/s32k1xx/hardware/s32k1xx_lpi2c.h +++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_lpi2c.h @@ -239,7 +239,7 @@ /* 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(n) ((n) & LPI2C_MCFGR1_PRESCALE_MASK) # define LPI2C_MCFGR1_PRESCALE_1 (0) # define LPI2C_MCFGR1_PRESCALE_2 (1) # define LPI2C_MCFGR1_PRESCALE_4 (2) @@ -254,7 +254,7 @@ /* 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(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) @@ -266,7 +266,7 @@ /* 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_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) @@ -281,17 +281,17 @@ #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) +# 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) +# 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) +# define LPI2C_MCFG2_FILTSDA_CYCLES(n) (((n) << LPI2C_MCFG2_FILTSDA_SHIFT) & LPI2C_MCFG2_FILTSDA_MASK) /* Bits 31-28 Reserved */ /* LPI2C Master Config Register 3 */ @@ -299,56 +299,56 @@ /* 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) +# 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) +# 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) +# 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) +# 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) +# 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) +# 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) +# 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) +# 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) +# 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) +# 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) +# define LPI2C_MCCR1_DATAVD(n) (((n) << LPI2C_MCCR1_DATAVD_SHIFT) & LPI2C_MCCR1_DATAVD_MASK) /* Bits 31-30 Reserved */ /* LPI2C Master FIFO Control Register */ @@ -356,13 +356,13 @@ #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*/ +# 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*/ +# define LPI2C_MFCR_RXWATER(n) (((n) << LPI2C_MFCR_RXWATER_SHIFT) & LPI2C_MFCR_RXWATER_MASK) /* Transmit FIFO Watermark*/ /* Bits 31-18 Reserved */ @@ -381,10 +381,10 @@ #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_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(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) @@ -478,7 +478,7 @@ /* 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_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) @@ -492,21 +492,21 @@ /* 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) +# 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) +# 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) +# 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) +# define LPI2C_SCFG2_FILTSDA_CYCLES(n) (((n) << LPI2C_SCFG2_FILTSDA_SHIFT) & LPI2C_SCFG2_FILTSDA_MASK) /* Bits 31-28 Reserved */ /* LPI2C Slave Address Match Register */ @@ -514,11 +514,11 @@ /* 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) +# 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) +# define LPI2C_SAMR_ADDR1(n) (((n) << LPI2C_SAMR_ADDR1_SHIFT) & LPI2C_SAMR_ADDR1_MASK) /* Bits 31-27 Reserved */ /* LPI2C Slave Address Status Register */ @@ -538,14 +538,14 @@ #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) +# 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) +# define LPI2C_SRDR_DATA(n) (((n) << LPI2C_SRDR_DATA_SHIFT) & LPI2C_SRDR_DATA_MASK) /* Bits 8-31 Reserved */ #endif /* __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_LPI2C_H */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c b/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c index 1a900fc724..cccfa6f150 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c +++ b/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c @@ -43,7 +43,9 @@ #include #include "arm_internal.h" +#include "s32k1xx_edma.h" #include "s32k1xx_pin.h" +#include "hardware/s32k1xx_dmamux.h" #include "hardware/s32k1xx_pinmux.h" #include "s32k1xx_lpi2c.h" #include "s32k1xx_periphclocks.h" @@ -163,6 +165,10 @@ struct s32k1xx_lpi2c_config_s #ifndef CONFIG_I2C_POLLED uint32_t irq; /* Event IRQ */ #endif +#ifdef CONFIG_S32K1XX_LPI2C_DMA + uint32_t dma_rxreqsrc; /* DMA mux rx source */ + uint32_t dma_txreqsrc; /* DMA mux tx source */ +#endif }; /* I2C Device Private Data */ @@ -202,6 +208,11 @@ struct s32k1xx_lpi2c_priv_s struct s32k1xx_trace_s trace[CONFIG_I2C_NTRACE]; #endif +#ifdef CONFIG_S32K1XX_LPI2C_DMA + DMACH_HANDLE rxdma; /* rx DMA handle */ + DMACH_HANDLE txdma; /* tx DMA handle */ + uint16_t cmnds[CONFIG_S32K1XX_LPI2C_DMA_MAXMSG]; /* Commands */ +#endif uint32_t status; /* End of transfer SR2|SR1 status */ }; @@ -273,6 +284,13 @@ static int s32k1xx_lpi2c_transfer(struct i2c_master_s *dev, static int s32k1xx_lpi2c_reset(struct i2c_master_s *dev); #endif +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static void s32k1xx_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result); +static void s32k1xx_txdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -318,6 +336,10 @@ static const struct s32k1xx_lpi2c_config_s s32k1xx_lpi2c0_config = #ifndef CONFIG_I2C_POLLED .irq = S32K1XX_IRQ_LPI2C0M, #endif +#ifdef CONFIG_LPI2C0_DMA + .dma_rxreqsrc = S32K1XX_DMACHAN_LPI2C0_RX, + .dma_txreqsrc = S32K1XX_DMACHAN_LPI2C0_TX, +#endif }; static struct s32k1xx_lpi2c_priv_s s32k1xx_lpi2c0_priv = @@ -348,6 +370,10 @@ static const struct s32k1xx_lpi2c_config_s s32k1xx_lpi2c1_config = #ifndef CONFIG_I2C_POLLED .irq = S32K1XX_IRQ_LPI2C1M, #endif +#ifdef CONFIG_LPI2C1_DMA + .dma_rxreqsrc = S32K1XX_DMACHAN_LPI2C1_RX, + .dma_txreqsrc = S32K1XX_DMACHAN_LPI2C1_TX, +#endif }; static struct s32k1xx_lpi2c_priv_s s32k1xx_lpi2c1_priv = @@ -478,13 +504,17 @@ s32k1xx_lpi2c_sem_waitdone(struct s32k1xx_lpi2c_priv_s *priv) flags = enter_critical_section(); +#ifdef CONFIG_S32K1XX_LPI2C_DMA + if (priv->rxdma == NULL && priv->txdma == NULL) + { +#endif /* 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 | \ + regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | LPI2C_MIER_SDIE; s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MIER_OFFSET, regval); } @@ -507,7 +537,10 @@ s32k1xx_lpi2c_sem_waitdone(struct s32k1xx_lpi2c_priv_s *priv) * are currently disabled but will be temporarily re-enabled below when * nxsem_tickwait_uninterruptible() sleeps. */ +#ifdef CONFIG_S32K1XX_LPI2C_DMA + } +#endif priv->intstate = INTSTATE_WAITING; do { @@ -755,6 +788,112 @@ s32k1xx_lpi2c_sem_destroy(struct s32k1xx_lpi2c_priv_s *priv) #endif } +/**************************************************************************** + * Name: s32k1xx_rxdma_callback + * + * Description: + * This function performs the next I2C operation + * + ****************************************************************************/ +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static void s32k1xx_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct s32k1xx_lpi2c_priv_s *priv = (struct s32k1xx_lpi2c_priv_s *)arg; + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MIER_OFFSET, 0, + LPI2C_MIER_SDIE); + + if (result != OK) + { + priv->status = s32k1xx_lpi2c_getstatus(priv); + + if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0) + { + i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", priv->status); + + s32k1xx_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + /* Clear the TX and RX FIFOs */ + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Clear the error */ + + s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MSR_OFFSET, + (priv->status & (LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF | + LPI2C_MSR_PLTF))); + + if (priv->intstate == INTSTATE_WAITING) + { + /* inform the thread that transfer is complete + * and wake it up + */ + + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } + } + } +} +#endif + +/**************************************************************************** + * Name: s32k1xx_txdma_callback + * + * Description: + * This function performs the next I2C operation + * + ****************************************************************************/ +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static void s32k1xx_txdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct s32k1xx_lpi2c_priv_s *priv = (struct s32k1xx_lpi2c_priv_s *)arg; + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MIER_OFFSET, 0, + LPI2C_MIER_SDIE); + + if (result != OK) + { + priv->status = s32k1xx_lpi2c_getstatus(priv); + + if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0) + { + i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", priv->status); + + s32k1xx_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + /* Clear the TX and RX FIFOs */ + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Clear the error */ + + s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MSR_OFFSET, + (priv->status & (LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF | + LPI2C_MSR_PLTF))); + + if (priv->intstate == INTSTATE_WAITING) + { + /* inform the thread that transfer is complete + * and wake it up + */ + + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } + } + } +} +#endif + /**************************************************************************** * Name: s32k1xx_lpi2c_trace* * @@ -1142,6 +1281,20 @@ s32k1xx_lpi2c_getstatus(struct s32k1xx_lpi2c_priv_s *priv) return s32k1xx_lpi2c_getreg(priv, S32K1XX_LPI2C_MSR_OFFSET); } +/**************************************************************************** + * Name: imxrt_lpi2c_getenabledints + * + * Description: + * Get 32-bit status + * + ****************************************************************************/ + +static inline uint32_t +s32k1xx_lpi2c_getenabledints(struct s32k1xx_lpi2c_priv_s *priv) +{ + return s32k1xx_lpi2c_getreg(priv, S32K1XX_LPI2C_MIER_OFFSET); +} + /**************************************************************************** * Name: s32k1xx_lpi2c_isr_process * @@ -1154,7 +1307,87 @@ static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s *priv) { uint32_t status = s32k1xx_lpi2c_getstatus(priv); - /* Check for new trace setup */ +#ifdef CONFIG_S32K1XX_LPI2C_DMA + uint32_t current_status = status; + + /* Condition the status with only the enabled interrupts */ + + status &= s32k1xx_lpi2c_getenabledints(priv); + + if (priv->rxdma != NULL || priv->txdma != NULL) + { + /* End of packet or Stop */ + + if ((status & (LPI2C_MSR_SDF | LPI2C_MSR_EPF)) != 0) + { + s32k1xx_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Acknowledge End of packet or Stop */ + + s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MSR_OFFSET, status & + (LPI2C_MSR_SDF | + LPI2C_MSR_EPF)); + } + + /* Is there an Error condition */ + + if (current_status & LPI2C_MSR_ERROR_MASK) + { + s32k1xx_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + /* Shutdown DMA */ + + if (priv->rxdma != NULL) + { + s32k1xx_dmach_stop(priv->rxdma); + } + + if (priv->txdma != NULL) + { + s32k1xx_dmach_stop(priv->txdma); + } + + /* Clear the TX and RX FIFOs */ + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Clear the error */ + + s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MSR_OFFSET, + (current_status & (LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF))); + + /* Return the full error status */ + + status = current_status; + } + + /* Mark that this transaction stopped */ + + priv->msgv = NULL; + priv->msgc = 0; + priv->dcnt = -1; + + if (priv->intstate == INTSTATE_WAITING) + { + /* Update Status once at the end */ + + priv->status = status; + + /* inform the thread that transfer is complete + * and wake it up + */ + + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } + + return OK; + } + +#endif /* Check for new trace setup */ s32k1xx_lpi2c_tracenew(priv, status); @@ -1297,8 +1530,8 @@ static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s *priv) * and wake it up */ - nxsem_post(&priv->sem_isr); priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); } #else priv->status = status; @@ -1350,8 +1583,8 @@ static int s32k1xx_lpi2c_isr_process(struct s32k1xx_lpi2c_priv_s *priv) * and wake it up */ - nxsem_post(&priv->sem_isr); priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); } #else priv->status = status; @@ -1491,6 +1724,223 @@ static int s32k1xx_lpi2c_deinit(struct s32k1xx_lpi2c_priv_s *priv) * Device Driver Operations ****************************************************************************/ +/**************************************************************************** + * Name: s32k1xx_lpi2c_dma_command_configure + * + * Description: + * Create a command TCD + * + ****************************************************************************/ + +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static int +s32k1xx_lpi2c_dma_command_configure(struct s32k1xx_lpi2c_priv_s + *priv, uint16_t *ccmd, + uint32_t ncmd) +{ + struct s32k1xx_edma_xfrconfig_s config; + memset(&config, 0, sizeof(config)); + + config.saddr = (uint32_t) ccmd; + config.daddr = priv->config->base + S32K1XX_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 s32k1xx_dmach_xfrsetup(priv->txdma, &config); +} +#endif + +/**************************************************************************** + * Name: s32k1xx_lpi2c_dma_data_configure + * + * Description: + * Create a data TCD + * + ****************************************************************************/ + +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static int s32k1xx_lpi2c_dma_data_configure(struct s32k1xx_lpi2c_priv_s + *priv, + struct i2c_msg_s *msg) +{ + DMACH_HANDLE dma; + struct s32k1xx_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 + S32K1XX_LPI2C_MRDR_OFFSET; + config.daddr = (uint32_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 = (uint32_t) msg->buffer; + config.daddr = priv->config->base + S32K1XX_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 s32k1xx_dmach_xfrsetup(dma, &config) ? 0 : msg->length; +} +#endif + +/**************************************************************************** + * Name: s32k1xx_lpi2c_configure_dma_transfer + * + * Description: + * DMA based I2C transfer function + * + ****************************************************************************/ + +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static int s32k1xx_lpi2c_form_command_list(struct s32k1xx_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: s32k1xx_lpi2c_dma_transfer + * + * Description: + * DMA based I2C transfer function + * + ****************************************************************************/ + +#ifdef CONFIG_S32K1XX_LPI2C_DMA +static int s32k1xx_lpi2c_dma_transfer(struct s32k1xx_lpi2c_priv_s *priv) +{ + int m; + int ntotcmds = 0; + int ncmds = 0; + uint16_t *ccmnd = NULL; + + /* Disable Interrupts */ + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MIER_OFFSET, + LPI2C_MIER_RDIE | LPI2C_MIER_TDIE, 0); + + /* Disable DMA */ + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MDER_OFFSET, LPI2C_MDER_TDDE | + LPI2C_MDER_RDDE, 0); + + /* Turn off auto_stop option */ + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MCFGR1_OFFSET, 0, + LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP); + + /* Form chains of tcd 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 = s32k1xx_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 */ + + s32k1xx_lpi2c_dma_command_configure(priv, ccmnd, ncmds - ntotcmds); + + ntotcmds += ncmds; + + DEBUGASSERT(ntotcmds < CONFIG_S32K1XX_LPI2C_DMA_MAXMSG); + + s32k1xx_lpi2c_dma_data_configure(priv, &priv->msgv[m]); + } + } + + s32k1xx_lpi2c_putreg(priv, S32K1XX_LPI2C_MIER_OFFSET, + LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | + LPI2C_MIER_PLTIE | LPI2C_MIER_FEIE); + + s32k1xx_dmach_start(priv->rxdma, s32k1xx_rxdma_callback, (void *)priv); + s32k1xx_dmach_start(priv->txdma, s32k1xx_txdma_callback, (void *)priv); + + s32k1xx_lpi2c_modifyreg(priv, S32K1XX_LPI2C_MDER_OFFSET, 0, + LPI2C_MDER_TDDE | LPI2C_MDER_RDDE); + return OK; +} +#endif + /**************************************************************************** * Name: s32k1xx_lpi2c_transfer * @@ -1548,8 +1998,27 @@ static int s32k1xx_lpi2c_transfer(struct i2c_master_s *dev, * the BUSY flag. */ +#ifdef CONFIG_S32K1XX_LPI2C_DMA + if (priv->rxdma || priv->txdma) + { + s32k1xx_lpi2c_dma_transfer(priv); + } +#endif + if (s32k1xx_lpi2c_sem_waitdone(priv) < 0) { +#ifdef CONFIG_S32K1XX_LPI2C_DMA + if (priv->rxdma != NULL) + { + s32k1xx_dmach_stop(priv->rxdma); + } + + if (priv->txdma != NULL) + { + s32k1xx_dmach_stop(priv->txdma); + } + +#endif ret = -ETIMEDOUT; i2cerr("ERROR: Timed out: MCR: status: 0x%" PRIx32 "\n", priv->status); @@ -1787,6 +2256,22 @@ struct i2c_master_s *s32k1xx_i2cbus_initialize(int port) { s32k1xx_lpi2c_sem_init(priv); s32k1xx_lpi2c_init(priv); + +#ifdef CONFIG_S32K1XX_LPI2C_DMA + if (priv->config->dma_txreqsrc != 0) + { + priv->txdma = s32k1xx_dmach_alloc(priv->config->dma_txreqsrc | + DMAMUX_CHCFG_ENBL, 0); + DEBUGASSERT(priv->txdma != NULL); + } + + if (priv->config->dma_rxreqsrc != 0) + { + priv->rxdma = s32k1xx_dmach_alloc(priv->config->dma_rxreqsrc | + DMAMUX_CHCFG_ENBL, 0); + DEBUGASSERT(priv->rxdma != NULL); + } +#endif } leave_critical_section(flags); @@ -1828,6 +2313,22 @@ int s32k1xx_i2cbus_uninitialize(struct i2c_master_s *dev) /* Disable power and other HW resource (GPIO's) */ +#ifdef CONFIG_S32K1XX_LPI2C_DMA + if (priv->rxdma != NULL) + { + s32k1xx_dmach_stop(priv->rxdma); + s32k1xx_dmach_free(priv->rxdma); + priv->rxdma = NULL; + } + + if (priv->txdma != NULL) + { + s32k1xx_dmach_stop(priv->txdma); + s32k1xx_dmach_free(priv->txdma); + priv->txdma = NULL; + } +#endif + s32k1xx_lpi2c_deinit(priv); /* Release unused resources */