summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/sama5/sam_ssc.c
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-11-12 15:53:02 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-11-12 15:53:02 -0600
commit5c8d3bedfaa4be1002cb6dd1114b7a2e59304053 (patch)
tree19a7671ddf4f0e6ce60f08c568b90d2e4d367d2f /nuttx/arch/arm/src/sama5/sam_ssc.c
parentd018d8159b0acbc0a312ce6038921b127b59bd96 (diff)
downloadpx4-nuttx-5c8d3bedfaa4be1002cb6dd1114b7a2e59304053.tar.gz
px4-nuttx-5c8d3bedfaa4be1002cb6dd1114b7a2e59304053.tar.bz2
px4-nuttx-5c8d3bedfaa4be1002cb6dd1114b7a2e59304053.zip
SAMA5 SSC: Fix DMA data width: 16 not 32 bits
Diffstat (limited to 'nuttx/arch/arm/src/sama5/sam_ssc.c')
-rw-r--r--nuttx/arch/arm/src/sama5/sam_ssc.c137
1 files changed, 127 insertions, 10 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_ssc.c b/nuttx/arch/arm/src/sama5/sam_ssc.c
index c90cfe335..df42da89a 100644
--- a/nuttx/arch/arm/src/sama5/sam_ssc.c
+++ b/nuttx/arch/arm/src/sama5/sam_ssc.c
@@ -200,13 +200,31 @@
/* DMA configuration */
-#define DMA_FLAGS(pid) \
- (((pid) << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHAHB_AHB_IF2 | \
- DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | \
- DMACH_FLAG_PERIPHWIDTH_32BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
- ((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \
- DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT | \
- DMACH_FLAG_MEMCHUNKSIZE_4)
+#define DMA_PID(pid) ((pid) << DMACH_FLAG_PERIPHPID_SHIFT)
+
+#define DMA8_FLAGS \
+ (DMACH_FLAG_PERIPHAHB_AHB_IF2 | DMACH_FLAG_PERIPHH2SEL | \
+ DMACH_FLAG_PERIPHISPERIPH | DMACH_FLAG_PERIPHWIDTH_8BITS | \
+ DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
+ ((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \
+ DMACH_FLAG_MEMWIDTH_16BITS | DMACH_FLAG_MEMINCREMENT | \
+ DMACH_FLAG_MEMCHUNKSIZE_4)
+
+#define DMA16_FLAGS \
+ (DMACH_FLAG_PERIPHAHB_AHB_IF2 | DMACH_FLAG_PERIPHH2SEL | \
+ DMACH_FLAG_PERIPHISPERIPH | DMACH_FLAG_PERIPHWIDTH_16BITS | \
+ DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
+ ((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \
+ DMACH_FLAG_MEMWIDTH_16BITS | DMACH_FLAG_MEMINCREMENT | \
+ DMACH_FLAG_MEMCHUNKSIZE_4)
+
+#define DMA32_FLAGS \
+ (DMACH_FLAG_PERIPHAHB_AHB_IF2 | DMACH_FLAG_PERIPHH2SEL | \
+ DMACH_FLAG_PERIPHISPERIPH | DMACH_FLAG_PERIPHWIDTH_32BITS | \
+ DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
+ ((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \
+ DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT | \
+ DMACH_FLAG_MEMCHUNKSIZE_4)
/* DMA timeout. The value is not critical; we just don't want the system to
* hang in the event that a DMA does not finish. This is set to
@@ -456,6 +474,7 @@ static int ssc_tx_configure(struct sam_ssc_s *priv);
#endif
static uint32_t ssc_mck2divider(struct sam_ssc_s *priv);
static void ssc_clocking(struct sam_ssc_s *priv);
+static int ssc_dma_flags(struct sam_ssc_s *priv, uint32_t *dmaflags);
static int ssc_dma_allocate(struct sam_ssc_s *priv);
static void ssc_dma_free(struct sam_ssc_s *priv);
#ifdef CONFIG_SAMA5_SSC0
@@ -1888,12 +1907,34 @@ static uint32_t ssc_rxdatawidth(struct i2s_dev_s *dev, int bits)
{
#ifdef SSC_HAVE_RX
struct sam_ssc_s *priv = (struct sam_ssc_s *)dev;
+ uint32_t dmaflags;
+ int ret;
+
DEBUGASSERT(priv && bits > 1);
/* Save the new data width */
priv->datalen = bits;
+ /* Upate the DMA flags */
+
+ ret = ssc_dma_flags(priv, &dmaflags);
+ if (ret < 0)
+ {
+ i2sdbg("ERROR: ssc_dma_flags failed: %d\n", ret);
+ return 0;
+ }
+
+ /* Reconfigure the RX DMA (and TX DMA if applicable) */
+
+ sam_dmaconfig(priv->rx.dma, dmaflags);
+#ifdef SSC_HAVE_RX
+ if (priv->txenab)
+ {
+ sam_dmaconfig(priv->tx.dma, dmaflags);
+ }
+#endif
+
#ifdef SSC_HAVE_MCK2
/* Check if the receiver is driven by the MCK/2 */
@@ -2067,14 +2108,36 @@ static uint32_t ssc_txdatawidth(struct i2s_dev_s *dev, int bits)
{
#ifdef SSC_HAVE_TX
struct sam_ssc_s *priv = (struct sam_ssc_s *)dev;
+ uint32_t dmaflags;
+ int ret;
+
DEBUGASSERT(priv && bits > 1);
/* Save the new data width */
priv->datalen = bits;
+ /* Upate the DMA flags */
+
+ ret = ssc_dma_flags(priv, &dmaflags);
+ if (ret < 0)
+ {
+ i2sdbg("ERROR: ssc_dma_flags failed: %d\n", ret);
+ return 0;
+ }
+
+ /* Reconfigure the RX DMA (and RX DMA if applicable) */
+
+ sam_dmaconfig(priv->tx.dma, dmaflags);
+#ifdef SSC_HAVE_RX
+ if (priv->rxenab)
+ {
+ sam_dmaconfig(priv->rx.dma, dmaflags);
+ }
+#endif
+
#ifdef SSC_HAVE_MCK2
- /* Check if the receiver is driven by the MCK/2 */
+ /* Check if the transmitter is driven by the MCK/2 */
if (priv->txclk == SSC_CLKSRC_MCKDIV)
{
@@ -2545,6 +2608,48 @@ static void ssc_clocking(struct sam_ssc_s *priv)
}
/****************************************************************************
+ * Name: ssc_dma_flags
+ *
+ * Description:
+ * Determine DMA FLAGS based on PID and data width
+ *
+ * Input Parameters:
+ * priv - Partially initialized I2C device structure.
+ * dmaflags - Location to return the DMA flags.
+ *
+ * Returned Value:
+ * OK on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int ssc_dma_flags(struct sam_ssc_s *priv, uint32_t *dmaflags)
+{
+ uint32_t regval;
+
+ switch (priv->datalen)
+ {
+ case 8:
+ regval = DMA8_FLAGS;
+ break;
+
+ case 16:
+ regval = DMA16_FLAGS;
+ break;
+
+ case 32:
+ regval = DMA32_FLAGS;
+ break;
+
+ default:
+ i2sdbg("ERROR: Unsupported data width: %d\n", priv->datalen);
+ return -ENOSYS;
+ }
+
+ *dmaflags = (regval | DMA_PID(priv->pid));
+ return OK;
+}
+
+/****************************************************************************
* Name: ssc_dma_allocate
*
* Description:
@@ -2561,6 +2666,18 @@ static void ssc_clocking(struct sam_ssc_s *priv)
static int ssc_dma_allocate(struct sam_ssc_s *priv)
{
+ uint32_t dmaflags;
+ int ret;
+
+ /* Get the DMA flags for this channel */
+
+ ret = ssc_dma_flags(priv, &dmaflags);
+ if (ret < 0)
+ {
+ i2sdbg("ERROR: ssc_dma_flags failed: %d\n", ret);
+ return ret;
+ }
+
/* Allocate DMA channels. These allocations exploit that fact that
* SSC0 is managed by DMAC0 and SSC1 is managed by DMAC1. Hence,
* the SSC number (sscno) is the same as the DMAC number.
@@ -2571,7 +2688,7 @@ static int ssc_dma_allocate(struct sam_ssc_s *priv)
{
/* Allocate an RX DMA channel */
- priv->rx.dma = sam_dmachannel(priv->sscno, DMA_FLAGS(priv->pid));
+ priv->rx.dma = sam_dmachannel(priv->sscno, dmaflags);
if (!priv->rx.dma)
{
i2sdbg("ERROR: Failed to allocate the RX DMA channel\n");
@@ -2594,7 +2711,7 @@ static int ssc_dma_allocate(struct sam_ssc_s *priv)
{
/* Allocate a TX DMA channel */
- priv->tx.dma = sam_dmachannel(priv->sscno, DMA_FLAGS(priv->pid));
+ priv->tx.dma = sam_dmachannel(priv->sscno, dmaflags);
if (!priv->tx.dma)
{
i2sdbg("ERROR: Failed to allocate the TX DMA channel\n");