static void rsnd_dma_of_path(struct rsnd_dma *dma, int is_play, struct rsnd_mod **mod_from, struct rsnd_mod **mod_to) { struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_dai_stream *io = rsnd_mod_to_io(this); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; int i, index; for (i = 0; i < MOD_MAX; i++) mod[i] = NULL; /* * in play case... * * src -> dst * * mem -> SSI * mem -> SRC -> SSI * mem -> SRC -> DVC -> SSI */ mod[0] = NULL; /* for "mem" */ index = 1; for (i = 1; i < MOD_MAX; i++) { if (!src) { mod[i] = ssi; } else if (!dvc) { mod[i] = src; src = NULL; } else { if ((!is_play) && (this == src)) this = dvc; mod[i] = (is_play) ? src : dvc; i++; mod[i] = (is_play) ? dvc : src; src = NULL; dvc = NULL; } if (mod[i] == this) index = i; if (mod[i] == ssi) break; } if (is_play) { *mod_from = mod[index - 1]; *mod_to = mod[index]; } else { *mod_from = mod[index]; *mod_to = mod[index - 1]; } }
static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) { struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; int is_play = rsnd_io_is_play(io); desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); return; } desc->callback = rsnd_dmaen_complete; desc->callback_param = mod; if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return; } dma_async_issue_pending(dmaen->chan); }
void rsnd_dma_start(struct rsnd_dma *dma) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; desc = dmaengine_prep_dma_cyclic(dma->chan, (dma->addr) ? dma->addr : substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), dma->dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); return; } desc->callback = rsnd_dma_complete; desc->callback_param = dma; if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return; } dma_async_issue_pending(dma->chan); }
static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); }
static void rsnd_dma_of_name(struct rsnd_dma *dma, int is_play, char *dma_name) { struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_dai_stream *io = rsnd_mod_to_io(this); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; struct rsnd_mod *src_mod, *dst_mod; int i, index; for (i = 0; i < MOD_MAX; i++) mod[i] = NULL; /* * in play case... * * src -> dst * * mem -> SSI * mem -> SRC -> SSI * mem -> SRC -> DVC -> SSI */ mod[0] = NULL; /* for "mem" */ index = 1; for (i = 1; i < MOD_MAX; i++) { if (!src) { mod[i] = ssi; } else if (!dvc) { mod[i] = src; src = NULL; } else { mod[i] = dvc; dvc = NULL; } if (mod[i] == this) index = i; if (mod[i] == ssi) break; } if (is_play) { src_mod = mod[index - 1]; dst_mod = mod[index]; } else { src_mod = mod[index]; dst_mod = mod[index + 1]; } index = 0; index = _rsnd_dma_of_name(dma_name + index, src_mod); *(dma_name + index++) = '_'; index = _rsnd_dma_of_name(dma_name + index, dst_mod); }
void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); if (!dmac) return; dma->ops->quit(io, dma); }
static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); }
static void rsnd_dma_complete(void *data) { struct rsnd_dma *dma = (struct rsnd_dma *)data; struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); /* * Renesas sound Gen1 needs 1 DMAC, * Gen2 needs 2 DMAC. * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. * But, Audio-DMAC-peri-peri doesn't have interrupt, * and this driver is assuming that here. * * If Audio-DMAC-peri-peri has interrpt, * rsnd_dai_pointer_update() will be called twice, * ant it will breaks io->byte_pos */ rsnd_dai_pointer_update(io, io->byte_per_period); }