From 6a7a05294f342e9bb647afe629ac0ede7d8ce4bd Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 26 Apr 2009 16:06:29 +0000 Subject: Extend SPI interface for word sizes >8bits git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1740 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/imx/imx_cspi.h | 2 + nuttx/arch/arm/src/imx/imx_spi.c | 191 ++++++++++++++++++++++++-------------- 2 files changed, 125 insertions(+), 68 deletions(-) (limited to 'nuttx/arch/arm/src/imx') diff --git a/nuttx/arch/arm/src/imx/imx_cspi.h b/nuttx/arch/arm/src/imx/imx_cspi.h index a42ca296a..71f9ad7cc 100755 --- a/nuttx/arch/arm/src/imx/imx_cspi.h +++ b/nuttx/arch/arm/src/imx/imx_cspi.h @@ -131,6 +131,8 @@ #define CSPI_INTCS_ROEN (1 << 14) /* BIT 14: RXFIFO Overflow Interrupt Enable */ #define CSPI_INTCS_BOEN (1 << 15) /* Bit 15: Bit Count Overflow Interrupt Enable */ +#define CSPI_INTCS_ALLINTS 0x0000ff00 + /* CSPI Sample Period Control Register */ #define CSPI_SPCR_WAIT_SHIFT 0 diff --git a/nuttx/arch/arm/src/imx/imx_spi.c b/nuttx/arch/arm/src/imx/imx_spi.c index a408ba9b8..b168290e2 100755 --- a/nuttx/arch/arm/src/imx/imx_spi.c +++ b/nuttx/arch/arm/src/imx/imx_spi.c @@ -87,12 +87,17 @@ struct imx_spidev_s { const struct spi_ops_s *ops; /* Common SPI operations */ +#ifndef CONFIG_SPI_POLLWAIT + sem_t sem; /* Wait for transfer to complete */ +#endif uint32 base; /* SPI register base address */ uint32 frequency; /* Current desired SCLK frequency */ uint32 actual; /* Current actual SCLK frequency */ ubyte mode; /* Current mode */ ubyte nbytes; /* Current number of bits per word */ +#ifndef CONFIG_SPI_POLLWAIT ubyte irq; /* SPI IRQ number */ +#endif }; /**************************************************************************** @@ -103,16 +108,20 @@ struct imx_spidev_s static inline uint32 spi_getreg(struct imx_spidev_s *priv, unsigned int offset); static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, uint32 value); -static ubyte spi_waitspif(struct imx_spidev_s *priv); -static ubyte spi_transfer(struct imx_spidev_s *priv, ubyte ch); +#ifndef CONFIG_SPI_POLLWAIT +static inline struct imx_spidev_s *spi_mapirq(int irq); +static int spi_interrupt(int irq, void *context); +#endif +static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords); /* SPI methods */ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); -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); -static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen); +static ubyte spi_send(FAR struct spi_dev_s *dev, uint16 wd); +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t buflen); +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen); /**************************************************************************** * Private Data @@ -122,13 +131,13 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t static const struct spi_ops_s g_spiops = { - imx_spiselect, /* Provided externally by board logic */ - spi_setfrequency, - spi_setmode, - imx_spistatus, /* Provided externally by board logic */ - spi_sndbyte, - spi_sndblock, - spi_recvblock, + .select = imx_spiselect, /* Provided externally by board logic */ + .frequency = spi_setfrequency, + .setmode = spi_setmode, + .status = imx_spistatus, /* Provided externally by board logic */ + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, }; /* This supports is up to two SPI busses/ports */ @@ -139,14 +148,18 @@ static struct imx_spidev_s g_spidev[] = { .ops = &g_spiops, .base = IMX_CSPI1_VBASE +#ifndef CONFIG_SPI_POLLWAIT .irq = IMX_IRQ_CSPI1, +#endif }, #endif -#ifndef CONFIG_SPI1_DISABLE +#ifndef CONFIG_SPI2_DISABLE { .ops = &g_spiops, .base = IMX_CSPI2_VBASE +#ifndef CONFIG_SPI_POLLWAIT .irq = IMX_IRQ_CSPI2, +#endif }, #endif }; @@ -201,62 +214,93 @@ static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, ui } /**************************************************************************** - * Name: spi_waitspif + * Name: spi_mapirq * * Description: - * Wait space available in the Tx FIFO. + * Map an IRQ number into the appropriate SPI device * * Input Parameters: - * priv - Device-specific state data + * irq - The IRQ number to be mapped * * Returned Value: - * Status register mode bits + * On success, a reference to the private data structgure for this IRQ. + * NULL on failrue. * ****************************************************************************/ -static uint32 spi_waitspif(struct imx_spidev_s *priv) +#ifndef CONFIG_SPI_POLLWAIT +static inline struct imx_spidev_s *spi_mapirq(int irq) { - uint32 status; - - /* Wait for the device to be ready to accept another byte (or for an error - * to be reported). - */ -#error "Missing logic" - return status; + switch (irq) + { +#ifndef CONFIG_SPI1_DISABLE + case IMX_IRQ_CSPI1: + return &g_spidev[SPI1_NDX]; +#endif +#ifndef CONFIG_SPI2_DISABLE + case IMX_IRQ_CSPI2: + return &g_spidev[SPI2_NDX]; +#endif + default: + return NULL; + } } +#endif /**************************************************************************** * Name: spi_transfer * * Description: - * Send one byte on SPI, return the response + * Exchange a block data with the SPI device * * Input Parameters: * priv - Device-specific state data - * ch - the byte to send + * 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 ubytes; + * if the interface uses >8 bits per word, then this is the + * number of uint16's * * Returned Value: - * response + * 0: success, <0:Negated error number on failure * ****************************************************************************/ -static ubyte spi_transfer(struct imx_spidev_s *priv, ubyte ch) +#ifndef CONFIG_SPI_POLLWAIT +static int spi_interrupt(int irq, void *context) { - ubyte status; - - /* Send the byte, repeating if some error occurs */ - - for(;;) - { -#error "Missing logic" - - /* Wait for the device to be ready to accept another byte */ + struct imx_spidev_s *priv = spi_mapirq(irq); + DBGASSERT(priv != NULL); +# error "Missing logic" + return OK; +} +#endif - status = spi_waitspif(oriv); +/**************************************************************************** + * Name: spi_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 ubytes; + * if the interface uses >8 bits per word, then this is the + * number of uint16's + * + * Returned Value: + * 0: success, <0:Negated error number on failure + * + ****************************************************************************/ - /* Return the next byte from the Rx FIFO */ +static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer, + void *rxbuffer, unsigned int nwords) +{ #error "Missing logic" - } } /**************************************************************************** @@ -396,24 +440,28 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) } /**************************************************************************** - * Name: spi_sndbyte + * Name: spi_send * * Description: - * Send one byte on SPI + * Exchange one word on SPI * * Input Parameters: * dev - Device-specific state data - * ch - The byte to send + * 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 ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) +static uint16 spi_send(FAR struct spi_dev_s *dev, uint16 wd) { - struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; - return spi_transfer(priv, ch); + struct imx_spidev_s *priv = (struct imx_spidev_s*)dev; + uint16 response = 0; + + (void)spi_transfer(priv, &wd, &response, 1); + return response; } /************************************************************************* @@ -425,24 +473,20 @@ static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) * Input Parameters: * dev - Device-specific state data * buffer - A pointer to the buffer of data to be sent - * buflen - the length of data to send from the buffer + * buflen - 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 ubytes; if nbits >8, the data is packed into uint16's * * Returned Value: * None * ****************************************************************************/ -static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen) +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t buflen) { struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; - uint32 response; - - /* Loop while thre are bytes remaining to be sent */ - - while (buflen-- > 0) - { - response = spi_transfer(priv, *buffer++); - } + (void)spi_transfer(priv, buffer, NULL, buflen); } /**************************************************************************** @@ -454,23 +498,20 @@ static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, siz * Input Parameters: * dev - Device-specific state data * buffer - A pointer to the buffer in which to recieve data - * buflen - the length of data that can be received in the buffer + * buflen - 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 ubytes; if nbits >8, the data is packed into uint16's * * Returned Value: * None * ****************************************************************************/ -static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen) +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen) { struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; - - /* Loop while thre are bytes remaining to be sent */ - - while (buflen-- > 0) - { - *buffer = (ubyte)spi_transfer(prive, 0xff); - } + (void)spi_transfer(priv, NULL, buffer, buflen); } /**************************************************************************** @@ -584,7 +625,13 @@ FAR struct spi_dev_s *up_spiinitialize(int port) /* Disable SPI */ #error "Missing logic" - /* Initialize control rebistger: min frequency, ignore ready, master mode, mode=0, 8-bit */ + /* Initialize the state structure */ + +ifndef CONFIG_SPI_POLLWAIT + sem_init(&priv->sem, 0, 0); +#endif + + /* Initialize control register: min frequency, ignore ready, master mode, mode=0, 8-bit */ spi_putreg(priv, IMX_CSPI_CTRL_OFFSET, CSPI_CTRL_DIV512 | /* Lowest frequency */ @@ -603,10 +650,14 @@ FAR struct spi_dev_s *up_spiinitialize(int port) /* Enable interrupts on data ready (and certain error conditions */ +ifndef CONFIG_SPI_POLLWAIT spi_putreg(priv, CSPI_INTCS_OFFSET, CSPI_INTCS_RREN | /* RXFIFO Data Ready Interrupt Enable */ CSPI_INTCS_ROEN | /* RXFIFO Overflow Interrupt Enable */ CSPI_INTCS_BOEN); /* Bit Count Overflow Interrupt Enable */ +#else + spi_putreg(priv, CSPI_INTCS_OFFSET, 0); /* No interrupts */ +#endif /* Set the clock source=bit clock and number of clocks inserted between * transactions = 2. @@ -620,7 +671,9 @@ FAR struct spi_dev_s *up_spiinitialize(int port) /* Attach the interrupt */ - irq_attach(priv->irq, (xcpt_t)imx_spinterrupt); +ifndef CONFIG_SPI_POLLWAIT + irq_attach(priv->irq, (xcpt_t)spi_interrupt); +#endif /* Enable SPI */ @@ -630,7 +683,9 @@ FAR struct spi_dev_s *up_spiinitialize(int port) /* Enable SPI interrupts */ +ifndef CONFIG_SPI_POLLWAIT up_enable_irq(priv->irq); +#endif return (FAR struct spi_dev_s *)priv; } -- cgit v1.2.3