return mod->ops->name;
}
--- -char *rsnd_mod_dma_name(struct rsnd_mod *mod)
+++ +struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod)
{
--- - if (!mod || !mod->ops)
--- - return "unknown";
--- -
--- - if (!mod->ops->dma_name)
--- - return mod->ops->name;
+++ + if (!mod || !mod->ops || !mod->ops->dma_req)
+++ + return NULL;
--- - return mod->ops->dma_name(mod);
+++ + return mod->ops->dma_req(mod);
}
- void rsnd_mod_init(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- -void rsnd_mod_init(struct rsnd_mod *mod,
++ +int rsnd_mod_init(struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
+ struct clk *clk,
enum rsnd_mod_type type,
int id)
{
- mod->priv = priv;
++ + int ret = clk_prepare(clk);
++ +
++ + if (ret)
++ + return ret;
++ +
mod->id = id;
mod->ops = ops;
mod->type = type;
- }
-
- /*
- * rsnd_dma functions
- */
- void rsnd_dma_stop(struct rsnd_dma *dma)
- {
- dmaengine_terminate_all(dma->chan);
- }
-
- 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);
- }
-
- 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);
- }
-
- int rsnd_dma_available(struct rsnd_dma *dma)
- {
- return !!dma->chan;
- }
-
- #define DMA_NAME_SIZE 16
- #define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
- static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
- {
- if (mod)
- return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
- rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
- else
- return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
-
- }
-
- static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
- struct rsnd_mod *mod_to,
- char *dma_name)
- {
- int index = 0;
-
- index = _rsnd_dma_of_name(dma_name + index, mod_from);
- *(dma_name + index++) = '_';
- index = _rsnd_dma_of_name(dma_name + index, mod_to);
- }
-
- 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;
- }
+ mod->clk = clk;
- -}
- -
- -/*
- - * rsnd_dma functions
- - */
- -void rsnd_dma_stop(struct rsnd_dma *dma)
- -{
- - dmaengine_terminate_all(dma->chan);
- -}
- -
- -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);
- -}
- -
- -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);
- -}
- -
- -int rsnd_dma_available(struct rsnd_dma *dma)
- -{
- - return !!dma->chan;
- -}
- -
- -#define DMA_NAME_SIZE 16
- -#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
- -static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
- -{
- - if (mod)
- - return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
- - rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
- - else
- - return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
- -
- -}
- -
- -static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
- - struct rsnd_mod *mod_to,
- - char *dma_name)
- -{
- - int index = 0;
- -
- - index = _rsnd_dma_of_name(dma_name + index, mod_from);
- - *(dma_name + index++) = '_';
- - index = _rsnd_dma_of_name(dma_name + index, mod_to);
- -}
- -
- -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];
-- - }
-- -}
-- -
-- -int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
-- - int is_play, int id)
-- -{
-- - struct device *dev = rsnd_priv_to_dev(priv);
-- - struct dma_slave_config cfg;
-- - struct rsnd_mod *mod_from;
-- - struct rsnd_mod *mod_to;
-- - char dma_name[DMA_NAME_SIZE];
-- - dma_cap_mask_t mask;
-- - int ret;
-- -
-- - if (dma->chan) {
-- - dev_err(dev, "it already has dma channel\n");
-- - return -EIO;
-- - }
-- -
-- - dma_cap_zero(mask);
-- - dma_cap_set(DMA_SLAVE, mask);
-- -
-- - rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
-- - rsnd_dma_of_name(mod_from, mod_to, dma_name);
-- -
-- - cfg.slave_id = id;
-- - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-- - cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1);
-- - cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0);
-- - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-- - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-- -
-- - dev_dbg(dev, "dma : %s %pad -> %pad\n",
-- - dma_name, &cfg.src_addr, &cfg.dst_addr);
-- -
-- - dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
-- - (void *)id, dev,
-- - dma_name);
-- - if (!dma->chan) {
-- - dev_err(dev, "can't get dma channel\n");
-- - goto rsnd_dma_channel_err;
-- - }
-- -
-- - ret = dmaengine_slave_config(dma->chan, &cfg);
-- - if (ret < 0)
-- - goto rsnd_dma_init_err;
-- -
-- - dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
-- - dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-- -
-- - return 0;
-- -
-- -rsnd_dma_init_err:
-- - rsnd_dma_quit(priv, dma);
-- -rsnd_dma_channel_err:
-- -
-- - /*
-- - * DMA failed. try to PIO mode
-- - * see
-- - * rsnd_ssi_fallback()
-- - * rsnd_rdai_continuance_probe()
-- - */
-- - return -EAGAIN;
++ + return ret;
}
-- -void rsnd_dma_quit(struct rsnd_priv *priv,
-- - struct rsnd_dma *dma)
++ +void rsnd_mod_quit(struct rsnd_mod *mod)
{
-- - if (dma->chan)
-- - dma_release_channel(dma->chan);
-- -
-- - dma->chan = NULL;
++ + if (mod->clk)
++ + clk_unprepare(mod->clk);
}
/*
drv[i].playback.formats = RSND_FMTS;
drv[i].playback.channels_min = 2;
drv[i].playback.channels_max = 2;
+++ + drv[i].playback.stream_name = rdai[i].playback.name;
rdai[i].playback.info = &info->dai_info[i].playback;
+ rdai[i].playback.rdai = rdai + i;
rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
}
if (cmod) {
drv[i].capture.formats = RSND_FMTS;
drv[i].capture.channels_min = 2;
drv[i].capture.channels_max = 2;
+++ + drv[i].capture.stream_name = rdai[i].capture.name;
rdai[i].capture.info = &info->dai_info[i].capture;
+ rdai[i].capture.rdai = rdai + i;
rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
}
pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) {
- ret |= rsnd_dai_call(remove, &rdai->playback, rdai);
- ret |= rsnd_dai_call(remove, &rdai->capture, rdai);
+ ret |= rsnd_dai_call(remove, &rdai->playback, priv);
+ ret |= rsnd_dai_call(remove, &rdai->capture, priv);
}
++ + for (i = 0; i < ARRAY_SIZE(remove_func); i++)
++ + remove_func[i](pdev, priv);
++ +
+ snd_soc_unregister_component(&pdev->dev);
+ snd_soc_unregister_platform(&pdev->dev);
+
return ret;
}