mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 01:21:26 +08:00
SAMA5 SSC: Verify that the requested bit width is supported. Correct some alignment tests that depend upon the data bit width.
This commit is contained in:
+113
-13
@@ -111,12 +111,24 @@
|
|||||||
# endif
|
# endif
|
||||||
# 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
|
# ifndef CONFIG_SAMA5_SSC0_DATALEN
|
||||||
# define CONFIG_SAMA5_SSC0_DATALEN 16
|
# define CONFIG_SAMA5_SSC0_DATALEN 16
|
||||||
# endif
|
# 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
|
# error Invalid value for CONFIG_SAMA5_SSC0_DATALEN
|
||||||
|
# else
|
||||||
|
# error Valid but supported value for CONFIG_SAMA5_SSC0_DATALEN
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Check for SSC0 RX support */
|
/* Check for SSC0 RX support */
|
||||||
@@ -187,12 +199,24 @@
|
|||||||
# endif
|
# endif
|
||||||
# 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
|
# ifndef CONFIG_SAMA5_SSC1_DATALEN
|
||||||
# define CONFIG_SAMA5_SSC1_DATALEN 16
|
# define CONFIG_SAMA5_SSC1_DATALEN 16
|
||||||
# endif
|
# 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
|
# error Invalid value for CONFIG_SAMA5_SSC1_DATALEN
|
||||||
|
# else
|
||||||
|
# error Valid but supported value for CONFIG_SAMA5_SSC1_DATALEN
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Check for SSC1 RX support */
|
/* Check for SSC1 RX support */
|
||||||
@@ -451,7 +475,10 @@ struct sam_ssc_s
|
|||||||
struct i2s_dev_s dev; /* Externally visible I2S interface */
|
struct i2s_dev_s dev; /* Externally visible I2S interface */
|
||||||
uintptr_t base; /* SSC controller register base address */
|
uintptr_t base; /* SSC controller register base address */
|
||||||
sem_t exclsem; /* Assures mutually exclusive acess to SSC */
|
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 pid; /* Peripheral ID */
|
||||||
uint8_t rxfslen; /* RX frame sync length */
|
uint8_t rxfslen; /* RX frame sync length */
|
||||||
uint8_t txfslen; /* TX 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);
|
static void ssc_txdma_callback(DMA_HANDLE handle, void *arg, int result);
|
||||||
#endif
|
#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_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate);
|
||||||
static uint32_t ssc_rxdatawidth(struct i2s_dev_s *dev, int bits);
|
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);
|
DEBUGASSERT(bfcontainer && bfcontainer->apb);
|
||||||
|
|
||||||
apb = bfcontainer->apb;
|
apb = bfcontainer->apb;
|
||||||
DEBUGASSERT(((uintptr_t)apb->samp & 3) == 0);
|
DEBUGASSERT(((uintptr_t)apb->samp % priv->align) == 0);
|
||||||
|
|
||||||
/* No data received yet */
|
/* 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];
|
samp = (uintptr_t)&apb->samp[apb->curbyte];
|
||||||
nbytes = apb->nbytes - 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
|
/* Physical address of the SSC THR register and of the buffer location
|
||||||
* in RAM.
|
* in RAM.
|
||||||
@@ -2004,6 +2033,60 @@ static void ssc_txdma_callback(DMA_HANDLE handle, void *arg, int result)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
* Name: ssc_rxsamplerate
|
||||||
*
|
*
|
||||||
@@ -2067,11 +2150,16 @@ static uint32_t ssc_rxdatawidth(struct i2s_dev_s *dev, int bits)
|
|||||||
|
|
||||||
DEBUGASSERT(priv && bits > 1);
|
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);
|
ret = ssc_dma_flags(priv, &dmaflags);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@@ -2145,7 +2233,7 @@ static int ssc_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
|
|||||||
int ret;
|
int ret;
|
||||||
#endif
|
#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",
|
i2svdbg("apb=%p nmaxbytes=%d arg=%p timeout=%d\n",
|
||||||
apb, apb->nmaxbytes, arg, timeout);
|
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);
|
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 */
|
/* Upate the DMA flags */
|
||||||
|
|
||||||
@@ -2355,12 +2448,13 @@ static int ssc_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
|
|||||||
* alignment.
|
* 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",
|
i2svdbg("apb=%p nbytes=%d arg=%p timeout=%d\n",
|
||||||
apb, apb->nbytes - apb->curbyte, arg, timeout);
|
apb, apb->nbytes - apb->curbyte, arg, timeout);
|
||||||
|
|
||||||
ssc_dump_buffer("Sending", &apb->samp[apb->curbyte],
|
ssc_dump_buffer("Sending", &apb->samp[apb->curbyte],
|
||||||
apb->nbytes - apb->curbyte);
|
apb->nbytes - apb->curbyte);
|
||||||
|
DEBUGASSERT(((uintptr_t)&apb->samp[apb->curbyte] & priv->align) == 0);
|
||||||
|
|
||||||
#ifdef SSC_HAVE_TX
|
#ifdef SSC_HAVE_TX
|
||||||
/* Allocate a buffer container in advance */
|
/* 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->base = SAM_SSC0_VBASE;
|
||||||
priv->datalen = CONFIG_SAMA5_SSC0_DATALEN;
|
priv->datalen = CONFIG_SAMA5_SSC0_DATALEN;
|
||||||
|
#ifdef CONFIG_DEBUG
|
||||||
|
priv->align = SAMA5_SSC0_DATAMASK;
|
||||||
|
#endif
|
||||||
priv->pid = SAM_PID_SSC0;
|
priv->pid = SAM_PID_SSC0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3301,6 +3398,9 @@ static void ssc1_configure(struct sam_ssc_s *priv)
|
|||||||
|
|
||||||
priv->base = SAM_SSC1_VBASE;
|
priv->base = SAM_SSC1_VBASE;
|
||||||
priv->datalen = CONFIG_SAMA5_SSC1_DATALEN;
|
priv->datalen = CONFIG_SAMA5_SSC1_DATALEN;
|
||||||
|
#ifdef CONFIG_DEBUG
|
||||||
|
priv->align = SAMA5_SSC1_DATAMASK;
|
||||||
|
#endif
|
||||||
priv->pid = SAM_PID_SSC1;
|
priv->pid = SAM_PID_SSC1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user