summaryrefslogtreecommitdiffstats
path: root/nuttx/arch/arm/src/lm3s
diff options
context:
space:
mode:
authorpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2009-05-23 14:26:22 +0000
committerpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2009-05-23 14:26:22 +0000
commite18553405951901dc7f3d21f10fa3938df08523b (patch)
tree316c1d9d389dcf684a9a02d4cc9c8ff701b30581 /nuttx/arch/arm/src/lm3s
parentfa637c271409b54b13e3548089c16e6e00b8e327 (diff)
Add LM3S SSI driver
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@1818 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/arch/arm/src/lm3s')
-rw-r--r--nuttx/arch/arm/src/lm3s/Make.defs2
-rw-r--r--nuttx/arch/arm/src/lm3s/chip.h8
-rw-r--r--nuttx/arch/arm/src/lm3s/lm3s_ethernet.c30
-rw-r--r--nuttx/arch/arm/src/lm3s/lm3s_internal.h26
-rwxr-xr-xnuttx/arch/arm/src/lm3s/lm3s_ssi.c1266
-rw-r--r--nuttx/arch/arm/src/lm3s/lm3s_ssi.h44
6 files changed, 1333 insertions, 43 deletions
diff --git a/nuttx/arch/arm/src/lm3s/Make.defs b/nuttx/arch/arm/src/lm3s/Make.defs
index 42bb065d2c..6a9416aa63 100644
--- a/nuttx/arch/arm/src/lm3s/Make.defs
+++ b/nuttx/arch/arm/src/lm3s/Make.defs
@@ -47,7 +47,7 @@ CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
CHIP_ASRCS =
CHIP_CSRCS = lm3s_start.c lm3s_syscontrol.c lm3s_irq.c \
lm3s_gpio.c lm3s_gpioirq.c lm3s_timerisr.c lm3s_lowputc.c \
- lm3s_serial.c
+ lm3s_serial.c lm3s_ssi.c
ifdef CONFIG_NET
CHIP_CSRCS += lm3s_ethernet.c
diff --git a/nuttx/arch/arm/src/lm3s/chip.h b/nuttx/arch/arm/src/lm3s/chip.h
index 04639cbeed..0abfc2f987 100644
--- a/nuttx/arch/arm/src/lm3s/chip.h
+++ b/nuttx/arch/arm/src/lm3s/chip.h
@@ -50,9 +50,9 @@
/* Get customizations for each supported chip (only the LM3S6918 right now) */
#ifdef CONFIG_ARCH_CHIP_LM3S6918
-# define LMS_NUARTS 2 /* Two UART modules */
-# define LMS_NSSI 2 /* Two SSI modules */
-# define LMS_NETHCONTROLLERS 1 /* One ethenet controller */
+# define LM3S_NUARTS 2 /* Two UART modules */
+# define LM3S_NSSI 2 /* Two SSI modules */
+# define LM3S_NETHCONTROLLERS 1 /* One ethenet controller */
#else
# error "No Ethernet support for this LM3S chip"
#endif
@@ -63,7 +63,7 @@
#include "lm3s_syscontrol.h" /* System control module */
#include "lm3s_gpio.h" /* GPIO modules */
#include "lm3s_uart.h" /* UART modules */
-#include "lm2s_ssi.h" /* SSI modules */
+#include "lm3s_ssi.h" /* SSI modules */
#include "lm3s_ethernet.h" /* Ethernet MAC and PHY */
#include "lm3s_flash.h" /* FLASH */
diff --git a/nuttx/arch/arm/src/lm3s/lm3s_ethernet.c b/nuttx/arch/arm/src/lm3s/lm3s_ethernet.c
index 963705e6ee..aa3189c192 100644
--- a/nuttx/arch/arm/src/lm3s/lm3s_ethernet.c
+++ b/nuttx/arch/arm/src/lm3s/lm3s_ethernet.c
@@ -179,7 +179,7 @@ struct lm3s_driver_s
* multiple Ethernet controllers.
*/
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
uint32 ld_base; /* Ethernet controller base address */
int ld-irq; /* Ethernet controller IRQ */
#endif
@@ -201,7 +201,7 @@ struct lm3s_driver_s
* Private Data
****************************************************************************/
-static struct lm3s_driver_s g_lm3sdev[LMS_NETHCONTROLLERS];
+static struct lm3s_driver_s g_lm3sdev[LM3S_NETHCONTROLLERS];
/****************************************************************************
* Private Function Prototypes
@@ -209,7 +209,7 @@ static struct lm3s_driver_s g_lm3sdev[LMS_NETHCONTROLLERS];
/* Miscellaneous low level helpers */
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
static uint32 lm3s_ethin(struct lm3s_driver_s *priv, int offset);
static void lm3s_ethout(struct lm3s_driver_s *priv, int offset, uint32 value);
#else
@@ -263,7 +263,7 @@ static int lm3s_txavail(struct uip_driver_s *dev);
*
****************************************************************************/
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
static uint32 lm3s_ethin(struct lm3s_driver_s *priv, int offset)
{
return getreg32(priv->ld_base + offset);
@@ -291,7 +291,7 @@ static inline uint32 lm3s_ethin(struct lm3s_driver_s *priv, int offset)
*
****************************************************************************/
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
static void lm3s_ethout(struct lm3s_driver_s *priv, int offset, uint32 value)
{
putreg32(value, priv->ld_base + offset);
@@ -325,7 +325,7 @@ static void lm3s_ethreset(struct lm3s_driver_s *priv)
uint32 regval;
volatile uint32 delay;
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
# error "If multiple interfaces are supported, this function would have to be redesigned"
#endif
@@ -830,7 +830,7 @@ static int lm3s_interrupt(int irq, FAR void *context)
register struct lm3s_driver_s *priv;
uint32 ris;
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
# error "A mechanism to associate and interface with an IRQ is needed"
#else
priv = &g_lm3sdev[0];
@@ -1096,7 +1096,7 @@ static int lm3s_ifup(struct uip_driver_s *dev)
/* Enable the Ethernet interrupt */
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
up_enable_irq(priv->irq);
#else
up_enable_irq(LM3S_IRQ_ETHCON);
@@ -1164,7 +1164,7 @@ static int lm3s_ifdown(struct uip_driver_s *dev)
/* Disable the Ethernet interrupt */
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
up_disable_irq(priv->irq);
#else
up_disable_irq(LM3S_IRQ_ETHCON);
@@ -1278,7 +1278,7 @@ static int lm3s_txavail(struct uip_driver_s *dev)
*
****************************************************************************/
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
int lm3s_initialize(int intf)
#else
static inline int lm3s_initialize(int intf)
@@ -1291,12 +1291,12 @@ static inline int lm3s_initialize(int intf)
ndbg("Setting up eth%d\n", intf);
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
# error "This debug check only works with one interface"
#else
DEBUGASSERT((getreg32(LM3S_SYSCON_DC4) & (SYSCON_DC4_EMAC0|SYSCON_DC4_EPHY0)) == (SYSCON_DC4_EMAC0|SYSCON_DC4_EPHY0));
#endif
- DEBUGASSERT((unsigned)intf < LMS_NETHCONTROLLERS);
+ DEBUGASSERT((unsigned)intf < LM3S_NETHCONTROLLERS);
/* Initialize the driver structure */
@@ -1308,7 +1308,7 @@ static inline int lm3s_initialize(int intf)
/* Create a watchdog for timing polling for and timing of transmisstions */
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
# error "A mechanism to associate base address an IRQ with an interface is needed"
priv->ld_base = ??; /* Ethernet controller base address */
priv->ld_irq = ??; /* Ethernet controller IRQ number */
@@ -1335,7 +1335,7 @@ static inline int lm3s_initialize(int intf)
/* Attach the IRQ to the driver */
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
ret = irq_attach(priv->irq, lm3s_interrupt);
#else
ret = irq_attach(LM3S_IRQ_ETHCON, lm3s_interrupt);
@@ -1364,7 +1364,7 @@ static inline int lm3s_initialize(int intf)
*
************************************************************************************/
-#if LMS_NETHCONTROLLERS == 1
+#if LM3S_NETHCONTROLLERS == 1
void up_netinitialize(void)
{
(void)lm3s_initialize(0);
diff --git a/nuttx/arch/arm/src/lm3s/lm3s_internal.h b/nuttx/arch/arm/src/lm3s/lm3s_internal.h
index 6640241e6d..3a52344a25 100644
--- a/nuttx/arch/arm/src/lm3s/lm3s_internal.h
+++ b/nuttx/arch/arm/src/lm3s/lm3s_internal.h
@@ -308,10 +308,34 @@ EXTERN int weak_function gpio_irqinitialize(void);
*
****************************************************************************/
-#if LMS_NETHCONTROLLERS > 1
+#if LM3S_NETHCONTROLLERS > 1
EXTERN int lm3s_initialize(int intf);
#endif
+/****************************************************************************
+ * The external functions, lm3s_spiselect and lm3s_spistatus must be provided
+ * by board-specific logic. The are implementations of the select and status
+ * methods SPI interface defined by struct spi_ops_s (see include/nuttx/spi.h).
+ * All othermethods (including up_spiinitialize()) are provided by common
+ * logic. To use this common SPI logic on your board:
+ *
+ * 1. Provide lm3s_spiselect() and lm3s_spistatus() functions in your
+ * board-specific logic. This function will perform chip selection and
+ * status operations using GPIOs in the way your board is configured.
+ * 2. Add a call to up_spiinitialize() in your low level initialization
+ * logic
+ * 3. The handle returned by up_spiinitialize() 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).
+ *
+ ****************************************************************************/
+
+struct spi_dev_s;
+enum spi_dev_e;
+EXTERN void lm3s_spiselect(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected);
+EXTERN ubyte lm3s_spistatus(FAR struct spi_dev_s *dev, enum spi_dev_e devid);
+
#undef EXTERN
#if defined(__cplusplus)
}
diff --git a/nuttx/arch/arm/src/lm3s/lm3s_ssi.c b/nuttx/arch/arm/src/lm3s/lm3s_ssi.c
new file mode 100755
index 0000000000..a880d2b239
--- /dev/null
+++ b/nuttx/arch/arm/src/lm3s/lm3s_ssi.c
@@ -0,0 +1,1266 @@
+/****************************************************************************
+ * arch/arm/src/lm32/lm32_spi.c
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include <semaphore.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+
+#include <arch/irq.h>
+#include <arch/board/board.h>
+
+#include "up_internal.h"
+#include "up_arch.h"
+
+#include "chip.h"
+#include "lm3s_internal.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* How many SSI modules does this chip support? The LM3S6918 supports 2 SSI
+ * modules (others may support more -- in such case, the following must be
+ * expanded).
+ */
+
+#if LM3S_NSSI == 0
+# undef CONFIG_SSI0_DISABLE
+# define CONFIG_SSI0_DISABLE 1
+# undef CONFIG_SSI1_DISABLE
+# define CONFIG_SSI1_DISABLE 1
+#elif LM3S_NSSI == 1
+# undef CONFIG_SSI1_DISABLE
+# define CONFIG_SSI1_DISABLE 1
+#endif
+
+/* Which SSI modules have been enabled? */
+
+#ifndef CONFIG_SSI0_DISABLE
+# define SSI0_NDX 0 /* Index to SSI0 in g_ssidev[] */
+# ifndef CONFIG_SSI1_DISABLE
+# define SSI1_NDX 1 /* Index to SSI1 in g_ssidev[] */
+# define NSSI_ENABLED 2 /* Two SSI interfaces: SSI0 & SSI1 */
+# else
+# define NSSI_ENABLED 1 /* One SSI interface: SSI0 */
+# define SSI_BASE LM3S_SSI0_BASE
+# define SSI_IRQ LM3S_IRQ_SSI0
+# endif
+#else
+# ifndef CONFIG_SSI1_DISABLE
+# define SSI1_NDX 0 /* Index to SSI1 in g_ssidev[] */
+# define NSSI_ENABLED 1 /* One SSI interface: SSI1 */
+# define SSI_BASE LM3S_SSI1_BASE
+# define SSI_IRQ LM3S_IRQ_SSI1
+# else
+# define NSSI_ENABLED 0 /* No SSI interfaces */
+# endif
+#endif
+
+/* Compile the rest of the file only if at least one SSI interface has been
+ * enabled.
+ */
+
+#if NSSI_ENABLED > 0
+
+/* The number of (16-bit) words that will fit in the Tx FIFO */
+
+#define LM3S_TXFIFO_WORDS 8
+
+/****************************************************************************
+ * Private Type Definitions
+ ****************************************************************************/
+
+struct lm32_ssidev_s
+{
+ const struct spi_ops_s *ops; /* Common SPI operations */
+#ifndef CONFIG_SSI_POLLWAIT
+ sem_t xfrsem; /* Wait for transfer to complete */
+#endif
+ sem_t exclsem; /* For exclusive access to the SSI bus */
+
+ /* 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 ubyte is
+ * nbits <=8 and uint16 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. Differnt 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 lm32_ssidev_s *priv);
+ void (*rxword)(struct lm32_ssidev_s *priv);
+
+#if NSSI_ENABLED > 1
+ uint32 base; /* SSI register base address */
+#endif
+ uint32 frequency; /* Current desired SCLK frequency */
+ uint32 actual; /* Current actual SCLK frequency */
+
+ int ntxwords; /* Number of words left to transfer on the Tx FIFO */
+ int nrxwords; /* Number of words received on the Rx FIFO */
+ int nwords; /* Number of words to be exchanged */
+
+ ubyte mode; /* Current mode */
+ ubyte nbits; /* Current number of bits per word */
+#if !defined(CONFIG_SSI_POLLWAIT) && NSSI_ENABLED > 1
+ ubyte irq; /* SSI IRQ number */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SSI register access */
+
+static inline uint32 ssi_getreg(struct lm32_ssidev_s *priv, unsigned int offset);
+static inline void ssi_putreg(struct lm32_ssidev_s *priv, unsigned int offset, uint32 value);
+
+/* Misc helpers */
+
+static uint32 ssi_disable(struct lm32_ssidev_s *priv);
+static void ssi_enable(struct lm32_ssidev_s *priv, uint32 enable);
+static void ssi_semtake(sem_t *sem);
+#define ssi_semgive(s) sem_post(s);
+
+/* SSI data transfer */
+
+static void ssi_txnull(struct lm32_ssidev_s *priv);
+static void ssi_txuint16(struct lm32_ssidev_s *priv);
+static void ssi_txubyte(struct lm32_ssidev_s *priv);
+static void ssi_rxnull(struct lm32_ssidev_s *priv);
+static void ssi_rxuint16(struct lm32_ssidev_s *priv);
+static void ssi_rxubyte(struct lm32_ssidev_s *priv);
+static inline boolean ssi_txfifofull(struct lm32_ssidev_s *priv);
+static inline boolean ssi_rxfifonotempty(struct lm32_ssidev_s *priv);
+static int ssi_performtx(struct lm32_ssidev_s *priv);
+static inline void ssi_performrx(struct lm32_ssidev_s *priv);
+static int ssi_transfer(struct lm32_ssidev_s *priv, const void *txbuffer,
+ void *rxbuffer, unsigned int nwords);
+
+/* Interrupt handling */
+
+#ifndef CONFIG_SSI_POLLWAIT
+static inline struct lm32_ssidev_s *ssi_mapirq(int irq);
+static int ssi_interrupt(int irq, void *context);
+#endif
+
+/* SPI methods */
+
+static void ssi_setfrequencyinternal(struct lm32_ssidev_s *priv, uint32 frequency);
+static uint32 ssi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);
+static void ssi_setmodeinternal(struct lm32_ssidev_s *priv, enum spi_mode_e mode);
+static void ssi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
+static void ssi_setbitsinternal(struct lm32_ssidev_s *priv, int nbits);
+static void ssi_setbits(FAR struct spi_dev_s *dev, int nbits);
+static uint16 ssi_send(FAR struct spi_dev_s *dev, uint16 wd);
+#ifdef CONFIG_SPI_EXCHANGE
+static void ssi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
+ FAR void *rxbuffer, size_t nwords);
+#else
+static void ssi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords);
+static void ssi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Common SSI operations */
+
+static const struct spi_ops_s g_spiops =
+{
+ .select = lm3s_spiselect, /* Provided externally by board logic */
+ .setfrequency = ssi_setfrequency,
+ .setmode = ssi_setmode,
+ .setbits = ssi_setbits,
+ .status = lm3s_spistatus, /* Provided externally by board logic */
+ .send = ssi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = ssi_exchange,
+#else
+ .sndblock = ssi_sndblock,
+ .recvblock = ssi_recvblock,
+#endif
+};
+
+/* This supports is up to two SSI busses/ports */
+
+static struct lm32_ssidev_s g_ssidev[] =
+{
+#ifndef CONFIG_SSI0_DISABLE
+ {
+ .ops = &g_spiops,
+#if NSSI_ENABLED > 1
+ .base = IMX_CSSI0_VBASE,
+#endif
+#if !defined(CONFIG_SSI_POLLWAIT) && NSSI_ENABLED > 1
+ .irq = IMX_IRQ_CSSI0,
+#endif
+ },
+#endif
+#ifndef CONFIG_SSI1_DISABLE
+ {
+ .ops = &g_spiops,
+#if NSSI_ENABLED > 1
+ .base = IMX_CSSI1_VBASE,
+#endif
+#if !defined(CONFIG_SSI_POLLWAIT) && NSSI_ENABLED > 1
+ .irq = IMX_IRQ_CSSI1,
+#endif
+ },
+#endif
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ssi_getreg
+ *
+ * Description:
+ * Read the SSI register at this offeset
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * offset - Offset to the SSI register from the register base address
+ *
+ * Returned Value:
+ * Value of the register at this offset
+ *
+ ****************************************************************************/
+
+static inline uint32 ssi_getreg(struct lm32_ssidev_s *priv, unsigned int offset)
+{
+#if NSSI_ENABLED > 1
+ return getreg32(priv->base + offset);
+#else
+ return getreg32(SSI_BASE + offset);
+#endif
+}
+
+/****************************************************************************
+ * Name: ssi_putreg
+ *
+ * Description:
+ * Write the value to the SSI register at this offeset
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * offset - Offset to the SSI register from the register base address
+ * value - Value to write
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void ssi_putreg(struct lm32_ssidev_s *priv, unsigned int offset, uint32 value)
+{
+#if NSSI_ENABLED > 1
+ putreg32(value, priv->base + offset);
+#else
+ putreg32(value, SSI_BASE + offset);
+#endif
+}
+
+/****************************************************************************
+ * Name: ssi_disable
+ *
+ * Description:
+ * Disable SSI operation. NOTE: The SSI must be disabled before any control
+ * registers can be re-programmed.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * State of the SSI before the SSE was disabled
+ *
+ ****************************************************************************/
+
+static uint32 ssi_disable(struct lm32_ssidev_s *priv)
+{
+ uint32 retval;
+ uint32 regval;
+
+ retval = ssi_getreg(priv, LM3S_SSI_CR1_OFFSET);
+ regval = (retval & ~SSI_CR1_SSE);
+ ssi_putreg(priv, LM3S_SSI_CR1_OFFSET, regval);
+ return retval;
+}
+
+/****************************************************************************
+ * Name: ssi_enable
+ *
+ * Description:
+ * Restore the SSI operational state
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * enable - The previous operational state
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void ssi_enable(struct lm32_ssidev_s *priv, uint32 enable)
+{
+ uint32 regval = ssi_getreg(priv, LM3S_SSI_CR1_OFFSET);
+ regval &= ~SSI_CR1_SSE;
+ regval |= (enable & SSI_CR1_SSE);
+ ssi_putreg(priv, LM3S_SSI_CR1_OFFSET, regval);
+}
+
+/****************************************************************************
+ * Name: ssi_semtake
+ *
+ * Description:
+ * Wait for a semaphore (handling interruption by signals);
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * enable - The previous operational state
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void ssi_semtake(sem_t *sem)
+{
+ int ret;
+ do
+ {
+ ret = sem_wait(sem);
+ }
+ while (ret < 0 && errno == EINTR);
+ DEBUGASSERT(ret == 0);
+}
+
+/****************************************************************************
+ * Name: ssi_txnull, ssi_txuint16, and ssi_txubyte
+ *
+ * Description:
+ * Transfer all ones, a ubyte, or uint16 to Tx FIFO and update the txbuffer
+ * pointer appropriately. The selected function dependes 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 ssi_txnull(struct lm32_ssidev_s *priv)
+{
+ ssi_putreg(priv, LM3S_SSI_DR_OFFSET, 0xffff);
+}
+
+static void ssi_txuint16(struct lm32_ssidev_s *priv)
+{
+ uint16 *ptr = (uint16*)priv->txbuffer;
+ ssi_putreg(priv, LM3S_SSI_DR_OFFSET, (uint32)(*ptr++));
+ priv->txbuffer = (void*)ptr;
+}
+
+static void ssi_txubyte(struct lm32_ssidev_s *priv)
+{
+ ubyte *ptr = (ubyte*)priv->txbuffer;
+ ssi_putreg(priv, LM3S_SSI_DR_OFFSET, (uint32)(*ptr++));
+ priv->txbuffer = (void*)ptr;
+}
+
+/****************************************************************************
+ * Name: ssi_rxnull, ssi_rxuint16, and ssi_rxubyte
+ *
+ * Description:
+ * Discard input, save a ubyte, or or save a uint16 from Tx FIFO in the
+ * user rxvbuffer and update the rxbuffer pointer appropriately. The
+ * selected function dependes on (1) if there is a desination 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 ssi_rxnull(struct lm32_ssidev_s *priv)
+{
+ (void)ssi_getreg(priv, LM3S_SSI_DR_OFFSET);
+}
+
+static void ssi_rxuint16(struct lm32_ssidev_s *priv)
+{
+ uint16 *ptr = (uint16*)priv->rxbuffer;
+ *ptr++ = (uint16)ssi_getreg(priv, LM3S_SSI_DR_OFFSET);
+ priv->rxbuffer = (void*)ptr;
+}
+
+static void ssi_rxubyte(struct lm32_ssidev_s *priv)
+{
+ ubyte *ptr = (ubyte*)priv->rxbuffer;
+ *ptr++ = (ubyte)ssi_getreg(priv, LM3S_SSI_DR_OFFSET);
+ priv->rxbuffer = (void*)ptr;
+}
+
+/****************************************************************************
+ * Name: ssi_txfifofull
+ *
+ * Description:
+ * Return TRUE if the Tx FIFO is not full
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * TRUE: Not full
+ *
+ ****************************************************************************/
+
+static inline boolean ssi_txfifofull(struct lm32_ssidev_s *priv)
+{
+ return (ssi_getreg(priv, LM3S_SSI_SR_OFFSET) & SSI_SR_TNF) != 0;
+}
+
+/****************************************************************************
+ * Name: ssi_rxfifonotempty
+ *
+ * Description:
+ * Return TRUE if the Rx FIFO is not empty
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * TRUE: Not empty
+ *
+ ****************************************************************************/
+
+static inline boolean ssi_rxfifonotempty(struct lm32_ssidev_s *priv)
+{
+ return (ssi_getreg(priv, LM3S_SSI_SR_OFFSET) & SSI_SR_RNE) != 0;
+}
+
+/****************************************************************************
+ * Name: ssi_performtx
+ *
+ * Description:
+ * If the Tx FIFO is empty, then transfer as many words as we can to
+ * the FIFO.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * The number of words written to the Tx FIFO (a value from 0 to 8,
+ * inclusive).
+ *
+ ****************************************************************************/
+
+static int ssi_performtx(struct lm32_ssidev_s *priv)
+{
+ uint32 regval;
+ int ntxd = 0; /* Number of words written to Tx FIFO */
+
+ /* Check if the Tx FIFO is full */
+
+ if (!ssi_txfifofull(priv))
+ {
+ /* Not full.. Check if all of the Tx words have been sent */
+
+ if (priv->ntxwords > 0)
+ {
+ /* No.. Transfer more words until either the Tx FIFO is full or
+ * until all of the user provided data has been sent.
+ */
+
+ for (; ntxd < priv->ntxwords && !ssi_txfifofull(priv); ntxd++)
+ {
+ priv->txword(priv);
+ }
+
+ /* Update the count of words to to transferred */
+
+ priv->ntxwords -= ntxd;
+
+ /* Make sure that the Tx FIFO half-empty interrupt is enabled */
+
+#ifndef CONFIG_SSI_POLLWAIT
+ regval = ssi_getreg(priv, LM3S_SSI_IM_OFFSET);
+ regval |= SSI_IM_TX;
+ ssi_putreg(priv, LM3S_SSI_IM_OFFSET, regval);
+#endif
+ }
+#ifndef CONFIG_SSI_POLLWAIT
+ else
+ {
+ /* Yes.. The transfer is complete, disable Tx FIFO half-empty interrupt */
+
+ regval = ssi_getreg(priv, LM3S_SSI_IM_OFFSET);
+ regval &= ~SSI_IM_TX;
+ ssi_putreg(priv, LM3S_SSI_IM_OFFSET, regval);
+ }
+#endif
+ }
+ return ntxd;
+}
+
+/****************************************************************************
+ * Name: ssi_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 ssi_performrx(struct lm32_ssidev_s *priv)
+{
+ /* Loop while data is available in the Rx FIFO */
+
+ while (ssi_rxfifonotempty(priv))
+ {
+ /* 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++;
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: ssi_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
+ *
+ ****************************************************************************/
+
+static int ssi_transfer(struct lm32_ssidev_s *priv, const void *txbuffer,
+ void *rxbuffer, unsigned int nwords)
+{
+#ifndef CONFIG_SSI_POLLWAIT
+ irqstate_t flags;
+#endif
+ int ntxd;
+
+ ssi_semtake(&priv->exclsem);
+
+ /* Set up to perform the transfer */
+
+ priv->txbuffer = (ubyte*)txbuffer; /* Source buffer */
+ priv->rxbuffer = (ubyte*)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 > 8)
+ {
+ priv->txword = ssi_txuint16;
+ priv->rxword = ssi_rxuint16;
+ }
+ else
+ {
+ priv->txword = ssi_txubyte;
+ priv->rxword = ssi_rxubyte;
+ }
+
+ if (!txbuffer)
+ {
+ priv->txword = ssi_txnull;
+ }
+
+ if (!rxbuffer)
+ {
+ priv->rxword = ssi_rxnull;
+ }
+
+ /* Prime the Tx FIFO to start the sequence (saves one interrupt) */
+
+#ifndef CONFIG_SSI_POLLWAIT
+ flags = irqsave();
+ ntxd = ssi_performtx(priv);
+
+ /* 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.
+ */
+
+ irqrestore(flags);
+ ssi_semtake(&priv->xfrsem);
+
+#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 */
+
+ ntxd = ssi_performtx(priv);
+
+ /* Handle incoming Rx FIFO transfers */
+
+ ssi_performrx(priv);
+
+ /* If there are other threads at this same priority level,
+ * the following may help:
+ */
+
+ sched_yield();
+ }
+ while (priv->nrxwords < priv->nwords);
+#endif
+ ssi_semgive(&priv->exclsem);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ssi_mapirq
+ *
+ * Description:
+ * Map an IRQ number into the appropriate SSI 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 failrue.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SSI_POLLWAIT
+static inline struct lm32_ssidev_s *ssi_mapirq(int irq)
+{
+ switch (irq)
+ {
+#ifndef CONFIG_SSI0_DISABLE
+ case LM3S_IRQ_SSI0:
+ return &g_ssidev[SSI0_NDX];
+#endif
+#ifndef CONFIG_SSI1_DISABLE
+ case LM3S_IRQ_SSI1:
+ return &g_ssidev[SSI1_NDX];
+#endif
+ default:
+ return NULL;
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: ssi_interrupt
+ *
+ * Description:
+ * Exchange a block data with the SSI 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
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SSI_POLLWAIT
+static int ssi_interrupt(int irq, void *context)
+{
+ struct lm32_ssidev_s *priv = ssi_mapirq(irq);
+ int ntxd;
+
+ DEBUGASSERT(priv != NULL);
+
+ /* Handle outgoing Tx FIFO transfers */
+
+ ntxd = ssi_performtx(priv);
+
+ /* Handle incoming Rx FIFO transfers */
+
+ ssi_performrx(priv);
+
+ /* Check if the transfer is complete */
+
+ if (priv->nrxwords >= priv->nwords)
+ {
+ /* Yes, wake up the waiting thread */
+
+ ssi_semgive(&priv->xfrsem);
+ }
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ssi_setfrequency
+ *
+ * Description:
+ * Set the SPI frequency.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * frequency - The SPI frequency requested
+ *
+ * Returned Value:
+ * Returns the actual frequency selected
+ *
+ ****************************************************************************/
+
+static void ssi_setfrequencyinternal(struct lm32_ssidev_s *priv, uint32 frequency)
+{
+ uint32 maxdvsr;
+ uint32 cpsdvsr;
+ uint32 regval;
+ uint32 scr;
+
+ if (priv && frequency != priv->frequency)
+ {
+ /* "The serial bit rate is derived by dividing down the input clock
+ * (FSysClk). The clock is first divided by an even prescale value
+ * CPSDVSR from 2 to 254, which is programmed in the SSI Clock Prescale
+ * (SSI_CPSR) register ... The clock is further divided by a value
+ * from 1 to 256, which is 1 + SCR, where SCR is the value programmed
+ * i n the SSI Control0 (SSICR0) register ...
+ *
+ * "The frequency of the output clock SSIClk is defined by:
+ *
+ * "SSIClk = FSysClk / (CPSDVSR * (1 + SCR))
+ *
+ * "Note: Although the SSIClk transmit clock can theoretically be 25 MHz,
+ * the module may not be able to operate at that speed. For master mode,
+ * the system clock must be at least two times faster than the SSIClk.
+ * For slave mode, the system clock must be at least 12 times faster
+ * than the SSIClk."
+ */
+
+ if (frequency > SYSCLK_FREQUENCY/2)
+ {
+ frequency = SYSCLK_FREQUENCY/2;
+ }
+
+ /* Find optimal values for CPSDVSR and SCR. This loop is inefficient,
+ * but should not have to execute many times.
+ *
+ * EXAMPLE 1: SYSCLK_FREQUENCY=50,000,0000 and frequency=400,000.
+ *
+ * maxcvsr = 125
+ * 1. cpsdvsr = 2, scr = 61 -> DONE
+ *
+ * This would correspond to an actual frequency of:
+ * 50,000,000 / (2 * (62)) = 403,226
+ *
+ * EXAMPLE 2: SYSCLK_FREQUENCY=50,000,0000 and frequency=25,000,000.
+ *
+ * maxcvsr = 2
+ * 1. cpsdvsr = 2, scr = 0 -> DONE
+ *
+ * This would correspond to an actual frequency of:
+ * 50,000,000 / (2 * (1)) = 25,000,000
+ */
+
+ maxdvsr = SYSCLK_FREQUENCY / frequency;
+ cpsdvsr = 0;
+ do
+ {
+ cpsdvsr += 2;
+ scr = (maxdvsr / cpsdvsr) - 1;
+ }
+ while (scr > 255);
+
+ /* Set CPDVSR */
+
+ DEBUGASSERT(cpdvsr < 255);
+ ssi_putreg(priv, LM3S_SSI_CPSR_OFFSET, cpsdvsr);
+
+ /* Set SCR */
+
+ regval = ssi_getreg(priv, LM3S_SSI_CR0_OFFSET);
+ regval &= ~SSI_CR0_SCR_MASK;
+ regval |= (scr << SSI_CR0_SCR_SHIFT);
+ ssi_putreg(priv, LM3S_SSI_CR0_OFFSET, regval);
+
+ /* Calcluate the actual frequency */
+
+ priv->actual = SYSCLK_FREQUENCY / (cpsdvsr * (scr + 1));
+ }
+}
+
+static uint32 ssi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s *)dev;
+ uint32 enable;
+
+ /* NOTE that the SSI must be disabled when setting any configuration registers. */
+
+ ssi_semtake(&priv->exclsem);
+ enable = ssi_disable(priv);
+ ssi_setfrequencyinternal(priv, frequency);
+ ssi_enable(priv, enable);
+ ssi_semgive(&priv->exclsem);
+ return priv->actual;
+}
+
+/****************************************************************************
+ * Name: ssi_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 ssi_setmodeinternal(struct lm32_ssidev_s *priv, enum spi_mode_e mode)
+{
+ uint32 modebits;
+ uint32 regval;
+
+ ssi_semtake(&priv->exclsem);
+ if (priv && mode != priv->mode)
+ {
+ /* 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 = SSI_CR0_SPH;
+ break;
+
+ case SPIDEV_MODE2: /* CPOL=1 CHPHA=0 */
+ modebits = SSI_CR0_SPO;
+ break;
+
+ case SPIDEV_MODE3: /* CPOL=1 CHPHA=1 */
+ modebits = SSI_CR0_SPH|SSI_CR0_SPO;
+ break;
+
+ default:
+ return;
+ }
+
+ /* Then set the selected mode */
+
+ regval = ssi_getreg(priv, LM3S_SSI_CR0_OFFSET);
+ regval &= ~SSI_CR0_FRF_MASK;
+ regval |= modebits;
+ ssi_putreg(priv, LM3S_SSI_CR0_OFFSET, regval);
+ }
+}
+
+static void ssi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s *)dev;
+ uint32 enable;
+
+ /* NOTE that the SSI must be disabled when setting any configuration registers. */
+
+ ssi_semtake(&priv->exclsem);
+ enable = ssi_disable(priv);
+ ssi_setmodeinternal(priv, mode);
+ ssi_enable(priv, enable);
+ ssi_semgive(&priv->exclsem);
+}
+
+/****************************************************************************
+ * Name: ssi_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 ssi_setbitsinternal(struct lm32_ssidev_s *priv, int nbits)
+{
+ uint32 regval;
+
+ ssi_semtake(&priv->exclsem);
+ if (priv && nbits != priv->nbits && nbits >=4 && nbits <= 16)
+ {
+ regval = ssi_getreg(priv, LM3S_SSI_CR0_OFFSET);
+ regval &= ~SSI_CR0_DSS_MASK;
+ regval |= ((nbits - 1) << SSI_CR0_DSS_SHIFT);
+ ssi_putreg(priv, LM3S_SSI_CR0_OFFSET, regval);
+
+ priv->nbits = nbits;
+ }
+}
+
+static void ssi_setbits(FAR struct spi_dev_s *dev, int nbits)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s *)dev;
+ uint32 enable;
+
+ /* NOTE that the SSI must be disabled when setting any configuration registers. */
+
+ ssi_semtake(&priv->exclsem);
+ enable = ssi_disable(priv);
+ ssi_setbitsinternal(priv, nbits);
+ ssi_enable(priv, enable);
+ ssi_semgive(&priv->exclsem);
+}
+
+/****************************************************************************
+ * Name: ssi_send
+ *
+ * Description:
+ * Exchange one word on SPI
+ *
+ * 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 uint16 ssi_send(FAR struct spi_dev_s *dev, uint16 wd)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s*)dev;
+ uint16 response = 0;
+
+ (void)ssi_transfer(priv, &wd, &response, 1);
+ 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 ssi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
+ FAR void *rxbuffer, size_t nwords)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s *)dev;
+ (void)ssi_transfer(priv, txbuffer, rxbuffer, nwords);
+}
+#endif
+
+/*************************************************************************
+ * Name: ssi_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 ubytes; if nbits >8, the data is packed into uint16's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_EXCHANGE
+static void ssi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s *)dev;
+ (void)ssi_transfer(priv, buffer, NULL, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Name: ssi_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 recieve 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 ubytes; if nbits >8, the data is packed into uint16's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_EXCHANGE
+static void ssi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords)
+{
+ struct lm32_ssidev_s *priv = (struct lm32_ssidev_s *)dev;
+ (void)ssi_transfer(priv, NULL, buffer, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_spiinitialize
+ *
+ * Description:
+ * Initialize common parts the selected SPI port. Initialization of
+ * chip select GPIOs must have been performed by board specific logic
+ * prior to calling this function. Specifically: GPIOs should have
+ * been configured for output, and all chip selects disabled.
+ *
+ * One GPIO, SS (PB2 on the eZ8F091) is reserved as a chip select. However,
+ * If multiple devices on on the bus, then multiple chip selects will be
+ * required. Theregore, all GPIO chip management is deferred to board-
+ * specific logic.
+ *
+ * Input Parameter:
+ * Port number (for hardware that has mutiple SSI interfaces)
+ *
+ * Returned Value:
+ * Valid SPI device structure reference on succcess; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct spi_dev_s *up_spiinitialize(int port)
+{
+ struct lm32_ssidev_s *priv;
+ irqstate_t flags;
+ ubyte regval;
+
+ /* Set up for the selected port */
+
+ flags = irqsave();
+ switch (port)
+ {
+#ifndef CONFIG_SSI0_DISABLE
+ case 0:
+ /* Select SSI0 */
+
+ priv = &g_ssidev[SSI0_NDX];
+
+ /* Enable the SSI0 peripheral */
+
+ regval = getreg32(LM3S_SYSCON_RCGC1);
+ regval |= SYSCON_RCGC1_SSI0;
+ putreg32(regval, LM3S_SYSCON_RCGC1);
+
+ /* Configure SSI0 GPIOs (NOTE that SS is not initialized here, the
+ * logic in this file makes no assumptions about chip select)
+ */
+
+ lm3s_configgpio(GPIO_SSI0_CLK); /* PA2: SSI0 clock (SSI0Clk) */
+ /* lm3s_configgpio(GPIO_SSI0_FSS); PA3: SSI0 frame (SSI0Fss) */
+ lm3s_configgpio(GPIO_SSI0_RX); /* PA4: SSI0 receive (SSI0Rx) */
+ lm3s_configgpio(GPIO_SSI0_TX); /* PA5: SSI0 transmit (SSI0Tx) */
+ break;
+#endif /* CONFIG_SSI0_DISABLE */
+
+#ifndef CONFIG_SSI1_DISABLE
+ case 1:
+ /* Select SSI0 */
+
+ priv = &g_ssidev[SSI1_NDX];
+
+ /* Enable the SSI1 peripheral */
+
+ regval = getreg32(LM3S_SYSCON_RCGC1);
+ regval |= SYSCON_RCGC1_SSI1;
+ putreg32(regval, LM3S_SYSCON_RCGC1);
+
+ /* Configure SSI1 GPIOs */
+
+ lm3s_configgpio(GPIO_SSI1_CLK); /* PE0: SSI1 clock (SSI1Clk) */
+ /* lm3s_configgpio(GPIO_SSI1_FSS); PE1: SSI1 frame (SSI1Fss) */
+ lm3s_configgpio(GPIO_SSI1_RX); /* PE2: SSI1 receive (SSI1Rx) */
+ lm3s_configgpio(GPIO_SSI1_TX); /* PE3: SSI1 transmit (SSI1Tx) */
+ break;
+#endif /* CONFIG_SSI1_DISABLE */
+
+ default:
+ irqrestore(flags);
+ return NULL;
+ }
+
+ /* Initialize the state structure */
+
+#ifndef CONFIG_SSI_POLLWAIT
+ sem_init(&priv->xfrsem, 0, 0);
+#endif
+ sem_init(&priv->exclsem, 0, 1);
+
+ /* Set all CR1 fields to reset state. This will be master mode. */
+
+ ssi_putreg(priv, LM3S_SSI_CR1_OFFSET, 0);
+
+ /* Set all CR0 fields to the reset state. This will also select Freescale SPI mode. */
+
+ ssi_putreg(priv, LM3S_SSI_CR0_OFFSET, 0);
+
+ /* Set the initial mode to mode 0 */
+
+ ssi_setmodeinternal(priv, SPIDEV_MODE0);
+
+ /* Set the initial data width to 8-bits */
+
+ ssi_setbitsinternal(priv, 8);
+
+ /* Set the initialize clock frequency for detection */
+
+ ssi_setfrequencyinternal(priv, 400000);
+
+ /* Enable interrupts on data ready in the RX FIFL (and certain error conditions) */
+
+#ifndef CONFIG_SSI_POLLWAIT
+ ssi_putreg(priv, LM3S_SSI_IM_OFFSET,
+ SSI_IM_ROR | /* SSI Rx FIFO Overrun */
+ SSI_IM_RT | /* SSI Rx FIFO Time-Out */
+ SSI_IM_RX); /* SSI Rx FIFO half full or more */
+
+ /* Attach the interrupt */
+
+#if NSSI_ENABLED > 1
+ irq_attach(priv->irq, (xcpt_t)ssi_interrupt);
+#else
+ irq_attach(SSI_IRQ, (xcpt_t)ssi_interrupt);
+#endif
+#endif /* CONFIG_SSI_POLLWAIT */
+
+ /* Enable the SSI for operation */
+
+ ssi_enable(priv, SSI_CR1_SSE);
+
+ /* Enable SSI interrupts */
+
+#ifndef CONFIG_SSI_POLLWAIT
+#if NSSI_ENABLED > 1
+ up_enable_irq(priv->irq);
+#else
+ up_enable_irq(SSI_IRQ);
+#endif
+#endif /* CONFIG_SSI_POLLWAIT */
+ irqrestore(flags);
+ return (FAR struct spi_dev_s *)priv;
+}
+
+#endif /* NSSI_ENABLED > 0 */
diff --git a/nuttx/arch/arm/src/lm3s/lm3s_ssi.h b/nuttx/arch/arm/src/lm3s/lm3s_ssi.h
index 8ffdc9a448..10832dda11 100644
--- a/nuttx/arch/arm/src/lm3s/lm3s_ssi.h
+++ b/nuttx/arch/arm/src/lm3s/lm3s_ssi.h
@@ -43,7 +43,7 @@
#include <nuttx/config.h>
#include <sys/types.h>
-#if LMS_NSSI > 0
+#if LM3S_NSSI > 0
/************************************************************************************
* Definitions
@@ -97,7 +97,7 @@
#define LM3S_SSI0_PCELLID2 (LM3S_SSI0_BASE + LM3S_SSI_PCELLID2_OFFSET)
#define LM3S_SSI0_PCELLID3 (LM3S_SSI0_BASE + LM3S_SSI_PCELLID3_OFFSET)
-#if LMS_NSSI > 1
+#if LM3S_NSSI > 1
#define LM3S_SSI1_CR0 (LM3S_SSI1_BASE + LM3S_SSI_CR0_OFFSET)
#define LM3S_SSI1_CR1 (LM3S_SSI1_BASE + LM3S_SSI_CR1_OFFSET)
#define LM3S_SSI1_DR (LM3S_SSI1_BASE + LM3S_SSI_DR_OFFSET)
@@ -143,18 +143,18 @@
#define LM3S_SSI_PCELLID1(n) (LM3S_SSI_BASE(n) + LM3S_SSI_PCELLID1_OFFSET)
#define LM3S_SSI_PCELLID2(n) (LM3S_SSI_BASE(n) + LM3S_SSI_PCELLID2_OFFSET)
#define LM3S_SSI_PCELLID3(n) (LM3S_SSI_BASE(n) + LM3S_SSI_PCELLID3_OFFSET)
-#endif /* LMS_NSSI > 1 */
+#endif /* LM3S_NSSI > 1 */
/* SSI register bit defitiions ******************************************************/
/* SSI Control 0 (SSICR0), offset 0x000 */
-#define SSI_CR0_DSS_SHIFT 0 /* Bits 3-0: SSI Data Size Select
+#define SSI_CR0_DSS_SHIFT 0 /* Bits 3-0: SSI Data Size Select */
#define SSI_CR0_DSS_MASK (0x0f << SSI_CR0_DSS_SHIFT)
#define SSI_CR0_DSS(n) ((n-1) << SSI_CR0_DSS_SHIFT) /* n={4,5,..16} */
#define SSI_CR0_FRF_SHIFT 4 /* Bits 5-4: SSI Frame Format Select */
#define SSI_CR0_FRF_MASK (3 << SSI_CR0_FRF_SHIFT)
-#define SSI_CR0_FRF_SPI (0 << SSI_CR0_FRF_SHIFT) /* Freescale SPI format */e
+#define SSI_CR0_FRF_SPI (0 << SSI_CR0_FRF_SHIFT) /* Freescale SPI format */
#define SSI_CR0_FRF_SSFF (1 << SSI_CR0_FRF_SHIFT) /* TI synchronous serial fram format */
#define SSI_CR0_FRF_UWIRE (2 << SSI_CR0_FRF_SHIFT) /* MICROWIRE frame format */
#define SSI_CR0_SPO (1 << 6) /* Bit 6: SSI Serial Clock Polarity */
@@ -187,37 +187,37 @@
/* SSI Interrupt Mask (SSIIM), offset 0x014 */
-#define SSI_IM_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Interrupt Mask */
-#define SSI_IM_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Interrupt Mask */
-#define SSI_IM_RX (1 << 2) /* Bit 2: SSI Receive FIFO Interrupt Mask */
-#define SSI_IM_TX (1 << 3) /* Bit 3: SSI Transmit FIFO Interrupt Mask */
+#define SSI_IM_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Interrupt Mask */
+#define SSI_IM_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Interrupt Mask */
+#define SSI_IM_RX (1 << 2) /* Bit 2: SSI Receive FIFO Interrupt Mask */
+#define SSI_IM_TX (1 << 3) /* Bit 3: SSI Transmit FIFO Interrupt Mask */
/* SSI Raw Interrupt Status (SSIRIS), offset 0x018 */
-#define SSI_RIS_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Raw Interrupt Status */
-#define SSI_RIS_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Raw Interrupt Status */
-#define SSI_RIS_RX (1 << 2) /* Bit 2: SSI Receive FIFO Raw Interrupt Status */
-#define SSI_RIS_TX (1 << 3) /* Bit 3: SSI Transmit FIFO Raw Interrupt Status */
+#define SSI_RIS_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Raw Interrupt Status */
+#define SSI_RIS_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Raw Interrupt Status */
+#define SSI_RIS_RX (1 << 2) /* Bit 2: SSI Receive FIFO Raw Interrupt Status */
+#define SSI_RIS_TX (1 << 3) /* Bit 3: SSI Transmit FIFO Raw Interrupt Status */
/* SSI Masked Interrupt Status (SSIMIS), offset 0x01c */
-#define SSI_MIS_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Masked Interrupt Status */
-#define SSI_MIS_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Masked Interrupt Status */
-#define SSI_MIS_RX (1 << 2) /* Bit 2: SSI Receive FIFO Masked Interrupt Status */
-#define SSI_MIS_TX (1 << 3) /* Bit 3: SSI Transmit FIFO Masked Interrupt Status */
+#define SSI_MIS_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Masked Interrupt Status */
+#define SSI_MIS_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Masked Interrupt Status */
+#define SSI_MIS_RX (1 << 2) /* Bit 2: SSI Receive FIFO Masked Interrupt Status */
+#define SSI_MIS_TX (1 << 3) /* Bit 3: SSI Transmit FIFO Masked Interrupt Status */
/* SSI Interrupt Clear (SSIICR), offset 0x020 */
-#define SSI_ICR_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Interrupt Clear */
-#define SSI_ICR_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Interrupt Clear */
+#define SSI_ICR_ROR (1 << 0) /* Bit 0: SSI Receive Overrun Interrupt Clear */
+#define SSI_ICR_RT (1 << 1) /* Bit 1: SSI Receive Time-Out Interrupt Clear */
/* SSI Peripheral Identification n (SSIPERIPHIDn), offset 0xfd0-0xfec */
-#define SSI_PERIPHID_MASK 0xff /* Bits 7-0: SSI Peripheral ID n */
+#define SSI_PERIPHID_MASK 0xff /* Bits 7-0: SSI Peripheral ID n */
/* SSI PrimeCell Identification n (SSIPCELLIDn), offset 0xff0-0xffc */
-#define SSI_PCELLID_MASK 0xff /* Bits 7-0: SSI Prime cell ID */
+#define SSI_PCELLID_MASK 0xff /* Bits 7-0: SSI Prime cell ID */
/************************************************************************************
* Public Types
@@ -231,5 +231,5 @@
* Public Function Prototypes
************************************************************************************/
-#endif /* LMS_NSSI > 0 */
+#endif /* LM3S_NSSI > 0 */
#endif /* __ARCH_ARM_SRC_LM3S_LM3S_SSI_H */