^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * kirkwood-dma.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (c) 2010 Arnaud Patard <apatard@mandriva.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mbus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "kirkwood.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct snd_soc_pcm_runtime *soc_runtime = subs->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) return snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(soc_runtime, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static const struct snd_pcm_hardware kirkwood_dma_snd_hw = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) .info = SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) SNDRV_PCM_INFO_MMAP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) SNDRV_PCM_INFO_BLOCK_TRANSFER |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) SNDRV_PCM_INFO_PAUSE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .periods_min = KIRKWOOD_SND_MIN_PERIODS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .periods_max = KIRKWOOD_SND_MAX_PERIODS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .fifo_size = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct kirkwood_dma_data *priv = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long mask, status, cause;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) mask = readl(priv->io + KIRKWOOD_INT_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (unlikely(cause)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) __func__, cause);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* we've enabled only bytes interrupts ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) KIRKWOOD_INT_CAUSE_REC_BYTES)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) printk(KERN_WARNING "%s: unexpected interrupt %lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* ack int */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) writel(status, priv->io + KIRKWOOD_INT_CAUSE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) snd_pcm_period_elapsed(priv->substream_play);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) snd_pcm_period_elapsed(priv->substream_rec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned long dma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) const struct mbus_dram_target_info *dram)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* First disable and clear windows */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* try to find matching cs for current dma address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) for (i = 0; i < dram->num_cs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) const struct mbus_dram_window *cs = dram->cs + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) writel(cs->base & 0xffff0000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) writel(((cs->size - 1) & 0xffff0000) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) (cs->mbus_attr << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) (dram->mbus_dram_target_id << 4) | 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int kirkwood_dma_open(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct kirkwood_dma_data *priv = kirkwood_priv(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) const struct mbus_dram_target_info *dram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* Ensure that all constraints linked to dma burst are fulfilled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) err = snd_pcm_hw_constraint_minmax(runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) priv->burst * 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) KIRKWOOD_AUDIO_BUF_MAX-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) err = snd_pcm_hw_constraint_step(runtime, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) priv->burst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) err = snd_pcm_hw_constraint_step(substream->runtime, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) priv->burst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!priv->substream_play && !priv->substream_rec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) "kirkwood-i2s", priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * Enable Error interrupts. We're only ack'ing them but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * it's useful for diagnostics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) dram = mv_mbus_dram_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) addr = substream->dma_buffer.addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (priv->substream_play)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) priv->substream_play = substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) kirkwood_dma_conf_mbus_windows(priv->io,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) KIRKWOOD_PLAYBACK_WIN, addr, dram);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (priv->substream_rec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) priv->substream_rec = substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) kirkwood_dma_conf_mbus_windows(priv->io,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) KIRKWOOD_RECORD_WIN, addr, dram);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int kirkwood_dma_close(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct kirkwood_dma_data *priv = kirkwood_priv(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) priv->substream_play = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) priv->substream_rec = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (!priv->substream_play && !priv->substream_rec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) writel(0, priv->io + KIRKWOOD_ERR_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) free_irq(priv->irq, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int kirkwood_dma_hw_params(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) runtime->dma_bytes = params_buffer_bytes(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static int kirkwood_dma_hw_free(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) snd_pcm_set_runtime_buffer(substream, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static int kirkwood_dma_prepare(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct kirkwood_dma_data *priv = kirkwood_priv(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) unsigned long size, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* compute buffer size in term of "words" as requested in specs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) size = frames_to_bytes(runtime, runtime->buffer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) size = (size>>2)-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) count = snd_pcm_lib_period_bytes(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static snd_pcm_uframes_t kirkwood_dma_pointer(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct kirkwood_dma_data *priv = kirkwood_priv(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) snd_pcm_uframes_t count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) count = bytes_to_frames(substream->runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) count = bytes_to_frames(substream->runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) int stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct snd_pcm_substream *substream = pcm->streams[stream].substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) struct snd_dma_buffer *buf = &substream->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) buf->dev.type = SNDRV_DMA_TYPE_DEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) buf->dev.dev = pcm->card->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) buf->area = dma_alloc_coherent(pcm->card->dev, size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) &buf->addr, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (!buf->area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) buf->bytes = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) buf->private_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static int kirkwood_dma_new(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct snd_card *card = rtd->card->snd_card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) struct snd_pcm *pcm = rtd->pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) ret = kirkwood_dma_preallocate_dma_buffer(pcm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) SNDRV_PCM_STREAM_PLAYBACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) ret = kirkwood_dma_preallocate_dma_buffer(pcm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) SNDRV_PCM_STREAM_CAPTURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static void kirkwood_dma_free_dma_buffers(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct snd_pcm *pcm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct snd_pcm_substream *substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct snd_dma_buffer *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) for (stream = 0; stream < 2; stream++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) substream = pcm->streams[stream].substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (!substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) buf = &substream->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (!buf->area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) dma_free_coherent(pcm->card->dev, buf->bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) buf->area, buf->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) buf->area = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) const struct snd_soc_component_driver kirkwood_soc_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .open = kirkwood_dma_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .close = kirkwood_dma_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .hw_params = kirkwood_dma_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .hw_free = kirkwood_dma_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .prepare = kirkwood_dma_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .pointer = kirkwood_dma_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .pcm_construct = kirkwood_dma_new,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .pcm_destruct = kirkwood_dma_free_dma_buffers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) };