From e494bbd7cde4735e12503038bfb9900b915d49f2 Mon Sep 17 00:00:00 2001 From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> Date: Sun, 26 Apr 2009 18:58:49 +0000 Subject: [PATCH] Extend SPI interface so that we can set number of bits per word git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1742 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 5 +- Documentation/NuttX.html | 4 ++ TODO | 25 ++++++++-- arch/arm/src/imx/imx_spi.c | 88 ++++++++++++++++++++++++++++++++---- arch/z80/src/ez80/ez80_spi.c | 1 + include/nuttx/spi.h | 68 +++++++++++++++++++++++++--- 6 files changed, 172 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4464c8615e..ba377d4940 100644 --- a/ChangeLog +++ b/ChangeLog @@ -703,4 +703,7 @@ number of bits per word is greater an 8 (such as with many 9-bit display interfaces). -- this might have broken a few things which will need to be retested! - + * arch/arm/src/imx: Added i.MX SPI driver + * SPI: Add a method to set the number of bits per word. Also add an + alternative interface for so that (eventually) I can phase the sndblock + and recvblock methods and replace them with a single exchange method diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 15977d93da..b48a764edc 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -1389,6 +1389,10 @@ nuttx-0.4.6 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> number of bits per word is greater an 8 (such as with many 9-bit display interfaces). -- this might have broken a few things which will need to be retested! + * arch/arm/src/imx: Added i.MX SPI driver + * SPI: Add a method to set the number of bits per word. Also add an + alternative interface for so that (eventually) I can phase the sndblock + and recvblock methods and replace them with a single exchange method pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/TODO b/TODO index ac208f540d..1007989d18 100644 --- a/TODO +++ b/TODO @@ -21,9 +21,9 @@ NuttX TODO List (Last updated April 12, 2009) (2) ARM (arch/arm/) (1) ARM/C5471 (arch/arm/src/c5471/) (3) ARM/DM320 (arch/arm/src/dm320/) - (1) ARM/i.MX (arch/arm/src/imx/) - (6) ARM/LPC214x (arch/arm/src/lpc214x/) - (3) ARM/STR71x (arch/arm/src/str71x/) + (2) ARM/i.MX (arch/arm/src/imx/) + (3) ARM/LPC214x (arch/arm/src/lpc214x/) + (4) ARM/STR71x (arch/arm/src/str71x/) (4) pjrc-8052 / MCS51 (arch/pjrc-8051/) (2) Hitachi/Renesas SH-1 (arch/sh/src/sh1) (4) Renesas M16C/26 (arch/sh/src/m16c) @@ -483,6 +483,10 @@ o ARM/i.MX (arch/arm/src/imx/) Status: Open (and in work) Priority: Medium (high if you need i.MX1/L support) + Description: SPI methods are not thread safe. Needs a semaphore to protect from re-entrancy. + Status: Open + Priority: Medium -- Will be very high if you do SPI access from multiple threads. + o ARM/LPC214x (arch/arm/src/lpc214x/) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -509,9 +513,16 @@ o ARM/LPC214x (arch/arm/src/lpc214x/) Priority: High Description: At present the SPI driver is polled. Should it be interrupt driven? + Look at arch/arm/src/imx/imx_spi.c -- that is a good example of an + interrupt driven SPI driver. Should be very easy to part that architecture + to the LPC. Status: Open Priority: Medium + Description: SPI methods are not thread safe. Needs a semaphore to protect from re-entrancy. + Status: Open + Priority: Medium -- Will be very high if you do SPI access from multiple threads. + Description: At present the SPI driver is polled -AND- there is a rather large, arbitrary, delay in one of the block access routines. The purpose of the delay is to avoid a race conditions. This begs for a re-design -OR- at a minimum, some @@ -535,6 +546,10 @@ o ARM/STR71x (arch/arm/src/str71x/) Status: Open Priority: Medium + Description: SPI methods are not thread safe. Needs a semaphore to protect from re-entrancy. + Status: Open + Priority: Medium -- Will be very high if you do SPI access from multiple threads. + o pjrc-8052 / MCS51 (arch/pjrc-8051/) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -704,6 +719,10 @@ o z80/z8/ez80 (arch/z80) Status: Open Priority: Med + Description: SPI methods are not thread safe. Needs a semaphore to protect from re-entrancy. + Status: Open + Priority: Medium -- Will be very high if you do SPI access from multiple threads. + Description: A "generic" I2C driver has been coded for the eZ8Encore! However, this remains untested since I have no I2C devices for the board (yet). diff --git a/arch/arm/src/imx/imx_spi.c b/arch/arm/src/imx/imx_spi.c index 54fd5502e2..437bd009d7 100755 --- a/arch/arm/src/imx/imx_spi.c +++ b/arch/arm/src/imx/imx_spi.c @@ -166,9 +166,15 @@ static int spi_interrupt(int irq, void *context); 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 void spi_setbits(FAR struct spi_dev_s *dev, int nbits); static uint16 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); +#ifdef CONFIG_SPI_EXCHANGE +static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords); +#else +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords); +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords); +#endif /**************************************************************************** * Private Data @@ -181,10 +187,15 @@ static const struct spi_ops_s g_spiops = .select = imx_spiselect, /* Provided externally by board logic */ .setfrequency = spi_setfrequency, .setmode = spi_setmode, + .setbits = spi_setbits, .status = imx_spistatus, /* Provided externally by board logic */ .send = spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = spi_exchange, +#else .sndblock = spi_sndblock, .recvblock = spi_recvblock, +#endif }; /* This supports is up to two SPI busses/ports */ @@ -794,6 +805,34 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) } } +/**************************************************************************** + * Name: spi_setbits + * + * Description: + * Set the number if bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) +{ + struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; + if (priv && nbits != priv->nbits && nbits > 0 && nbits <= 16) + { + uint32 regval = spi_getreg(priv, CSPI_CTRL_OFFSET); + regval &= ~CSPI_CTRL_BITCOUNT_MASK; + regval |= ((nbits - 1) << CSPI_CTRL_BITCOUNT_SHIFT); + spi_putreg(priv, CSPI_CTRL_OFFSET, regval); + priv->nbits = nbits; + } +} + /**************************************************************************** * Name: spi_send * @@ -819,6 +858,35 @@ static uint16 spi_send(FAR struct spi_dev_s *dev, uint16 wd) return response; } +/**************************************************************************** + * Name: SPI_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 recieve 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 ubytes; if nbits >8, the data is packed into uint16's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_EXCHANGE +static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, + FAR void *rxbuffer, size_t nwords) +{ + struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; + (void)spi_transfer(priv, txbuffer, rxbuffer, nwords); +} +#endif + /************************************************************************* * Name: spi_sndblock * @@ -828,7 +896,7 @@ static uint16 spi_send(FAR struct spi_dev_s *dev, uint16 wd) * 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 in number of words. + * 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 ubytes; if nbits >8, the data is packed into uint16's @@ -838,11 +906,13 @@ static uint16 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) +#ifndef CONFIG_SPI_EXCHANGE +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords) { struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; - (void)spi_transfer(priv, buffer, NULL, buflen); + (void)spi_transfer(priv, buffer, NULL, nwords); } +#endif /**************************************************************************** * Name: spi_recvblock @@ -853,7 +923,7 @@ static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size * 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 in number + * 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 ubytes; if nbits >8, the data is packed into uint16's @@ -863,11 +933,13 @@ static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size * ****************************************************************************/ -static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen) +#ifndef CONFIG_SPI_EXCHANGE +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords) { struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; - (void)spi_transfer(priv, NULL, buffer, buflen); + (void)spi_transfer(priv, NULL, buffer, nwords); } +#endif /**************************************************************************** * Public Functions diff --git a/arch/z80/src/ez80/ez80_spi.c b/arch/z80/src/ez80/ez80_spi.c index 20db1035a9..8e34de10e6 100755 --- a/arch/z80/src/ez80/ez80_spi.c +++ b/arch/z80/src/ez80/ez80_spi.c @@ -80,6 +80,7 @@ static const struct spi_ops_s g_spiops = ez80_spiselect, /* Provided externally by board logic */ spi_setfrequency, spi_setmode, + NULL, /* Variable number of bits not implemented */ ez80_spistatus, /* Provided externally by board logic */ spi_send, spi_sndblock, diff --git a/include/nuttx/spi.h b/include/nuttx/spi.h index 7e60a53b3e..200232735f 100644 --- a/include/nuttx/spi.h +++ b/include/nuttx/spi.h @@ -104,6 +104,23 @@ #define SPI_SETMODE(d,m) ((d)->ops->mode ? (d)->ops->mode(d,m) : (void)) +/**************************************************************************** + * Name: SPI_SETBITS + * + * Description: + * Set the number if bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +#define SPI_SETBITS(d,b) ((d)->ops->setbits ? (d)->ops->setbits(d,b) : (void)) + /**************************************************************************** * Name: SPI_STATUS * @@ -156,7 +173,7 @@ * 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 in number of words. + * 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 ubytes; if nbits >8, the data is packed into uint16's @@ -166,18 +183,22 @@ * ****************************************************************************/ -#define SPI_SNDBLOCK(d,b,l) ((d)->ops->sndblock(d,b,l)) +#ifdef CONFIG_SPI_EXCHANGE +# define SPI_SNDBLOCK(d,b,l) ((d)->ops->exchange(d,b,0,l)) +#else +# define SPI_SNDBLOCK(d,b,l) ((d)->ops->sndblock(d,b,l)) +#endif /**************************************************************************** * Name: SPI_RECVBLOCK * * Description: - * Revice a block of data from SPI. Required. + * Receive a block of data from SPI. Required. * * 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 in number + * 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 ubytes; if nbits >8, the data is packed into uint16's @@ -187,7 +208,35 @@ * ****************************************************************************/ -#define SPI_RECVBLOCK(d,b,l) ((d)->ops->recvblock(d,b,l)) +#ifdef CONFIG_SPI_EXCHANGE +# define SPI_RECVBLOCK(d,b,l) ((d)->ops->exchange(d,0,b,l)) +#else +# define SPI_RECVBLOCK(d,b,l) ((d)->ops->recvblock(d,b,l)) +#endif + +/**************************************************************************** + * Name: SPI_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 recieve 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 ubytes; if nbits >8, the data is packed into uint16's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_EXCHANGE +# define SPI_EXCHANGE(d,t,r,l) ((d)->ops->exchange(d,t,r,l)) +#endif /**************************************************************************** * Name: SPI_REGISTERCALLBACK @@ -247,10 +296,15 @@ struct spi_ops_s void (*select)(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected); uint32 (*setfrequency)(FAR struct spi_dev_s *dev, uint32 frequency); void (*setmode)(FAR struct spi_dev_s *dev, enum spi_mode_e mode); + void (*setbits)(FAR struct spi_dev_s *dev, int nbits); ubyte (*status)(FAR struct spi_dev_s *dev, enum spi_dev_e devid); uint16 (*send)(FAR struct spi_dev_s *dev, uint16 wd); - void (*sndblock)(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t buflen); - void (*recvblock)(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen); +#ifdef CONFIG_SPI_EXCHANGE + void (*exchange)(FAR struct spi_dev_s *dev, FAR const void *txbuffer, FAR void *rxbuffer, size_t nwords); +#else + void (*sndblock)(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords); + void (*recvblock)(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords); +#endif int (*registercallback)(FAR struct spi_dev_s *dev, mediachange_t callback, void *arg); }; -- GitLab