diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-08-02 14:26:49 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-08-02 14:26:49 -0600 |
commit | 2799307735d82cc4a366b64d4906745bc2094dec (patch) | |
tree | 1b71e64ff71c82344e576648bd7c2afc009dee24 | |
parent | 0bd9ed4a62af7738e3df9257a7e223006da43ba1 (diff) | |
download | nuttx-2799307735d82cc4a366b64d4906745bc2094dec.tar.gz nuttx-2799307735d82cc4a366b64d4906745bc2094dec.tar.bz2 nuttx-2799307735d82cc4a366b64d4906745bc2094dec.zip |
SAMA5 SSC: Verify that the requested bit width is supported. Correct some alignment tests that depend upon the data bit width.
-rw-r--r-- | nuttx/arch/arm/src/sama5/sam_ssc.c | 126 |
1 files changed, 113 insertions, 13 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_ssc.c b/nuttx/arch/arm/src/sama5/sam_ssc.c index 7f7dfc00a..475cf06b2 100644 --- a/nuttx/arch/arm/src/sama5/sam_ssc.c +++ b/nuttx/arch/arm/src/sama5/sam_ssc.c @@ -111,12 +111,24 @@ # endif # endif + /* The SSC can handle most any bit width from 2 to 32. However, the DMA + * logic here is constrained to byte, half-word, and word sizes. + */ + # ifndef CONFIG_SAMA5_SSC0_DATALEN # define CONFIG_SAMA5_SSC0_DATALEN 16 # endif -# if CONFIG_SAMA5_SSC0_DATALEN < 2 || CONFIG_SAMA5_SSC0_DATALEN > 32 +# if CONFIG_SAMA5_SSC0_DATALEN == 8 +# define SAMA5_SSC0_DATAMASK 0 +# elif CONFIG_SAMA5_SSC0_DATALEN == 16 +# define SAMA5_SSC0_DATAMASK 1 +# elif CONFIG_SAMA5_SSC0_DATALEN == 32 +# define SAMA5_SSC0_DATAMASK 3 +# elif CONFIG_SAMA5_SSC0_DATALEN < 2 || CONFIG_SAMA5_SSC0_DATALEN > 32 # error Invalid value for CONFIG_SAMA5_SSC0_DATALEN +# else +# error Valid but supported value for CONFIG_SAMA5_SSC0_DATALEN # endif /* Check for SSC0 RX support */ @@ -187,12 +199,24 @@ # endif # endif + /* The SSC can handle most any bit width from 2 to 32. However, the DMA + * logic here is constrained to byte, half-word, and word sizes. + */ + # ifndef CONFIG_SAMA5_SSC1_DATALEN # define CONFIG_SAMA5_SSC1_DATALEN 16 # endif -# if CONFIG_SAMA5_SSC1_DATALEN < 2 || CONFIG_SAMA5_SSC1_DATALEN > 32 +# if CONFIG_SAMA5_SSC1_DATALEN == 8 +# define SAMA5_SSC1_DATAMASK 0 +# elif CONFIG_SAMA5_SSC1_DATALEN == 16 +# define SAMA5_SSC1_DATAMASK 1 +# elif CONFIG_SAMA5_SSC1_DATALEN == 32 +# define SAMA5_SSC1_DATAMASK 3 +# elif CONFIG_SAMA5_SSC1_DATALEN < 2 || CONFIG_SAMA5_SSC1_DATALEN > 32 # error Invalid value for CONFIG_SAMA5_SSC1_DATALEN +# else +# error Valid but supported value for CONFIG_SAMA5_SSC1_DATALEN # endif /* Check for SSC1 RX support */ @@ -451,7 +475,10 @@ struct sam_ssc_s struct i2s_dev_s dev; /* Externally visible I2S interface */ uintptr_t base; /* SSC controller register base address */ sem_t exclsem; /* Assures mutually exclusive acess to SSC */ - uint8_t datalen; /* Data width (2-32) */ + uint8_t datalen; /* Data width (8, 16, or 32) */ +#ifdef CONFIG_DEBUG + uint8_t align; /* Log2 of data width (0, 1, or 3) */ +#endif uint8_t pid; /* Peripheral ID */ uint8_t rxfslen; /* RX frame sync length */ uint8_t txfslen; /* TX frame sync length */ @@ -598,7 +625,9 @@ static void ssc_tx_schedule(struct sam_ssc_s *priv, int result); static void ssc_txdma_callback(DMA_HANDLE handle, void *arg, int result); #endif -/* I2S methods */ +/* I2S methods (and close friends) */ + +static int ssc_checkwidth(struct sam_ssc_s *priv, int bits); static uint32_t ssc_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate); static uint32_t ssc_rxdatawidth(struct i2s_dev_s *dev, int bits); @@ -1294,7 +1323,7 @@ static int ssc_rxdma_setup(struct sam_ssc_s *priv) DEBUGASSERT(bfcontainer && bfcontainer->apb); apb = bfcontainer->apb; - DEBUGASSERT(((uintptr_t)apb->samp & 3) == 0); + DEBUGASSERT(((uintptr_t)apb->samp % priv->align) == 0); /* No data received yet */ @@ -1714,7 +1743,7 @@ static int ssc_txdma_setup(struct sam_ssc_s *priv) samp = (uintptr_t)&apb->samp[apb->curbyte]; nbytes = apb->nbytes - apb->curbyte; - DEBUGASSERT((samp & 3) == 0 && (nbytes & 3) == 0); /* REVISIT */ + DEBUGASSERT((samp & priv->align) == 0 && (nbytes & priv->align) == 0); /* Physical address of the SSC THR register and of the buffer location * in RAM. @@ -2005,6 +2034,60 @@ static void ssc_txdma_callback(DMA_HANDLE handle, void *arg, int result) #endif /**************************************************************************** + * Name: ssc_checkwidth + * + * Description: + * Check for a valid bit width. The SSC is capable of handling most any + * bit width from 2 to 32, but the DMA logic in this driver is constrained + * to 8-, 16-, and 32-bit data widths + * + * Input Parameters: + * dev - Device-specific state data + * rate - The I2S sample rate in samples (not bits) per second + * + * Returned Value: + * Returns the resulting bitrate + * + ****************************************************************************/ + +static int ssc_checkwidth(struct sam_ssc_s *priv, int bits) +{ + /* The SSC can handle most any bit width from 2 to 32. However, the DMA + * logic here is constrained to byte, half-word, and word sizes. + */ + + switch (bits) + { + case 8: +#ifdef CONFIG_DEBUG + priv->align = 0; +#endif + break; + + case 16: +#ifdef CONFIG_DEBUG + priv->align = 1; +#endif + break; + + case 32: +#ifdef CONFIG_DEBUG + priv->align = 3; +#endif + break; + + default: + i2sdbg("ERROR: Unsupported or invalid data width: %d\n", bits); + return (bits < 2 || bits > 32) ? -EINVAL : -ENOSYS; + } + + /* Save the new data width */ + + priv->datalen = bits; + return OK; +} + +/**************************************************************************** * Name: ssc_rxsamplerate * * Description: @@ -2067,11 +2150,16 @@ static uint32_t ssc_rxdatawidth(struct i2s_dev_s *dev, int bits) DEBUGASSERT(priv && bits > 1); - /* Save the new data width */ + /* Check if this is a bit width that we are configured to handle */ - priv->datalen = bits; + ret = ssc_checkwidth(priv, bits); + if (ret < 0) + { + i2sdbg("ERROR: ssc_checkwidth failed: %d\n", ret); + return 0; + } - /* Upate the DMA flags */ + /* Update the DMA flags */ ret = ssc_dma_flags(priv, &dmaflags); if (ret < 0) @@ -2145,7 +2233,7 @@ static int ssc_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, int ret; #endif - DEBUGASSERT(priv && apb && ((uintptr_t)apb->samp & 3) == 0); + DEBUGASSERT(priv && apb && ((uintptr_t)apb->samp & priv->align) == 0); i2svdbg("apb=%p nmaxbytes=%d arg=%p timeout=%d\n", apb, apb->nmaxbytes, arg, timeout); @@ -2273,9 +2361,14 @@ static uint32_t ssc_txdatawidth(struct i2s_dev_s *dev, int bits) DEBUGASSERT(priv && bits > 1); - /* Save the new data width */ + /* Check if this is a bit width that we are configured to handle */ - priv->datalen = bits; + ret = ssc_checkwidth(priv, bits); + if (ret < 0) + { + i2sdbg("ERROR: ssc_checkwidth failed: %d\n", ret); + return 0; + } /* Upate the DMA flags */ @@ -2355,12 +2448,13 @@ static int ssc_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, * alignment. */ - DEBUGASSERT(priv && apb && ((uintptr_t)&apb->samp[apb->curbyte] & 3) == 0); + DEBUGASSERT(priv && apb); i2svdbg("apb=%p nbytes=%d arg=%p timeout=%d\n", apb, apb->nbytes - apb->curbyte, arg, timeout); ssc_dump_buffer("Sending", &apb->samp[apb->curbyte], apb->nbytes - apb->curbyte); + DEBUGASSERT(((uintptr_t)&apb->samp[apb->curbyte] & priv->align) == 0); #ifdef SSC_HAVE_TX /* Allocate a buffer container in advance */ @@ -3163,6 +3257,9 @@ static void ssc0_configure(struct sam_ssc_s *priv) priv->base = SAM_SSC0_VBASE; priv->datalen = CONFIG_SAMA5_SSC0_DATALEN; +#ifdef CONFIG_DEBUG + priv->align = SAMA5_SSC0_DATAMASK; +#endif priv->pid = SAM_PID_SSC0; } #endif @@ -3301,6 +3398,9 @@ static void ssc1_configure(struct sam_ssc_s *priv) priv->base = SAM_SSC1_VBASE; priv->datalen = CONFIG_SAMA5_SSC1_DATALEN; +#ifdef CONFIG_DEBUG + priv->align = SAMA5_SSC1_DATAMASK; +#endif priv->pid = SAM_PID_SSC1; } #endif |