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 &lt;spudmonkey@racsa.co.cr&gt;
 	  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 &lt;spudmonkey@racsa.co.cr&gt;
 
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