This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 7eeba71366 audio: add audio_dma device driver.
7eeba71366 is described below
commit 7eeba713666dbc4a6c31fa3d730073b97a753fdd
Author: ZhongAn <[email protected]>
AuthorDate: Mon Jun 25 20:22:32 2018 +0800
audio: add audio_dma device driver.
Signed-off-by: ZhongAn <[email protected]>
---
drivers/audio/Kconfig | 6 +
drivers/audio/Make.defs | 4 +
drivers/audio/audio_dma.c | 613 ++++++++++++++++++++++++++++++++++++++++
include/nuttx/audio/audio_dma.h | 41 +++
4 files changed, 664 insertions(+)
diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig
index dd6c628a64..6437d7e317 100644
--- a/drivers/audio/Kconfig
+++ b/drivers/audio/Kconfig
@@ -492,4 +492,10 @@ config AUDIO_I2S
depends on AUDIO
depends on I2S
+config AUDIO_DMA
+ bool "Audio DMA"
+ select AUDIO_DRIVER_SPECIFIC_BUFFERS
+ depends on AUDIO
+ depends on DMA
+
endif # DRIVERS_AUDIO
diff --git a/drivers/audio/Make.defs b/drivers/audio/Make.defs
index 33109cba24..31de28713c 100644
--- a/drivers/audio/Make.defs
+++ b/drivers/audio/Make.defs
@@ -93,6 +93,10 @@ ifeq ($(CONFIG_AUDIO_I2S),y)
CSRCS += audio_i2s.c
endif
+ifeq ($(CONFIG_AUDIO_DMA),y)
+CSRCS += audio_dma.c
+endif
+
# Include Audio driver support
DEPPATH += --dep-path audio
diff --git a/drivers/audio/audio_dma.c b/drivers/audio/audio_dma.c
new file mode 100644
index 0000000000..700a393a8c
--- /dev/null
+++ b/drivers/audio/audio_dma.c
@@ -0,0 +1,613 @@
+/****************************************************************************
+ * drivers/audio/audio_dma.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/audio/audio_dma.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/queue.h>
+
+#include <debug.h>
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct audio_dma_s
+{
+ struct audio_lowerhalf_s dev;
+ struct dma_chan_s *chan;
+ uintptr_t src_addr;
+ uintptr_t dst_addr;
+ uint8_t *alloc_addr;
+ uint8_t alloc_index;
+ uint8_t fifo_width;
+ bool playback;
+ bool xrun;
+ struct dq_queue_s pendq;
+ apb_samp_t buffer_size;
+ apb_samp_t buffer_num;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int audio_dma_getcaps(struct audio_lowerhalf_s *dev, int type,
+ struct audio_caps_s *caps);
+static int audio_dma_shutdown(struct audio_lowerhalf_s *dev);
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_configure(struct audio_lowerhalf_s *dev,
+ void *session,
+ const struct audio_caps_s *caps);
+static int audio_dma_start(struct audio_lowerhalf_s *dev,
+ void *session);
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+static int audio_dma_stop(struct audio_lowerhalf_s *dev, void *session);
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+static int audio_dma_pause(struct audio_lowerhalf_s *dev,
+ void *session);
+static int audio_dma_resume(struct audio_lowerhalf_s *dev,
+ void *session);
+#endif
+static int audio_dma_reserve(struct audio_lowerhalf_s *dev,
+ void **session);
+static int audio_dma_release(struct audio_lowerhalf_s *dev,
+ void *session);
+#else
+static int audio_dma_configure(struct audio_lowerhalf_s *dev,
+ const struct audio_caps_s *caps);
+static int audio_dma_start(struct audio_lowerhalf_s *dev);
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+static int audio_dma_stop(struct audio_lowerhalf_s *dev);
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+static int audio_dma_pause(struct audio_lowerhalf_s *dev);
+static int audio_dma_resume(struct audio_lowerhalf_s *dev);
+#endif
+static int audio_dma_reserve(struct audio_lowerhalf_s *dev);
+static int audio_dma_release(struct audio_lowerhalf_s *dev);
+#endif
+static int audio_dma_allocbuffer(struct audio_lowerhalf_s *dev,
+ struct audio_buf_desc_s *bufdesc);
+static int audio_dma_freebuffer(struct audio_lowerhalf_s *dev,
+ struct audio_buf_desc_s *bufdesc);
+static int audio_dma_enqueuebuffer(struct audio_lowerhalf_s *dev,
+ struct ap_buffer_s *apb);
+static int audio_dma_ioctl(struct audio_lowerhalf_s *dev, int cmd,
+ unsigned long arg);
+static void audio_dma_callback(struct dma_chan_s *chan, void *arg,
+ ssize_t len);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct audio_ops_s g_audio_dma_ops =
+{
+ .getcaps = audio_dma_getcaps,
+ .configure = audio_dma_configure,
+ .shutdown = audio_dma_shutdown,
+ .start = audio_dma_start,
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+ .stop = audio_dma_stop,
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+ .pause = audio_dma_pause,
+ .resume = audio_dma_resume,
+#endif
+ .allocbuffer = audio_dma_allocbuffer,
+ .freebuffer = audio_dma_freebuffer,
+ .enqueuebuffer = audio_dma_enqueuebuffer,
+ .ioctl = audio_dma_ioctl,
+ .reserve = audio_dma_reserve,
+ .release = audio_dma_release,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int audio_dma_getcaps(struct audio_lowerhalf_s *dev, int type,
+ struct audio_caps_s *caps)
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+
+ /* Validate the structure */
+
+ DEBUGASSERT(caps && caps->ac_len >= sizeof(struct audio_caps_s));
+ audinfo("type=%d ac_type=%d\n", type, caps->ac_type);
+
+ /* Fill in the caller's structure based on requested info */
+
+ caps->ac_format.hw = 0;
+ caps->ac_controls.w = 0;
+
+ switch (caps->ac_type)
+ {
+ /* Caller is querying for the types of units we support */
+
+ case AUDIO_TYPE_QUERY:
+
+ /* Provide our overall capabilities. The interfacing software
+ * must then call us back for specific info for each capability.
+ */
+
+ caps->ac_channels = 2; /* Stereo output */
+
+ switch (caps->ac_subtype)
+ {
+ case AUDIO_TYPE_QUERY:
+
+ /* We don't decode any formats! Only something above us in
+ * the audio stream can perform decoding on our behalf.
+ */
+
+ /* The types of audio units we implement */
+
+ if (audio_dma->playback)
+ caps->ac_controls.b[0] = AUDIO_TYPE_OUTPUT;
+ else
+ caps->ac_controls.b[0] = AUDIO_TYPE_INPUT;
+ caps->ac_format.hw = 1 << (AUDIO_FMT_PCM - 1);
+ break;
+
+ default:
+ caps->ac_controls.b[0] = AUDIO_SUBFMT_END;
+ break;
+ }
+
+ break;
+
+ /* Provide capabilities of our OUTPUT unit */
+
+ case AUDIO_TYPE_OUTPUT:
+ case AUDIO_TYPE_INPUT:
+
+ caps->ac_channels = 2;
+
+ switch (caps->ac_subtype)
+ {
+ case AUDIO_TYPE_QUERY:
+
+ /* Report the Sample rates we support */
+
+ caps->ac_controls.hw[0] = AUDIO_SAMP_RATE_8K |
+ AUDIO_SAMP_RATE_11K |
+ AUDIO_SAMP_RATE_16K |
+ AUDIO_SAMP_RATE_22K |
+ AUDIO_SAMP_RATE_32K |
+ AUDIO_SAMP_RATE_44K |
+ AUDIO_SAMP_RATE_48K |
+ AUDIO_SAMP_RATE_96K |
+ AUDIO_SAMP_RATE_128K |
+ AUDIO_SAMP_RATE_160K |
+ AUDIO_SAMP_RATE_172K |
+ AUDIO_SAMP_RATE_192K;
+ break;
+ }
+
+ break;
+ }
+
+ /* Return the length of the audio_caps_s struct for validation of
+ * proper Audio device type.
+ */
+
+ return caps->ac_len;
+}
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_configure(struct audio_lowerhalf_s *dev,
+ void *session,
+ const struct audio_caps_s *caps)
+#else
+static int audio_dma_configure(struct audio_lowerhalf_s *dev,
+ const struct audio_caps_s *caps)
+#endif
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+ struct dma_config_s cfg;
+ int ret = -EINVAL;
+
+ DEBUGASSERT(audio_dma && caps);
+ audinfo("ac_type: %d\n", caps->ac_type);
+
+ /* Process the configure operation */
+
+ switch (caps->ac_type)
+ {
+ case AUDIO_TYPE_OUTPUT:
+ if (audio_dma->playback)
+ {
+ memset(&cfg, 0, sizeof(struct dma_config_s));
+ cfg.direction = DMA_MEM_TO_DEV;
+ if (audio_dma->fifo_width)
+ cfg.dst_width = audio_dma->fifo_width;
+ else
+ cfg.dst_width = caps->ac_controls.b[2] / 8;
+ ret = DMA_CONFIG(audio_dma->chan, &cfg);
+ }
+ break;
+ case AUDIO_TYPE_INPUT:
+ if (!audio_dma->playback)
+ {
+ memset(&cfg, 0, sizeof(struct dma_config_s));
+ cfg.direction = DMA_DEV_TO_MEM;
+ if (audio_dma->fifo_width)
+ cfg.src_width = audio_dma->fifo_width;
+ else
+ cfg.src_width = caps->ac_controls.b[2] / 8;
+ ret = DMA_CONFIG(audio_dma->chan, &cfg);
+ }
+ break;
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+static int audio_dma_shutdown(struct audio_lowerhalf_s *dev)
+{
+ /* apps enqueued buffers, but doesn't start. stop here to
+ * clear audio_dma->pendq.
+ */
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ audio_dma_stop(dev, NULL);
+#else
+ audio_dma_stop(dev);
+#endif
+#endif
+
+ return OK;
+}
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_start(struct audio_lowerhalf_s *dev, void *session)
+#else
+static int audio_dma_start(struct audio_lowerhalf_s *dev)
+#endif
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+
+ return DMA_START_CYCLIC(audio_dma->chan, audio_dma_callback, audio_dma,
+ audio_dma->dst_addr, audio_dma->src_addr,
+ audio_dma->buffer_num * audio_dma->buffer_size,
+ audio_dma->buffer_size);
+}
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_stop(struct audio_lowerhalf_s *dev, void *session)
+#else
+static int audio_dma_stop(struct audio_lowerhalf_s *dev)
+#endif
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+ struct ap_buffer_s *apb;
+
+ DMA_STOP(audio_dma->chan);
+
+ while (!dq_empty(&audio_dma->pendq))
+ {
+ apb = (struct ap_buffer_s *)dq_remfirst(&audio_dma->pendq);
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ audio_dma->dev.upper(audio_dma->dev.priv, AUDIO_CALLBACK_DEQUEUE,
+ apb, OK, NULL);
+#else
+ audio_dma->dev.upper(audio_dma->dev.priv, AUDIO_CALLBACK_DEQUEUE,
+ apb, OK);
+#endif
+ }
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ audio_dma->dev.upper(audio_dma->dev.priv, AUDIO_CALLBACK_COMPLETE,
+ NULL, OK, NULL);
+#else
+ audio_dma->dev.upper(audio_dma->dev.priv, AUDIO_CALLBACK_COMPLETE,
+ NULL, OK);
+#endif
+ audio_dma->xrun = false;
+ return OK;
+}
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_pause(struct audio_lowerhalf_s *dev, void *session)
+#else
+static int audio_dma_pause(struct audio_lowerhalf_s *dev)
+#endif
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+
+ return DMA_PAUSE(audio_dma->chan);
+}
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_resume(struct audio_lowerhalf_s *dev, void *session)
+#else
+static int audio_dma_resume(struct audio_lowerhalf_s *dev)
+#endif
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+
+ if (dq_empty(&audio_dma->pendq))
+ {
+ return -EINVAL;
+ }
+
+ return DMA_RESUME(audio_dma->chan);
+}
+#endif
+
+static int audio_dma_allocbuffer(struct audio_lowerhalf_s *dev,
+ struct audio_buf_desc_s *bufdesc)
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+ struct ap_buffer_s *apb;
+
+ if (bufdesc->numbytes != audio_dma->buffer_size)
+ {
+ return -EINVAL;
+ }
+
+ if (audio_dma->alloc_index == audio_dma->buffer_num)
+ {
+ return -ENOMEM;
+ }
+
+ if (!audio_dma->alloc_addr)
+ {
+ audio_dma->alloc_addr = kumm_memalign(32,
+ audio_dma->buffer_num *
+ audio_dma->buffer_size);
+ if (!audio_dma->alloc_addr)
+ {
+ return -ENOMEM;
+ }
+
+ if (audio_dma->playback)
+ audio_dma->src_addr = up_addrenv_va_to_pa(audio_dma->alloc_addr);
+ else
+ audio_dma->dst_addr = up_addrenv_va_to_pa(audio_dma->alloc_addr);
+ }
+
+ apb = kumm_zalloc(sizeof(struct ap_buffer_s));
+ *bufdesc->u.pbuffer = apb;
+
+ /* Test if the allocation was successful or not */
+
+ if (*bufdesc->u.pbuffer == NULL)
+ {
+ return -ENOMEM;
+ }
+
+ /* Populate the buffer contents */
+
+ apb->i.channels = 2;
+ apb->crefs = 1;
+ apb->nmaxbytes = audio_dma->buffer_size;
+ apb->samp = audio_dma->alloc_addr +
+ audio_dma->alloc_index *
+ audio_dma->buffer_size;
+ audio_dma->alloc_index++;
+ nxmutex_init(&apb->lock);
+
+ return sizeof(struct audio_buf_desc_s);
+}
+
+static int audio_dma_freebuffer(struct audio_lowerhalf_s *dev,
+ struct audio_buf_desc_s *bufdesc)
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+ struct ap_buffer_s *apb;
+
+ apb = bufdesc->u.buffer;
+ audio_dma->alloc_index--;
+ nxmutex_destroy(&apb->lock);
+ kumm_free(apb);
+
+ if (audio_dma->alloc_index == 0)
+ {
+ kumm_free(audio_dma->alloc_addr);
+ audio_dma->alloc_addr = NULL;
+ }
+
+ return sizeof(struct audio_buf_desc_s);
+}
+
+static int audio_dma_enqueuebuffer(struct audio_lowerhalf_s *dev,
+ struct ap_buffer_s *apb)
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+ irqstate_t flags;
+
+ if (audio_dma->playback)
+ up_clean_dcache((uintptr_t)apb->samp,
+ (uintptr_t)apb->samp + apb->nbytes);
+
+ apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
+
+ flags = enter_critical_section();
+ dq_addlast(&apb->dq_entry, &audio_dma->pendq);
+ leave_critical_section(flags);
+
+ if (audio_dma->xrun)
+ {
+ audio_dma->xrun = false;
+ return audio_dma_resume(dev);
+ }
+
+ return OK;
+}
+
+static int audio_dma_ioctl(struct audio_lowerhalf_s *dev, int cmd,
+ unsigned long arg)
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)dev;
+ struct ap_buffer_info_s *bufinfo;
+
+ switch (cmd)
+ {
+ /* Report our preferred buffer size and quantity */
+
+ case AUDIOIOC_GETBUFFERINFO:
+ audinfo("AUDIOIOC_GETBUFFERINFO:\n");
+ bufinfo = (struct ap_buffer_info_s *)arg;
+ bufinfo->buffer_size = audio_dma->buffer_size;
+ bufinfo->nbuffers = audio_dma->buffer_num;
+
+ return OK;
+
+ case AUDIOIOC_SETBUFFERINFO:
+ audinfo("AUDIOIOC_GETBUFFERINFO:\n");
+ bufinfo = (struct ap_buffer_info_s *)arg;
+ audio_dma->buffer_size = bufinfo->buffer_size;
+ audio_dma->buffer_num = bufinfo->nbuffers;
+ kumm_free(audio_dma->alloc_addr);
+ audio_dma->alloc_addr = NULL;
+ audio_dma->alloc_index = 0;
+
+ return OK;
+ }
+
+ return -ENOTTY;
+}
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_reserve(struct audio_lowerhalf_s *dev, void **session)
+#else
+static int audio_dma_reserve(struct audio_lowerhalf_s *dev)
+#endif
+{
+ return OK;
+}
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+static int audio_dma_release(struct audio_lowerhalf_s *dev, void *session)
+#else
+static int audio_dma_release(struct audio_lowerhalf_s *dev)
+#endif
+{
+ return OK;
+}
+
+static void audio_dma_callback(struct dma_chan_s *chan,
+ void *arg, ssize_t len)
+{
+ struct audio_dma_s *audio_dma = (struct audio_dma_s *)arg;
+ struct ap_buffer_s *apb;
+ bool final = false;
+
+ apb = (struct ap_buffer_s *)dq_remfirst(&audio_dma->pendq);
+ if (!apb)
+ {
+ /* xrun */
+
+ DMA_PAUSE(audio_dma->chan);
+ audio_dma->xrun = true;
+ return;
+ }
+
+ if (!audio_dma->playback)
+ up_invalidate_dcache((uintptr_t)apb->samp,
+ (uintptr_t)apb->samp + apb->nbytes);
+
+ if ((apb->flags & AUDIO_APB_FINAL) != 0)
+ final = true;
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ audio_dma->dev.upper(audio_dma->dev.priv, AUDIO_CALLBACK_DEQUEUE,
+ apb, OK, NULL);
+#else
+ audio_dma->dev.upper(audio_dma->dev.priv, AUDIO_CALLBACK_DEQUEUE,
+ apb, OK);
+#endif
+ if (final)
+ {
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ audio_dma_stop(&audio_dma->dev, NULL);
+#else
+ audio_dma_stop(&audio_dma->dev);
+#endif
+ }
+ else if (dq_empty(&audio_dma->pendq))
+ {
+ /* xrun */
+
+ DMA_PAUSE(audio_dma->chan);
+ audio_dma->xrun = true;
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+struct audio_lowerhalf_s *audio_dma_initialize(struct dma_dev_s *dma_dev,
+ uint8_t chan_num,
+ bool playback,
+ uint8_t fifo_width,
+ uintptr_t fifo_addr)
+{
+ struct audio_dma_s *audio_dma;
+
+ if (!dma_dev)
+ {
+ return NULL;
+ }
+
+ audio_dma = kmm_zalloc(sizeof(struct audio_dma_s));
+ if (!audio_dma)
+ {
+ return NULL;
+ }
+
+ audio_dma->chan = DMA_GET_CHAN(dma_dev, chan_num);
+ if (!audio_dma->chan)
+ {
+ kmm_free(audio_dma);
+ return NULL;
+ }
+
+ audio_dma->playback = playback;
+ audio_dma->fifo_width = fifo_width;
+
+ if (audio_dma->playback)
+ audio_dma->dst_addr = up_addrenv_va_to_pa((void *)fifo_addr);
+ else
+ audio_dma->src_addr = up_addrenv_va_to_pa((void *)fifo_addr);
+
+ audio_dma->buffer_size = CONFIG_AUDIO_BUFFER_NUMBYTES;
+ audio_dma->buffer_num = CONFIG_AUDIO_NUM_BUFFERS;
+ dq_init(&audio_dma->pendq);
+
+ audio_dma->dev.ops = &g_audio_dma_ops;
+ return &audio_dma->dev;
+}
diff --git a/include/nuttx/audio/audio_dma.h b/include/nuttx/audio/audio_dma.h
new file mode 100644
index 0000000000..4ad79431ab
--- /dev/null
+++ b/include/nuttx/audio/audio_dma.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+ * include/nuttx/audio/audio_dma.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_AUDIO_AUDIO_DMA_H
+#define __INCLUDE_NUTTX_AUDIO_AUDIO_DMA_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/audio/audio.h>
+#include <nuttx/dma/dma.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+struct audio_lowerhalf_s *audio_dma_initialize(struct dma_dev_s *dma_dev,
+ uint8_t chan_num,
+ bool playback,
+ uint8_t fifo_width,
+ uintptr_t fifo_addr);
+#endif