diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-05-23 14:26:22 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-05-23 14:26:22 +0000 |
commit | 3b9ec2b7dd4cf15048d5196b3a4c2e5f4683634d (patch) | |
tree | 316c1d9d389dcf684a9a02d4cc9c8ff701b30581 | |
parent | 39b40937f83f939a221978a92c3a239d1ce53c32 (diff) | |
download | px4-nuttx-3b9ec2b7dd4cf15048d5196b3a4c2e5f4683634d.tar.gz px4-nuttx-3b9ec2b7dd4cf15048d5196b3a4c2e5f4683634d.tar.bz2 px4-nuttx-3b9ec2b7dd4cf15048d5196b3a4c2e5f4683634d.zip |
Add LM3S SSI driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1818 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/ChangeLog | 3 | ||||
-rw-r--r-- | nuttx/Documentation/NuttX.html | 5 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/imx/imx_spi.c | 14 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lm3s/Make.defs | 2 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lm3s/chip.h | 8 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lm3s/lm3s_ethernet.c | 30 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lm3s/lm3s_internal.h | 26 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/lm3s/lm3s_ssi.c | 1266 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lm3s/lm3s_ssi.h | 44 | ||||
-rw-r--r-- | nuttx/configs/eagle100/README.txt | 4 | ||||
-rw-r--r-- | nuttx/configs/eagle100/httpd/defconfig | 15 | ||||
-rw-r--r-- | nuttx/configs/eagle100/nettest/defconfig | 15 | ||||
-rw-r--r-- | nuttx/configs/eagle100/nsh/defconfig | 15 | ||||
-rw-r--r-- | nuttx/configs/eagle100/ostest/defconfig | 15 |
14 files changed, 1385 insertions, 77 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index f0e37fe0d..7a1ca792e 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -724,8 +724,9 @@ 0.4.7 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> - * arch/arm/src/lm2s: Added an Ethernet driver for the LM3S6918 + * arch/arm/src/lm3s: Added an Ethernet driver for the LM3S6918 * configs/eagle100/nettest: Added an examples/nettest configuration for the Micromint Eagle100 board. * Documentation/NuttxPortingGuide.html: Added a section on NuttX device drivers. + * arch/arm/src/lm3s: Added an SSI driver for the LM3S6918 diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html index f2717ad04..4c67353fb 100644 --- a/nuttx/Documentation/NuttX.html +++ b/nuttx/Documentation/NuttX.html @@ -8,7 +8,7 @@ <tr align="center" bgcolor="#e4e4e4"> <td> <h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1> - <p>Last Updated: May 21, 2009</p> + <p>Last Updated: May 23, 2009</p> </td> </tr> </table> @@ -1414,10 +1414,11 @@ buildroot-0.1.5 2009-04-25 <spudmonkey@racsa.co.cr> <pre><ul> nuttx-0.4.7 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> - * arch/arm/src/lm2s: Added an Ethernet driver for the LM3S6918 + * arch/arm/src/lm3s: Added an Ethernet driver for the LM3S6918 * configs/eagle100/nettest: Added an examples/nettest configuration for the Micromint Eagle100 board. * Documentation/NuttxPortingGuide.html: Added a section on NuttX device drivers. + * arch/arm/src/lm3s: Added an SSI driver for the LM3S6918 pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/nuttx/arch/arm/src/imx/imx_spi.c b/nuttx/arch/arm/src/imx/imx_spi.c index 437bd009d..f1b3262a0 100755 --- a/nuttx/arch/arm/src/imx/imx_spi.c +++ b/nuttx/arch/arm/src/imx/imx_spi.c @@ -59,7 +59,7 @@ * Definitions ****************************************************************************/ -/* The i.MX1/L supports 2 SPI interfaces. Which have been endabled? */ +/* The i.MX1/L supports 2 SPI interfaces. Which have been enabled? */ #ifndef CONFIG_SPI1_DISABLE # define SPI1_NDX 0 /* Index to SPI1 in g_spidev[] */ @@ -503,7 +503,7 @@ static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer, priv->nwords = nwords; /* Total number of exchanges */ /* Set up the low-level data transfer function pointers */ - + if (priv->nbits > 8) { priv->txword = spi_txuint16; @@ -514,7 +514,7 @@ static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer, priv->txword = spi_txubyte; priv->rxword = spi_rxubyte; } - + if (!txbuffer) { priv->txword = spi_txnull; @@ -533,7 +533,7 @@ static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer, spi_startxfr(priv, ntxd); /* Enable transmit empty interrupt */ - + regval = spi_getreg(priv, CSPI_INTCS_OFFSET); regval |= CSPI_INTCS_TEEN; spi_putreg(priv, CSPI_INTCS_OFFSET, regval); @@ -809,7 +809,7 @@ 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. + * Set the number of bits per word. * * Input Parameters: * dev - Device-specific state data @@ -995,11 +995,11 @@ FAR struct spi_dev_s *up_spiinitialize(int port) #ifndef CONFIG_SPI2_DISABLE case 2: - /* Select SPI1 */ + /* Select SPI2 */ priv = &g_spidev[SPI2_NDX]; - /* Configure SPI1 GPIOs */ + /* Configure SPI2 GPIOs */ /* SCLK: AIN of Port A, pin 0 -OR- AIN of Port D, pin 7 */ #if 1 diff --git a/nuttx/arch/arm/src/lm3s/Make.defs b/nuttx/arch/arm/src/lm3s/Make.defs index 42bb065d2..6a9416aa6 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 04639cbee..0abfc2f98 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 963705e6e..aa3189c19 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 6640241e6..3a52344a2 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 000000000..a880d2b23 --- /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 8ffdc9a44..10832dda1 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 */ diff --git a/nuttx/configs/eagle100/README.txt b/nuttx/configs/eagle100/README.txt index 729a60208..c1b32b950 100644 --- a/nuttx/configs/eagle100/README.txt +++ b/nuttx/configs/eagle100/README.txt @@ -200,6 +200,10 @@ Eagle100-specific Configuration Options CONFIG_UARTn_PARTIY - 0=no parity, 1=odd parity, 2=even parity CONFIG_UARTn_2STOP - Two stop bits + CONFIG_SSI0_DISABLE - Select to disable support for SSI0 + CONFIG_SSI1_DISABLE - Select to disable support for SSI1 + CONFIG_SSI_POLLWAIT - Select to disable interrupt driven SSI support. + CONFIG_LM3S_ETHERNET - This must be set (along with CONFIG_NET) to build the LM3S Ethernet driver CONFIG_LM3S_ETHLEDS - Enable to use Ethernet LEDs on the board. diff --git a/nuttx/configs/eagle100/httpd/defconfig b/nuttx/configs/eagle100/httpd/defconfig index 3f507db7e..23104ef0b 100644 --- a/nuttx/configs/eagle100/httpd/defconfig +++ b/nuttx/configs/eagle100/httpd/defconfig @@ -121,12 +121,15 @@ CONFIG_UART0_2STOP=0 CONFIG_UART1_2STOP=0 # -# LM3S6918 specific SPI device driver settings +# LM3S6918 specific SSI device driver settings # -# CONFIG_SPIn_DISABLE - select to disable all support for -# the SPI -CONFIG_SPI1_DISABLE=n -CONFIG_SPI2_DISABLE=y +# CONFIG_SSIn_DISABLE - select to disable all support for +# the SSI +# CONFIG_SSI_POLLWAIT - Select to disable interrupt driven SSI support +# +CONFIG_SSI0_DISABLE=n +CONFIG_SSI1_DISABLE=y +CONFIG_SSI_POLLWAIT=n # # LM3S6918 specific serial device driver settings @@ -142,7 +145,7 @@ CONFIG_SPI2_DISABLE=y # CONFIG_LM3S_MULTICAST - Set to enable multicast frames # CONFIG_LM3S_PROMISCUOUS - Set to enable promiscuous mode # CONFIG_LM3S_BADCRC - Set to enable bad CRC rejection. -# +# CONFIG_LM3S_ETHERNET=y CONFIG_LM3S_ETHLEDS=n CONFIG_LM3S_BOARDMAC=y diff --git a/nuttx/configs/eagle100/nettest/defconfig b/nuttx/configs/eagle100/nettest/defconfig index d2585df77..4d63e556e 100644 --- a/nuttx/configs/eagle100/nettest/defconfig +++ b/nuttx/configs/eagle100/nettest/defconfig @@ -121,12 +121,15 @@ CONFIG_UART0_2STOP=0 CONFIG_UART1_2STOP=0 # -# LM3S6918 specific SPI device driver settings +# LM3S6918 specific SSI device driver settings # -# CONFIG_SPIn_DISABLE - select to disable all support for -# the SPI -CONFIG_SPI1_DISABLE=n -CONFIG_SPI2_DISABLE=y +# CONFIG_SSIn_DISABLE - select to disable all support for +# the SSI +# CONFIG_SSI_POLLWAIT - Select to disable interrupt driven SSI support +# +CONFIG_SSI0_DISABLE=n +CONFIG_SSI1_DISABLE=y +CONFIG_SSI_POLLWAIT=n # # LM3S6918 specific serial device driver settings @@ -142,7 +145,7 @@ CONFIG_SPI2_DISABLE=y # CONFIG_LM3S_MULTICAST - Set to enable multicast frames # CONFIG_LM3S_PROMISCUOUS - Set to enable promiscuous mode # CONFIG_LM3S_BADCRC - Set to enable bad CRC rejection. -# +# CONFIG_LM3S_ETHERNET=y CONFIG_LM3S_ETHLEDS=n CONFIG_LM3S_BOARDMAC=y diff --git a/nuttx/configs/eagle100/nsh/defconfig b/nuttx/configs/eagle100/nsh/defconfig index 871642923..dd765ce15 100644 --- a/nuttx/configs/eagle100/nsh/defconfig +++ b/nuttx/configs/eagle100/nsh/defconfig @@ -121,12 +121,15 @@ CONFIG_UART0_2STOP=0 CONFIG_UART1_2STOP=0 # -# LM3S6918 specific SPI device driver settings +# LM3S6918 specific SSI device driver settings # -# CONFIG_SPIn_DISABLE - select to disable all support for -# the SPI -CONFIG_SPI1_DISABLE=n -CONFIG_SPI2_DISABLE=y +# CONFIG_SSIn_DISABLE - select to disable all support for +# the SSI +# CONFIG_SSI_POLLWAIT - Select to disable interrupt driven SSI support +# +CONFIG_SSI0_DISABLE=n +CONFIG_SSI1_DISABLE=y +CONFIG_SSI_POLLWAIT=n # # LM3S6918 specific serial device driver settings @@ -142,7 +145,7 @@ CONFIG_SPI2_DISABLE=y # CONFIG_LM3S_MULTICAST - Set to enable multicast frames # CONFIG_LM3S_PROMISCUOUS - Set to enable promiscuous mode # CONFIG_LM3S_BADCRC - Set to enable bad CRC rejection. -# +# CONFIG_LM3S_ETHERNET=n CONFIG_LM3S_ETHLEDS=n CONFIG_LM3S_BOARDMAC=y diff --git a/nuttx/configs/eagle100/ostest/defconfig b/nuttx/configs/eagle100/ostest/defconfig index 9d445f36e..b10c979e5 100644 --- a/nuttx/configs/eagle100/ostest/defconfig +++ b/nuttx/configs/eagle100/ostest/defconfig @@ -121,12 +121,15 @@ CONFIG_UART0_2STOP=0 CONFIG_UART1_2STOP=0 # -# LM3S6918 specific SPI device driver settings +# LM3S6918 specific SSI device driver settings # -# CONFIG_SPIn_DISABLE - select to disable all support for -# the SPI -CONFIG_SPI1_DISABLE=n -CONFIG_SPI2_DISABLE=y +# CONFIG_SSIn_DISABLE - select to disable all support for +# the SSI +# CONFIG_SSI_POLLWAIT - Select to disable interrupt driven SSI support +# +CONFIG_SSI0_DISABLE=n +CONFIG_SSI1_DISABLE=y +CONFIG_SSI_POLLWAIT=n # # LM3S6918 specific serial device driver settings @@ -142,7 +145,7 @@ CONFIG_SPI2_DISABLE=y # CONFIG_LM3S_MULTICAST - Set to enable multicast frames # CONFIG_LM3S_PROMISCUOUS - Set to enable promiscuous mode # CONFIG_LM3S_BADCRC - Set to enable bad CRC rejection. -# +# CONFIG_LM3S_ETHERNET=n CONFIG_LM3S_ETHLEDS=n CONFIG_LM3S_BOARDMAC=y |