diff --git a/arch/renesas/include/rx65n/irq.h b/arch/renesas/include/rx65n/irq.h index 71828521246..991ccd8b08f 100644 --- a/arch/renesas/include/rx65n/irq.h +++ b/arch/renesas/include/rx65n/irq.h @@ -116,7 +116,9 @@ #ifdef CONFIG_RX65N_RSPI0 # define RX65N_SPRI0_IRQ (RX65N_RSPI0_IRQBASE) # define RX65N_SPTI0_IRQ (RX65N_RSPI0_IRQBASE + 1) -# define RX65N_RSPI1_IRQBASE (RX65N_RSPI0_IRQBASE + 2) +# define RX65N_SPEI0_IRQ (RX65N_RSPI0_IRQBASE + 2) +# define RX65N_SPII0_IRQ (RX65N_RSPI0_IRQBASE + 3) +# define RX65N_RSPI1_IRQBASE (RX65N_RSPI0_IRQBASE + 4) #else # define RX65N_RSPI1_IRQBASE (RX65N_RSPI0_IRQBASE) #endif @@ -124,7 +126,9 @@ #ifdef CONFIG_RX65N_RSPI1 # define RX65N_SPRI1_IRQ (RX65N_RSPI1_IRQBASE) # define RX65N_SPTI1_IRQ (RX65N_RSPI1_IRQBASE + 1) -# define RX65N_QSPI_IRQBASE (RX65N_RSPI1_IRQBASE + 2) +# define RX65N_SPEI1_IRQ (RX65N_RSPI1_IRQBASE + 2) +# define RX65N_SPII1_IRQ (RX65N_RSPI1_IRQBASE + 3) +# define RX65N_QSPI_IRQBASE (RX65N_RSPI1_IRQBASE + 4) #else # define RX65N_QSPI_IRQBASE (RX65N_RSPI1_IRQBASE) #endif @@ -374,7 +378,9 @@ #ifdef CONFIG_RX65N_RSPI2 # define RX65N_SPRI2_IRQ (RX65N_RSPI2_IRQBASE) # define RX65N_SPTI2_IRQ (RX65N_RSPI2_IRQBASE + 1) -# define RX65N_IRQ_GROUPBL_IRQBASE (RX65N_RSPI2_IRQBASE + 2) +# define RX65N_SPEI2_IRQ (RX65N_RSPI2_IRQBASE + 2) +# define RX65N_SPII2_IRQ (RX65N_RSPI2_IRQBASE + 3) +# define RX65N_IRQ_GROUPBL_IRQBASE (RX65N_RSPI2_IRQBASE + 4) #else # define RX65N_IRQ_GROUPBL_IRQBASE (RX65N_RSPI2_IRQBASE) #endif diff --git a/arch/renesas/src/rx65n/Kconfig b/arch/renesas/src/rx65n/Kconfig index b3a8e776bcb..3d24edee077 100644 --- a/arch/renesas/src/rx65n/Kconfig +++ b/arch/renesas/src/rx65n/Kconfig @@ -203,6 +203,75 @@ config RX65N_RTC config RX65N_CARRY bool "RTC" default y + +config RX65N_RSPI + bool "RSPI" + select SPI + select SPI_DRIVER + default n + +if RX65N_RSPI + +config RX65N_DATA_TRANSFER_MODE + bool "Data transfer mode" + default y + +if RX65N_DATA_TRANSFER_MODE + +config RX65N_RSPI_SW_DT_MODE + bool "Software DT mode" + default n + +config RX65N_RSPI_DTC_DT_MODE + bool "DTC DT mode" + depends on !RX65N_RSPI_SW_DT_MODE + select RX65N_DTC + default y + +endif + +config RX65N_RSPI_HIGHSPEED + bool "Speed: 0:Normal,1:High" + default y + +config RX65N_RSPI_BITORDER + bool "Bit order: 0:MSBF,1:LSBF" + default y + +config RX65N_RSPI_BUF_SIZE + int "RSPI buffer size(1-4)" + default 1 + range 1 4 + +config RX65N_RSPI_SPCKD_DELAY + int "RSPI clock delay" + default 2 + range 0 7 + +config RX65N_RSPI_SSLND_DELAY + int "RSPI SSL negation delay" + default 2 + range 0 7 + +config RX65N_RSPI_SPND_DELAY + int "RSPI next access delay" + default 2 + range 0 7 + +config RX65N_RSPI0 + bool "RSPI0" + default y + +config RX65N_RSPI1 + bool "RSPI1" + default n + +config RX65N_RSPI2 + bool "RSPI2" + default n + +endif + config RX65N_RIIC0 bool "RIIC0" default n @@ -341,6 +410,20 @@ config RX65N_RIIC2_RCV_IN_BYTE_UNITS endif #RX65N_RIIC2 +config RX65N_USBDEV + bool "USB0 Device" + default n + depends on USBDEV + +if RX65N_USBDEV + +config RX65N_TEST_INTEP + bool "Testing RX65N Interrupt endpoint" + default n + depends on SERIAL_IFLOWCONTROL && CDCACM_IFLOWCONTROL + +endif #RX65N_USBDEV + config RX65N_DTC bool "DTC" default n @@ -500,6 +583,74 @@ config RX65N_EMAC0 select NETDEVICES select ARCH_HAVE_PHY +config RX65N_RSPI + bool "RSPI" + select SPI + select SPI_DRIVER + default n + +if RX65N_RSPI + +config RX65N_DATA_TRANSFER_MODE + bool "Data transfer mode" + default y + +if RX65N_DATA_TRANSFER_MODE + +config RX65N_RSPI_SW_DT_MODE + bool "Software DT mode" + default n + +config RX65N_RSPI_DTC_DT_MODE + bool "DTC DT mode" + depends on !RX65N_RSPI_SW_DT_MODE + select RX65N_DTC + default y + +endif + +config RX65N_RSPI_HIGHSPEED + bool "Speed: 0:Normal,1:High" + default y + +config RX65N_RSPI_BITORDER + bool "Bit order: 0:MSBF,1:LSBF" + default y + +config RX65N_RSPI_BUF_SIZE + int "RSPI buffer size(1-4)" + default 1 + range 1 4 + +config RX65N_RSPI_SPCKD_DELAY + int "RSPI clock delay" + default 2 + range 0 7 + +config RX65N_RSPI_SSLND_DELAY + int "RSPI SSL negation delay" + default 2 + range 0 7 + +config RX65N_RSPI_SPND_DELAY + int "RSPI next access delay" + default 2 + range 0 7 + +config RX65N_RSPI0 + bool "RSPI0" + default y + +config RX65N_RSPI1 + bool "RSPI1" + default n + +config RX65N_RSPI2 + bool "RSPI2" + default n + +endif + config RX65N_RIIC0 bool "RIIC0" default n diff --git a/arch/renesas/src/rx65n/Make.defs b/arch/renesas/src/rx65n/Make.defs index 0844537071b..8f401d02ae5 100644 --- a/arch/renesas/src/rx65n/Make.defs +++ b/arch/renesas/src/rx65n/Make.defs @@ -63,6 +63,10 @@ ifeq ($(CONFIG_USBDEV),y) CHIP_CSRCS += rx65n_usbdev.c endif +ifeq ($(CONFIG_RX65N_RSPI),y) +CHIP_CSRCS += rx65n_rspi.c +endif + ifeq ($(CONFIG_I2C),y) CHIP_CSRCS += rx65n_riic.c endif diff --git a/arch/renesas/src/rx65n/rx65n_definitions.h b/arch/renesas/src/rx65n/rx65n_definitions.h index 79dfa42513d..81d8293c14d 100644 --- a/arch/renesas/src/rx65n/rx65n_definitions.h +++ b/arch/renesas/src/rx65n/rx65n_definitions.h @@ -227,6 +227,12 @@ #define RX65N_GRPAL0_ERI10_MASK (1U << 9) #define RX65N_GRPAL0_TEI11_MASK (1U << 12) #define RX65N_GRPAL0_ERI11_MASK (1U << 13) +#define RX65N_GRPAL0_SPII0_MASK (1U << 16) +#define RX65N_GRPAL0_SPEI0_MASK (1U << 17) +#define RX65N_GRPAL0_SPII1_MASK (1U << 18) +#define RX65N_GRPAL0_SPEI1_MASK (1U << 19) +#define RX65N_GRPAL0_SPII2_MASK (1U << 20) +#define RX65N_GRPAL0_SPEI2_MASK (1U << 21) #define RX65N_GRPBL0_TEI12_MASK (1U << 16) #define RX65N_GRPBL0_ERI12_MASK (1U << 17) @@ -1443,6 +1449,163 @@ #define USB_INT_BRDY (0x0001u) #define USB_BMREQUESTTYPERECIP (0x001Fu) /* b4-0: Recipient */ +/* Start of RSPI interface related definitions */ + +#if defined(CONFIG_SPI) || defined(CONFIG_SPI_DRIVER) + #define HAVE_RSPI_DRIVER 1 +#endif + +#define RX65N_RSPI0_BASE (0x000D0100) +#define RX65N_RSPI1_BASE (0x000D0140) +#define RX65N_RSPI2_BASE (0x000D0300) + +/* Tx and Rx vector number */ + +#define RX65N_RSPI0_RXVECT (38) +#define RX65N_RSPI0_TXVECT (39) +#define RX65N_RSPI1_RXVECT (40) +#define RX65N_RSPI1_TXVECT (41) +#define RX65N_RSPI2_RXVECT (108) +#define RX65N_RSPI2_TXVECT (109) + +#define RX65N_PCLK_FREQUENCY RX_PCLKA + +/* RSPI Register offsets */ + +#define RX65N_RSPI_SPCR_OFFSET (0x0000) /* RSPI Control Register */ +#define RX65N_RSPI_SSLP_OFFSET (0x0001) /* RSPI Slave Select Polarity Register */ +#define RX65N_RSPI_SPPCR_OFFSET (0x0002) /* RSPI Pin Control Register */ +#define RX65N_RSPI_SPSR_OFFSET (0x0003) /* RSPI Status Register */ +#define RX65N_RSPI_SPDR_OFFSET (0x0004) /* RSPI Data Register */ +#define RX65N_RSPI_SPSCR_OFFSET (0x0008) /* RSPI Sequence Control Register */ +#define RX65N_RSPI_SPSSR_OFFSET (0x0009) /* RSPI Sequence Status Register */ +#define RX65N_RSPI_SPBR_OFFSET (0x000A) /* RSPI Bit Rate Register */ +#define RX65N_RSPI_SPDCR_OFFSET (0x000B) /* RSPI Data Control Register */ +#define RX65N_RSPI_SPCKD_OFFSET (0x000C) /* RSPI Clock Delay Register */ +#define RX65N_RSPI_SSLND_OFFSET (0x000D) /* RSPI Slave Select Negation Delay Register */ +#define RX65N_RSPI_SPND_OFFSET (0x000E) /* RSPI Next-Access Delay Register */ +#define RX65N_RSPI_SPCR2_OFFSET (0x000F) /* RSPI Control Register 2 */ +#define RX65N_RSPI_SPCMD0_OFFSET (0x0010) /* RSPI Command Registers 0 */ +#define RX65N_RSPI_SPCMD1_OFFSET (0x0012) /* RSPI Command Registers 1 */ +#define RX65N_RSPI_SPCMD2_OFFSET (0x0014) /* RSPI Command Registers 2 */ +#define RX65N_RSPI_SPCMD3_OFFSET (0x0016) /* RSPI Command Registers 3 */ +#define RX65N_RSPI_SPCMD4_OFFSET (0x0018) /* RSPI Command Registers 4 */ +#define RX65N_RSPI_SPCMD5_OFFSET (0x001A) /* RSPI Command Registers 5 */ +#define RX65N_RSPI_SPCMD6_OFFSET (0x001C) /* RSPI Command Registers 6 */ +#define RX65N_RSPI_SPCMD7_OFFSET (0x001E) /* RSPI Command Registers 7 */ +#define RX65N_RSPI_SPDCR2_OFFSET (0x0020) /* RSPI Data Control Register 2 */ + +/* RSPI Control Register bits */ + +#define RSPI_SPCR_SMPS (1 << 0) /* RSPI Mode Select */ +#define RSPI_SPCR_TXMD (1 << 1) /* Communications Operating Mode Select */ +#define RSPI_SPCR_MODFEN (1 << 2) /* Mode Fault Error Detection Enable */ +#define RSPI_SPCR_MSTR (1 << 3) /* RSPI Master/Slave Mode Select */ +#define RSPI_SPCR_SPEIE (1 << 4) /* RSPI Error Interrupt Enable */ +#define RSPI_SPCR_SPTIE (1 << 5) /* Transmit Buffer Empty Interrupt Enable */ +#define RSPI_SPCR_SPE (1 << 6) /* RSPI Function Enable */ +#define RSPI_SPCR_SPRIE (1 << 7) /* RSPI Receive Buffer Full Interrupt Enable */ + +/* RSPI Slave Select Polarity Register bits */ + +#define RSPI_SSLP_SSL0P (1 << 0) /* SSL0 Signal Polarity Setting */ +#define RSPI_SSLP_SSL1P (1 << 1) /* SSL0 Signal Polarity Setting */ +#define RSPI_SSLP_SSL2P (1 << 2) /* SSL0 Signal Polarity Setting */ +#define RSPI_SSLP_SSL3P (1 << 3) /* SSL0 Signal Polarity Setting */ + +/* RSPI Pin Control Register bits */ + +#define RSPI_SPPCR_SPLP (1 << 0) /* 0: Normal mode. 1: Loopback mode (reversed transmit data = receive). */ +#define RSPI_SPPCR_SPLP2 (1 << 1) /* 0: Normal mode. 1: Loopback mode (transmit data = receive data). */ +#define RSPI_SPPCR_MOIFV (1 << 4) /* 0: MOSI pin idles low. 1: MOSI pin idles high. */ +#define RSPI_SPPCR_MOIFE (1 << 5) /* 0: MOSI pin idles at final previous data. 1: MOSI pin idles at MOIFV. */ + +/* RSPI status register bits */ + +#define RSPI_SPSR_OVRF (1 << 0) /* Overrun Error Flag */ +#define RSPI_SPSR_IDLNF (1 << 1) /* RSPI Idle Flag */ +#define RSPI_SPSR_MODF (1 << 2) /* Mode Fault Error Flag */ +#define RSPI_SPSR_PERF (1 << 3) /* Parity Error Flag */ +#define RSPI_SPSR_UDRF (1 << 4) /* Underrun Error Flag */ +#define RSPI_SPSR_SPTEF (1 << 5) /* Transmit Buffer Empty Flag */ +#define RSPI_SPSR_SPRF (1 << 7) /* Receive Buffer Full Flag */ +#define RSPI_SPSR_MODF_UDRF_MASK (0xAB) /* Protect reserved bits. */ + +/* RSPI Data Control Register bit and mask */ + +#define RSPI_SPDCR_MASK (0x73) /* Mask for SPDCR*/ +#define RSPI_SPDCR_SPFC0 (1 << 0) /* b0 used for number of frame calculation with b1 */ +#define RSPI_SPDCR_SPFC1 (1 << 1) /* b1 used for number of frame calculation with b0 */ +#define RSPI_SPDCR_SPRDTD (1 << 4) /* RSPI Receive/Transmit Data Select*/ +#define RSPI_SPDCR_SPLW (1 << 5) /* RSPI Longword Access Word Access Specification */ +#define RSPI_SPDCR_SPBYT (1 << 6) /* RSPI Byte Access Specification*/ +#define RSPI_SPDCR_SPFC_MASK (0x3) /* SPFC mask */ + +/* RSPI command register bits */ + +#define RSPI_SPCMD_MASK (0xFF << 0) /* RSPI Command Register mask */ +#define RSPI_SPCMD_PHA (1 << 0) /* RSPCK Phase Setting */ +#define RSPI_SPCMD_POL (1 << 1) /* RSPCK Polarity Setting */ +#define RSPI_SPCMD_BRDV0 (1 << 2) /* Bit Rate Division Setting bit b2 */ +#define RSPI_SPCMD_BRDV1 (1 << 3) /* Bit Rate Division Setting bit b3 */ +#define RSPI_SPCMD_SSLA0 (1 << 4) /* SSL Signal Assertion Setting bit b4 */ +#define RSPI_SPCMD_SSLA1 (1 << 5) /* SSL Signal Assertion Setting bit b5 */ +#define RSPI_SPCMD_SSLA2 (1 << 6) /* SSL Signal Assertion Setting bit b6 */ +#define RSPI_SPCMD_SSLKP (1 << 7) /* SSL Signal Level Keeping bit b7 */ +#define RSPI_SPCMD_SPB0 (1 << 8) /* RSPI Data Length Setting bit b8 */ +#define RSPI_SPCMD_SPB1 (1 << 9) /* RSPI Data Length Setting bit b9 */ +#define RSPI_SPCMD_SPB2 (1 << 10) /* RSPI Data Length Setting bit b10 */ +#define RSPI_SPCMD_SPB3 (1 << 11) /* RSPI Data Length Setting bit b11 */ +#define RSPI_SPCMD_LSBF (1 << 12) /* RSPI LSB First bit b12 */ +#define RSPI_SPCMD_SPNDEN (1 << 13) /* RSPI Next-Access Delay Enable bit */ +#define RSPI_SPCMD_SLNDEN (1 << 14) /* SSL Negation Delay Setting Enable bit */ +#define RSPI_SPCMD_SCKDEN (1 << 15) /* SCKDEN RSPCK Delay Setting Enable bit */ +#define RSPI_SPCMD_BRDV_MASK (3 << 2) /* Bit Rate Division Setting mask */ +#define RSPI_SPCMD_SPB_MASK (15 << 8) /* RSPI Data Length Setting */ + +/* RSPI clock delay register bit */ + +#define RSPI_SPCKD_MASK (7 << 0) /* RSPCK Delay Setting mask */ +#define RSPI_SPCKD_SCKDL0 (1 << 0) /* SCKDL0 bit */ +#define RSPI_SPCKD_SCKDL1 (1 << 1) /* SCKDL1 bit */ +#define RSPI_SPCKD_SCKDL2 (1 << 2) /* SCKDL2 bit */ + +/* RSPI Slave Select Negation Delay Register bit */ + +#define RSPI_SSLND_MASK (7 << 0) /* SSL Negation Delay Setting mask */ +#define RSPI_SSLND_SLNDL0 (1 << 0) /* SLNDL0 bit */ +#define RSPI_SSLND_SLNDL1 (1 << 1) /* SLNDL1 bit */ +#define RSPI_SSLND_SLNDL2 (1 << 2) /* SLNDL2 bit */ + +/* RSPI clock delay register bit */ + +#define RSPI_SPND_MASK (7 << 0) /* RSPI Next-Access Delay mask */ +#define RSPI_SPND_SPNDL0 (1 << 0) /* SPNDL0 bit */ +#define RSPI_SPND_SPNDL1 (1 << 1) /* SPNDL1 bit */ +#define RSPI_SPND_SPNDL2 (1 << 2) /* SPNDL2 bit */ + +/* RSPI RSPI Control Register 2 bit */ + +#define RSPI_SPCR2_MASK (0x1F << 0) /* RSPI Control Register 2 mask */ +#define RSPI_SPCR2_SPPE (1 << 0) /* Parity Enable bit */ +#define RSPI_SPCR2_SPOE (1 << 1) /* Parity Mode bit */ +#define RSPI_SPCR2_SPIIE (1 << 2) /* RSPI Idle Interrupt Enable */ +#define RSPI_SPCR2_PTE (1 << 3) /* Parity Self-Diagnosis bit */ +#define RSPI_SPCR2_SCKASE (1 << 4) /* RSPCK Auto-Stop Function Enable bit */ + +/* RSPI Sequence Control Register 2 bit */ + +#define RSPI_SPSCR_MASK (7 << 0) /* RSPI Sequence Control Register mask */ +#define RSPI_SPSCR_SPSLN0 (1 << 0) /* SPSLN0 bit */ +#define RSPI_SPSCR_SPSLN1 (1 << 1) /* SPSLN1 bit */ +#define RSPI_SPSCR_SPSLN2 (1 << 2) /* SPSLN2 bit */ + +/* Set RSPI data control register 2 bit */ + +#define RSPI_SPDCR2_BYSW (1 << 0) /* RSPI Byte Swap */ + +/* End of RSPI interface related definitions */ + /* RIIC related definitions */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_DRIVER) diff --git a/arch/renesas/src/rx65n/rx65n_irq.c b/arch/renesas/src/rx65n/rx65n_irq.c index 0ff09339d2a..d4cd4541c30 100644 --- a/arch/renesas/src/rx65n/rx65n_irq.c +++ b/arch/renesas/src/rx65n/rx65n_irq.c @@ -426,6 +426,74 @@ void up_disable_irq(int irq) #endif #endif + +#ifdef CONFIG_RX65N_RSPI0 + if (irq == RX65N_SPRI0_IRQ) + { + ICU.IER[0x04].BIT.IEN6 = 0; + } + + if (irq == RX65N_SPTI0_IRQ) + { + ICU.IER[0x04].BIT.IEN7 = 0; + } + + if (irq == RX65N_SPEI0_IRQ) + { + ICU.GENAL0.BIT.EN17 = 0; + } + + if (irq == RX65N_SPII0_IRQ) + { + ICU.GENAL0.BIT.EN16 = 0; + } +#endif + +#ifdef CONFIG_RX65N_RSPI1 + if (irq == RX65N_SPRI1_IRQ) + { + ICU.IER[0x05].BIT.IEN0 = 0; + } + + if (irq == RX65N_SPTI1_IRQ) + { + ICU.IER[0x05].BIT.IEN1 = 0; + } + + if (irq == RX65N_SPEI1_IRQ) + { + ICU.GENAL0.BIT.EN19 = 0; + } + + if (irq == RX65N_SPII1_IRQ) + { + ICU.GENAL0.BIT.EN18 = 0; + } +#endif + +#ifdef CONFIG_RX65N_RSPI2 + if (irq == RX65N_SPRI2_IRQ) + { + ICU.IER[13].BIT.IEN4 = 0; + } + + if (irq == RX65N_SPTI2_IRQ) + { + ICU.IER[13].BIT.IEN5 = 0; + } + + if (irq == RX65N_SPEI2_IRQ) + { + ICU.GENAL0.BIT.EN21 = 0; + } + + if (irq == RX65N_SPII2_IRQ) + { + ICU.GENAL0.BIT.EN20 = 0; + } + +#endif + #ifdef CONFIG_RX65N_RIIC0 if (irq == RX65N_RIIC0_RXI0_IRQ) { @@ -856,6 +924,74 @@ void up_enable_irq(int irq) #endif #endif + +#ifdef CONFIG_RX65N_RSPI0 + if (irq == RX65N_SPRI0_IRQ) + { + ICU.IER[0x04].BIT.IEN6 = 1; + } + + if (irq == RX65N_SPTI0_IRQ) + { + ICU.IER[0x04].BIT.IEN7 = 1; + } + + if (irq == RX65N_SPEI0_IRQ) + { + ICU.GENAL0.BIT.EN17 = 1; + } + + if (irq == RX65N_SPII0_IRQ) + { + ICU.GENAL0.BIT.EN16 = 1; + } +#endif + +#ifdef CONFIG_RX65N_RSPI1 + if (irq == RX65N_SPRI1_IRQ) + { + ICU.IER[0x05].BIT.IEN0 = 1; + } + + if (irq == RX65N_SPTI1_IRQ) + { + ICU.IER[0x05].BIT.IEN1 = 1; + } + + if (irq == RX65N_SPEI1_IRQ) + { + ICU.GENAL0.BIT.EN19 = 1; + } + + if (irq == RX65N_SPII1_IRQ) + { + ICU.GENAL0.BIT.EN18 = 1; + } +#endif + +#ifdef CONFIG_RX65N_RSPI2 + if (irq == RX65N_SPRI2_IRQ) + { + ICU.IER[13].BIT.IEN4 = 1; + } + + if (irq == RX65N_SPTI2_IRQ) + { + ICU.IER[13].BIT.IEN5 = 1; + } + + if (irq == RX65N_SPEI2_IRQ) + { + ICU.GENAL0.BIT.EN21 = 1; + } + + if (irq == RX65N_SPII2_IRQ) + { + ICU.GENAL0.BIT.EN20 = 1; + } + +#endif + #ifdef CONFIG_RX65N_RIIC0 if (irq == RX65N_RIIC0_RXI0_IRQ) { diff --git a/arch/renesas/src/rx65n/rx65n_rspi.c b/arch/renesas/src/rx65n/rx65n_rspi.c new file mode 100644 index 00000000000..f0a6b375957 --- /dev/null +++ b/arch/renesas/src/rx65n/rx65n_rspi.c @@ -0,0 +1,2557 @@ +/**************************************************************************** + * arch/renesas/src/rx65n/rx65n_rspi.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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip.h" +#include "up_arch.h" +#include "rx65n_definitions.h" +#include "rx65n_rspi.h" +#include "rx65n_dtc.h" + +#include +#include + +#if defined(CONFIG_RX65N_RSPI0) || defined(CONFIG_RX65N_RSPI1) || defined(CONFIG_RX65N_RSPI2) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Default bit rate */ + +#define RSPI_BRDV_DEFAULT 0 + +/* The number of words that will fit in the Tx FIFO */ + +#define RX65N_TXFIFO_WORDS BUFSIZE_4FRAME + +/* Interrupt priority */ + +#define RX65N_RSPI_INTRRUPT_PRIO 15 + +/* RSPI power on and off */ + +#define RSPI_POWER_ON 0 +#define RSPI_POWER_OFF 1 + +/* RSPI Register protection enable and disable */ + +#define REG_PROTECTION_ON 1 +#define REG_PROTECTION_OFF 0 + +/* Frequency divisor */ + +enum FREQ_DIVISOR +{ + FREQ_DIVISOR_2 = 2, + FREQ_DIVISOR_4 = 4, + FREQ_DIVISOR_6 = 6, + FREQ_DIVISOR_8 = 8, + FREQ_DIVISOR_10 = 10, + FREQ_DIVISOR_12 = 12, + FREQ_DIVISOR_24 = 24, + FREQ_DIVISOR_48 = 48, + FREQ_DIVISOR_96 = 96, +}; + +/* The number of words that will fit in the buffer */ + +enum BUF_SIZE +{ + BUFSIZE_1FRAME = 1, + BUFSIZE_2FRAME = 2, + BUFSIZE_3FRAME = 3, + BUFSIZE_4FRAME = 4, +}; + +/* RSPI events */ + +typedef enum +{ + RSPI_EVT_TRANSFER_COMPLETE, /* The data transfer completed */ + RSPI_EVT_TRANSFER_ABORTED, /* The data transfer was aborted */ + RSPI_EVT_ERR_MODE_FAULT, /* Mode fault error */ + RSPI_EVT_ERR_READ_OVF, /* Read overflow */ + RSPI_EVT_ERR_PARITY, /* Parity error */ + RSPI_EVT_ERR_UNDER_RUN, /* Under run error */ + RSPI_EVT_ERR_UNDEF /* Undefined/unknown error event */ +} rspi_event_t; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rx65n_rspidev_s +{ + struct spi_dev_s rspidev; /* Externally visible part of the RSPI interface */ + uint32_t rspibase; /* RSPIn base address */ + uint32_t rspiclock; /* Clocking for the RSPI module */ + +#ifndef CONFIG_SPI_POLLWAIT + uint8_t rspitxirq; /* RSPI tx IRQ number */ + uint8_t rspirxirq; /* RSPI rx IRQ number */ + uint8_t rspierirq; /* RSPI error IRQ number */ + uint8_t rspiidlirq; /* RSPI idle IRQ number */ + uint32_t rspigrpbase; + uint32_t rspierimask; + uint32_t rspiidlimask; + sem_t waitsem; /* Wait for transfer to complete */ +#endif + +#ifdef CONFIG_RX65N_RSPI_SW_DT_MODE + /* These following are the source and destination buffers of the transfer. + * they are retained in this structure so that they will be accessible + * from an interrupt handler. The actual type of the buffer is uint8_t is + * nbits <=8 and uint16_t is nbits >8. + */ + + void *txbuffer; /* Source buffer */ + void *rxbuffer; /* Destination buffer */ + + /* These are functions pointers that are configured to perform the + * appropriate transfer for the particular kind of exchange that is + * occurring. Different functions may be selected depending on (1) + * if the tx or txbuffer is NULL and depending on the number of bits + * per word. + */ + + void (*txword)(struct rx65n_rspidev_s *priv); + void (*rxword)(struct rx65n_rspidev_s *priv); +#else + DTC_HANDLE dtchandle; /* DTC channel handle for data transfers */ + dtc_transfer_data_t *p_txdt; /* Pointer Tx data transfer */ + dtc_transfer_data_t *p_rxdt; /* Pointer Rx data transfer */ + sem_t txsem; + sem_t rxsem; + uint8_t txvec; /* DTC activation source of RSPI Tx */ + uint8_t rxvec; /* DTC activation source of RSPI Rx */ +#endif + + bool initialized; /* Has RSPI interface been initialized */ + sem_t exclsem; /* Held while chip is selected for mutual exclusion */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + + int ntxwords; /* Number of words left to transfer on the Tx Buffer */ + int nrxwords; /* Number of words received on the Rx Buffer */ + int nwords; /* Number of words to be exchanged */ + + uint8_t nbits; /* Width of word in bits (4 through 16) */ + uint8_t mode; /* Mode 0,1,2,3 */ + uint8_t bufsize; /* Buf size: 1,2,3 or 4 word */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +static inline uint32_t rspi_getreg32(FAR struct rx65n_rspidev_s *priv, + uint8_t offset); +static inline uint16_t rspi_getreg16(FAR struct rx65n_rspidev_s *priv, + uint8_t offset); +static inline uint8_t rspi_getreg8(FAR struct rx65n_rspidev_s *priv, + uint8_t offset); +static inline void rspi_putreg32(FAR struct rx65n_rspidev_s *priv, + uint8_t offset, uint32_t value); +static inline void rspi_putreg16(FAR struct rx65n_rspidev_s *priv, + uint8_t offset, uint16_t value); +static inline void rspi_putreg8(FAR struct rx65n_rspidev_s *priv, + uint8_t offset, uint8_t value); + +/* SPI data transfer */ + +#if defined(CONFIG_RX65N_RSPI_SW_DT_MODE) +static void rspi_txnull(struct rx65n_rspidev_s *priv); +static void rspi_txuint32(struct rx65n_rspidev_s *priv); +static void rspi_txuint16(struct rx65n_rspidev_s *priv); +static void rspi_txuint8(struct rx65n_rspidev_s *priv); +static void rspi_rxnull(struct rx65n_rspidev_s *priv); +static void rspi_rxuint32(struct rx65n_rspidev_s *priv); +static void rspi_rxuint16(struct rx65n_rspidev_s *priv); +static void rspi_rxuint8(struct rx65n_rspidev_s *priv); +static void rspi_performtx(struct rx65n_rspidev_s *priv); +static inline void rspi_performrx(struct rx65n_rspidev_s *priv); +#endif +static int rspi_transfer(struct rx65n_rspidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords); + +/* Interrupt handling */ + +#ifndef CONFIG_SPI_POLLWAIT +static inline struct rx65n_rspidev_s *rspi_mapirq(int irq); +static int rspi_idlinterrupt(int irq, void *context, FAR void *arg); +static int rspi_erinterrupt(int irq, void *context, FAR void *arg); +static int rspi_txinterrupt(int irq, void *context, FAR void *arg); +static int rspi_rxinterrupt(int irq, void *context, FAR void *arg); +#endif + +/* SPI methods */ + +static int rspi_lock(FAR struct spi_dev_s *dev, bool lock); +static uint32_t rspi_setfrequency(FAR struct spi_dev_s *dev, + uint32_t frequency); +static void rspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); +static void rspi_setbits(FAR struct spi_dev_s *dev, int nbits); +#ifdef CONFIG_SPI_HWFEATURES +static int rspi_hwfeatures(FAR struct spi_dev_s *dev, + spi_hwfeatures_t features); +#endif +static uint32_t rspi_send(FAR struct spi_dev_s *dev, uint32_t wd); +static void rspi_exchange(FAR struct spi_dev_s *dev, + FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords); +#ifdef CONFIG_SPI_TRIGGER +static int rspi_trigger(FAR struct spi_dev_s *dev); +#endif +#ifndef CONFIG_SPI_EXCHANGE +static void rspi_sndblock(FAR struct spi_dev_s *dev, + FAR const void *txbuffer, + size_t nwords); +static void rspi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer, + size_t nwords); +#endif + +/* Initialization */ + +static void rspi_bus_initialize(FAR struct rx65n_rspidev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI0 +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) +dtc_transfer_data_t g_tx0dt; +dtc_transfer_data_t g_rx0dt; +#endif +static const struct spi_ops_s g_rspi0ops = +{ + .lock = rspi_lock, + .select = rx65n_rspi0select, + .setfrequency = rspi_setfrequency, + .setmode = rspi_setmode, + .setbits = rspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = rspi_hwfeatures, +#endif + .status = rx65n_rspi0status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = rx65n_rspi0cmddata, +#endif + .send = rspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = rspi_exchange, +#else + .sndblock = rspi_sndblock, + .recvblock = rspi_recvblock, +#endif + +#ifdef CONFIG_SPI_CALLBACK + .registercallback = rx65n_rspi0register, /* Provided externally */ +#else + .registercallback = 0, +#endif +}; + +static struct rx65n_rspidev_s g_rspi0dev = +{ + .rspidev = + { + &g_rspi0ops + }, + .rspibase = RX65N_RSPI0_BASE, + .rspiclock = RX65N_PCLK_FREQUENCY, +#ifndef CONFIG_SPI_POLLWAIT + .rspitxirq = RX65N_SPTI0_IRQ, + .rspirxirq = RX65N_SPRI0_IRQ, + .rspierirq = RX65N_SPEI0_IRQ, + .rspiidlirq = RX65N_SPII0_IRQ, + .rspigrpbase = RX65N_GRPAL0_ADDR, + .rspierimask = RX65N_GRPAL0_SPEI0_MASK, + .rspiidlimask = RX65N_GRPAL0_SPII0_MASK, +#endif +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) + .p_txdt = &g_tx0dt, + .p_rxdt = &g_rx0dt, + .txvec = RX65N_RSPI0_TXVECT, + .rxvec = RX65N_RSPI0_RXVECT, +#endif +}; +#endif + +#ifdef CONFIG_RX65N_RSPI1 +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) +dtc_transfer_data_t g_tx1dt; +dtc_transfer_data_t g_rx1dt; +#endif +static const struct spi_ops_s g_rspi1ops = +{ + .lock = rspi_lock, + .select = rx65n_rspi1select, + .setfrequency = rspi_setfrequency, + .setmode = rspi_setmode, + .setbits = rspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = rspi_hwfeatures, +#endif + .status = rx65n_rspi1status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = rx65n_rspi1cmddata, +#endif + .send = rspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = rspi_exchange, +#else + .sndblock = rspi_sndblock, + .recvblock = rspi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = rspi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = rx65n_rspi1register, /* Provided externally */ +#else + .registercallback = 0, +#endif +}; + +static struct rx65n_rspidev_s g_rspi1dev = +{ + .rspidev = + { + &g_rspi1ops + }, + .rspibase = RX65N_RSPI1_BASE, + .rspiclock = RX65N_PCLK_FREQUENCY, +#ifndef CONFIG_SPI_POLLWAIT + .rspitxirq = RX65N_SPTI1_IRQ, + .rspirxirq = RX65N_SPRI1_IRQ, + .rspierirq = RX65N_SPEI1_IRQ, + .rspiidlirq = RX65N_SPII1_IRQ, + .rspigrpbase = RX65N_GRPAL0_ADDR, + .rspierimask = RX65N_GRPAL0_SPEI1_MASK, + .rspiidlimask = RX65N_GRPAL0_SPII1_MASK, +#endif +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) + .p_txdt = &g_tx1dt, + .p_rxdt = &g_rx1dt, + .txvec = RX65N_RSPI1_TXVECT, + .rxvec = RX65N_RSPI1_RXVECT, +#endif +}; +#endif + +#ifdef CONFIG_RX65N_RSPI2 +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) +dtc_transfer_data_t g_tx2dt; +dtc_transfer_data_t g_rx2dt; +#endif +static const struct spi_ops_s g_rspi2ops = +{ + .lock = rspi_lock, + .select = rx65n_rspi2select, + .setfrequency = rspi_setfrequency, + .setmode = rspi_setmode, + .setbits = rspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = rspi_hwfeatures, +#endif + .status = rx65n_rspi2status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = rx65n_rspi2cmddata, +#endif + .send = rspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = rspi_exchange, +#else + .sndblock = rspi_sndblock, + .recvblock = rspi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = rspi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = rx65n_rspi2register, /* Provided externally */ +#else + .registercallback = 0, +#endif +}; + +static struct rx65n_rspidev_s g_rspi2dev = +{ + .rspidev = + { + &g_rspi2ops + }, + .rspibase = RX65N_RSPI2_BASE, + .rspiclock = RX65N_PCLK_FREQUENCY, +#ifndef CONFIG_SPI_POLLWAIT + .rspitxirq = RX65N_SPTI2_IRQ, + .rspirxirq = RX65N_SPRI2_IRQ, + .rspierirq = RX65N_SPEI2_IRQ, + .rspiidlirq = RX65N_SPII2_IRQ, + .rspigrpbase = RX65N_GRPAL0_ADDR, + .rspierimask = RX65N_GRPAL0_SPEI2_MASK, + .rspiidlimask = RX65N_GRPAL0_SPII2_MASK, +#endif +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) + .p_txdt = &g_tx2dt, + .p_rxdt = &g_rx2dt, + .txvec = RX65N_RSPI2_TXVECT, + .rxvec = RX65N_RSPI2_RXVECT, +#endif +}; +#endif + +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) +dtc_static_transfer_data_cfg_t tx_cfg = +{ +#if CONFIG_RX65N_RSPI_BUF_SIZE > 1 + .transfer_mode = DTC_TRANSFER_MODE_BLOCK, +#else + .transfer_mode = DTC_TRANSFER_MODE_NORMAL, +#endif + .data_size = DTC_DATA_SIZE_BYTE, + .src_addr_mode = DTC_SRC_ADDR_INCR, + .chain_transfer_enable = DTC_CHAIN_TRANSFER_DISABLE, + .chain_transfer_mode = DTC_CHAIN_TRANSFER_CONTINUOUSLY, + .response_interrupt = DTC_INTERRUPT_AFTER_ALL_COMPLETE, + .repeat_block_side = DTC_REPEAT_BLOCK_DESTINATION, + .dest_addr_mode = DTC_DES_ADDR_FIXED, + .source_addr = (uint32_t)NULL, /* This will set dynamically */ + .dest_addr = (uint32_t)NULL, /* Set data register address */ + .transfer_count = 0, /* This will set dynamically */ +#if CONFIG_RX65N_RSPI_BUF_SIZE > 1 + .block_size = CONFIG_RX65N_RSPI_BUF_SIZE, /* Looks like tx fifo size */ +#else + .block_size = 0, +#endif + .rsv = 0, + .writeback_disable = DTC_WRITEBACK_ENABLE, + .sequence_end = DTC_SEQUENCE_TRANSFER_CONTINUE, + .refer_index_table_enable = DTC_REFER_INDEX_TABLE_DISABLE, + .disp_add_enable = DTC_SRC_ADDR_DISP_ADD_DISABLE, +}; + +dtc_static_transfer_data_cfg_t rx_cfg = +{ +#if CONFIG_RX65N_RSPI_BUF_SIZE > 1 + .transfer_mode = DTC_TRANSFER_MODE_BLOCK, +#else + .transfer_mode = DTC_TRANSFER_MODE_NORMAL, +#endif + .data_size = DTC_DATA_SIZE_BYTE, + .src_addr_mode = DTC_SRC_ADDR_FIXED, + .chain_transfer_enable = DTC_CHAIN_TRANSFER_DISABLE, + .chain_transfer_mode = DTC_CHAIN_TRANSFER_CONTINUOUSLY, + .response_interrupt = DTC_INTERRUPT_AFTER_ALL_COMPLETE, + .repeat_block_side = DTC_REPEAT_BLOCK_SOURCE, + .dest_addr_mode = DTC_DES_ADDR_INCR, + .source_addr = (uint32_t)NULL, /* Set data register address */ + .dest_addr = (uint32_t)NULL, /* This will set dynamically */ + .transfer_count = 0, /* This will set dynamically */ +#if CONFIG_RX65N_RSPI_BUF_SIZE > 1 + .block_size = CONFIG_RX65N_RSPI_BUF_SIZE, /* Looks like tx fifo size */ +#else + .block_size = 0, +#endif + .rsv = 0, + .writeback_disable = DTC_WRITEBACK_ENABLE, + .sequence_end = DTC_SEQUENCE_TRANSFER_CONTINUE, + .refer_index_table_enable = DTC_REFER_INDEX_TABLE_DISABLE, + .disp_add_enable = DTC_SRC_ADDR_DISP_ADD_DISABLE, +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_rspi0/1/2 select and rx65n_rspi0/1/2 status + * + * Description: + * The external functions, rx65n_rspi0/1/2 select, rx65n_rspi0/1/2 status,and + * rx65n_rspi0/1/2 cmddata must be provided by board-specific logic. These + * are implementations of the select, status, and cmddata methods of the SPI + * interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h). All + * other methods (including rx65n_rspibus_initialize()) are provided by + * common R656N logic. To use thiscommon SPI logic on your board: + * + * 1. Provide logic in stm32_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide stm32_spi1/2/...select() and stm32_spi1/2/...status() + * functions in your board-specific logic. These functions will + * perform chip selection and status operations using GPIOs in the + * way your board is configured. + * 3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file, + * then provide stm32_spi1/2/...cmddata() functions in your + * board-specific logic.These functions will perform cmd/data + * selection operations using GPIOs in the way your board is configured. + * 4. Add a calls to stm32_spibus_initialize() in your low level + * application initialization logic + * 5. The handle returned by stm32_spibus_initialize() may then be used to + * bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ +#ifdef CONFIG_RX65N_RSPI0 +void rx65n_rspi0select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : + "de-assert"); +} + +uint8_t rx65n_rspi0status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +int rx65n_rspi0cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_RX65N_RSPI1 +void rx65n_rspi1select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : + "de-assert"); +} + +uint8_t rx65n_rspi1status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +int rx65n_rspi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_RX65N_RSPI2 +void rx65n_rspi2select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : + "de-assert"); +} + +uint8_t rx65n_rspi2status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +int rx65n_rspi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +/**************************************************************************** + * Name: rx65n_rspi0/1/2register + * + * Description: + * If the board supports a card detect callback to inform the SPI-based + * MMC/SD driver when an SD card is inserted or removed, then + * CONFIG_SPI_CALLBACK should be defined and the following function(s) + * must be implemented. These functions implements the registercallback + * method of the SPI interface (see include/nuttx/spi/spi.h for details) + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ +#ifdef CONFIG_SPI_CALLBACK +#ifdef CONFIG_RX65N_RSPI0 +int rx65n_rspi0register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg) +{ + spiinfo("INFO: Registering rspi0 device\n"); + return OK; +} +#endif + +#ifdef CONFIG_RX65N_RSPI1 +int rx65n_rspi1register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg) +{ + spiinfo("INFO: Registering rspi1 device\n"); + return OK; +} +#endif + +#ifdef CONFIG_RX65N_RSPI2 +int rx65n_rspi2register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg) +{ + spiinfo("INFO: Registering rspi2 device\n"); + return OK; +} +#endif +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rspi_getreg32 + * + * Description: + * Read the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * + * Returned Value: + * Value of the register at this offset + * + ****************************************************************************/ + +static inline uint32_t rspi_getreg32(struct rx65n_rspidev_s *priv, + uint8_t offset) +{ + return getreg32(priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_getreg16 + * + * Description: + * Read the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * + * Returned Value: + * Value of the register at this offset + * + ****************************************************************************/ + +static inline uint16_t rspi_getreg16(struct rx65n_rspidev_s *priv, + uint8_t offset) +{ + return getreg16(priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_getreg8 + * + * Description: + * Read the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * + * Returned Value: + * Value of the register at this offset + * + ****************************************************************************/ + +static inline uint8_t rspi_getreg8(struct rx65n_rspidev_s *priv, + uint8_t offset) +{ + return getreg8(priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_putreg32 + * + * Description: + * Write the value to the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_putreg32(struct rx65n_rspidev_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_putreg16 + * + * Description: + * Write the value to the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_putreg16(struct rx65n_rspidev_s *priv, + uint8_t offset, uint16_t value) +{ + putreg16(value, priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_putreg8 + * + * Description: + * Write the value to the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_putreg8(struct rx65n_rspidev_s *priv, + uint8_t offset, uint8_t value) +{ + putreg8(value, priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_txnull, rspi_txuint16, and rspi_txuint8 + * + * Description: + * Transfer all ones, a uint8_t, or uint16_t to Tx FIFO and update + * the txbuffer pointer appropriately. The selected function depends + * on (1) if there is a source txbuffer provided, and (2) if the + * number of bits per word is <=8 or >8. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_RX65N_RSPI_SW_DT_MODE) +static void rspi_txnull(struct rx65n_rspidev_s *priv) +{ + rspi_putreg32(priv, RX65N_RSPI_SPDR_OFFSET, 0xffff); +} + +static void rspi_txuint32(struct rx65n_rspidev_s *priv) +{ + uint32_t *ptr = (uint32_t *)priv->txbuffer; + rspi_putreg32(priv, RX65N_RSPI_SPDR_OFFSET, *ptr++); + priv->txbuffer = (void *)ptr; +} + +static void rspi_txuint16(struct rx65n_rspidev_s *priv) +{ + uint16_t *ptr = (uint16_t *)priv->txbuffer; + rspi_putreg16(priv, RX65N_RSPI_SPDR_OFFSET, *ptr++); + priv->txbuffer = (void *)ptr; +} + +static void rspi_txuint8(struct rx65n_rspidev_s *priv) +{ + uint8_t *ptr = (uint8_t *)priv->txbuffer; + rspi_putreg8(priv, RX65N_RSPI_SPDR_OFFSET, *ptr++); + priv->txbuffer = (void *)ptr; +} +#endif + +/**************************************************************************** + * Name: rspi_rxnull,rspi_rxuint16, and rspi_rxuint8 + * + * Description: + * Discard input, save a uint8_t, or or save a uint16_t from Tx FIFO in the + * user rxvbuffer and update the rxbuffer pointer appropriately. The + * selected function dependes on (1) if there is a destination rxbuffer + * provided, and (2) if the number of bits per word is <=8 or >8. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_RX65N_RSPI_SW_DT_MODE) +static void rspi_rxnull(struct rx65n_rspidev_s *priv) +{ + rspi_getreg32(priv, RX65N_RSPI_SPDR_OFFSET); +} + +static void rspi_rxuint32(struct rx65n_rspidev_s *priv) +{ + uint32_t *ptr = (uint32_t *)priv->rxbuffer; + *ptr++ = (uint32_t)rspi_getreg32(priv, RX65N_RSPI_SPDR_OFFSET); + priv->rxbuffer = (void *)ptr; +} + +static void rspi_rxuint16(struct rx65n_rspidev_s *priv) +{ + uint16_t *ptr = (uint16_t *)priv->rxbuffer; + *ptr++ = (uint16_t)rspi_getreg16(priv, RX65N_RSPI_SPDR_OFFSET); + priv->rxbuffer = (void *)ptr; +} + +static void rspi_rxuint8(struct rx65n_rspidev_s *priv) +{ + uint8_t *ptr = (uint8_t *)priv->rxbuffer; + *ptr++ = (uint8_t)rspi_getreg8(priv, RX65N_RSPI_SPDR_OFFSET); + priv->rxbuffer = (void *)ptr; +} +#endif + +/**************************************************************************** + * Name: rspi_performtx + * + * Description: + * If the Tx FIFO is empty, then transfer as many words as we can to + * the FIFO. + * + * Input Parameters: + * + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_RX65N_RSPI_SW_DT_MODE) +static void rspi_performtx(struct rx65n_rspidev_s *priv) +{ + uint8_t regval8; + int ntxd = 0; /* Number of words written to Tx FIFO */ + + /* Check if the Tx FIFO is empty */ + + if ((rspi_getreg8(priv, RX65N_RSPI_SPSR_OFFSET) & RSPI_SPSR_SPTEF) != 0) + { + /* Check if all of the Tx words have been sent */ + + if (priv->ntxwords > 0) + { + /* No.. + * Transfer more words until either the TxFIFO is full or + * until all of the user provided data has been sent. + */ + + for (; ntxd < priv->ntxwords && ntxd < priv->bufsize; ntxd++) + { + priv->txword(priv); + } + + /* Update the count of words to be transferred */ + + priv->ntxwords -= ntxd; + + /* Add dummy data in FIFO to make it full */ + + if (ntxd < priv->bufsize) + { + while (ntxd != priv->bufsize) + { + rspi_txnull(priv); + ntxd++; + } + } + } + else + { + /* Yes.. The transfer is complete, + * disable Tx FIFO empty interrupt + */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~RSPI_SPCR_SPTIE; + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + } + } +} +#endif + +/**************************************************************************** + * Name: rspi_performrx + * + * Description: + * Transfer as many bytes as possible from the Rx FIFO to the user Rx + * buffer (if one was provided). + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_RX65N_RSPI_SW_DT_MODE) +static inline void rspi_performrx(struct rx65n_rspidev_s *priv) +{ + /* Loop while data is available in the Rx FIFO (SPRXn) */ + + while ((rspi_getreg8(priv, RX65N_RSPI_SPSR_OFFSET) & RSPI_SPSR_SPRF) != 0) + { + /* Have all of the requested words been transferred from the Rx FIFO? */ + + if (priv->nrxwords < priv->nwords) + { + /* No.. Read more data from Rx FIFO */ + + priv->rxword(priv); + priv->nrxwords++; + } + else + { + rspi_rxnull(priv); /* Reading dummy data send */ + } + } +} +#endif + +/**************************************************************************** + * Name: rspi_startxfr + * + * Description: + * If data was added to the Tx FIFO, then start the exchange + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_startxfr(struct rx65n_rspidev_s *priv) +{ + uint8_t regval8; + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= RSPI_SPCR_SPE; + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); +} + +/**************************************************************************** + * Name: spi_dtcrxsetup + * + * Description: + * Setup to perform RX DTC + * + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI_DTC_DT_MODE +static dtc_err_t rspi_dtctxsetup(FAR struct rx65n_rspidev_s *priv, + FAR const void *txbuffer, FAR const void *txdummy, + size_t nwords) +{ + dtc_err_t ret = DTC_SUCCESS; + dtc_dynamic_transfer_data_cfg_t dcfg; + + /* 8- or 16-bit mode? */ + + if (priv->nbits >= 4 && priv->nbits <= 8) + { + if (txbuffer) + { + dcfg.data_size = DTC_DATA_SIZE_BYTE; + } + else + { + txbuffer = txdummy; + dcfg.data_size = DTC_DATA_SIZE_BYTE; + } + } + else if (priv->nbits > 8 && priv->nbits <= 16) + { + if (txbuffer) + { + dcfg.data_size = DTC_DATA_SIZE_WORD; + } + else + { + txbuffer = txdummy; + dcfg.data_size = DTC_DATA_SIZE_WORD; + } + } + else + { + spierr("ERROR: RSPI not supporting: %d bit word\n", priv->nbits); + } + + dcfg.source_addr = (uint32_t)txbuffer; + dcfg.dest_addr = priv->rspibase + RX65N_RSPI_SPDR_OFFSET; + + /* Configure block size if buf size is configured as more than 1 */ + + if (CONFIG_RX65N_RSPI_BUF_SIZE - 1) + { + /* Configure DTC in Block transfer mode */ + + dcfg.block_size = CONFIG_RX65N_RSPI_BUF_SIZE; + dcfg.transfer_count = nwords / CONFIG_RX65N_RSPI_BUF_SIZE; + } + else + { + dcfg.transfer_count = nwords; + } + + /* Configure the RX DTC */ + + ret = rx65n_dtc_setup_dynamic_transferdata(priv->dtchandle, priv->txvec, + (uint32_t)&dcfg, 0); + if (ret < 0) + { + spierr("ERROR:[%d] Fail to configure DTC information for TX\n", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: spi_dtcrxsetup + * + * Description: + * Setup to perform RX DTC + * + ****************************************************************************/ + +static dtc_err_t rspi_dtcrxsetup(FAR struct rx65n_rspidev_s *priv, + FAR void *rxbuffer, FAR void *rxdummy, + size_t nwords) +{ + dtc_err_t ret = DTC_SUCCESS; + dtc_dynamic_transfer_data_cfg_t dcfg; + + /* 8- or 16-bit mode */ + + if (priv->nbits >= 4 && priv->nbits <= 8) + { + if (rxbuffer) + { + dcfg.data_size = DTC_DATA_SIZE_BYTE; + } + else + { + rxbuffer = rxdummy; + dcfg.data_size = DTC_DATA_SIZE_BYTE; + } + } + else if (priv->nbits > 8 && priv->nbits <= 16) + { + if (rxbuffer) + { + dcfg.data_size = DTC_DATA_SIZE_WORD; + } + else + { + rxbuffer = rxdummy; + dcfg.data_size = DTC_DATA_SIZE_WORD; + } + } + else + { + spierr("ERROR: RSPI not supporting: %d bit word\n", nbits); + } + + dcfg.source_addr = priv->rspibase + RX65N_RSPI_SPDR_OFFSET; + dcfg.dest_addr = (uint32_t)rxbuffer; + + /* Configure block size if buf size is configured as more than 1 */ + + if (CONFIG_RX65N_RSPI_BUF_SIZE - 1) + { + /* Configure DTC in Block transfer mode */ + + dcfg.block_size = CONFIG_RX65N_RSPI_BUF_SIZE; + dcfg.transfer_count = nwords / CONFIG_RX65N_RSPI_BUF_SIZE; + } + else + { + dcfg.transfer_count = nwords; + } + + /* Configure the RX DTC */ + + ret = rx65n_dtc_setup_dynamic_transferdata(priv->dtchandle, + priv->rxvec, (uint32_t)&dcfg, 0); + if (ret < 0) + { + spierr("ERROR:[%d] Fail to configure DTC information for RX\n", ret); + return ret; + } + + return ret; +} + +#endif + +/**************************************************************************** + * Name: rspi_transfer + * + * Description: + * Exchange a block data with the SPI device + * + * Input Parameters: + * priv - Device-specific state data + * txbuffer - The buffer of data to send to the device (may be NULL). + * rxbuffer - The buffer to receive data from the device (may be NULL). + * nwords - The total number of words to be exchanged. If the interface + * uses <= 8 bits per word, then this is the number of + * uint8_t's; if the interface uses >8 bits per word, then this + * is the number of uint16_t's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ +#ifdef CONFIG_RX65N_RSPI_SW_DT_MODE +static int rspi_transfer(struct rx65n_rspidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords) +{ + uint8_t regval8; +#ifndef CONFIG_SPI_POLLWAIT + irqstate_t flags; +#endif + + /* Set up to perform the transfer */ + + priv->txbuffer = (uint8_t *)txbuffer; /* Source buffer */ + priv->rxbuffer = (uint8_t *)rxbuffer; /* Destination buffer */ + priv->ntxwords = nwords; /* Number of words left to send */ + priv->nrxwords = 0; /* Number of words received */ + priv->nwords = nwords; /* Total number of exchanges */ + + /* Set up the low-level data transfer function pointers */ + + if (priv->nbits > 16) + { + priv->txword = rspi_txuint32; + priv->rxword = rspi_rxuint32; + } + + if (priv->nbits > 8) + { + priv->txword = rspi_txuint16; + priv->rxword = rspi_rxuint16; + } + else + { + priv->txword = rspi_txuint8; + priv->rxword = rspi_rxuint8; + } + + if (!txbuffer) + { + priv->txword = rspi_txnull; + } + + if (!rxbuffer) + { + priv->rxword = rspi_rxnull; + } + + /* Copied data to start the sequence (saves one interrupt) */ + +#ifndef CONFIG_SPI_POLLWAIT + flags = enter_critical_section(); + + /* Enable interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= (RSPI_SPCR_SPEIE | RSPI_SPCR_SPTIE | RSPI_SPCR_SPRIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Start transmission */ + + rspi_performtx(priv); + rspi_startxfr(priv); + + /* Enable Idle interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 |= (RSPI_SPCR2_SPIIE); /* RSPI Idle Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); + + leave_critical_section(flags); + + /* Wait for the transfer to complete. Since there is no handshake + * with SPI, the following should complete even if there are problems + * with the transfer, so it should be safe with no timeout. + */ + + /* Wait to be signaled from the interrupt handler */ + + return nxsem_wait_uninterruptible(&priv->waitsem); + +#else + /* Perform the transfer using polling logic. This will totally + * dominate the CPU until the transfer is complete. Only recommended + * if (1) your SPI is very fast, and (2) if you only use very short + * transfers. + */ + + do + { + /* Handle outgoing Tx FIFO transfers */ + + rspi_performtx(priv); + + /* Handle incoming Rx FIFO transfers */ + + rspi_performrx(priv); + + /* Resume the transfer */ + + rspi_startxfr(priv); + + /* If there are other threads at this same priority level, + * the following may help: + */ + + sched_yield(); + } + while (priv->nrxwords < priv->nwords); + + return OK; +#endif +} +#elif defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) +static int rspi_transfer(struct rx65n_rspidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords) +{ + uint8_t regval8; + static uint16_t rxdummy = 0xffff; + static const uint16_t txdummy = 0xffff; + irqstate_t flags; + int ret; + + /* Disable RSPI */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= (~RSPI_SPCR_SPE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Setup DTC */ + + ret = rspi_dtctxsetup(priv, txbuffer, &txdummy, nwords); + if (ret > 1) + { + spierr("ERROR:Fail to setup DTC for TX transfer\n"); + return EINVAL; + } + + ret = rspi_dtcrxsetup(priv, rxbuffer, &rxdummy, nwords); + if (ret > 1) + { + spierr("ERROR:[%d] Fail to setup DTC for RX transfer\n"); + return EINVAL; + } + + flags = enter_critical_section(); + + /* Enable RSPI source for DTC trigger */ + + rx65n_dtc_srcactivation(priv->dtchandle, priv->txvec); + rx65n_dtc_srcactivation(priv->dtchandle, priv->rxvec); + + /* Enable TX, RX and Error interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= (RSPI_SPCR_SPEIE | RSPI_SPCR_SPRIE | RSPI_SPCR_SPTIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Enable RSPI */ + + rspi_startxfr(priv); + + /* Wait for transfer completion */ + + leave_critical_section(flags); + + /* Wait to be signaled from the interrupt handler */ + + return nxsem_wait_uninterruptible(&priv->waitsem); +} + +#endif + +/**************************************************************************** + * Name: rspi_mapirq + * + * Description: + * Map an IRQ number into the appropriate SPI device + * + * Input Parameters: + * irq - The IRQ number to be mapped + * + * Returned Value: + * On success, a reference to the private data structgure for this IRQ. + * NULL on failure. + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static inline struct rx65n_rspidev_s *rspi_mapirq(int irq) +{ + switch (irq) + { +#ifdef CONFIG_RX65N_RSPI0 + case RX65N_SPRI0_IRQ: + case RX65N_SPTI0_IRQ: + case RX65N_SPEI0_IRQ: + case RX65N_SPII0_IRQ: + return &g_rspi0dev; +#endif +#ifdef CONFIG_RX65N_RSPI1 + case RX65N_SPRI1_IRQ: + case RX65N_SPTI1_IRQ: + case RX65N_SPEI1_IRQ: + case RX65N_SPII1_IRQ: + return &g_rspi1dev; +#endif +#ifdef CONFIG_RX65N_RSPI2 + case RX65N_SPRI2_IRQ: + case RX65N_SPTI2_IRQ: + case RX65N_SPEI2_IRQ: + case RX65N_SPII2_IRQ: + return &g_rspi2dev; +#endif + default: + return NULL; + } +} +#endif + +/**************************************************************************** + * Name: rspi_errhandle + * + * Description: + * RSPI common error handler + * + * Input Parameters: + * priv - Device-specific state data + * bus - channel number + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static void rspi_errhandle(struct rx65n_rspidev_s *priv, uint8_t bus) +{ + uint8_t regval8; + rspi_event_t event = RSPI_EVT_ERR_UNDEF; + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPSR_OFFSET); + + /* Identify and clear error condition . */ + + if (regval8 & RSPI_SPSR_OVRF) + { + /* Overrun error */ + + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_READ_OVF; + } + + /* Clear error source: OVRF flag. */ + + regval8 &= (~RSPI_SPSR_OVRF); + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + + if (regval8 & RSPI_SPSR_MODF) + { + if (regval8 & RSPI_SPSR_UDRF) + { + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_UNDER_RUN; + } + + /* Clear error source : MODF flag and UDRF */ + + regval8 &= RSPI_SPSR_MODF_UDRF_MASK; + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + else + { + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_MODE_FAULT; + } + + /* Clear error source : MODF flag */ + + regval8 &= (~RSPI_SPSR_MODF); + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + } + + if (regval8 & RSPI_SPSR_PERF) + { + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_PARITY; + } + + /* Clear error source: PERF flag */ + + regval8 &= (~RSPI_SPSR_PERF); + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + + /* Disable the RSPI operation . */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= (~(RSPI_SPCR_SPTIE | RSPI_SPCR_SPRIE | RSPI_SPCR_SPE)); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Yes, wake up the waiting thread . */ + + nxsem_post(&priv->waitsem); +} +#endif + +/**************************************************************************** + * Name: rspi_idlinterrupt + * + * Description: + * RSPI IDLE interrupt handler invoke on transmission/reception completion + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_idlinterrupt(int irq, void *context, FAR void *arg) +{ + uint8_t regval8; + + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + + /* Disable Idle interrupt in SPCR2 */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 &= ~(RSPI_SPCR2_SPIIE); /* RSPI Idle Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); + + /* Disable ransmit/receive interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~(RSPI_SPCR_SPRIE | RSPI_SPCR_SPTIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Yes, wake up the waiting thread */ + + nxsem_post(&priv->waitsem); + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_erinterrupt + * + * Description: + * RSPI common error interrupt handler + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_erinterrupt(int irq, void *context, FAR void *arg) +{ + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + +#ifdef CONFIG_RX65N_RSPI0 + rspi_errhandle(priv, RX65N_RSPI_CHANNEL0); +#endif + +#ifdef CONFIG_RX65N_RSPI1 + rspi_errhandle(priv, RX65N_RSPI_CHANNEL1); +#endif + +#ifdef CONFIG_RX65N_RSPI2 + rspi_errhandle(priv, RX65N_RSPI_CHANNEL2); +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_rxinterrupt + * + * Description: + * Receive buffer full interrupt handler to process a block data from SPI + * device + * + * Input Parameters: + * priv - Device-specific state data + * rxbuffer - The buffer to receive data from the device (may be NULL). + * nwords - The total number of words to be exchanged. If the interface + * uses <= 8 bits per word, then this is the number of + * uint8_t's; if the interface uses >8 bits per word, then this + * is the number of uint16_t's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_rxinterrupt(int irq, void *context, FAR void *arg) +{ +#ifdef CONFIG_RX65N_RSPI_DTC_DT_MODE + uint8_t regval8; +#endif + + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + +#ifdef CONFIG_RX65N_RSPI_SW_DT_MODE + /* Handle incoming Rx FIFO transfers */ + + rspi_performrx(priv); +#else + + /* Disable ransmit/receive interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~(RSPI_SPCR_SPRIE | RSPI_SPCR_SPTIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Yes, wake up the waiting thread */ + + nxsem_post(&priv->waitsem); + +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_txinterrupt + * + * Description: + * Transmit buffer empty interrupt handler to process a block data for SPI + * device + * + * Input Parameters: + * priv - Device-specific state data + * txbuffer - The buffer of data to send to the device (may be NULL). + * nwords - The total number of words to be exchanged. If the interface + * uses <= 8 bits per word, then this is the number of + * uint8_t's; if the interface uses >8 bits per word, then this + * is the number of uint16_t's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_txinterrupt(int irq, void *context, FAR void *arg) +{ + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + +#ifdef CONFIG_RX65N_RSPI_DTC_DT_MODE + uint8_t regval8; +#endif + + DEBUGASSERT(priv != NULL); + +#ifdef CONFIG_RX65N_RSPI_SW_DT_MODE + /* Handle outgoing Tx FIFO transfers */ + + rspi_performtx(priv); + +#else + + /* DTC transfer completion */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + if ((regval8 & RSPI_SPCR_TXMD) == 1) + { + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~(RSPI_SPCR_SPRIE | RSPI_SPCR_SPTIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Yes, wake up the waiting thread */ + + nxsem_post(&priv->waitsem); + } + +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_lock + * + * Description: + * On SPI buses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the SPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the SPI is properly + * configured for the device. If the SPI bus is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock spi bus, false: unlock SPI bus + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +static int rspi_lock(FAR struct spi_dev_s *dev, bool lock) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + int ret; + + if (lock) + { + ret = nxsem_wait_uninterruptible(&priv->exclsem); + } + else + { + ret = nxsem_post(&priv->exclsem); + } + + return ret; +} + +/**************************************************************************** + * Name: rspi_setfrequency + * + * Description: + * Set the RSPI frequency. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The SPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32_t rspi_setfrequency(FAR struct spi_dev_s *dev, + uint32_t frequency) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + uint32_t actual; + + DEBUGASSERT(priv); + actual = priv->actual; + + if (frequency != priv->frequency) + { + /* Below formula used to calculate bit rate + * Bit rate f(PCLK)/(2 × (n + 1) × 2^N) . + * n denotes SPBR setting (0,1,2..255) . + * N denotes a BRDV[1:0] bit setting (0, 1, 2, 3) . + */ + + uint16_t regval16; + uint32_t brdv; + uint8_t spbr; + + /* N=0 as per fit code */ + + brdv = RSPI_BRDV_DEFAULT; + + DEBUGASSERT(brdv < 4); + + if (frequency >= priv->rspiclock / FREQ_DIVISOR_2) + { + actual = priv->rspiclock / FREQ_DIVISOR_2; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_4) + { + actual = priv->rspiclock / FREQ_DIVISOR_4; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_6) + { + actual = priv->rspiclock / FREQ_DIVISOR_6; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_8) + { + actual = priv->rspiclock / FREQ_DIVISOR_8; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_10) + { + actual = priv->rspiclock / FREQ_DIVISOR_10; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_12) + { + actual = priv->rspiclock / FREQ_DIVISOR_12; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_24) + { + actual = priv->rspiclock / FREQ_DIVISOR_24; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_48) + { + actual = priv->rspiclock / FREQ_DIVISOR_48; + } + else /* (frequency >= priv->rspiclock / FREQ_DIVISOR_96) */ + { + actual = priv->rspiclock / FREQ_DIVISOR_96; + } + + /* Calculate n and set the n in SPBR */ + + spbr = (priv->rspiclock / (2 * actual * ((1 << brdv)))) - 1; + rspi_putreg8(priv, RX65N_RSPI_SPBR_OFFSET, spbr); + + /* Set the N as BRDV[1:0] in SPCMD0 b2 and b3 */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 &= ~(RSPI_SPCMD_BRDV_MASK); + regval16 |= (brdv << 2); + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + /* Save the frequency and actual frequency in RSPI device structure */ + + priv->frequency = frequency; + priv->actual = actual; + } + + return actual; +} + +/**************************************************************************** + * Name: rspi_setmode + * + * Description: + * Set the SPI mode. Optional. See enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void rspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + + uint16_t regval16; + + if (priv && mode != priv->mode) + { + uint32_t modebits; + + /* Select the CTL register bits based on the selected mode */ + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0 CHPHA=0 */ + modebits = 0; + break; + + case SPIDEV_MODE1: /* CPOL=0 CHPHA=1 */ + modebits = RSPI_SPCMD_PHA; + break; + + case SPIDEV_MODE2: /* CPOL=1 CHPHA=0 */ + modebits = RSPI_SPCMD_POL; + break; + + case SPIDEV_MODE3: /* CPOL=1 CHPHA=1 */ + modebits = RSPI_SPCMD_PHA | RSPI_SPCMD_POL; + break; + + default: + spiwarn("Warning: Unsupported RSPI mode: %d\n", mode); + return; + } + + /* Then set the selected mode */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 &= ~(RSPI_SPCMD_PHA | RSPI_SPCMD_POL); + regval16 |= modebits; + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + /* Save the mode so that subsequent re-configurations will be faster */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: rspi_setbits + * + * Description: + * Set the number of bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void rspi_setbits(FAR struct spi_dev_s *dev, int nbits) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + uint8_t regval8; + uint16_t regval16; + + if (priv && nbits != priv->nbits && nbits > 0 && nbits <= 16) + { + if (nbits >= 4 && nbits <= 8) + { + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR_OFFSET); + regval8 |= RSPI_SPDCR_SPBYT; + rspi_putreg8(priv, RX65N_RSPI_SPDCR_OFFSET, regval8); + } + else if (nbits > 8 && nbits <= 16) + { + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR_OFFSET); + regval8 &= ~(RSPI_SPDCR_SPLW | RSPI_SPDCR_SPBYT); + rspi_putreg8(priv, RX65N_RSPI_SPDCR_OFFSET, regval8); + } + else + { + spierr("ERROR: RSPI not supporting: %d bit word\n", nbits); + } + + /* Configure command data register for this transfer */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 |= (RSPI_SPCMD_SPB_MASK & ((nbits - 1) << 8)); + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + priv->nbits = nbits; + } + else + { + spiwarn("Warning: Unsupported RSPI Word width: %d\n", nbits); + } +} + +/**************************************************************************** + * Name: rspi_send + * + * Description: + * Exchange one word on RSPI + * + * Input Parameters: + * dev - Device-specific state data + * wd - The word to send. the size of the data is determined by the + * number of bits selected for the SPI interface. + * + * Returned Value: + * response + * + ****************************************************************************/ + +static uint32_t rspi_send(FAR struct spi_dev_s *dev, uint32_t wd) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + uint32_t response = 0; + + rspi_transfer(priv, &wd, &response, 1); + return response; +} + +/**************************************************************************** + * Name: rspi_exchange + * + * Description: + * Exahange a block of data from SPI. Required. + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to the buffer in which to receive data + * nwords - the length of data that to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_EXCHANGE +static void rspi_exchange(FAR struct spi_dev_s *dev, + FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + rspi_transfer(priv, txbuffer, rxbuffer, nwords); +} +#endif + +/**************************************************************************** + * Name: rspi_sndblock + * + * Description: + * Send a block of data on SPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void rspi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, + size_t nwords) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + rspi_transfer(priv, buffer, NULL, nwords); +} +#endif + +/**************************************************************************** + * Name: rspi_recvblock + * + * Description: + * Revice a block of data from SPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer in which to receive data + * nwords - the length of data that can be received in the buffer in number + * of words. The wordsize is determined by the number of + * bits-per-word selected for the SPI interface. If nbits <= 8, + * the data is packed into uint8_t's; if nbits >8, the data is + * packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void rspi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, + size_t nwords) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + rspi_transfer(priv, NULL, buffer, nwords); +} +#endif + +/**************************************************************************** + * Function Name: rspi_interrupt_init + * Description : Configure ICU for RSPI interrupt + * Arguments : none + * Return Value : none + ****************************************************************************/ + +void rspi_interrupt_init(FAR struct rx65n_rspidev_s *priv, uint8_t bus) +{ + /* Enable error interrupt source bit */ + + IEN(ICU, GROUPAL0) = 0; /* Disable Group AL0 interrupts */ + IR(ICU, GROUPAL0) = 0; /* Clear interrupt flag */ + IPR(ICU, GROUPAL0) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(ICU, GROUPAL0) = 1; /* Enable Group AL0 interrupt */ + +#ifdef CONFIG_RX65N_RSPI0 + if (bus == RX65N_RSPI_CHANNEL0) + { + /* Configure Transmit empty buffer interrupt source bit */ + + IEN(RSPI0, SPTI0) = 0; /* Disable SPTI0 interrupts */ + IR(RSPI0, SPTI0) = 0; /* Clear interrupt flag */ + IPR(RSPI0, SPTI0) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI0, SPTI0) = 1; /* Enable SPTI0 interrupt */ + ICU.IER[0x04].BIT.IEN7 = 1; + + /* Configure Receive buffer full interrupt source bit */ + + IEN(RSPI0, SPRI0) = 0; /* Disable SPRI0 interrupts */ + IR(RSPI0, SPRI0) = 0; /* Clear interrupt flag */ + IPR(RSPI0, SPRI0) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI0, SPRI0) = 1; /* Enable SPRI0 interrupt */ + ICU.IER[0x04].BIT.IEN6 = 1; + + /* Enable error interrupt source bit */ + + ICU.GENAL0.BIT.EN17 = 1; + + /* Enable Idle interrupt source bit */ + + ICU.GENAL0.BIT.EN16 = 1; + } +#endif + +#ifdef CONFIG_RX65N_RSPI1 + if (bus == RX65N_RSPI_CHANNEL1) + { + /* Configure Transmit empty buffer interrupt */ + + IEN(RSPI1, SPTI1) = 0; /* Disable SPTI1 interrupts */ + IR(RSPI1, SPTI1) = 0; /* Clear interrupt flag */ + IPR(RSPI1, SPTI1) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI1, SPTI1) = 1; /* Enable SPTI1 interrupt */ + ICU.IER[0x05].BIT.IEN1 = 1; + + /* Configure Receive buffer full interrupt */ + + IEN(RSPI1, SPRI1) = 0; /* Disable SPRI1 interrupts */ + IR(RSPI1, SPRI1) = 0; /* Clear interrupt flag */ + IPR(RSPI1, SPRI1) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI1, SPRI1) = 1; /* Enable SPRI1 interrupt */ + ICU.IER[0x05].BIT.IEN0 = 1; + + /* Enable error interrupt source bit */ + + ICU.GENAL0.BIT.EN19 = 1; + + /* Enable Idle interrupt source bit */ + + ICU.GENAL0.BIT.EN18 = 1; + } +#endif + +#ifdef CONFIG_RX65N_RSPI2 + if (bus == RX65N_RSPI_CHANNEL2) + { + /* Configure Transmit empty buffer interrupt */ + + IEN(RSPI2, SPTI2) = 0; /* Disable SPTI2 interrupts */ + IR(RSPI2, SPTI2) = 0; /* Clear interrupt flag */ + IPR(RSPI2, SPTI2) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI2, SPTI2) = 1; /* Enable SPTI2 interrupt */ + ICU.IER[13].BIT.IEN5 = 1; + + /* Configure Receive buffer full interrupt */ + + IEN(RSPI2, SPRI2) = 0; /* Disable SPRI2 interrupts */ + IR(RSPI2, SPRI2) = 0; /* Clear interrupt flag */ + IPR(RSPI2, SPRI2) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI2, SPRI2) = 1; /* Enable SPRI2 interrupt */ + ICU.IER[13].BIT.IEN4 = 1; + + /* Enable error interrupt source bit */ + + ICU.GENAL0.BIT.EN21 = 1; + + /* Enable Idle interrupt source bit */ + + ICU.GENAL0.BIT.EN20 = 1; + } +#endif +} + +/**************************************************************************** + * Function Name: power_on_off + * Description : Switches power to an RSPI channel. Required by FIT spec. + * Arguments : + * channel -Which channel to use. + * on_or_off -0 means 1 means off + * Return Value : none + ****************************************************************************/ + +static void rspi_power_on_off (uint8_t channel, uint8_t on_or_off) +{ + SYSTEM.PRCR.WORD = 0xa50bu; + + switch (channel) + { + case RX65N_RSPI_CHANNEL0: + MSTP(RSPI0) = on_or_off; + break; + case RX65N_RSPI_CHANNEL1: + MSTP(RSPI1) = on_or_off; + break; + case RX65N_RSPI_CHANNEL2: + MSTP(RSPI2) = on_or_off; + break; + } +} + +/**************************************************************************** + * Function Name: rspi_reg_protect + * Description : Register protection enable/disable. Required by FIT spec. + * Arguments : + * enable - used to enable and disable protection + * Return Value : none + ****************************************************************************/ + +static void rspi_reg_protect (uint8_t enable) +{ + SYSTEM.PRCR.WORD = 0xa50b; + MPC.PWPR.BIT.B0WI = 0; + MPC.PWPR.BIT.PFSWE = 1; +} + +/**************************************************************************** + * Name: rspi_bus_initialize + * + * Description: + * Initialize the selected RSPI bus in its default state (Master, 8-bit, + * mode 0, etc.) + * + * Input Parameters: + * priv - private SPI device structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_bus_initialize(FAR struct rx65n_rspidev_s *priv) +{ + uint8_t regval8; + uint16_t regval16; + +#if defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) + int ret; +#endif + +#ifdef CONFIG_RX65N_RSPI_SW_DT_MODE +#ifndef CONFIG_SPI_POLLWAIT + /* Initialize the semaphore that is used to wake up the waiting + * thread when the transfer completes. This semaphore is used for + * signaling and, hence, should not have priority inheritance enabled. + */ + + nxsem_init(&priv->waitsem, 0, 0); + nxsem_set_protocol(&priv->waitsem, SEM_PRIO_NONE); +#endif +#elif defined(CONFIG_RX65N_RSPI_DTC_DT_MODE) + /* Initialize the SPI semaphores that is used to wait for DTC completion */ + + nxsem_init(&priv->rxsem, 0, 0); + nxsem_init(&priv->txsem, 0, 0); + + /* These semaphores are used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + nxsem_set_protocol(&priv->rxsem, SEM_PRIO_NONE); + nxsem_set_protocol(&priv->txsem, SEM_PRIO_NONE); + + /* Prepare Transmit and receive parameter */ + + priv->dtchandle = rx65n_dtc_gethandle(0); + ret = rx65n_dtc_setup_static_transferdata(priv->dtchandle, + priv->txvec, (uint32_t)&tx_cfg, + (uint32_t)priv->p_txdt, (uint32_t)0); + if (ret < 0) + { + spierr("ERROR:[%d] Fail to configure DTC information for TX\n", ret); + return; + } + + ret = rx65n_dtc_setup_static_transferdata(priv->dtchandle, + priv->rxvec, (uint32_t)&rx_cfg, + (uint32_t)priv->p_rxdt, (uint32_t)0); + if (ret < 0) + { + spierr("ERROR:[%d] Fail to configure DTC information for RX\n", ret); + return; + } + +#endif + nxsem_init(&priv->exclsem, 0, 1); + + /* Initialize control register */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 = regval8 & (~RSPI_SPCR_SMPS); /* RSPI operation (4-wire method) */ + regval8 = regval8 & (~RSPI_SPCR_TXMD); /* Full-duplex synchronous serial communications */ + regval8 = regval8 | (RSPI_SPCR_MSTR); /* Master mode */ + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* RSPI Pin Control Register */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPPCR_OFFSET); + regval8 &= (~(RSPI_SPPCR_SPLP /* Loopback mode */ + | RSPI_SPPCR_SPLP2 /* Loopback mode */ + | RSPI_SPPCR_MOIFV /* MOSI pin idles high */ + | RSPI_SPPCR_MOIFE)); /* MOSI pin idles at MOIFV */ + rspi_putreg8(priv, RX65N_RSPI_SPPCR_OFFSET, regval8); + + /* Sets polarity of SSL signal */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SSLP_OFFSET); + regval8 &= (~(RSPI_SSLP_SSL0P + | RSPI_SSLP_SSL1P + | RSPI_SSLP_SSL2P + | RSPI_SSLP_SSL3P)); /* RSPCK is low when idle */ + rspi_putreg8(priv, RX65N_RSPI_SSLP_OFFSET, regval8); + + /* Inititalize frequency, frame size and SPI mode */ + + priv->frequency = 0; + priv->mode = SPIDEV_MODE0; + + /* Select a default frequency of approx. 400KHz */ + + rspi_setfrequency((FAR struct spi_dev_s *)priv, 400000); + + /* Configure data control register SPDCR + * Four frames can be transmitted or received in one round of transmission + * or reception activation. + */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR_OFFSET); + regval8 &= (~RSPI_SPDCR_MASK); +#ifdef CONFIG_RX65N_RSPI_BUF_SIZE + regval8 |= (RSPI_SPDCR_SPFC_MASK & (CONFIG_RX65N_RSPI_BUF_SIZE -1)); + priv->bufsize = CONFIG_RX65N_RSPI_BUF_SIZE; +#else + regval8 |= (RSPI_SPDCR_SPFC0 | RSPI_SPDCR_SPFC1); /* 4 frames */ + priv->bufsize = BUFSIZE_4FRAME; +#endif + regval8 |= (RSPI_SPDCR_SPBYT); + priv->nbits = 8; + rspi_putreg8(priv, RX65N_RSPI_SPDCR_OFFSET, regval8); + + /* Configure RSPI clock delay registers SPCKD */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCKD_OFFSET); + regval8 &= (~RSPI_SPCKD_MASK); +#if CONFIG_RX65N_RSPI_SPCKD_DELAY + regval8 |= (RSPI_SPCKD_MASK & CONFIG_RX65N_RSPI_SPCKD_DELAY); +#else + regval8 |= (RSPI_SPCKD_SCKDL1); /* 2RSPCK delay */ +#endif + rspi_putreg8(priv, RX65N_RSPI_SPCKD_OFFSET, regval8); + + /* Configure RSPI slave select negation delay register SSLND */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SSLND_OFFSET); + regval8 &= (~RSPI_SSLND_MASK); +#if CONFIG_RX65N_RSPI_SSLND_DELAY + regval8 |= (RSPI_SSLND_MASK & CONFIG_RX65N_RSPI_SSLND_DELAY); +#else + regval8 |= (RSPI_SSLND_SLNDL1); /* 2RSPCK delay */ +#endif + rspi_putreg8(priv, RX65N_RSPI_SSLND_OFFSET, regval8); + + /* Configure RSPI next-access delay register SPND */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPND_OFFSET); + regval8 &= (~RSPI_SPND_MASK); +#if CONFIG_RX65N_RSPI_SPND_DELAY + regval8 |= (RSPI_SPND_MASK & CONFIG_RX65N_RSPI_SPND_DELAY); +#else + regval8 |= (RSPI_SPND_SPNDL1); /* 2RSPCK delay */ +#endif + rspi_putreg8(priv, RX65N_RSPI_SPND_OFFSET, regval8); + + /* Configure RSPI Control Register 2 */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 &= (~RSPI_SPCR2_MASK); /* Clear all bit */ +#ifdef CONFIG_RX65N_RSPI_HIGHSPEED + regval8 |= (RSPI_SPCR2_SCKASE); +#endif + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); + + /* Configure RSPI sequence control register SPSCR */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPSCR_OFFSET); + regval8 &= (~RSPI_SPSCR_MASK); + rspi_putreg8(priv, RX65N_RSPI_SPSCR_OFFSET, regval8); + + /* Configure the SPCMD0 command register */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 &= (~RSPI_SPCMD_MASK); + regval16 |= ((RSPI_SPCMD_SPB0 | RSPI_SPCMD_SPB1 | RSPI_SPCMD_SPB2) +#if CONFIG_RX65N_RSPI_BITORDER + | (RSPI_SPCMD_LSBF) /* RSPI LSB First */ +#endif + | (RSPI_SPCMD_SPNDEN) /* RSPI Next-Access Delay Enable */ + | (RSPI_SPCMD_SLNDEN) /* SSL Negation Delay Setting Enable */ + | (RSPI_SPCMD_SCKDEN)); /* RSPCK Delay Setting Enable */ + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + /* Configure Set RSPI data control register 2 (SPDCR2) */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR2_OFFSET); + regval8 &= (~RSPI_SPDCR2_BYSW); + rspi_putreg8(priv, RX65N_RSPI_SPDCR2_OFFSET, regval8); + +#ifndef CONFIG_SPI_POLLWAIT + /* Disable all interrupt in SPCR */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~(RSPI_SPCR_SPEIE /* RSPI Error Interrupt Enable */ + | RSPI_SPCR_SPTIE /* Transmit Buffer Empty Interrupt Enable */ + | RSPI_SPCR_SPRIE); /* RSPI Receive Buffer Full Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Disable Idle interrupt in SPCR2 */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 &= ~(RSPI_SPCR2_SPIIE); /* RSPI Idle Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); +#endif + + /* Attach the interrupt */ + +#ifndef CONFIG_SPI_POLLWAIT + irq_attach(priv->rspitxirq, (xcpt_t)rspi_txinterrupt, NULL); + irq_attach(priv->rspirxirq, (xcpt_t)rspi_rxinterrupt, NULL); + irq_attach(priv->rspierirq, (xcpt_t)rspi_erinterrupt, NULL); + irq_attach(priv->rspiidlirq, (xcpt_t)rspi_idlinterrupt, NULL); +#endif + + /* Enable RSPI functionality */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= (RSPI_SPCR_SPE); /* RSPI Function Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Enable SPI irq */ + +#ifndef CONFIG_SPI_POLLWAIT + up_enable_irq(priv->rspitxirq); + up_enable_irq(priv->rspirxirq); + up_enable_irq(priv->rspierirq); + up_enable_irq(priv->rspiidlirq); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_rspibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *rx65n_rspibus_initialize(int bus) +{ + FAR struct rx65n_rspidev_s *priv = NULL; + irqstate_t flags = enter_critical_section(); + +#ifdef CONFIG_RX65N_RSPI0 + if (bus == RX65N_RSPI_CHANNEL0) + { + /* Select RSPI0 */ + + priv = &g_rspi0dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure RSPI0 pins for 4WIRE mode + * RSPCKA,MOSIA, MISOA and SSLA0 + */ + + rspi_reg_protect(REG_PROTECTION_OFF); /* Disable protection */ + rspi_pinconfig(bus); + + /* Switches power to an RSPI channel */ + + rspi_power_on_off(bus, RSPI_POWER_ON); + + /* Configure interrupt controller for RSPI */ + + rspi_interrupt_init(priv, bus); + + /* Set up default configuration: Master, 8-bit, etc. */ + + rspi_bus_initialize(priv); + + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_RX65N_RSPI1 + if (bus == RX65N_RSPI_CHANNEL1) + { + /* Select SPI1 */ + + priv = &g_rspi1dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI1 pins 4WIRE mode: RSPCKB, MOSIB, MISOB and SSLB0 */ + + rspi_reg_protect(REG_PROTECTION_OFF); /* Disable protection */ + rspi_pinconfig(bus); + + /* Switches power to an RSPI channel */ + + rspi_power_on_off(bus, RSPI_POWER_ON); + + /* Configure interrupt controller for RSPI */ + + rspi_interrupt_init(priv, bus); + + /* Set up default configuration: Master, 8-bit, etc. */ + + rspi_bus_initialize(priv); + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_RX65N_RSPI2 + if (bus == RX65N_RSPI_CHANNEL2) + { + /* Select SPI2 */ + + priv = &g_rspi2dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI2 pins 4WIRE mode: RSPCKC, MOSIC, MISOC and SSLC0 */ + + rspi_reg_protect(REG_PROTECTION_OFF); /* Disable protection */ + rspi_pinconfig(bus); + + /* Switches power to an RSPI channel */ + + rspi_power_on_off(bus, RSPI_POWER_ON); + + /* Configure interrupt controller for RSPI */ + + rspi_interrupt_init(priv, bus); + + /* Set up default configuration: Master, 8-bit, etc. */ + + rspi_bus_initialize(priv); + + priv->initialized = true; + } + } + else +#endif + { + spierr("ERROR: Unsupported RSPI bus: %d\n", bus); + return NULL; + } + + leave_critical_section(flags); + return (FAR struct spi_dev_s *)priv; +} + +#endif /* CONFIG_RX65N_RSPI0 || CONFIG_RX65N_RSPI1 || CONFIG_RX65N_RSPI2 */ diff --git a/arch/renesas/src/rx65n/rx65n_rspi.h b/arch/renesas/src/rx65n/rx65n_rspi.h new file mode 100644 index 00000000000..105acdd8b41 --- /dev/null +++ b/arch/renesas/src/rx65n/rx65n_rspi.h @@ -0,0 +1,167 @@ +/**************************************************************************** + * arch/renesas/src/rx65n/rx65n_rspi.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_RENESAS_SRC_RX65N_RX65N_RSPI_H +#define __ARCH_RENESAS_SRC_RX65N_RX65N_RSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct spi_dev_s; + +/**************************************************************************** + * Name: rx65n_rspibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * bus number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *rx65n_rspibus_initialize(int bus); + +/**************************************************************************** + * Name: rx65n_rspi0/1/2 select and rx65n_rspi0/1/2 status + * + * Description: + * The external functions, rx65n_rspi0/1/2 select, rx65n_rspi0/1/2 status, + * and rx65n_rspi0/1/2 cmddata must be provided by board-specific logic. + * These are implementations of the select, status, and cmddata methods of + * the SPI interface defined by struct spi_ops_s + * (see include/nuttx/spi/spi.h). All other methods (including + * rx65n_rspibus_initialize()) are provided by common R656N logic. + * To use this common SPI logic on your board: + * + * 1. Provide logic in stm32_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide stm32_spi1/2/...select() and stm32_spi1/2/...status() + * functions in your board-specific logic. These functions will + * perform chip selection and status operations using GPIOs in the + * way your board is configured. + * 3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file, + * then provide stm32_spi1/2/...cmddata() functions in your + * board-specific logic. These functions will perform cmd/data + * selection operations using GPIOs in the way your board is + * configured. + * 4. Add a calls to stm32_spibus_initialize() in your low level + * application initialization logic + * 5. The handle returned by stm32_spibus_initialize() may then be used + * to bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ +#ifdef CONFIG_RX65N_RSPI0 +void rx65n_rspi0select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t rx65n_rspi0status(FAR struct spi_dev_s *dev, uint32_t devid); +int rx65n_rspi0cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +#ifdef CONFIG_RX65N_RSPI1 +void rx65n_rspi1select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t rx65n_rspi1status(FAR struct spi_dev_s *dev, uint32_t devid); +int rx65n_rspi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +#ifdef CONFIG_RX65N_RSPI2 +void rx65n_rspi2select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected); +uint8_t rx65n_rspi2status(FAR struct spi_dev_s *dev, uint32_t devid); +int rx65n_rspi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif + +/**************************************************************************** + * Name: rx65n_rspi0/1/2register + * + * Description: + * If the board supports a card detect callback to inform the SPI-based + * MMC/SD driver when an SD card is inserted or removed, then + * CONFIG_SPI_CALLBACK should be defined and the following function(s) + * must be implemented. These functions implements the registercallback + * method of the SPI interface (see include/nuttx/spi/spi.h for details) + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CALLBACK +#ifdef CONFIG_RX65N_RSPI0 +int rx65n_rspi0register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg); +#endif + +#ifdef CONFIG_RX65N_RSPI1 +int rx65n_rspi1register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg); +#endif + +#ifdef CONFIG_RX65N_RSPI2 +int rx65n_rspi2register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg); +#endif +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RENESAS_SRC_RX65N_RX65N_RSPI_H */ diff --git a/arch/renesas/src/rx65n/rx65n_rspi_sw.c b/arch/renesas/src/rx65n/rx65n_rspi_sw.c new file mode 100644 index 00000000000..b68c75f9838 --- /dev/null +++ b/arch/renesas/src/rx65n/rx65n_rspi_sw.c @@ -0,0 +1,2154 @@ +/**************************************************************************** + * arch/renesas/src/rx65n/rx65n_rspi_sw.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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip.h" +#include "up_arch.h" +#include "rx65n_definitions.h" +#include "rx65n_rspi.h" + +#include +#include + +#if defined(CONFIG_RX65N_RSPI0) || defined(CONFIG_RX65N_RSPI1) || defined(CONFIG_RX65N_RSPI2) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Default bit rate */ + +#define RSPI_BRDV_DEFAULT 0 + +/* The number of words that will fit in the Tx FIFO */ + +#define RX65N_TXFIFO_WORDS BUFSIZE_4FRAME + +/* Interrupt priority */ + +#define RX65N_RSPI_INTRRUPT_PRIO 15 + +/* RSPI power on and off */ + +#define RSPI_POWER_ON 0 +#define RSPI_POWER_OFF 1 + +/* RSPI Register protection enable and disable */ + +#define REG_PROTECTION_ON 1 +#define REG_PROTECTION_OFF 0 + +/* Frequency divisor */ + +enum FREQ_DIVISOR +{ + FREQ_DIVISOR_2 = 2, + FREQ_DIVISOR_4 = 4, + FREQ_DIVISOR_6 = 6, + FREQ_DIVISOR_8 = 8, + FREQ_DIVISOR_10 = 10, + FREQ_DIVISOR_12 = 12, + FREQ_DIVISOR_24 = 24, + FREQ_DIVISOR_48 = 48, + FREQ_DIVISOR_96 = 96, +}; + +/* The number of words that will fit in the buffer */ + +enum BUF_SIZE +{ + BUFSIZE_1FRAME = 1, + BUFSIZE_2FRAME = 2, + BUFSIZE_3FRAME = 3, + BUFSIZE_4FRAME = 4, +}; + +/* RSPI events */ + +typedef enum +{ + RSPI_EVT_TRANSFER_COMPLETE, /* The data transfer completed */ + RSPI_EVT_TRANSFER_ABORTED, /* The data transfer was aborted */ + RSPI_EVT_ERR_MODE_FAULT, /* Mode fault error */ + RSPI_EVT_ERR_READ_OVF, /* Read overflow */ + RSPI_EVT_ERR_PARITY, /* Parity error */ + RSPI_EVT_ERR_UNDER_RUN, /* Under run error */ + RSPI_EVT_ERR_UNDEF /* Undefined/unknown error event */ +} rspi_event_t; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rx65n_rspidev_s +{ + struct spi_dev_s rspidev; /* Externally visible part of the RSPI interface */ + uint32_t rspibase; /* RSPIn base address */ + uint32_t rspiclock; /* Clocking for the RSPI module */ + +#ifndef CONFIG_SPI_POLLWAIT + uint8_t rspitxirq; /* RSPI tx IRQ number */ + uint8_t rspirxirq; /* RSPI rx IRQ number */ + uint8_t rspierirq; /* RSPI error IRQ number */ + uint8_t rspiidlirq; /* RSPI idle IRQ number */ + uint32_t rspigrpbase; + uint32_t rspierimask; + uint32_t rspiidlimask; + sem_t waitsem; /* Wait for transfer to complete */ +#endif + + /* These following are the source and destination buffers of the transfer. + * they are retained in this structure so that they will be accessible + * from an interrupt handler. The actual type of the buffer is uint8_t is + * nbits <=8 and uint16_t is nbits >8. + */ + + void *txbuffer; /* Source buffer */ + void *rxbuffer; /* Destination buffer */ + + /* These are functions pointers that are configured to perform the + * appropriate transfer for the particular kind of exchange that is + * occurring. Different functions may be selected depending on (1) + * if the tx or txbuffer is NULL and depending on the number of bits + * per word. + */ + + void (*txword)(struct rx65n_rspidev_s *priv); + void (*rxword)(struct rx65n_rspidev_s *priv); + + bool initialized; /* Has RSPI interface been initialized */ + sem_t exclsem; /* Held while chip is selected for mutual exclusion */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + + int ntxwords; /* Number of words left to transfer on the Tx Buffer */ + int nrxwords; /* Number of words received on the Rx Buffer */ + int nwords; /* Number of words to be exchanged */ + + uint8_t nbits; /* Width of word in bits (4 through 16) */ + uint8_t mode; /* Mode 0,1,2,3 */ + uint8_t bufsize; /* Buf size: 1,2,3 or 4 word */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +static inline uint32_t rspi_getreg32(FAR struct rx65n_rspidev_s *priv, + uint8_t offset); +static inline uint16_t rspi_getreg16(FAR struct rx65n_rspidev_s *priv, + uint8_t offset); +static inline uint8_t rspi_getreg8(FAR struct rx65n_rspidev_s *priv, + uint8_t offset); +static inline void rspi_putreg32(FAR struct rx65n_rspidev_s *priv, + uint8_t offset, uint32_t value); +static inline void rspi_putreg16(FAR struct rx65n_rspidev_s *priv, + uint8_t offset, uint16_t value); +static inline void rspi_putreg8(FAR struct rx65n_rspidev_s *priv, + uint8_t offset, uint8_t value); + +/* SPI data transfer */ + +static void rspi_txnull(struct rx65n_rspidev_s *priv); +static void rspi_txuint32(struct rx65n_rspidev_s *priv); +static void rspi_txuint16(struct rx65n_rspidev_s *priv); +static void rspi_txuint8(struct rx65n_rspidev_s *priv); +static void rspi_rxnull(struct rx65n_rspidev_s *priv); +static void rspi_rxuint32(struct rx65n_rspidev_s *priv); +static void rspi_rxuint16(struct rx65n_rspidev_s *priv); +static void rspi_rxuint8(struct rx65n_rspidev_s *priv); +static void rspi_performtx(struct rx65n_rspidev_s *priv); +static inline void rspi_performrx(struct rx65n_rspidev_s *priv); +static int rspi_transfer(struct rx65n_rspidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords); + +/* Interrupt handling */ + +#ifndef CONFIG_SPI_POLLWAIT +static inline struct rx65n_rspidev_s *rspi_mapirq(int irq); +static int rspi_idlinterrupt(int irq, void *context, FAR void *arg); +static int rspi_erinterrupt(int irq, void *context, FAR void *arg); +static int rspi_txinterrupt(int irq, void *context, FAR void *arg); +static int rspi_rxinterrupt(int irq, void *context, FAR void *arg); +#endif + +/* SPI methods */ + +static int rspi_lock(FAR struct spi_dev_s *dev, bool lock); +static uint32_t rspi_setfrequency(FAR struct spi_dev_s *dev, + uint32_t frequency); +static void rspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); +static void rspi_setbits(FAR struct spi_dev_s *dev, int nbits); +#ifdef CONFIG_SPI_HWFEATURES +static int rspi_hwfeatures(FAR struct spi_dev_s *dev, + spi_hwfeatures_t features); +#endif +static uint32_t rspi_send(FAR struct spi_dev_s *dev, uint32_t wd); +static void rspi_exchange(FAR struct spi_dev_s *dev, + FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords); +#ifdef CONFIG_SPI_TRIGGER +static int rspi_trigger(FAR struct spi_dev_s *dev); +#endif +#ifndef CONFIG_SPI_EXCHANGE +static void rspi_sndblock(FAR struct spi_dev_s *dev, + FAR const void *txbuffer, + size_t nwords); +static void rspi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer, + size_t nwords); +#endif + +/* Initialization */ + +static void rspi_bus_initialize(FAR struct rx65n_rspidev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI0 +static const struct spi_ops_s g_rspi0ops = +{ + .lock = rspi_lock, + .select = rx65n_rspi0select, + .setfrequency = rspi_setfrequency, + .setmode = rspi_setmode, + .setbits = rspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = rspi_hwfeatures, +#endif + .status = rx65n_rspi0status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = rx65n_rspi0cmddata, +#endif + .send = rspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = rspi_exchange, +#else + .sndblock = rspi_sndblock, + .recvblock = rspi_recvblock, +#endif + +#ifdef CONFIG_SPI_CALLBACK + .registercallback = rx65n_rspi0register, /* Provided externally */ +#else + .registercallback = NULL, +#endif +}; + +static struct rx65n_rspidev_s g_rspi0dev = +{ + .rspidev = + { + &g_rspi0ops + }, + .rspibase = RX65N_RSPI0_BASE, + .rspiclock = RX65N_PCLK_FREQUENCY, +#ifndef CONFIG_SPI_POLLWAIT + .rspitxirq = RX65N_SPTI0_IRQ, + .rspirxirq = RX65N_SPRI0_IRQ, + .rspierirq = RX65N_SPEI0_IRQ, + .rspiidlirq = RX65N_SPII0_IRQ, + .rspigrpbase = RX65N_GRPAL0_ADDR, + .rspierimask = RX65N_GRPAL0_SPEI0_MASK, + .rspiidlimask = RX65N_GRPAL0_SPII0_MASK, +#endif +}; +#endif + +#ifdef CONFIG_RX65N_RSPI1 +static const struct spi_ops_s g_rspi1ops = +{ + .lock = rspi_lock, + .select = rx65n_rspi1select, + .setfrequency = rspi_setfrequency, + .setmode = rspi_setmode, + .setbits = rspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = rspi_hwfeatures, +#endif + .status = rx65n_rspi1status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = rx65n_rspi1cmddata, +#endif + .send = rspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = rspi_exchange, +#else + .sndblock = rspi_sndblock, + .recvblock = rspi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = rspi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = rx65n_rspi1register, /* Provided externally */ +#else + .registercallback = NULL, +#endif +}; + +static struct rx65n_rspidev_s g_rspi1dev = +{ + .rspidev = + { + &g_rspi1ops + }, + .rspibase = RX65N_RSPI1_BASE, + .rspiclock = RX65N_PCLK_FREQUENCY, +#ifndef CONFIG_SPI_POLLWAIT + .rspitxirq = RX65N_SPTI1_IRQ, + .rspirxirq = RX65N_SPRI1_IRQ, + .rspierirq = RX65N_SPEI1_IRQ, + .rspiidlirq = RX65N_SPII1_IRQ, + .rspigrpbase = RX65N_GRPAL0_ADDR, + .rspierimask = RX65N_GRPAL0_SPEI1_MASK, + .rspiidlimask = RX65N_GRPAL0_SPII1_MASK, +#endif +}; +#endif + +#ifdef CONFIG_RX65N_RSPI2 +static const struct spi_ops_s g_rspi2ops = +{ + .lock = rspi_lock, + .select = rx65n_rspi2select, + .setfrequency = rspi_setfrequency, + .setmode = rspi_setmode, + .setbits = rspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = rspi_hwfeatures, +#endif + .status = rx65n_rspi2status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = rx65n_rspi2cmddata, +#endif + .send = rspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = rspi_exchange, +#else + .sndblock = rspi_sndblock, + .recvblock = rspi_recvblock, +#endif +#ifdef CONFIG_SPI_TRIGGER + .trigger = rspi_trigger, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = rx65n_rspi2register, /* Provided externally */ +#else + .registercallback = NULL, +#endif +}; + +static struct rx65n_rspidev_s g_rspi2dev = +{ + .rspidev = + { + &g_rspi2ops + }, + .rspibase = RX65N_RSPI2_BASE, + .rspiclock = RX65N_PCLK_FREQUENCY, +#ifndef CONFIG_SPI_POLLWAIT + .rspitxirq = RX65N_SPTI2_IRQ, + .rspirxirq = RX65N_SPRI2_IRQ, + .rspierirq = RX65N_SPEI2_IRQ, + .rspiidlirq = RX65N_SPII2_IRQ, + .rspigrpbase = RX65N_GRPAL0_ADDR, + .rspierimask = RX65N_GRPAL0_SPEI2_MASK, + .rspiidlimask = RX65N_GRPAL0_SPII2_MASK, +#endif +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_rspi0/1/2 select and rx65n_rspi0/1/2 status + * + * Description: + * The external functions, rx65n_rspi0/1/2 select, rx65n_rspi0/1/2 status,and + * rx65n_rspi0/1/2 cmddata must be provided by board-specific logic. These + * are implementations of the select, status, and cmddata methods of the SPI + * interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h). All + * other methods (including rx65n_rspibus_initialize()) are provided by + * common R656N logic. To use thiscommon SPI logic on your board: + * + * 1. Provide logic in stm32_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide stm32_spi1/2/...select() and stm32_spi1/2/...status() + * functions in your board-specific logic. These functions will + * perform chip selection and status operations using GPIOs in the + * way your board is configured. + * 3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file, + * then provide stm32_spi1/2/...cmddata() functions in your + * board-specific logic.These functions will perform cmd/data + * selection operations using GPIOs in the way your board is configured. + * 4. Add a calls to stm32_spibus_initialize() in your low level + * application initialization logic + * 5. The handle returned by stm32_spibus_initialize() may then be used to + * bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ +#ifdef CONFIG_RX65N_RSPI0 +void rx65n_rspi0select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : + "de-assert"); +} + +uint8_t rx65n_rspi0status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +int rx65n_rspi0cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_RX65N_RSPI1 +void rx65n_rspi1select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : + "de-assert"); +} + +uint8_t rx65n_rspi1status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +int rx65n_rspi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_RX65N_RSPI2 +void rx65n_rspi2select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : + "de-assert"); +} + +uint8_t rx65n_rspi2status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +int rx65n_rspi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +/**************************************************************************** + * Name: rx65n_rspi0/1/2register + * + * Description: + * If the board supports a card detect callback to inform the SPI-based + * MMC/SD driver when an SD card is inserted or removed, then + * CONFIG_SPI_CALLBACK should be defined and the following function(s) + * must be implemented. These functions implements the registercallback + * method of the SPI interface (see include/nuttx/spi/spi.h for details) + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ +#ifdef CONFIG_SPI_CALLBACK +#ifdef CONFIG_RX65N_RSPI0 +int rx65n_rspi0register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg) +{ + spiinfo("INFO: Registering rspi0 device\n"); + return OK; +} +#endif + +#ifdef CONFIG_RX65N_RSPI1 +int rx65n_rspi1register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg) +{ + spiinfo("INFO: Registering rspi1 device\n"); + return OK; +} +#endif + +#ifdef CONFIG_RX65N_RSPI2 +int rx65n_rspi2register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, + FAR void *arg) +{ + spiinfo("INFO: Registering rspi2 device\n"); + return OK; +} +#endif +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rspi_getreg32 + * + * Description: + * Read the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * + * Returned Value: + * Value of the register at this offset + * + ****************************************************************************/ + +static inline uint32_t rspi_getreg32(struct rx65n_rspidev_s *priv, + uint8_t offset) +{ + return getreg32(priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_getreg16 + * + * Description: + * Read the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * + * Returned Value: + * Value of the register at this offset + * + ****************************************************************************/ + +static inline uint16_t rspi_getreg16(struct rx65n_rspidev_s *priv, + uint8_t offset) +{ + return getreg16(priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_getreg8 + * + * Description: + * Read the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * + * Returned Value: + * Value of the register at this offset + * + ****************************************************************************/ + +static inline uint8_t rspi_getreg8(struct rx65n_rspidev_s *priv, + uint8_t offset) +{ + return getreg8(priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_putreg32 + * + * Description: + * Write the value to the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_putreg32(struct rx65n_rspidev_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_putreg16 + * + * Description: + * Write the value to the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_putreg16(struct rx65n_rspidev_s *priv, + uint8_t offset, uint16_t value) +{ + putreg16(value, priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_putreg8 + * + * Description: + * Write the value to the RSPI register at this offeset + * + * Input Parameters: + * priv - Device-specific state data + * offset - Offset to the SPI register from the register base address + * value - Value to write + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_putreg8(struct rx65n_rspidev_s *priv, + uint8_t offset, uint8_t value) +{ + putreg8(value, priv->rspibase + offset); +} + +/**************************************************************************** + * Name: rspi_txnull, rspi_txuint16, and rspi_txuint8 + * + * Description: + * Transfer all ones, a uint8_t, or uint16_t to Tx FIFO and update + * the txbuffer pointer appropriately. The selected function depends + * on (1) if there is a source txbuffer provided, and (2) if the + * number of bits per word is <=8 or >8. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_txnull(struct rx65n_rspidev_s *priv) +{ + rspi_putreg32(priv, RX65N_RSPI_SPDR_OFFSET, 0xffff); +} + +static void rspi_txuint32(struct rx65n_rspidev_s *priv) +{ + uint32_t *ptr = (uint32_t *)priv->txbuffer; + rspi_putreg32(priv, RX65N_RSPI_SPDR_OFFSET, *ptr++); + priv->txbuffer = (void *)ptr; +} + +static void rspi_txuint16(struct rx65n_rspidev_s *priv) +{ + uint16_t *ptr = (uint16_t *)priv->txbuffer; + rspi_putreg16(priv, RX65N_RSPI_SPDR_OFFSET, *ptr++); + priv->txbuffer = (void *)ptr; +} + +static void rspi_txuint8(struct rx65n_rspidev_s *priv) +{ + uint8_t *ptr = (uint8_t *)priv->txbuffer; + rspi_putreg8(priv, RX65N_RSPI_SPDR_OFFSET, *ptr++); + priv->txbuffer = (void *)ptr; +} + +/**************************************************************************** + * Name: rspi_rxnull,rspi_rxuint16, and rspi_rxuint8 + * + * Description: + * Discard input, save a uint8_t, or or save a uint16_t from Tx FIFO in the + * user rxvbuffer and update the rxbuffer pointer appropriately. The + * selected function dependes on (1) if there is a destination rxbuffer + * provided, and (2) if the number of bits per word is <=8 or >8. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_rxnull(struct rx65n_rspidev_s *priv) +{ + rspi_getreg32(priv, RX65N_RSPI_SPDR_OFFSET); +} + +static void rspi_rxuint32(struct rx65n_rspidev_s *priv) +{ + uint32_t *ptr = (uint32_t *)priv->rxbuffer; + *ptr++ = (uint32_t)rspi_getreg32(priv, RX65N_RSPI_SPDR_OFFSET); + priv->rxbuffer = (void *)ptr; +} + +static void rspi_rxuint16(struct rx65n_rspidev_s *priv) +{ + uint16_t *ptr = (uint16_t *)priv->rxbuffer; + *ptr++ = (uint16_t)rspi_getreg16(priv, RX65N_RSPI_SPDR_OFFSET); + priv->rxbuffer = (void *)ptr; +} + +static void rspi_rxuint8(struct rx65n_rspidev_s *priv) +{ + uint8_t *ptr = (uint8_t *)priv->rxbuffer; + *ptr++ = (uint8_t)rspi_getreg8(priv, RX65N_RSPI_SPDR_OFFSET); + priv->rxbuffer = (void *)ptr; +} + +/**************************************************************************** + * Name: rspi_performtx + * + * Description: + * If the Tx FIFO is empty, then transfer as many words as we can to + * the FIFO. + * + * Input Parameters: + * + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_performtx(struct rx65n_rspidev_s *priv) +{ + uint8_t regval8; + int ntxd = 0; /* Number of words written to Tx FIFO */ + + /* Check if the Tx FIFO is empty */ + + if ((rspi_getreg8(priv, RX65N_RSPI_SPSR_OFFSET) & RSPI_SPSR_SPTEF) != 0) + { + /* Check if all of the Tx words have been sent */ + + if (priv->ntxwords > 0) + { + /* No.. + * Transfer more words until either the TxFIFO is full or + * until all of the user provided data has been sent. + */ + + for (; ntxd < priv->ntxwords && ntxd < priv->bufsize; ntxd++) + { + priv->txword(priv); + } + + /* Update the count of words to be transferred */ + + priv->ntxwords -= ntxd; + + /* Add dummy data in FIFO to make it full */ + + if (ntxd < priv->bufsize) + { + while (ntxd != priv->bufsize) + { + rspi_txnull(priv); + ntxd++; + } + } + } + else + { + /* Yes.. The transfer is complete, + * disable Tx FIFO empty interrupt + */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~RSPI_SPCR_SPTIE; + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + } + } +} + +/**************************************************************************** + * Name: rspi_performrx + * + * Description: + * Transfer as many bytes as possible from the Rx FIFO to the user Rx + * buffer (if one was provided). + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rspi_performrx(struct rx65n_rspidev_s *priv) +{ + /* Loop while data is available in the Rx FIFO (SPRXn) */ + + while ((rspi_getreg8(priv, RX65N_RSPI_SPSR_OFFSET) & RSPI_SPSR_SPRF) != 0) + { + /* Have all of the requested words been transferred from the Rx FIFO? */ + + if (priv->nrxwords < priv->nwords) + { + /* No.. Read more data from Rx FIFO */ + + priv->rxword(priv); + priv->nrxwords++; + } + else + { + rspi_rxnull(priv); /* Reading dummy data send */ + } + } +} + +/**************************************************************************** + * Name: rspi_startxfr + * + * Description: + * If data was added to the Tx FIFO, then start the exchange + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_startxfr(struct rx65n_rspidev_s *priv) +{ + uint8_t regval8; + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= RSPI_SPCR_SPE; + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); +} + +/**************************************************************************** + * Name: rspi_transfer + * + * Description: + * Exchange a block data with the SPI device + * + * Input Parameters: + * priv - Device-specific state data + * txbuffer - The buffer of data to send to the device (may be NULL). + * rxbuffer - The buffer to receive data from the device (may be NULL). + * nwords - The total number of words to be exchanged. If the interface + * uses <= 8 bits per word, then this is the number of + * uint8_t's; if the interface uses >8 bits per word, then this + * is the number of uint16_t's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +static int rspi_transfer(struct rx65n_rspidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords) +{ + uint8_t regval8; +#ifndef CONFIG_SPI_POLLWAIT + irqstate_t flags; +#endif + + /* Set up to perform the transfer */ + + priv->txbuffer = (uint8_t *)txbuffer; /* Source buffer */ + priv->rxbuffer = (uint8_t *)rxbuffer; /* Destination buffer */ + priv->ntxwords = nwords; /* Number of words left to send */ + priv->nrxwords = 0; /* Number of words received */ + priv->nwords = nwords; /* Total number of exchanges */ + + /* Set up the low-level data transfer function pointers */ + + if (priv->nbits > 16) + { + priv->txword = rspi_txuint32; + priv->rxword = rspi_rxuint32; + } + + if (priv->nbits > 8) + { + priv->txword = rspi_txuint16; + priv->rxword = rspi_rxuint16; + } + else + { + priv->txword = rspi_txuint8; + priv->rxword = rspi_rxuint8; + } + + if (!txbuffer) + { + priv->txword = rspi_txnull; + } + + if (!rxbuffer) + { + priv->rxword = rspi_rxnull; + } + + /* Copied data to start the sequence (saves one interrupt) */ + +#ifndef CONFIG_SPI_POLLWAIT + flags = enter_critical_section(); + + /* Enable interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= (RSPI_SPCR_SPEIE | RSPI_SPCR_SPTIE | RSPI_SPCR_SPRIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Start transmission */ + + rspi_performtx(priv); + rspi_startxfr(priv); + + /* Enable Idle interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 |= (RSPI_SPCR2_SPIIE); /* RSPI Idle Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); + + leave_critical_section(flags); + + /* Wait for the transfer to complete. Since there is no handshake + * with SPI, the following should complete even if there are problems + * with the transfer, so it should be safe with no timeout. + */ + + /* Wait to be signaled from the interrupt handler */ + + return nxsem_wait_uninterruptible(&priv->waitsem); + +#else + /* Perform the transfer using polling logic. This will totally + * dominate the CPU until the transfer is complete. Only recommended + * if (1) your SPI is very fast, and (2) if you only use very short + * transfers. + */ + + do + { + /* Handle outgoing Tx FIFO transfers */ + + rspi_performtx(priv); + + /* Handle incoming Rx FIFO transfers */ + + rspi_performrx(priv); + + /* Resume the transfer */ + + rspi_startxfr(priv); + + /* If there are other threads at this same priority level, + * the following may help: + */ + + sched_yield(); + } + while (priv->nrxwords < priv->nwords); + + return OK; +#endif +} + +/**************************************************************************** + * Name: rspi_mapirq + * + * Description: + * Map an IRQ number into the appropriate SPI device + * + * Input Parameters: + * irq - The IRQ number to be mapped + * + * Returned Value: + * On success, a reference to the private data structgure for this IRQ. + * NULL on failure. + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static inline struct rx65n_rspidev_s *rspi_mapirq(int irq) +{ + switch (irq) + { +#ifdef CONFIG_RX65N_RSPI0 + case RX65N_SPRI0_IRQ: + case RX65N_SPTI0_IRQ: + case RX65N_SPEI0_IRQ: + case RX65N_SPII0_IRQ: + return &g_rspi0dev; +#endif +#ifdef CONFIG_RX65N_RSPI1 + case RX65N_SPRI1_IRQ: + case RX65N_SPTI1_IRQ: + case RX65N_SPEI1_IRQ: + case RX65N_SPII1_IRQ: + return &g_rspi1dev; +#endif +#ifdef CONFIG_RX65N_RSPI2 + case RX65N_SPRI2_IRQ: + case RX65N_SPTI2_IRQ: + case RX65N_SPEI2_IRQ: + case RX65N_SPII2_IRQ: + return &g_rspi2dev; +#endif + default: + return NULL; + } +} +#endif + +/**************************************************************************** + * Name: rspi_errhandle + * + * Description: + * RSPI common error handler + * + * Input Parameters: + * priv - Device-specific state data + * bus - channel number + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static void rspi_errhandle(struct rx65n_rspidev_s *priv, uint8_t bus) +{ + uint8_t regval8; + + rspi_event_t event = RSPI_EVT_ERR_UNDEF; + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPSR_OFFSET); + + /* Identify and clear error condition . */ + + if (regval8 & RSPI_SPSR_OVRF) + { + /* Overrun error */ + + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_READ_OVF; + } + + /* Clear error source: OVRF flag. */ + + regval8 &= (~RSPI_SPSR_OVRF); + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + + if (regval8 & RSPI_SPSR_MODF) + { + if (regval8 & RSPI_SPSR_UDRF) + { + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_UNDER_RUN; + } + + /* Clear error source : MODF flag and UDRF */ + + regval8 &= RSPI_SPSR_MODF_UDRF_MASK; + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + else + { + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_MODE_FAULT; + } + + /* Clear error source : MODF flag */ + + regval8 &= (~RSPI_SPSR_MODF); + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + } + + if (regval8 & RSPI_SPSR_PERF) + { + if (RSPI_EVT_ERR_UNDEF == event) + { + event = RSPI_EVT_ERR_PARITY; + } + + /* Clear error source: PERF flag */ + + regval8 &= (~RSPI_SPSR_PERF); + rspi_putreg8(priv, RX65N_RSPI_SPSR_OFFSET, regval8); + } + + /* Disable the RSPI operation . */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= (~(RSPI_SPCR_SPTIE | RSPI_SPCR_SPRIE | RSPI_SPCR_SPE)); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Yes, wake up the waiting thread . */ + + nxsem_post(&priv->waitsem); +} +#endif + +/**************************************************************************** + * Name: rspi_idlinterrupt + * + * Description: + * RSPI IDLE interrupt handler invoke on transmission/reception completion + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_idlinterrupt(int irq, void *context, FAR void *arg) +{ + uint8_t regval8; + + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + + /* Disable Idle interrupt in SPCR2 */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 &= ~(RSPI_SPCR2_SPIIE); /* RSPI Idle Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); + + /* Disable ransmit/receive interrupt */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~(RSPI_SPCR_SPRIE | RSPI_SPCR_SPTIE); + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Yes, wake up the waiting thread */ + + nxsem_post(&priv->waitsem); + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_erinterrupt + * + * Description: + * RSPI common error interrupt handler + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_erinterrupt(int irq, void *context, FAR void *arg) +{ + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + +#ifdef CONFIG_RX65N_RSPI0 + rspi_errhandle(priv, RX65N_RSPI_CHANNEL0); +#endif + +#ifdef CONFIG_RX65N_RSPI1 + rspi_errhandle(priv, RX65N_RSPI_CHANNEL1); +#endif + +#ifdef CONFIG_RX65N_RSPI2 + rspi_errhandle(priv, RX65N_RSPI_CHANNEL2); +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_rxinterrupt + * + * Description: + * Receive buffer full interrupt handler to process a block data from SPI + * device + * + * Input Parameters: + * priv - Device-specific state data + * rxbuffer - The buffer to receive data from the device (may be NULL). + * nwords - The total number of words to be exchanged. If the interface + * uses <= 8 bits per word, then this is the number of + * uint8_t's; if the interface uses >8 bits per word, then this + * is the number of uint16_t's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_rxinterrupt(int irq, void *context, FAR void *arg) +{ + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + + /* Handle incoming Rx FIFO transfers */ + + rspi_performrx(priv); + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_txinterrupt + * + * Description: + * Transmit buffer empty interrupt handler to process a block data for SPI + * device + * + * Input Parameters: + * priv - Device-specific state data + * txbuffer - The buffer of data to send to the device (may be NULL). + * nwords - The total number of words to be exchanged. If the interface + * uses <= 8 bits per word, then this is the number of + * uint8_t's; if the interface uses >8 bits per word, then this + * is the number of uint16_t's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_POLLWAIT +static int rspi_txinterrupt(int irq, void *context, FAR void *arg) +{ + struct rx65n_rspidev_s *priv = rspi_mapirq(irq); + + DEBUGASSERT(priv != NULL); + + /* Handle outgoing Tx FIFO transfers */ + + rspi_performtx(priv); + + return OK; +} +#endif + +/**************************************************************************** + * Name: rspi_lock + * + * Description: + * On SPI buses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the SPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the SPI is properly + * configured for the device. If the SPI bus is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock spi bus, false: unlock SPI bus + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ + +static int rspi_lock(FAR struct spi_dev_s *dev, bool lock) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + int ret; + + if (lock) + { + ret = nxsem_wait_uninterruptible(&priv->exclsem); + } + else + { + ret = nxsem_post(&priv->exclsem); + } + + return ret; +} + +/**************************************************************************** + * Name: rspi_setfrequency + * + * Description: + * Set the RSPI frequency. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The SPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32_t rspi_setfrequency(FAR struct spi_dev_s *dev, + uint32_t frequency) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + uint32_t actual; + + DEBUGASSERT(priv); + actual = priv->actual; + + if (frequency != priv->frequency) + { + /* Below formula used to calculate bit rate + * Bit rate f(PCLK)/(2 × (n + 1) × 2^N) . + * n denotes SPBR setting (0,1,2..255) . + * N denotes a BRDV[1:0] bit setting (0, 1, 2, 3) . + */ + + uint16_t regval16; + uint32_t brdv; + uint8_t spbr; + + /* N=0 as per fit code */ + + brdv = RSPI_BRDV_DEFAULT; + + DEBUGASSERT(brdv < 4); + + if (frequency >= priv->rspiclock / FREQ_DIVISOR_2) + { + actual = priv->rspiclock / FREQ_DIVISOR_2; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_4) + { + actual = priv->rspiclock / FREQ_DIVISOR_4; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_6) + { + actual = priv->rspiclock / FREQ_DIVISOR_6; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_8) + { + actual = priv->rspiclock / FREQ_DIVISOR_8; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_10) + { + actual = priv->rspiclock / FREQ_DIVISOR_10; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_12) + { + actual = priv->rspiclock / FREQ_DIVISOR_12; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_24) + { + actual = priv->rspiclock / FREQ_DIVISOR_24; + } + else if (frequency >= priv->rspiclock / FREQ_DIVISOR_48) + { + actual = priv->rspiclock / FREQ_DIVISOR_48; + } + else /* (frequency >= priv->rspiclock / FREQ_DIVISOR_96) */ + { + actual = priv->rspiclock / FREQ_DIVISOR_96; + } + + /* Calculate n and set the n in SPBR */ + + spbr = (priv->rspiclock / (2 * actual * ((1 << brdv)))) - 1; + rspi_putreg8(priv, RX65N_RSPI_SPBR_OFFSET, spbr); + + /* Set the N as BRDV[1:0] in SPCMD0 b2 and b3 */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 &= ~(RSPI_SPCMD_BRDV_MASK); + regval16 |= (brdv << 2); + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + /* Save the frequency and actual frequency in RSPI device structure */ + + priv->frequency = frequency; + priv->actual = actual; + } + + return actual; +} + +/**************************************************************************** + * Name: rspi_setmode + * + * Description: + * Set the SPI mode. Optional. See enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void rspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + + uint16_t regval16; + + if (priv && mode != priv->mode) + { + uint32_t modebits; + + /* Select the CTL register bits based on the selected mode */ + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0 CHPHA=0 */ + modebits = 0; + break; + + case SPIDEV_MODE1: /* CPOL=0 CHPHA=1 */ + modebits = RSPI_SPCMD_PHA; + break; + + case SPIDEV_MODE2: /* CPOL=1 CHPHA=0 */ + modebits = RSPI_SPCMD_POL; + break; + + case SPIDEV_MODE3: /* CPOL=1 CHPHA=1 */ + modebits = RSPI_SPCMD_PHA | RSPI_SPCMD_POL; + break; + + default: + spiwarn("Warning: Unsupported RSPI mode: %d\n", mode); + return; + } + + /* Then set the selected mode */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 &= ~(RSPI_SPCMD_PHA | RSPI_SPCMD_POL); + regval16 |= modebits; + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + /* Save the mode so that subsequent re-configurations will be faster */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: rspi_setbits + * + * Description: + * Set the number of bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void rspi_setbits(FAR struct spi_dev_s *dev, int nbits) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + + uint8_t regval8; + uint16_t regval16; + + if (priv && nbits != priv->nbits && nbits > 0 && nbits <= 16) + { + if (nbits >= 4 && nbits <= 8) + { + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR_OFFSET); + regval8 |= RSPI_SPDCR_SPBYT; + rspi_putreg8(priv, RX65N_RSPI_SPDCR_OFFSET, regval8); + } + else if (nbits > 8 && nbits <= 16) + { + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR_OFFSET); + regval8 &= ~(RSPI_SPDCR_SPLW | RSPI_SPDCR_SPBYT); + rspi_putreg8(priv, RX65N_RSPI_SPDCR_OFFSET, regval8); + } + else + { + spierr("ERROR: RSPI not supporting: %d bit word\n", nbits); + } + + /* Configure command data register for this transfer */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 |= (RSPI_SPCMD_SPB_MASK & ((nbits - 1) << 8)); + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + priv->nbits = nbits; + } + else + { + spiwarn("Warning: Unsupported RSPI Word width: %d\n", nbits); + } +} + +/**************************************************************************** + * Name: rspi_send + * + * Description: + * Exchange one word on RSPI + * + * Input Parameters: + * dev - Device-specific state data + * wd - The word to send. the size of the data is determined by the + * number of bits selected for the SPI interface. + * + * Returned Value: + * response + * + ****************************************************************************/ + +static uint32_t rspi_send(FAR struct spi_dev_s *dev, uint32_t wd) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + uint32_t response = 0; + + rspi_transfer(priv, &wd, &response, 1); + return response; +} + +/**************************************************************************** + * Name: rspi_exchange + * + * Description: + * Exahange a block of data from SPI. Required. + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to the buffer in which to receive data + * nwords - the length of data that to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_EXCHANGE +static void rspi_exchange(FAR struct spi_dev_s *dev, + FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + rspi_transfer(priv, txbuffer, rxbuffer, nwords); +} +#endif + +/**************************************************************************** + * Name: rspi_sndblock + * + * Description: + * Send a block of data on SPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void rspi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, + size_t nwords) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + rspi_transfer(priv, buffer, NULL, nwords); +} +#endif + +/**************************************************************************** + * Name: rspi_recvblock + * + * Description: + * Revice a block of data from SPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer in which to receive data + * nwords - the length of data that can be received in the buffer in number + * of words. The wordsize is determined by the number of + * bits-per-word selected for the SPI interface. If nbits <= 8, + * the data is packed into uint8_t's; if nbits >8, the data is + * packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void rspi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, + size_t nwords) +{ + struct rx65n_rspidev_s *priv = (struct rx65n_rspidev_s *)dev; + rspi_transfer(priv, NULL, buffer, nwords); +} +#endif + +/**************************************************************************** + * Function Name: rspi_interrupt_init + * Description : Configure ICU for RSPI interrupt + * Arguments : none + * Return Value : none + ****************************************************************************/ + +void rspi_interrupt_init(FAR struct rx65n_rspidev_s *priv, uint8_t bus) +{ + /* Enable error interrupt source bit */ + + IEN(ICU, GROUPAL0) = 0; /* Disable Group AL0 interrupts */ + IR(ICU, GROUPAL0) = 0; /* Clear interrupt flag */ + IPR(ICU, GROUPAL0) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(ICU, GROUPAL0) = 1; /* Enable Group AL0 interrupt */ + +#ifdef CONFIG_RX65N_RSPI0 + if (bus == RX65N_RSPI_CHANNEL0) + { + /* Configure Transmit empty buffer interrupt source bit */ + + IEN(RSPI0, SPTI0) = 0; /* Disable SPTI0 interrupts */ + IR(RSPI0, SPTI0) = 0; /* Clear interrupt flag */ + IPR(RSPI0, SPTI0) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI0, SPTI0) = 1; /* Enable SPTI0 interrupt */ + ICU.IER[0x04].BIT.IEN7 = 1; + + /* Configure Receive buffer full interrupt source bit */ + + IEN(RSPI0, SPRI0) = 0; /* Disable SPRI0 interrupts */ + IR(RSPI0, SPRI0) = 0; /* Clear interrupt flag */ + IPR(RSPI0, SPRI0) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI0, SPRI0) = 1; /* Enable SPRI0 interrupt */ + ICU.IER[0x04].BIT.IEN6 = 1; + + /* Enable error interrupt source bit */ + + ICU.GENAL0.BIT.EN17 = 1; + + /* Enable Idle interrupt source bit */ + + ICU.GENAL0.BIT.EN16 = 1; + } +#endif + +#ifdef CONFIG_RX65N_RSPI1 + if (bus == RX65N_RSPI_CHANNEL1) + { + /* Configure Transmit empty buffer interrupt */ + + IEN(RSPI1, SPTI1) = 0; /* Disable SPTI1 interrupts */ + IR(RSPI1, SPTI1) = 0; /* Clear interrupt flag */ + IPR(RSPI1, SPTI1) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI1, SPTI1) = 1; /* Enable SPTI1 interrupt */ + ICU.IER[0x05].BIT.IEN1 = 1; + + /* Configure Receive buffer full interrupt */ + + IEN(RSPI1, SPRI1) = 0; /* Disable SPRI1 interrupts */ + IR(RSPI1, SPRI1) = 0; /* Clear interrupt flag */ + IPR(RSPI1, SPRI1) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI1, SPRI1) = 1; /* Enable SPRI1 interrupt */ + ICU.IER[0x05].BIT.IEN0 = 1; + + /* Enable error interrupt source bit */ + + ICU.GENAL0.BIT.EN19 = 1; + + /* Enable Idle interrupt source bit */ + + ICU.GENAL0.BIT.EN18 = 1; + } +#endif + +#ifdef CONFIG_RX65N_RSPI2 + if (bus == RX65N_RSPI_CHANNEL2) + { + /* Configure Transmit empty buffer interrupt */ + + IEN(RSPI2, SPTI2) = 0; /* Disable SPTI2 interrupts */ + IR(RSPI2, SPTI2) = 0; /* Clear interrupt flag */ + IPR(RSPI2, SPTI2) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI2, SPTI2) = 1; /* Enable SPTI2 interrupt */ + ICU.IER[13].BIT.IEN5 = 1; + + /* Configure Receive buffer full interrupt */ + + IEN(RSPI2, SPRI2) = 0; /* Disable SPRI2 interrupts */ + IR(RSPI2, SPRI2) = 0; /* Clear interrupt flag */ + IPR(RSPI2, SPRI2) = RX65N_RSPI_INTRRUPT_PRIO; + IEN(RSPI2, SPRI2) = 1; /* Enable SPRI2 interrupt */ + ICU.IER[13].BIT.IEN4 = 1; + + /* Enable error interrupt source bit */ + + ICU.GENAL0.BIT.EN21 = 1; + + /* Enable Idle interrupt source bit */ + + ICU.GENAL0.BIT.EN20 = 1; + } +#endif +} + +/**************************************************************************** + * Function Name: power_on_off + * Description : Switches power to an RSPI channel. Required by FIT spec. + * Arguments : + * channel -Which channel to use. + * on_or_off -0 means 1 means off + * Return Value : none + ****************************************************************************/ + +static void rspi_power_on_off (uint8_t channel, uint8_t on_or_off) +{ + SYSTEM.PRCR.WORD = 0xa50bu; + + switch (channel) + { + case RX65N_RSPI_CHANNEL0: + MSTP(RSPI0) = on_or_off; + break; + case RX65N_RSPI_CHANNEL1: + MSTP(RSPI1) = on_or_off; + break; + case RX65N_RSPI_CHANNEL2: + MSTP(RSPI2) = on_or_off; + break; + } +} + +/**************************************************************************** + * Function Name: rspi_reg_protect + * Description : Register protection enable/disable. Required by FIT spec. + * Arguments : + * enable - used to enable and disable protection + * Return Value : none + ****************************************************************************/ + +static void rspi_reg_protect (uint8_t enable) +{ + SYSTEM.PRCR.WORD = 0xa50b; + MPC.PWPR.BIT.B0WI = 0; + MPC.PWPR.BIT.PFSWE = 1; +} + +/**************************************************************************** + * Name: rspi_bus_initialize + * + * Description: + * Initialize the selected RSPI bus in its default state (Master, 8-bit, + * mode 0, etc.) + * + * Input Parameters: + * priv - private SPI device structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rspi_bus_initialize(FAR struct rx65n_rspidev_s *priv) +{ + uint8_t regval8; + uint16_t regval16; + +#ifndef CONFIG_SPI_POLLWAIT + /* Initialize the semaphore that is used to wake up the waiting + * thread when the transfer completes. This semaphore is used for + * signaling and, hence, should not have priority inheritance enabled. + */ + + nxsem_init(&priv->waitsem, 0, 0); + nxsem_set_protocol(&priv->waitsem, SEM_PRIO_NONE); +#endif + nxsem_init(&priv->exclsem, 0, 1); + + /* Initialize control register */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 = regval8 & (~RSPI_SPCR_SMPS); /* RSPI operation (4-wire method) */ + regval8 = regval8 & (~RSPI_SPCR_TXMD); /* Full-duplex synchronous serial communications */ + regval8 = regval8 | (RSPI_SPCR_MSTR); /* Master mode */ + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* RSPI Pin Control Register */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPPCR_OFFSET); + regval8 &= (~(RSPI_SPPCR_SPLP /* Loopback mode */ + | RSPI_SPPCR_SPLP2 /* Loopback mode */ + | RSPI_SPPCR_MOIFV /* MOSI pin idles high */ + | RSPI_SPPCR_MOIFE)); /* MOSI pin idles at MOIFV */ + rspi_putreg8(priv, RX65N_RSPI_SPPCR_OFFSET, regval8); + + /* Sets polarity of SSL signal */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SSLP_OFFSET); + regval8 &= (~(RSPI_SSLP_SSL0P + | RSPI_SSLP_SSL1P + | RSPI_SSLP_SSL2P + | RSPI_SSLP_SSL3P)); /* RSPCK is low when idle */ + rspi_putreg8(priv, RX65N_RSPI_SSLP_OFFSET, regval8); + + /* Inititalize frequency, frame size and SPI mode */ + + priv->frequency = 0; + priv->mode = SPIDEV_MODE0; + + /* Select a default frequency of approx. 400KHz */ + + rspi_setfrequency((FAR struct spi_dev_s *)priv, 400000); + + /* Configure data control register SPDCR + * Four frames can be transmitted or received in one round of transmission + * or reception activation. + */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR_OFFSET); + regval8 &= (~RSPI_SPDCR_MASK); +#ifdef CONFIG_RX65N_RSPI_BUF_SIZE + regval8 |= (RSPI_SPDCR_SPFC_MASK & (CONFIG_RX65N_RSPI_BUF_SIZE -1)); + priv->bufsize = CONFIG_RX65N_RSPI_BUF_SIZE; +#else + regval8 |= (RSPI_SPDCR_SPFC0 | RSPI_SPDCR_SPFC1); /* 4 frames */ + priv->bufsize = BUFSIZE_4FRAME; +#endif + regval8 |= (RSPI_SPDCR_SPBYT); + priv->nbits = 8; + rspi_putreg8(priv, RX65N_RSPI_SPDCR_OFFSET, regval8); + + /* Configure RSPI clock delay registers SPCKD */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCKD_OFFSET); + regval8 &= (~RSPI_SPCKD_MASK); +#if CONFIG_RX65N_RSPI_SPCKD_DELAY + regval8 |= (RSPI_SPCKD_MASK & CONFIG_RX65N_RSPI_SPCKD_DELAY); +#else + regval8 |= (RSPI_SPCKD_SCKDL1); /* 2RSPCK delay */ +#endif + rspi_putreg8(priv, RX65N_RSPI_SPCKD_OFFSET, regval8); + + /* Configure RSPI slave select negation delay register SSLND */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SSLND_OFFSET); + regval8 &= (~RSPI_SSLND_MASK); +#if CONFIG_RX65N_RSPI_SSLND_DELAY + regval8 |= (RSPI_SSLND_MASK & CONFIG_RX65N_RSPI_SSLND_DELAY); +#else + regval8 |= (RSPI_SSLND_SLNDL1); /* 2RSPCK delay */ +#endif + rspi_putreg8(priv, RX65N_RSPI_SSLND_OFFSET, regval8); + + /* Configure RSPI next-access delay register SPND */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPND_OFFSET); + regval8 &= (~RSPI_SPND_MASK); +#if CONFIG_RX65N_RSPI_SPND_DELAY + regval8 |= (RSPI_SPND_MASK & CONFIG_RX65N_RSPI_SPND_DELAY); +#else + regval8 |= (RSPI_SPND_SPNDL1); /* 2RSPCK delay */ +#endif + rspi_putreg8(priv, RX65N_RSPI_SPND_OFFSET, regval8); + + /* Configure RSPI Control Register 2 */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 &= (~RSPI_SPCR2_MASK); /* Clear all bit */ +#ifdef CONFIG_RX65N_RSPI_HIGHSPEED + regval8 |= (RSPI_SPCR2_SCKASE); +#endif + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); + + /* Configure RSPI sequence control register SPSCR */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPSCR_OFFSET); + regval8 &= (~RSPI_SPSCR_MASK); + rspi_putreg8(priv, RX65N_RSPI_SPSCR_OFFSET, regval8); + + /* Configure the SPCMD0 command register */ + + regval16 = rspi_getreg16(priv, RX65N_RSPI_SPCMD0_OFFSET); + regval16 &= (~RSPI_SPCMD_MASK); + regval16 |= ((RSPI_SPCMD_SPB0 | RSPI_SPCMD_SPB1 | RSPI_SPCMD_SPB2) +#if CONFIG_RX65N_RSPI_BITORDER + | (RSPI_SPCMD_LSBF) /* RSPI LSB First */ +#endif + | (RSPI_SPCMD_SPNDEN) /* RSPI Next-Access Delay Enable */ + | (RSPI_SPCMD_SLNDEN) /* SSL Negation Delay Setting Enable */ + | (RSPI_SPCMD_SCKDEN)); /* RSPCK Delay Setting Enable */ + rspi_putreg16(priv, RX65N_RSPI_SPCMD0_OFFSET, regval16); + + /* Configure Set RSPI data control register 2 (SPDCR2) */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPDCR2_OFFSET); + regval8 &= (~RSPI_SPDCR2_BYSW); + rspi_putreg8(priv, RX65N_RSPI_SPDCR2_OFFSET, regval8); + +#ifndef CONFIG_SPI_POLLWAIT + /* Disable all interrupt in SPCR */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 &= ~(RSPI_SPCR_SPEIE /* RSPI Error Interrupt Enable */ + | RSPI_SPCR_SPTIE /* Transmit Buffer Empty Interrupt Enable */ + | RSPI_SPCR_SPRIE); /* RSPI Receive Buffer Full Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Disable Idle interrupt in SPCR2 */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR2_OFFSET); + regval8 &= ~(RSPI_SPCR2_SPIIE); /* RSPI Idle Interrupt Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR2_OFFSET, regval8); +#endif + + /* Attach the interrupt */ + +#ifndef CONFIG_SPI_POLLWAIT + irq_attach(priv->rspitxirq, (xcpt_t)rspi_txinterrupt, NULL); + irq_attach(priv->rspirxirq, (xcpt_t)rspi_rxinterrupt, NULL); + irq_attach(priv->rspierirq, (xcpt_t)rspi_erinterrupt, NULL); + irq_attach(priv->rspiidlirq, (xcpt_t)rspi_idlinterrupt, NULL); +#endif + + /* Enable RSPI functionality */ + + regval8 = rspi_getreg8(priv, RX65N_RSPI_SPCR_OFFSET); + regval8 |= (RSPI_SPCR_SPE); /* RSPI Function Enable */ + rspi_putreg8(priv, RX65N_RSPI_SPCR_OFFSET, regval8); + + /* Enable SPI irq */ + +#ifndef CONFIG_SPI_POLLWAIT + up_enable_irq(priv->rspitxirq); + up_enable_irq(priv->rspirxirq); + up_enable_irq(priv->rspierirq); + up_enable_irq(priv->rspiidlirq); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_rspibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *rx65n_rspibus_initialize(int bus) +{ + FAR struct rx65n_rspidev_s *priv = NULL; + + irqstate_t flags = enter_critical_section(); + +#ifdef CONFIG_RX65N_RSPI0 + if (bus == RX65N_RSPI_CHANNEL0) + { + /* Select RSPI0 */ + + priv = &g_rspi0dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure RSPI0 pins for 4WIRE mode + * RSPCKA,MOSIA, MISOA and SSLA0 + */ + + rspi_reg_protect(REG_PROTECTION_OFF); /* Disable protection */ + rspi_pinconfig(bus); + + /* Switches power to an RSPI channel */ + + rspi_power_on_off(bus, RSPI_POWER_ON); + + /* Configure interrupt controller for RSPI */ + + rspi_interrupt_init(priv, bus); + + /* Set up default configuration: Master, 8-bit, etc. */ + + rspi_bus_initialize(priv); + + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_RX65N_RSPI1 + if (bus == RX65N_RSPI_CHANNEL1) + { + /* Select SPI1 */ + + priv = &g_rspi1dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI1 pins 4WIRE mode: RSPCKB, MOSIB, MISOB and SSLB0 */ + + rspi_reg_protect(REG_PROTECTION_OFF); /* Disable protection */ + rspi_pinconfig(bus); + + /* Switches power to an RSPI channel */ + + rspi_power_on_off(bus, RSPI_POWER_ON); + + /* Configure interrupt controller for RSPI */ + + rspi_interrupt_init(priv, bus); + + /* Set up default configuration: Master, 8-bit, etc. */ + + rspi_bus_initialize(priv); + priv->initialized = true; + } + } + else +#endif +#ifdef CONFIG_RX65N_RSPI2 + if (bus == RX65N_RSPI_CHANNEL2) + { + /* Select SPI2 */ + + priv = &g_rspi2dev; + + /* Only configure if the bus is not already configured */ + + if (!priv->initialized) + { + /* Configure SPI2 pins 4WIRE mode: RSPCKC, MOSIC, MISOC and SSLC0 */ + + rspi_reg_protect(REG_PROTECTION_OFF); /* Disable protection */ + rspi_pinconfig(bus); + + /* Switches power to an RSPI channel */ + + rspi_power_on_off(bus, RSPI_POWER_ON); + + /* Configure interrupt controller for RSPI */ + + rspi_interrupt_init(priv, bus); + + /* Set up default configuration: Master, 8-bit, etc. */ + + rspi_bus_initialize(priv); + + priv->initialized = true; + } + } + else +#endif + { + spierr("ERROR: Unsupported RSPI bus: %d\n", bus); + return NULL; + } + + leave_critical_section(flags); + return (FAR struct spi_dev_s *)priv; +} + +#endif /* CONFIG_RX65N_RSPI0 || CONFIG_RX65N_RSPI1 || CONFIG_RX65N_RSPI2 */ diff --git a/arch/renesas/src/rx65n/rx65n_vector.S b/arch/renesas/src/rx65n/rx65n_vector.S index 6598071022f..4220b2cad6f 100644 --- a/arch/renesas/src/rx65n/rx65n_vector.S +++ b/arch/renesas/src/rx65n/rx65n_vector.S @@ -580,6 +580,21 @@ _uprx65_groupal0_handler: multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 13, RX65N_ERI11_IRQ #endif /* CONFIG_RX65N_SCI11 */ +#ifdef CONFIG_RX65N_RSPI0 + multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 16, RX65N_SPII0_IRQ + multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 17, RX65N_SPEI0_IRQ +#endif /* CONFIG_RX65N_RSPI0 */ + +#ifdef CONFIG_RX65N_RSPI1 + multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 18, RX65N_SPII1_IRQ + multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 19, RX65N_SPEI1_IRQ +#endif /* CONFIG_RX65N_RSPI1 */ + +#ifdef CONFIG_RX65N_RSPI2 + multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 20, RX65N_SPII2_IRQ + multi_switching RX65N_GRPAL0_ADDR, RX65N_GENAL0_ADDR, 21, RX65N_SPEI2_IRQ +#endif /* CONFIG_RX65N_RSPI2 */ + /* TODO: Please write the others with * definition RX65N_XXX_IRQ in irq.h as IRQ number */ diff --git a/boards/renesas/rx65n/rx65n-grrose/README.txt b/boards/renesas/rx65n/rx65n-grrose/README.txt index 01c3a99fc64..e44c1376888 100644 --- a/boards/renesas/rx65n/rx65n-grrose/README.txt +++ b/boards/renesas/rx65n/rx65n-grrose/README.txt @@ -14,6 +14,9 @@ Contents - Contents - RTC - USB Device + - RSPI + - RIIC + - DTC - Debugging - Debugging @@ -215,6 +218,13 @@ Configure UDP blaster application as mentioned below : CONFIG_EXAMPLES_UDPBLASTER_HOSTIP=0x0a4b1801 (10.75.24.1) ------> Gateway IP CONFIG_EXAMPLES_UDPBLASTER_NETMASK=0xfffffe00 (255.255.254.0) --------> Netmask CONFIG_EXAMPLES_UDPBLASTER_TARGETIP=0x0a4b189b (10.75.24.155) ---------> Target IP + +RSPI +----------- + +For GRROSE board only channel 1 can be tested since RSPI channel1 pinout is only brought out as +Pin number 2 and 3 in CN4 is used for MOSIB and MISOB respectively. + RTC ========== @@ -251,6 +261,44 @@ xd 0 0x20000 > /dev/ttyACM0 The output of the commands mentioned above should be seen on the USB Device COM port on teraterm +RSPI Configurations +-------------------------- +The following configurations need to be enabled for RSPI + +CONFIG_SYSTEM_SPITOOL=y + +RSPI Testing +------------------------ +The following testing is executed as part of RSPI testing on RX65N target for GRROSE board + +On GRROSE board only channel 1 can be tested since RSPI channel1 pinout is only brought out. + +Following command can be used for testing RSPI communication to slave device. +spi exch -b 0 -x 4 aabbccdd +where b is bus number and x is Number of word to exchange. + +RIIC Configurations +-------------------------- +The following configurations need to be enabled for RIIC + +CONFIG_SYSTEM_I2CTOOL=y + +RIIC Testing +------------------------ + +On GRROSE board, none of the RIIC channel pins are brought out in the board so not tested for communication. + +DTC Configurations +-------------------------- +The following configurations need to be enabled for DTC. + +CONFIG_SYSTEM_SPITOOL=y + +DTC Testing +------------------------ + +DTC has been tested using RSPI driver. + Debugging ========== diff --git a/boards/renesas/rx65n/rx65n-grrose/include/rx65n_gpio.h b/boards/renesas/rx65n/rx65n-grrose/include/rx65n_gpio.h index a42bc121b0f..cb95028280c 100644 --- a/boards/renesas/rx65n/rx65n-grrose/include/rx65n_gpio.h +++ b/boards/renesas/rx65n/rx65n-grrose/include/rx65n_gpio.h @@ -49,6 +49,12 @@ #define RX65N_MAC_ADDRH 0x00000000 #endif +/* RSPI channel number */ + +#define RX65N_RSPI_CHANNEL0 0 +#define RX65N_RSPI_CHANNEL1 1 +#define RX65N_RSPI_CHANNEL2 2 + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -246,6 +252,23 @@ void sci6_init_port(void); #ifdef CONFIG_RX65N_SCI8 void sci8_init_port(void); #endif + +/**************************************************************************** + * Name: rspi_pinconfig + * + * Description: RSPI pinconfiguration for channel + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Description: + *RSPI pin(SCK,MOSI and MISO) configuration + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI + void rspi_pinconfig(int bus); +#endif + /**************************************************************************** * Name: riic0_init_port * diff --git a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c index 2cb46886adb..ffe982c5f2b 100644 --- a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c +++ b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c @@ -51,6 +51,11 @@ # include "rx65n_dtc.h" #endif +#ifdef HAVE_RSPI_DRIVER +# include +# include "rx65n_rspi.h" +#endif + #ifdef HAVE_RIIC_DRIVER # include # include "rx65n_riic.h" @@ -59,6 +64,80 @@ * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: rx65n_rspi_initialize + * + * Description: + * Initialize and register the RSPI driver. + * + ****************************************************************************/ +#ifdef CONFIG_RX65N_RSPI +static void rx65n_rspi_initialize(void) +{ + int ret; +#ifdef CONFIG_RX65N_RSPI0 + struct spi_dev_s *rspi0; +#endif +#ifdef CONFIG_RX65N_RSPI1 + struct spi_dev_s *rspi1; +#endif +#ifdef CONFIG_RX65N_RSPI2 + struct spi_dev_s *rspi2; +#endif + +#ifdef CONFIG_RX65N_RSPI0 + rspi0 = rx65n_rspibus_initialize(0); + if (!rspi0) + { + spierr("ERROR: [boot] FAILED to initialize SPI port 0\n"); + } + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(rspi0, 0); + if (ret < 0) + { + spierr("ERROR: [boot] FAILED to register driver for channel 0\n"); + } +#endif + +#endif + +#ifdef CONFIG_RX65N_RSPI1 + rspi1 = rx65n_rspibus_initialize(1); + if (!rspi1) + { + spierr("ERROR: [boot] FAILED to initialize SPI port 1\n"); + } + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(rspi1, 1); + if (ret < 0) + { + spierr("ERROR: [boot] FAILED to register driver for channel 1\n"); + } +#endif + +#endif + +#ifdef CONFIG_RX65N_RSPI2 + rspi2 = rx65n_rspibus_initialize(2); + if (!rspi2) + { + spierr("ERROR: [boot] FAILED to initialize SPI port 2\n"); + } + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(rspi2, 2); + if (ret < 0) + { + spierr("ERROR: [boot] FAILED to register driver for channel 2\n"); + } +#endif + +#endif +} +#endif + /**************************************************************************** * Name: rtc_driver_initialize * @@ -150,6 +229,11 @@ int rx65n_bringup(void) (void)rx65n_dtc_initialize(); #endif + +#ifdef CONFIG_RX65N_RSPI + (void)rx65n_rspi_initialize(); +#endif + #if defined(CONFIG_CDCACM) && !defined(CONFIG_CDCACM_CONSOLE) /* Initialize CDCACM */ diff --git a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c index 0b8a15f8c91..6588df83dd1 100644 --- a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c +++ b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c @@ -356,6 +356,106 @@ inline void sci8_init_port(void) } #endif +/**************************************************************************** + * Name: rspi_pinconfig + * + * Description: RSPI pinconfiguration for channel + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Description: + *RSPI pin(SCK,MOSI and MISO) configuration + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI +void rspi_pinconfig(int bus) +{ + /* Set RSPI signal ports to peripheral mode */ + + switch (bus) + { + case RX65N_RSPI_CHANNEL0: +#ifdef CONFIG_RX65N_RSPI0 + + /* Configure RSPCKA */ + + MPC.PC5PFS.BYTE = 0x0d; + PORTC.PMR.BIT.B5 = 1; + + /* Configure MOSIA */ + + MPC.PC6PFS.BYTE = 0x0d; /* This config will block SCI8 function */ + PORTC.PMR.BIT.B6 = 1; + + /* Configure MISOA */ + + MPC.PC7PFS.BYTE = 0x0d; /* This config will block SCI8 function */ + PORTC.PMR.BIT.B7 = 1; + + /* Configure SSLA0 */ + + MPC.PC4PFS.BYTE = 0x0d; + PORTC.PMR.BIT.B4 = 1; +#endif + break; + + case RX65N_RSPI_CHANNEL1: +#ifdef CONFIG_RX65N_RSPI1 + + /* Configure RSPCKB */ + + MPC.PE5PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B5 = 1; + + /* Configure MOSIB */ + + MPC.PE6PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B6 = 1; + + /* Configure MISOB */ + + MPC.PE7PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B7 = 1; + + /* Configure SSLB0 */ + + MPC.PE4PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B4 = 1; +#endif + break; + + case RX65N_RSPI_CHANNEL2: +#ifdef CONFIG_RX65N_RSPI2 + + /* Configure RSPCKC */ + + MPC.PD3PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B3 = 1; + + /* Configure MOSIC */ + + MPC.PD1PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B1 = 1; + + /* Configure MISOC */ + + MPC.PD2PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B2 = 1; + + /* Configure SSLC0 */ + + MPC.PD4PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B4 = 1; +#endif + break; + + default: + break; + } +} +#endif + /**************************************************************************** * Name: riic0_init_port * diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/README.txt b/boards/renesas/rx65n/rx65n-rsk2mb/README.txt index 49422798262..44ea05aee47 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/README.txt +++ b/boards/renesas/rx65n/rx65n-rsk2mb/README.txt @@ -13,6 +13,9 @@ Contents - Networking - RTC - USB Device + - RSPI + - RIIC + - DTC - Debugging Board Features @@ -180,6 +183,16 @@ Configure UDP blaster application as mentioned below : CONFIG_EXAMPLES_UDPBLASTER_HOSTIP=0x0a4b1801 (10.75.24.1) ------> Gateway IP CONFIG_EXAMPLES_UDPBLASTER_NETMASK=0xfffffe00 (255.255.254.0) --------> Netmask CONFIG_EXAMPLES_UDPBLASTER_TARGETIP=0x0a4b189b (10.75.24.155) ---------> Target IP + +RSPI +----------- + +For RX65N RSK2MB board, Following pin is configured for all channels in JA3. +Channel0: Pin number 7 and 8 in JA3 is used for MOSIA and MISOA respectively +Channel1: Pin number 35 and 36 in JA3 is used for MOSIB and MISOB respectively +Channel2: Pin number 18 and 19 in JA3 is used for MOSIC and MISOC respectively +and for enabling these pin need to select DSW-SEL0 by making off SW4-4 + RTC ========== @@ -216,6 +229,49 @@ xd 0 0x20000 > /dev/ttyACM0 The output of the commands mentioned above should be seen on the USB Device COM port on teraterm +RSPI Configurations +-------------------------- +The following configurations need to be enabled for RSPI + +CONFIG_SYSTEM_SPITOOL=y + +RSPI Testing +------------------------ +The following testing is executed as part of RSPI testing on RX65N target for RSK2MB board + +On RSK2MB board, all three channels 0, 1 and 2 has been brought out and tested. + +Following command can be used for testing RSPI communication to slave device. +spi exch -b 0 -x 4 aabbccdd +where b is bus number and x is Number of word to exchange. + +RIIC Configurations +-------------------------- +The following configurations need to be enabled for RIIC. + +CONFIG_SYSTEM_I2CTOOL=y + +RIIC Testing +------------------------ +The following testing is executed as part of RIIC testing on RX65N target for RSK2MB board + +On RSK2MB board only channel 0 can be tested. + +Following command can be used for testing RIIC communication with slave device. +i2c set -b 0 -a 53 -r 0 10 +where b is bus number, a is the slave address, r is the register address and 10 is the value to be written. + +DTC Configurations +-------------------------- +The following configurations need to be enabled for DTC. + +CONFIG_SYSTEM_SPITOOL=y + +DTC Testing +------------------------ + +DTC has been tested using RSPI driver. + Debugging ========== 1. NuttX needs to be compiled in Cygwin environment on Windows. diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/include/rx65n_gpio.h b/boards/renesas/rx65n/rx65n-rsk2mb/include/rx65n_gpio.h index 40a87ece04f..f7b0b9374f4 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/include/rx65n_gpio.h +++ b/boards/renesas/rx65n/rx65n-rsk2mb/include/rx65n_gpio.h @@ -49,6 +49,16 @@ #define RX65N_MAC_ADDRH 0x00000000 #endif +/* RSPI channel number */ + +#define RX65N_RSPI_CHANNEL0 0 +#define RX65N_RSPI_CHANNEL1 1 +#define RX65N_RSPI_CHANNEL2 2 + +/* DSW_SEL0 hardware setting in RSK2MB baord accordingly change this macro */ + +#define DSW_SEL0_ON 0 /* 1 means ON and 0 means OFF*/ + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -192,6 +202,23 @@ void sci8_init_port(void); #ifdef CONFIG_RX65N_SCI12 void sci12_init_port(void); #endif + +/**************************************************************************** + * Name: rspi_pinconfig + * + * Description: RSPI pinconfiguration for channel + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Description: + *RSPI pin(SCK,MOSI and MISO) configuration + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI +void rspi_pinconfig(int bus); +#endif + /**************************************************************************** * Name: riic0_init_port * diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c index 0e76415ecbc..0790b9b9729 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c +++ b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c @@ -50,6 +50,12 @@ #ifdef HAVE_DTC_DRIVER # include "rx65n_dtc.h" #endif + +#ifdef HAVE_RSPI_DRIVER +# include +# include "rx65n_rspi.h" +#endif + #ifdef HAVE_RIIC_DRIVER # include # include "rx65n_riic.h" @@ -58,6 +64,80 @@ * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: rx65n_rspi_initialize + * + * Description: + * Initialize and register the RSPI driver. + * + ****************************************************************************/ +#ifdef CONFIG_RX65N_RSPI +static void rx65n_rspi_initialize(void) +{ + int ret; +#ifdef CONFIG_RX65N_RSPI0 + struct spi_dev_s *rspi0; +#endif +#ifdef CONFIG_RX65N_RSPI1 + struct spi_dev_s *rspi1; +#endif +#ifdef CONFIG_RX65N_RSPI2 + struct spi_dev_s *rspi2; +#endif + +#ifdef CONFIG_RX65N_RSPI0 + rspi0 = rx65n_rspibus_initialize(0); + if (!rspi0) + { + spierr("ERROR: [boot] FAILED to initialize SPI port 0\n"); + } + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(rspi0, 0); + if (ret < 0) + { + spierr("ERROR: [boot] FAILED to register driver for channel 0\n"); + } +#endif + +#endif + +#ifdef CONFIG_RX65N_RSPI1 + rspi1 = rx65n_rspibus_initialize(1); + if (!rspi1) + { + spierr("ERROR: [boot] FAILED to initialize SPI port 1\n"); + } + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(rspi1, 1); + if (ret < 0) + { + spierr("ERROR: [boot] FAILED to register driver for channel 1\n"); + } +#endif + +#endif + +#ifdef CONFIG_RX65N_RSPI2 + rspi2 = rx65n_rspibus_initialize(2); + if (!rspi2) + { + spierr("ERROR: [boot] FAILED to initialize SPI port 2\n"); + } + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(rspi2, 2); + if (ret < 0) + { + spierr("ERROR: [boot] FAILED to register driver for channel 2\n"); + } +#endif + +#endif +} +#endif + /**************************************************************************** * Name: rtc_driver_initialize * @@ -149,6 +229,11 @@ int rx65n_bringup(void) (void)rx65n_dtc_initialize(); #endif + +#ifdef CONFIG_RX65N_RSPI + (void)rx65n_rspi_initialize(); +#endif + #if defined(CONFIG_CDCACM) && !defined(CONFIG_CDCACM_CONSOLE) /* Initialize CDCACM */ diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c index 7f2858302f9..d2481a3d247 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c +++ b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c @@ -321,6 +321,147 @@ inline void sci12_init_port(void) } #endif +/**************************************************************************** + * Name: rspi_pinconfig + * + * Description: RSPI pinconfiguration for channel + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Description: + *RSPI pin(SCK,MOSI and MISO) configuration + ****************************************************************************/ + +#ifdef CONFIG_RX65N_RSPI +void rspi_pinconfig(int bus) +{ + /* Set RSPI signal ports to peripheral mode */ + + switch (bus) + { + case RX65N_RSPI_CHANNEL0: +#ifdef CONFIG_RX65N_RSPI0 + + /* Configure RSPCKA */ + + MPC.PA5PFS.BYTE = 0x0d; + PORTA.PMR.BIT.B5 = 1; + + /* Configure MOSIA */ + + MPC.PA6PFS.BYTE = 0x0d; + PORTA.PMR.BIT.B6 = 1; + + /* Configure MISOA */ + + MPC.PA7PFS.BYTE = 0x0d; + PORTA.PMR.BIT.B7 = 1; + + /* Configure SSLA0 */ + + MPC.PA4PFS.BYTE = 0x0d; + PORTC.PMR.BIT.B4 = 1; +#endif + break; + + case RX65N_RSPI_CHANNEL1: +#ifdef CONFIG_RX65N_RSPI1 + + /* Configure RSPCKB */ + +#if DSW_SEL0_ON + MPC.P27PFS.BYTE = 0x0d; + PORT2.PMR.BIT.B7 = 1; +#else + MPC.PE5PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B5 = 1; +#endif + + /* Configure MOSIB */ + +#if DSW_SEL0_ON + MPC.P26PFS.BYTE = 0x0d; + PORT2.PMR.BIT.B6 = 1; +#else + MPC.PE6PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B6 = 1; +#endif + + /* Configure MISOB */ + +#if DSW_SEL0_ON + MPC.P30PFS.BYTE = 0x0d; + PORT3.PMR.BIT.BT0 = 1; +#else + MPC.PE7PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B7 = 1; +#endif + + /* Configure SSLB0 */ + +#if DSW_SEL0_ON + MPC.P57PFS.BYTE = 0x0d; + PORT5.PMR.BIT.B7 = 1; +#else + MPC.PE4PFS.BYTE = 0x0d; + PORTE.PMR.BIT.B4 = 1; +#endif + +#endif + break; + + case RX65N_RSPI_CHANNEL2: +#ifdef CONFIG_RX65N_RSPI2 + + /* Configure RSPCKC */ + +#if DSW_SEL0_ON + MPC.P56PFS.BYTE = 0x0d; + PORT5.PMR.BIT.B6 = 1; +#else + MPC.PD3PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B3 = 1; +#endif + /* Configure MOSIC */ + +#if DSW_SEL0_ON + MPC.P54PFS.BYTE = 0x0d; + PORT5.PMR.BIT.B4 = 1; +#else + MPC.PD1PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B1 = 1; +#endif + + /* Configure MISOC */ + +#if DSW_SEL0_ON + MPC.P55PFS.BYTE = 0x0d; + PORT5.PMR.BIT.B5 = 1; +#else + MPC.PD2PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B2 = 1; +#endif + + /* Configure SSLC0 */ + +#if DSW_SEL0_ON + MPC.P57PFS.BYTE = 0x0d; + PORT5.PMR.BIT.B7 = 1; +#else + MPC.PD4PFS.BYTE = 0x0d; + PORTD.PMR.BIT.B4 = 1; +#endif + +#endif + break; + + default: + break; + } +} +#endif + /**************************************************************************** * Name: riic0_init_port *