diff --git a/configs/olimex-strp711/src/up_spi.c b/configs/olimex-strp711/src/up_spi.c index 6397755315..595d5143f6 100644 --- a/configs/olimex-strp711/src/up_spi.c +++ b/configs/olimex-strp711/src/up_spi.c @@ -35,30 +35,6 @@ * ****************************************************************************/ -#warning "The following is incorrect" -/**************************************************************************** - * One the Olimex lpc214x board, the MMC slot is connect via SPI with the - * following SPI mode pinout: - * - * 1 CS: Chip select (low) - SSEL1 5 SCLK: Clock - SCK1 - * 2 DI: Data input - MOSI1 6 Vss2: Supply Voltage- GRND - * 3 Vss: Supply Voltage - GRND 7 DO: Data Output - MISO1 - * 4 Vdd: Power Supply - Vcc 8 - N/C - * - * The LPC214x supports two buffered SPI ports (SBPI0 and BSPI1). BSPI1 - * is used to interface with the MMC connect - * - * SCK1 - pin 47, P0.17/CAP1.2/SCK1/MAT1.2 - * MISO1 - pin 53, P0.18/CAP1.3/MISO1/MAT1.3 - * MOSI1 - pin 54, P0.19/MAT1.2/MOSI1/CAP1.2 - * SSEL1 - pin 55, P0.20/MAT1.3/SSEL1/EINT3 - * - * BSPI0 is available on the Olimex board (pins 27, 29, 30, and 31). - * Pin 27 is dedicated to a chip select, pins 30 and 31 connect to keys, nd - * pin 29 is unconnected. - * - ****************************************************************************/ - /**************************************************************************** * Included Files ****************************************************************************/ @@ -75,14 +51,199 @@ #include "chip.h" +#if defined(CONFIG_STR71X_BSPI0) || defined(CONFIG_STR71X_BSPI1) + /**************************************************************************** * Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_STR714X_BSPI0_TXFIFO_DEPTH +# define CONFIG_STR714X_BSPI0_TXFIFO_DEPTH 8 +#endif + +#ifndef CONFIG_STR714X_BSPI0_RXFIFO_DEPTH +# define CONFIG_STR714X_BSPI0_RXFIFO_DEPTH 8 +#endif + +#ifndef CONFIG_STR714X_BSPI1_TXFIFO_DEPTH +# define CONFIG_STR714X_BSPI1_TXFIFO_DEPTH 8 +#endif + +#ifndef CONFIG_STR714X_BSPI1_RXFIFO_DEPTH +# define CONFIG_STR714X_BSPI1_RXFIFO_DEPTH 8 +#endif + +/**************************************************************************** + * On the Olimex-STR-STR-P711, BSPI0 is not connected on board, but is + * available on a header for use in the prototyping area. BSPI connects + * to the MMC/SD card slot. + * + * GPIO pin configurations (STR710/STR711,2,5). + * BSP0: + * PIN NORMAL ALTERNATE Olimex-STR-STR-P711 Connection + * 123/52 P0.0 S0.MISO * UEXT-3 (Not connected on board) + * 124/53 P0.1 S0.MOSI * UEXT-4 " " " " "" " " + * 125/54 P0.2 S0.SCLK * UEXT-5 " " " " "" " " + * 126/55 P0.3 ~SO.SS ** UEXT-6 " " " " "" " " + * + * * Programming the AF function selects UART3 by default. BSPI must be + * enabled with the SPI_EN bit in the BOOTCR register + * * Programming the AF function selects I2C1 by default. BSPI must be + * enabled with the SPI_EN bit in the BOOTCR register + * + * BSP1 + * PIN NORMAL ALTERNATE Olimex-STR-STR-P711 Connection + * 127/56 P0.4 S1.MISO SD_CARDBOT DAT0/D0 + * 140/60 P0.5 S1.MOSI SD_CARDBOT CMD/DI + * 141/61 P0.6 S1.SCLK SD_CARDBOT CLK/SCLK + * 142/62 P0.7 ~S1.SS SD_CARDBOT CD/DAT/CS + * + ****************************************************************************/ + +#define BSPI0_GPIO0_MISO (0x0001) +#define BSPI0_GPIO0_MOSI (0x0002) +#define BSPI0_GPIO0_SCLK (0x0004) +#define BSPI0_GPIO0_SS (0x0008) +#define BSPIO_GPIO0_ALL (0x000f) + +#define BSPI1_GPIO0_MISO (0x0010) +#define BSPI1_GPIO0_MOSI (0x0020) +#define BSPI1_GPIO0_SCLK (0x0040) +#define BSPI1_GPIO0_SS (0x0080) +#define BSPI1_GPIO0_ALL (0x00f0) + +/* Configuration register settings ******************************************/ + +#if CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 1 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE1 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 2 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE12 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 3 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE13 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 4 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE14 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 5 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE15 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 6 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE16 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 7 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE17 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 8 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE18 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 9 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE19 +#elif CONFIG_STR714X_BSPI0_RXFIFO_DEPTH == 10 +# define STR71X_BSPI0_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE110 +#else +# error "Invaid RX FIFO depth setting" +#endif + +#define STR71X_BSPI0_CSR1DISABLE STR71X_BSPI0_CSR1RXFIFODEPTH +#define STR71X_BSPI0_CSR1ENABLE (STR71X_BSPICSR1_BSPE|STR71X_BSPICSR1_MSTR|STR71X_BSPI0_CSR1RXFIFODEPTH) + +#if CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 1 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE1 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 2 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE12 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 3 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE13 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 4 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE14 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 5 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE15 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 6 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE16 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 7 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE17 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 8 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE18 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 9 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE19 +#elif CONFIG_STR714X_BSPI0_TXFIFO_DEPTH == 10 +# define STR71X_BSPI0_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE110 +#else +# error "Invaid TX FIFO depth setting" +#endif + +#define STR71X_BSPI0_CSR2VALUE STR71X_BSPI0_CSR1TXFIFODEPTH + +#if CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 1 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE1 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 2 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE12 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 3 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE13 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 4 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE14 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 5 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE15 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 6 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE16 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 7 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE17 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 8 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE18 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 9 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE19 +#elif CONFIG_STR714X_BSPI1_RXFIFO_DEPTH == 10 +# define STR71X_BSPI1_CSR1RXFIFODEPTH STR71X_BSPICSR1_RFE110 +#else +# error "Invaid RX FIFO depth setting" +#endif + +#define STR71X_BSPI1_CSR1DISABLE STR71X_BSPI1_CSR1RXFIFODEPTH +#define STR71X_BSPI1_CSR1ENABLE (STR71X_BSPICSR1_BSPE|STR71X_BSPICSR1_MSTR|STR71X_BSPI1_CSR1RXFIFODEPTH) + +#if CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 1 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE1 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 2 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE12 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 3 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE13 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 4 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE14 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 5 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE15 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 6 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE16 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 7 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE17 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 8 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE18 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 9 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE19 +#elif CONFIG_STR714X_BSPI1_TXFIFO_DEPTH == 10 +# define STR71X_BSPI1_CSR1TXFIFODEPTH STR71X_BSPICSR2_TFE110 +#else +# error "Invaid TX FIFO depth setting" +#endif + +#define STR71X_BSPI1_CSR2VALUE STR71X_BSPI1_CSR1TXFIFODEPTH + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct str71x_spidev_s +{ + struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ + uint32 spibase; /* BSPIn base address */ + uint16 csbit; /* BSPIn SS bit int GPIO0 */ +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ +/* Helpers */ + +static inline uint16 spi_getreg(FAR struct str71x_spidev_s *priv, ubyte offset); +static inline void spi_putreg(FAR struct str71x_spidev_s *priv, ubyte offset, uint16 value); + +/* SPI methods */ + static void spi_select(FAR struct spi_dev_s *dev, boolean selected); static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); static ubyte spi_status(FAR struct spi_dev_s *dev); @@ -104,7 +265,23 @@ static const struct spi_ops_s g_spiops = .recvblock = spi_recvblock, }; -static struct spi_dev_s g_spidev = { &g_spiops }; +#ifdef CONFIG_STR71X_BSPI0 +static struct spi_dev_s g_spidev0 = +{ + .spidev = { &g_spiops }, + .spibase = STR71X_BSPI0_BASE, + .csbit = BSPI0_GPIO0_SS +}; +#endif + +#ifdef CONFIG_STR71X_BSPI1 +static struct spi_dev_s g_spidev1 = +{ + .spidev = { &g_spiops }, + .spibase = STR71X_BSPI1_BASE, + .csbit = BSPI1_GPIO0_SS +}; +#endif /**************************************************************************** * Public Data @@ -114,14 +291,55 @@ static struct spi_dev_s g_spidev = { &g_spiops }; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: spi_getreg + * + * Description: + * Get the contents of the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * + * Returned Value: + * The contents of the 16-bit register + * + ****************************************************************************/ + +static inline uint16 spi_getreg(FAR struct str71x_spidev_s *priv, ubyte offset) +{ + return getreg16(priv->spibase + offset); +} + +/**************************************************************************** + * Name: spi_putreg + * + * Description: + * Write a 16-bit value to the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * value - the 16-bit value to be written + * + * Returned Value: + * The contents of the 16-bit register + * + ****************************************************************************/ + +static inline void spi_putreg(FAR struct str71x_spidev_s *priv, ubyte offset, uint16 value) +{ + putreg16(priv, value, priv->spibase + offset); +} + /**************************************************************************** * Name: spi_select * * Description: - * Enable/disable the SPI chip select + * Enable/disable the SPI slave select * * Input Parameters: - * selected: TRUE: chip selected, FALSE: chip de-selected + * selected: TRUE: slave selected, FALSE: slave de-selected * * Returned Value: * None @@ -130,7 +348,55 @@ static struct spi_dev_s g_spidev = { &g_spiops }; static void spi_select(FAR struct spi_dev_s *dev, boolean selected) { -#warning "To be provided" + FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; + uint16 reg16; + + DEBUGASSERT(priv && priv->spibase); + + reg16 = spi_getreg(dev, STR71X_GPIO_PD_OFFSET); + if (selected) + { + /* Enable slave select (low enables) */ + + reg16 &= ~dev->cr; + spi_putreg(dev, STR71X_GPIO_PD_OFFSET, reg16); + } + else + { + /* Disable slave select (low enables) */ + + reg16 |= dev->cr; + spi_putreg(dev, STR71X_GPIO_PD_OFFSET, reg16); + +#if CONFIG_STR714X_BSPI0_TXFIFO_DEPTH > 1) + /* Wait while the TX FIFO is full */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_TFF) != 0); +#else + /* Wait until the TX FIFO is empty */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_TFE) == 0); +#endif + /* Write 0xff to the TX FIFO */ + + spi_putreg(ch, STR71X_BSPI_TXR_OFFSET, 0xff00); + + /* Wait for the TX FIFO empty */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_TFNE) != 0); + + /* Wait for the RX FIFO not empty */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_RFNE) == 0); + + /* Then read and discard bytes until the RX FIFO is empty */ + + do + { + (void)(spi_getreg(priv, STR71X_BSPI_RXR_OFFSET); + } + while (spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET & STR71X_BSPICSR2_RFNE); + } } /**************************************************************************** @@ -149,7 +415,50 @@ static void spi_select(FAR struct spi_dev_s *dev, boolean selected) static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) { -#warning "To be provided" + FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; + uint32 divisor; + uint32 cr1; + + DEBUGASSERT(priv && priv->spibase); + + /* The BSPI clock is determined by divider the APB1 clock (PCLK1). + * + * Eg. PCLK1 = 32MHz, frequency = 20000000: + * correct divisor is 2.1, calculated value is 2. + */ + + divisor = (STR41X_PCLK1 + (frequency >> 1)) / frequency; + + /* The divisor must be an even number and contrained to the range of + * 5 (master mode, or 7 for slave mode) and 255. These bits must + * be configured BEFORE the BSPE or MSTR bits.. i.e., before the SPI + * is put into master mode. + */ + + divisor <<= 1; /* The full, even divisor */ + if (divisor < 6) + { + divisor = 6; + } + else if (divisor > 254) + { + divisor = 254; + } + + /* The BSPI must be disable when the following setting is made. */ + + cr1 = spi_getreg(priv, STR71X_BSPI_CSR1_OFFSET); + cr1 &= ~(STR71X_BSPICSR1_BSPE|STR71X_BSPICSR1_MSTR); + spi_putreg(priv, STR71X_BSPI_CSR1_OFFSET, cr1); + + spi_putreg(priv, STR71X_BSPI_CLK_OFFSET. (uint16)divisor); + + /* Now we can enable the BSP in master mode */ + + cr |= (STR71X_BSPICSR1_BSPE|STR71X_BSPICSR1_MSTR); + spi_putreg(priv, STR71X_BSPI_CSR1_OFFSET, cr1); + + return STR41X_PCLK1 / divisor; } /**************************************************************************** @@ -168,7 +477,15 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) static ubyte spi_status(FAR struct spi_dev_s *dev) { -#warning "To be provided" + FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; + + DEBUGASSERT(priv && priv->spibase); + + /* I don't think there is anyway to determine these things on the Olimex + * board. + */ + + return SPI_STATUS_PRESENT; } /**************************************************************************** @@ -187,7 +504,31 @@ static ubyte spi_status(FAR struct spi_dev_s *dev) static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) { -#warning "To be provided" + FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; + + DEBUGASSERT(priv && priv->spibase); + +#if CONFIG_STR714X_BSPI0_TXFIFO_DEPTH > 1) + /* Wait while the TX FIFO is full */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_TFF) != 0); +#else + /* Wait until the TX FIFO is empty */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_TFE) == 0); +#endif + + /* Write the byte to the TX FIFO */ + + spi_putreg(ch, STR71X_BSPI_TXR_OFFSET, (uint16)ch << 8); + + /* Wait for the RX FIFO not empty */ + + while ((spi_getreg(priv, STR71X_BSPI_CSR2_OFFSET) & STR71X_BSPICSR2_RFNE) == 0); + + /* Get the received value from the RX FIFO and return it */ + + return (ubyte)(spi_getreg(priv, STR71X_BSPI_RXR_OFFSET) >> 8); } /************************************************************************* @@ -207,7 +548,58 @@ static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen) { + FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; + uint16 csr2; + + DEBUGASSERT(priv && priv->spibase); + spibase = priv->spibase; + #warning "To be provided" +=== + + /* Loop while thre are bytes remaining to be sent */ + + while (buflen > 0) + { + /* While the TX FIFO is not full and there are bytes left to send */ + + while ((spi_getreg(priv, STR71X_BSPI1_CSR2) & STR71X_BSPICSR2_TFF) == 0 && buflen > 0) + { + /* Send the data */ + + spi_putreg(priv, STR71X_BSPI_TXR_OFFSET, ((uint16)*buffer) << 8); + buffer++; + buflen--; + } + } + + /* Then discard all card responses until the RX & TX FIFOs are emptied. */ + + do + { + /* Is there anything in the RX fifo? */ + + csr2 = spi_getreg(priv, STR71X_BSPI1_CSR2); + if ((csr2 & STR71X_BSPICSR2_RFNE) != 0) + { + /* Yes.. Read and discard */ + + (void)spi_getreg(priv, STR71X_BSPI_RXR_OFFSET); + } + + /* There is a race condition where TFNE may go FALSE just before + * RFNE goes TRUE and this loop terminates prematurely. The nasty little + * delay in the following solves that (it could probably be tuned to + * improve performance). + */ + + else if ((csr2 & STR71X_BSPICSR2_TFNE) != 0) + { + up_udelay(100); + csr2 = spi_getreg(priv, STR71X_BSPI1_CSR2); + } + } + while ((csr2 & STR71X_BSPICSR2_RFNE) != 0 || (csr2 & STR71X_BSPICSR2_TFNE) == 0); } /**************************************************************************** @@ -227,7 +619,37 @@ static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, siz static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen) { -#warning "To be provided" + FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; + uint32 fifobytes = 0; + + DEBUGASSERT(priv && priv->spibase); + + /* While there is remaining to be sent (and no synchronization error has occurred) */ + + while (buflen || fifobytes) + { + /* Fill the transmit FIFO with 0xff... + * Write 0xff to the data register while (1) the TX FIFO is + * not full, (2) we have not exceeded the depth of the TX FIFO, + * and (3) there are more bytes to be sent. + */ + + while ((spi_getreg(priv, STR71X_BSPI1_CSR2) & STR71X_BSPICSR2_TFF) == 0 && + (fifobytes < CONFIG_STR714X_BSPI0_TXFIFO_DEPTH) && buflen > 0) + { + spi_putreg(priv, STR71X_BSPI_TXR_OFFSET, 0xff00); + buflen--; + fifobytes++; + } + + /* Now, read the RX data from the RX FIFO while the RX FIFO is not empty */ + + while ((spi_getreg(priv, STR71X_BSPI1_CSR2) & STR71X_BSPICSR2_RFNE) != 0) + { + *buffer++ = (ubyte)(spi_regreg(priv, STR71X_BSPI_RXR_OFFSET) >> 8); + fifobytes--; + } + } } /**************************************************************************** @@ -250,5 +672,105 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t b FAR struct spi_dev_s *up_spiinitialize(int port) { -#warning "To be provided" + FAR struct spi_dev_s *ret; + uint16 reg16; + +#ifdef CONFIG_STR71X_BSPI0 + if (port == 0) + { + /* The default, alternate functionality of the GPIO0 pin selections is + * UART3/I2C1. In order to have BSP0 functionality, we also have to + * set the BSPI0 enable bit in the PCU BOOTCR register. + */ + + reg16 = getreg16(STR71X_PCU_BOOTCR); + reg16 |= STR71X_PCUBOOTCR_BSPIOEN; + + /* Configure all GPIO pins to their alternate function EXCEPT + * for the SS pin .. will will configure that as an output + * and control the chip select as a normal GPIO. + */ + + reg16 = getreg16(STR71X_GPIO0_PC0); + reg16 |= BSPIO_GPIO0_ALL; + putreg16(reg16, STR71X_GPIO0_PC0); + + reg16 = getreg16(STR71X_GPIO0_PC1); + reg16 |= BSPIO_GPIO0_ALL; + reg17 &= ~BSPI0_GPIO0_SS; + putreg16(reg16, STR71X_GPIO0_PC1); + + reg16 = getreg16(STR71X_GPIO0_PC2); + reg16 |= BSPIO_GPIO0_ALL; + spi_putreg(priv, reg16, STR71X_GPIO0_PC2); + + /* Start with chip slave disabled */ + + reg16 = getreg16(STR71X_GPIO0_PD); + reg16 |= BSPI0_GPIO0_SS; + putreg16(reg16, STR71X_GPIO0_PD); + + /* Set the clock divider to the maximum */ + + putreg16(255, STR71X_BSPI1_CLK); + + /* Set FIFO sizes and disable the BSP1. It won't be enabled + * until the frequency is set. + */ + + putreg16(STR71X_BSPI0_CSR1DISABLE, STR71X_BSPI0_CSR1); + putreg16(STR71X_BSPI0_CSR2VALUE, STR71X_BSPI0_CSR2); + + ret = &g_spidev0.spidev; + } + else +#endif +#ifdef CONFIG_STR71X_BSPI1=y + if (port == 1) + { + /* Configure all GPIO pins to their alternate function EXCEPT + * for the SS pin .. will will configure that as an output + * and control the chip select as a normal GPIO. + */ + + reg16 = getreg16(STR71X_GPIO0_PC0); + reg16 |= BSPI1_GPIO0_ALL; + putreg16(reg16, STR71X_GPIO0_PC0); + + reg16 = getreg16(spi_putregSTR71X_GPIO0_PC1); + reg16 |= BSPI1_GPIO0_ALL; + reg17 &= ~BSPI1_GPIO0_SS; + putreg16(reg16, STR71X_GPIO0_PC1); + + reg16 = getreg16(STR71X_GPIO0_PC2); + reg16 |= BSPI1_GPIO0_ALL; + putreg16(reg16, STR71X_GPIO0_PC2); + + /* Start with chip slave disabled */ + + reg16 = getreg16(STR71X_GPIO0_PD); + reg17 |= BSPI1_GPIO1_SS; + putreg16(priv, reg16, STR71X_GPIO0_PD); + + /* Set the clock divider to the maximum */ + + putreg16(255, STR71X_BSPI1_CLK); + + /* Set FIFO sizes and disable the BSP1. It won't be enabled + * until the frequency is set. + */ + + putreg16(STR71X_BSPI1_CSR1DISABLE, STR71X_BSPI1_CSR1); + putreg16(STR71X_BSPI1_CSR2VALUE, STR71X_BSPI1_CSR2); + + ret = &g_spidev1.spidev; + } + else +#endif + { + ret = NULL; + } + return ret; } + +#endif /* CONFIG_STR71X_BSPI0 || CONFIG_STR71X_BSPI1 */