18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * kirkwood-dma.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) 2010 Arnaud Patard <apatard@mandriva.com> 68c2ecf20Sopenharmony_ci * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 168c2ecf20Sopenharmony_ci#include <linux/mbus.h> 178c2ecf20Sopenharmony_ci#include <sound/soc.h> 188c2ecf20Sopenharmony_ci#include "kirkwood.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *soc_runtime = subs->private_data; 238c2ecf20Sopenharmony_ci return snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(soc_runtime, 0)); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware kirkwood_dma_snd_hw = { 278c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 288c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 298c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 308c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 318c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 328c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 338c2ecf20Sopenharmony_ci .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES, 348c2ecf20Sopenharmony_ci .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, 358c2ecf20Sopenharmony_ci .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, 368c2ecf20Sopenharmony_ci .periods_min = KIRKWOOD_SND_MIN_PERIODS, 378c2ecf20Sopenharmony_ci .periods_max = KIRKWOOD_SND_MAX_PERIODS, 388c2ecf20Sopenharmony_ci .fifo_size = 0, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct kirkwood_dma_data *priv = dev_id; 448c2ecf20Sopenharmony_ci unsigned long mask, status, cause; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci mask = readl(priv->io + KIRKWOOD_INT_MASK); 478c2ecf20Sopenharmony_ci status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci cause = readl(priv->io + KIRKWOOD_ERR_CAUSE); 508c2ecf20Sopenharmony_ci if (unlikely(cause)) { 518c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: got err interrupt 0x%lx\n", 528c2ecf20Sopenharmony_ci __func__, cause); 538c2ecf20Sopenharmony_ci writel(cause, priv->io + KIRKWOOD_ERR_CAUSE); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* we've enabled only bytes interrupts ... */ 578c2ecf20Sopenharmony_ci if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \ 588c2ecf20Sopenharmony_ci KIRKWOOD_INT_CAUSE_REC_BYTES)) { 598c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unexpected interrupt %lx\n", 608c2ecf20Sopenharmony_ci __func__, status); 618c2ecf20Sopenharmony_ci return IRQ_NONE; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* ack int */ 658c2ecf20Sopenharmony_ci writel(status, priv->io + KIRKWOOD_INT_CAUSE); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES) 688c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(priv->substream_play); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (status & KIRKWOOD_INT_CAUSE_REC_BYTES) 718c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(priv->substream_rec); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return IRQ_HANDLED; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic void 778c2ecf20Sopenharmony_cikirkwood_dma_conf_mbus_windows(void __iomem *base, int win, 788c2ecf20Sopenharmony_ci unsigned long dma, 798c2ecf20Sopenharmony_ci const struct mbus_dram_target_info *dram) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int i; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* First disable and clear windows */ 848c2ecf20Sopenharmony_ci writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win)); 858c2ecf20Sopenharmony_ci writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* try to find matching cs for current dma address */ 888c2ecf20Sopenharmony_ci for (i = 0; i < dram->num_cs; i++) { 898c2ecf20Sopenharmony_ci const struct mbus_dram_window *cs = &dram->cs[i]; 908c2ecf20Sopenharmony_ci if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) { 918c2ecf20Sopenharmony_ci writel(cs->base & 0xffff0000, 928c2ecf20Sopenharmony_ci base + KIRKWOOD_AUDIO_WIN_BASE_REG(win)); 938c2ecf20Sopenharmony_ci writel(((cs->size - 1) & 0xffff0000) | 948c2ecf20Sopenharmony_ci (cs->mbus_attr << 8) | 958c2ecf20Sopenharmony_ci (dram->mbus_dram_target_id << 4) | 1, 968c2ecf20Sopenharmony_ci base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win)); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int kirkwood_dma_open(struct snd_soc_component *component, 1028c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int err; 1058c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 1068c2ecf20Sopenharmony_ci struct kirkwood_dma_data *priv = kirkwood_priv(substream); 1078c2ecf20Sopenharmony_ci const struct mbus_dram_target_info *dram; 1088c2ecf20Sopenharmony_ci unsigned long addr; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Ensure that all constraints linked to dma burst are fulfilled */ 1138c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(runtime, 1148c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1158c2ecf20Sopenharmony_ci priv->burst * 2, 1168c2ecf20Sopenharmony_ci KIRKWOOD_AUDIO_BUF_MAX-1); 1178c2ecf20Sopenharmony_ci if (err < 0) 1188c2ecf20Sopenharmony_ci return err; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_step(runtime, 0, 1218c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1228c2ecf20Sopenharmony_ci priv->burst); 1238c2ecf20Sopenharmony_ci if (err < 0) 1248c2ecf20Sopenharmony_ci return err; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_step(substream->runtime, 0, 1278c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 1288c2ecf20Sopenharmony_ci priv->burst); 1298c2ecf20Sopenharmony_ci if (err < 0) 1308c2ecf20Sopenharmony_ci return err; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (!priv->substream_play && !priv->substream_rec) { 1338c2ecf20Sopenharmony_ci err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED, 1348c2ecf20Sopenharmony_ci "kirkwood-i2s", priv); 1358c2ecf20Sopenharmony_ci if (err) 1368c2ecf20Sopenharmony_ci return err; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * Enable Error interrupts. We're only ack'ing them but 1408c2ecf20Sopenharmony_ci * it's useful for diagnostics 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci dram = mv_mbus_dram_info(); 1468c2ecf20Sopenharmony_ci addr = substream->dma_buffer.addr; 1478c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1488c2ecf20Sopenharmony_ci if (priv->substream_play) 1498c2ecf20Sopenharmony_ci return -EBUSY; 1508c2ecf20Sopenharmony_ci priv->substream_play = substream; 1518c2ecf20Sopenharmony_ci kirkwood_dma_conf_mbus_windows(priv->io, 1528c2ecf20Sopenharmony_ci KIRKWOOD_PLAYBACK_WIN, addr, dram); 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci if (priv->substream_rec) 1558c2ecf20Sopenharmony_ci return -EBUSY; 1568c2ecf20Sopenharmony_ci priv->substream_rec = substream; 1578c2ecf20Sopenharmony_ci kirkwood_dma_conf_mbus_windows(priv->io, 1588c2ecf20Sopenharmony_ci KIRKWOOD_RECORD_WIN, addr, dram); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int kirkwood_dma_close(struct snd_soc_component *component, 1658c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct kirkwood_dma_data *priv = kirkwood_priv(substream); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!priv) 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1738c2ecf20Sopenharmony_ci priv->substream_play = NULL; 1748c2ecf20Sopenharmony_ci else 1758c2ecf20Sopenharmony_ci priv->substream_rec = NULL; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!priv->substream_play && !priv->substream_rec) { 1788c2ecf20Sopenharmony_ci writel(0, priv->io + KIRKWOOD_ERR_MASK); 1798c2ecf20Sopenharmony_ci free_irq(priv->irq, priv); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int kirkwood_dma_hw_params(struct snd_soc_component *component, 1868c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 1878c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 1928c2ecf20Sopenharmony_ci runtime->dma_bytes = params_buffer_bytes(params); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int kirkwood_dma_hw_free(struct snd_soc_component *component, 1988c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci snd_pcm_set_runtime_buffer(substream, NULL); 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int kirkwood_dma_prepare(struct snd_soc_component *component, 2058c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 2088c2ecf20Sopenharmony_ci struct kirkwood_dma_data *priv = kirkwood_priv(substream); 2098c2ecf20Sopenharmony_ci unsigned long size, count; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* compute buffer size in term of "words" as requested in specs */ 2128c2ecf20Sopenharmony_ci size = frames_to_bytes(runtime, runtime->buffer_size); 2138c2ecf20Sopenharmony_ci size = (size>>2)-1; 2148c2ecf20Sopenharmony_ci count = snd_pcm_lib_period_bytes(substream); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 2178c2ecf20Sopenharmony_ci writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT); 2188c2ecf20Sopenharmony_ci writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR); 2198c2ecf20Sopenharmony_ci writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE); 2208c2ecf20Sopenharmony_ci } else { 2218c2ecf20Sopenharmony_ci writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT); 2228c2ecf20Sopenharmony_ci writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR); 2238c2ecf20Sopenharmony_ci writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t kirkwood_dma_pointer( 2318c2ecf20Sopenharmony_ci struct snd_soc_component *component, 2328c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct kirkwood_dma_data *priv = kirkwood_priv(substream); 2358c2ecf20Sopenharmony_ci snd_pcm_uframes_t count; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2388c2ecf20Sopenharmony_ci count = bytes_to_frames(substream->runtime, 2398c2ecf20Sopenharmony_ci readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT)); 2408c2ecf20Sopenharmony_ci else 2418c2ecf20Sopenharmony_ci count = bytes_to_frames(substream->runtime, 2428c2ecf20Sopenharmony_ci readl(priv->io + KIRKWOOD_REC_BYTE_COUNT)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return count; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, 2488c2ecf20Sopenharmony_ci int stream) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = pcm->streams[stream].substream; 2518c2ecf20Sopenharmony_ci struct snd_dma_buffer *buf = &substream->dma_buffer; 2528c2ecf20Sopenharmony_ci size_t size = kirkwood_dma_snd_hw.buffer_bytes_max; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci buf->dev.type = SNDRV_DMA_TYPE_DEV; 2558c2ecf20Sopenharmony_ci buf->dev.dev = pcm->card->dev; 2568c2ecf20Sopenharmony_ci buf->area = dma_alloc_coherent(pcm->card->dev, size, 2578c2ecf20Sopenharmony_ci &buf->addr, GFP_KERNEL); 2588c2ecf20Sopenharmony_ci if (!buf->area) 2598c2ecf20Sopenharmony_ci return -ENOMEM; 2608c2ecf20Sopenharmony_ci buf->bytes = size; 2618c2ecf20Sopenharmony_ci buf->private_data = NULL; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int kirkwood_dma_new(struct snd_soc_component *component, 2678c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct snd_card *card = rtd->card->snd_card; 2708c2ecf20Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 2718c2ecf20Sopenharmony_ci int ret; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); 2748c2ecf20Sopenharmony_ci if (ret) 2758c2ecf20Sopenharmony_ci return ret; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 2788c2ecf20Sopenharmony_ci ret = kirkwood_dma_preallocate_dma_buffer(pcm, 2798c2ecf20Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK); 2808c2ecf20Sopenharmony_ci if (ret) 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 2858c2ecf20Sopenharmony_ci ret = kirkwood_dma_preallocate_dma_buffer(pcm, 2868c2ecf20Sopenharmony_ci SNDRV_PCM_STREAM_CAPTURE); 2878c2ecf20Sopenharmony_ci if (ret) 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void kirkwood_dma_free_dma_buffers(struct snd_soc_component *component, 2958c2ecf20Sopenharmony_ci struct snd_pcm *pcm) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 2988c2ecf20Sopenharmony_ci struct snd_dma_buffer *buf; 2998c2ecf20Sopenharmony_ci int stream; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci for (stream = 0; stream < 2; stream++) { 3028c2ecf20Sopenharmony_ci substream = pcm->streams[stream].substream; 3038c2ecf20Sopenharmony_ci if (!substream) 3048c2ecf20Sopenharmony_ci continue; 3058c2ecf20Sopenharmony_ci buf = &substream->dma_buffer; 3068c2ecf20Sopenharmony_ci if (!buf->area) 3078c2ecf20Sopenharmony_ci continue; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci dma_free_coherent(pcm->card->dev, buf->bytes, 3108c2ecf20Sopenharmony_ci buf->area, buf->addr); 3118c2ecf20Sopenharmony_ci buf->area = NULL; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciconst struct snd_soc_component_driver kirkwood_soc_component = { 3168c2ecf20Sopenharmony_ci .name = DRV_NAME, 3178c2ecf20Sopenharmony_ci .open = kirkwood_dma_open, 3188c2ecf20Sopenharmony_ci .close = kirkwood_dma_close, 3198c2ecf20Sopenharmony_ci .hw_params = kirkwood_dma_hw_params, 3208c2ecf20Sopenharmony_ci .hw_free = kirkwood_dma_hw_free, 3218c2ecf20Sopenharmony_ci .prepare = kirkwood_dma_prepare, 3228c2ecf20Sopenharmony_ci .pointer = kirkwood_dma_pointer, 3238c2ecf20Sopenharmony_ci .pcm_construct = kirkwood_dma_new, 3248c2ecf20Sopenharmony_ci .pcm_destruct = kirkwood_dma_free_dma_buffers, 3258c2ecf20Sopenharmony_ci}; 326