diff options
Diffstat (limited to 'sound/soc/sh/rcar')
-rw-r--r-- | sound/soc/sh/rcar/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 57 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 255 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 289 | ||||
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 120 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 78 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 236 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 117 |
8 files changed, 790 insertions, 364 deletions
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 7d0051ced83..9ac53642980 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,2 +1,2 @@ -snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o +snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
\ No newline at end of file diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 69c44269ebd..fc41a0e8b09 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -57,6 +57,24 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) return (0x6 + ws) << 8; } +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai, + struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + int id = rsnd_mod_id(mod); + int shift = (id % 2) ? 16 : 0; + u32 mask, val; + + val = rsnd_adg_ssi_ws_timing_gen2(io); + + val = val << shift; + mask = 0xffff << shift; + + rsnd_mod_bset(mod, CMDOUT_TIMSEL, mask, val); + + return 0; +} + static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai, struct rsnd_mod *mod, struct rsnd_dai_stream *io, @@ -397,9 +415,8 @@ int rsnd_adg_probe(struct platform_device *pdev, { struct rsnd_adg *adg; struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk, *clk_orig; + struct clk *clk; int i; - bool use_old_style = false; adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); if (!adg) { @@ -407,45 +424,13 @@ int rsnd_adg_probe(struct platform_device *pdev, return -ENOMEM; } - clk_orig = devm_clk_get(dev, NULL); adg->clk[CLKA] = devm_clk_get(dev, "clk_a"); adg->clk[CLKB] = devm_clk_get(dev, "clk_b"); adg->clk[CLKC] = devm_clk_get(dev, "clk_c"); adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); - /* - * It request device dependent audio clock. - * But above all clks will indicate rsnd module clock - * if platform doesn't it - */ - for_each_rsnd_clk(clk, adg, i) { - if (clk_orig == clk) { - dev_warn(dev, - "doesn't have device dependent clock, use independent clock\n"); - use_old_style = true; - break; - } - } - - /* - * note: - * these exist in order to keep compatible with - * platform which has device independent audio clock, - * but will be removed soon - */ - if (use_old_style) { - adg->clk[CLKA] = devm_clk_get(NULL, "audio_clk_a"); - adg->clk[CLKB] = devm_clk_get(NULL, "audio_clk_b"); - adg->clk[CLKC] = devm_clk_get(NULL, "audio_clk_c"); - adg->clk[CLKI] = devm_clk_get(NULL, "audio_clk_internal"); - } - - for_each_rsnd_clk(clk, adg, i) { - if (IS_ERR(clk)) { - dev_err(dev, "Audio clock failed\n"); - return -EIO; - } - } + for_each_rsnd_clk(clk, adg, i) + dev_dbg(dev, "clk %d : %p\n", i, clk); rsnd_adg_ssi_clk_init(priv, adg); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 215b668166b..91880156e1a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -197,13 +197,12 @@ static void rsnd_dma_complete(void *data) * rsnd_dai_pointer_update() will be called twice, * ant it will breaks io->byte_pos */ - - rsnd_dai_pointer_update(io, io->byte_per_period); - if (dma->submit_loop) rsnd_dma_continue(dma); rsnd_unlock(priv, flags); + + rsnd_dai_pointer_update(io, io->byte_per_period); } static void __rsnd_dma_start(struct rsnd_dma *dma) @@ -256,11 +255,81 @@ 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_name(mod), rsnd_mod_id(mod)); + else + return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); + +} + +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; + break; + } else if (!dvc) { + mod[i] = src; + src = NULL; + } else { + mod[i] = dvc; + dvc = NULL; + } + + if (mod[i] == this) + index = i; + } + + 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); +} + 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; + char dma_name[DMA_NAME_SIZE]; dma_cap_mask_t mask; int ret; @@ -272,18 +341,23 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); + if (dev->of_node) + rsnd_dma_of_name(dma, is_play, dma_name); + else + snprintf(dma_name, DMA_NAME_SIZE, + is_play ? "tx" : "rx"); + + dev_dbg(dev, "dma name : %s\n", dma_name); + dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, (void *)id, dev, - is_play ? "tx" : "rx"); + dma_name); if (!dma->chan) { dev_err(dev, "can't get dma channel\n"); return -EIO; } - cfg.slave_id = id; - cfg.dst_addr = 0; /* use default addr when playback */ - cfg.src_addr = 0; /* use default addr when capture */ - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id); ret = dmaengine_slave_config(dma->chan, &cfg); if (ret < 0) @@ -310,23 +384,49 @@ void rsnd_dma_quit(struct rsnd_priv *priv, } /* + * settting function + */ +u32 rsnd_get_adinr(struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct device *dev = rsnd_priv_to_dev(priv); + u32 adinr = runtime->channels; + + switch (runtime->sample_bits) { + case 16: + adinr |= (8 << 16); + break; + case 32: + adinr |= (0 << 16); + break; + default: + dev_warn(dev, "not supported sample bits\n"); + return 0; + } + + return adinr; +} + +/* * rsnd_dai functions */ -#define __rsnd_mod_call(mod, func, rdai, io) \ +#define __rsnd_mod_call(mod, func, rdai...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ struct device *dev = rsnd_priv_to_dev(priv); \ dev_dbg(dev, "%s [%d] %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ - (mod)->ops->func(mod, rdai, io); \ + (mod)->ops->func(mod, rdai); \ }) -#define rsnd_mod_call(mod, func, rdai, io) \ +#define rsnd_mod_call(mod, func, rdai...) \ (!(mod) ? -ENODEV : \ !((mod)->ops->func) ? 0 : \ - __rsnd_mod_call(mod, func, (rdai), (io))) + __rsnd_mod_call(mod, func, rdai)) -#define rsnd_dai_call(rdai, io, fn) \ +#define rsnd_dai_call(fn, io, rdai...) \ ({ \ struct rsnd_mod *mod; \ int ret = 0, i; \ @@ -334,7 +434,7 @@ void rsnd_dma_quit(struct rsnd_priv *priv, mod = (io)->mod[i]; \ if (!mod) \ continue; \ - ret = rsnd_mod_call(mod, fn, (rdai), (io)); \ + ret = rsnd_mod_call(mod, fn, rdai); \ if (ret < 0) \ break; \ } \ @@ -468,10 +568,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv, - rsnd_dai_id(priv, rdai), - rsnd_dai_is_play(rdai, io)); - int ssi_id = rsnd_mod_id(mod); + int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); int ret; unsigned long flags; @@ -487,20 +584,20 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, if (ret < 0) goto dai_trigger_end; - ret = rsnd_dai_call(rdai, io, init); + ret = rsnd_dai_call(init, io, rdai); if (ret < 0) goto dai_trigger_end; - ret = rsnd_dai_call(rdai, io, start); + ret = rsnd_dai_call(start, io, rdai); if (ret < 0) goto dai_trigger_end; break; case SNDRV_PCM_TRIGGER_STOP: - ret = rsnd_dai_call(rdai, io, stop); + ret = rsnd_dai_call(stop, io, rdai); if (ret < 0) goto dai_trigger_end; - ret = rsnd_dai_call(rdai, io, quit); + ret = rsnd_dai_call(quit, io, rdai); if (ret < 0) goto dai_trigger_end; @@ -579,15 +676,27 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, }; +#define rsnd_path_parse(priv, io, type) \ +({ \ + struct rsnd_mod *mod; \ + int ret = 0; \ + int id = -1; \ + \ + if (rsnd_is_enable_path(io, type)) { \ + id = rsnd_info_id(priv, io, type); \ + if (id >= 0) { \ + mod = rsnd_##type##_mod_get(priv, id); \ + ret = rsnd_dai_connect(mod, io); \ + } \ + } \ + ret; \ +}) + static int rsnd_path_init(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { - struct rsnd_mod *mod; - struct rsnd_dai_platform_info *dai_info = rdai->info; int ret; - int ssi_id = -1; - int src_id = -1; /* * Gen1 is created by SRU/SSI, and this SRU is base module of @@ -599,38 +708,21 @@ static int rsnd_path_init(struct rsnd_priv *priv, * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is * using fixed path. */ - if (dai_info) { - if (rsnd_is_enable_path(io, ssi)) - ssi_id = rsnd_info_id(priv, io, ssi); - if (rsnd_is_enable_path(io, src)) - src_id = rsnd_info_id(priv, io, src); - } else { - /* get SSI's ID */ - mod = rsnd_ssi_mod_get_frm_dai(priv, - rsnd_dai_id(priv, rdai), - rsnd_dai_is_play(rdai, io)); - if (!mod) - return 0; - ssi_id = src_id = rsnd_mod_id(mod); - } - - ret = 0; /* SRC */ - if (src_id >= 0) { - mod = rsnd_src_mod_get(priv, src_id); - ret = rsnd_dai_connect(mod, io); - if (ret < 0) - return ret; - } + ret = rsnd_path_parse(priv, io, src); + if (ret < 0) + return ret; /* SSI */ - if (ssi_id >= 0) { - mod = rsnd_ssi_mod_get(priv, ssi_id); - ret = rsnd_dai_connect(mod, io); - if (ret < 0) - return ret; - } + ret = rsnd_path_parse(priv, io, ssi); + if (ret < 0) + return ret; + + /* DVC */ + ret = rsnd_path_parse(priv, io, dvc); + if (ret < 0) + return ret; return ret; } @@ -726,30 +818,15 @@ static int rsnd_dai_probe(struct platform_device *pdev, struct snd_soc_dai_driver *drv; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct rsnd_dai *rdai; - struct rsnd_mod *pmod, *cmod; + struct rsnd_ssi_platform_info *pmod, *cmod; struct device *dev = rsnd_priv_to_dev(priv); int dai_nr; int i; rsnd_of_parse_dai(pdev, of_data, priv); - /* - * dai_nr should be set via dai_info_nr, - * but allow it to keeping compatible - */ dai_nr = info->dai_info_nr; if (!dai_nr) { - /* get max dai nr */ - for (dai_nr = 0; dai_nr < 32; dai_nr++) { - pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); - cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); - - if (!pmod && !cmod) - break; - } - } - - if (!dai_nr) { dev_err(dev, "no dai\n"); return -EIO; } @@ -766,11 +843,10 @@ static int rsnd_dai_probe(struct platform_device *pdev, priv->rdai = rdai; for (i = 0; i < dai_nr; i++) { - if (info->dai_info) - rdai[i].info = &info->dai_info[i]; + rdai[i].info = &info->dai_info[i]; - pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); - cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); + pmod = rdai[i].info->playback.ssi; + cmod = rdai[i].info->capture.ssi; /* * init rsnd_dai @@ -788,8 +864,7 @@ static int rsnd_dai_probe(struct platform_device *pdev, drv[i].playback.channels_min = 2; drv[i].playback.channels_max = 2; - if (info->dai_info) - rdai[i].playback.info = &info->dai_info[i].playback; + rdai[i].playback.info = &info->dai_info[i].playback; rsnd_path_init(priv, &rdai[i], &rdai[i].playback); } if (cmod) { @@ -798,8 +873,7 @@ static int rsnd_dai_probe(struct platform_device *pdev, drv[i].capture.channels_min = 2; drv[i].capture.channels_max = 2; - if (info->dai_info) - rdai[i].capture.info = &info->dai_info[i].capture; + rdai[i].capture.info = &info->dai_info[i].capture; rsnd_path_init(priv, &rdai[i], &rdai[i].capture); } @@ -874,6 +948,20 @@ static struct snd_pcm_ops rsnd_pcm_ops = { static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); + struct rsnd_dai *rdai; + int i, ret; + + for_each_rsnd_dai(rdai, priv, i) { + ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd); + if (ret) + return ret; + + ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd); + if (ret) + return ret; + } + return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, SNDRV_DMA_TYPE_DEV, @@ -913,6 +1001,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_gen_probe, rsnd_ssi_probe, rsnd_src_probe, + rsnd_dvc_probe, rsnd_adg_probe, rsnd_dai_probe, }; @@ -942,7 +1031,7 @@ static int rsnd_probe(struct platform_device *pdev) return -ENODEV; } - priv->dev = dev; + priv->pdev = pdev; priv->info = info; spin_lock_init(&priv->lock); @@ -956,11 +1045,11 @@ static int rsnd_probe(struct platform_device *pdev) } for_each_rsnd_dai(rdai, priv, i) { - ret = rsnd_dai_call(rdai, &rdai->playback, probe); + ret = rsnd_dai_call(probe, &rdai->playback, rdai); if (ret) return ret; - ret = rsnd_dai_call(rdai, &rdai->capture, probe); + ret = rsnd_dai_call(probe, &rdai->capture, rdai); if (ret) return ret; } @@ -1003,11 +1092,11 @@ static int rsnd_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); for_each_rsnd_dai(rdai, priv, i) { - ret = rsnd_dai_call(rdai, &rdai->playback, remove); + ret = rsnd_dai_call(remove, &rdai->playback, rdai); if (ret) return ret; - ret = rsnd_dai_call(rdai, &rdai->capture, remove); + ret = rsnd_dai_call(remove, &rdai->capture, rdai); if (ret) return ret; } diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c new file mode 100644 index 00000000000..ed000700689 --- /dev/null +++ b/sound/soc/sh/rcar/dvc.c @@ -0,0 +1,289 @@ +/* + * Renesas R-Car DVC support + * + * Copyright (C) 2014 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +#define RSND_DVC_NAME_SIZE 16 +#define RSND_DVC_VOLUME_MAX 100 +#define RSND_DVC_VOLUME_NUM 2 + +#define DVC_NAME "dvc" + +struct rsnd_dvc { + struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ + struct rsnd_mod mod; + struct clk *clk; + long volume[RSND_DVC_VOLUME_NUM]; +}; + +#define rsnd_mod_to_dvc(_mod) \ + container_of((_mod), struct rsnd_dvc, mod) + +#define for_each_rsnd_dvc(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_dvc_nr(priv)) && \ + ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ + i++) + +static void rsnd_dvc_volume_update(struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 max = (0x00800000 - 1); + u32 vol[RSND_DVC_VOLUME_NUM]; + int i; + + for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) + vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; + + rsnd_mod_write(mod, DVC_VOL0R, vol[0]); + rsnd_mod_write(mod, DVC_VOL1R, vol[1]); +} + +static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); + + return 0; +} + +static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, + struct rsnd_dai *rdai) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(dvc_mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(dvc_mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(dvc_mod); + struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); + struct device *dev = rsnd_priv_to_dev(priv); + int dvc_id = rsnd_mod_id(dvc_mod); + int src_id = rsnd_mod_id(src_mod); + u32 route[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + if (src_id >= ARRAY_SIZE(route)) { + dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id); + return -EINVAL; + } + + clk_prepare_enable(dvc->clk); + + /* + * fixme + * it doesn't support CTU/MIX + */ + rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]); + + rsnd_mod_write(dvc_mod, DVC_SWRSR, 0); + rsnd_mod_write(dvc_mod, DVC_SWRSR, 1); + + rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); + + rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); + + /* enable Volume */ + rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x100); + + /* ch0/ch1 Volume */ + rsnd_dvc_volume_update(dvc_mod); + + rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); + + rsnd_mod_write(dvc_mod, DVC_DVUER, 1); + + rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io); + + return 0; +} + +static int rsnd_dvc_quit(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + + clk_disable_unprepare(dvc->clk); + + return 0; +} + +static int rsnd_dvc_start(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + rsnd_mod_write(mod, CMD_CTRL, 0x10); + + return 0; +} + +static int rsnd_dvc_stop(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + rsnd_mod_write(mod, CMD_CTRL, 0); + + return 0; +} + +static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = RSND_DVC_VOLUME_NUM; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; + + return 0; +} + +static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + int i; + + for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) + ucontrol->value.integer.value[i] = dvc->volume[i]; + + return 0; +} + +static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + int i, change = 0; + + for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { + if (ucontrol->value.integer.value[i] < 0 || + ucontrol->value.integer.value[i] > RSND_DVC_VOLUME_MAX) + return -EINVAL; + + change |= (ucontrol->value.integer.value[i] != dvc->volume[i]); + } + + if (change) { + for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) + dvc->volume[i] = ucontrol->value.integer.value[i]; + + rsnd_dvc_volume_update(mod); + } + + return change; +} + +static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_card *card = rtd->card->snd_card; + struct snd_kcontrol *kctrl; + static struct snd_kcontrol_new knew = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Playback Volume", + .info = rsnd_dvc_volume_info, + .get = rsnd_dvc_volume_get, + .put = rsnd_dvc_volume_put, + }; + int ret; + + if (!rsnd_dai_is_play(rdai, io)) { + dev_err(dev, "DVC%d is connected to Capture DAI\n", + rsnd_mod_id(mod)); + return -EINVAL; + } + + kctrl = snd_ctl_new1(&knew, mod); + if (!kctrl) + return -ENOMEM; + + ret = snd_ctl_add(card, kctrl); + if (ret < 0) + return ret; + + return 0; +} + +static struct rsnd_mod_ops rsnd_dvc_ops = { + .name = DVC_NAME, + .probe = rsnd_dvc_probe_gen2, + .init = rsnd_dvc_init, + .quit = rsnd_dvc_quit, + .start = rsnd_dvc_start, + .stop = rsnd_dvc_stop, + .pcm_new = rsnd_dvc_pcm_new, +}; + +struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) + id = 0; + + return &((struct rsnd_dvc *)(priv->dvc) + id)->mod; +} + +int rsnd_dvc_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dvc *dvc; + struct clk *clk; + char name[RSND_DVC_NAME_SIZE]; + int i, nr; + + nr = info->dvc_info_nr; + if (!nr) + return 0; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) { + dev_warn(dev, "CMD is not supported on Gen1\n"); + return -EINVAL; + } + + dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); + if (!dvc) { + dev_err(dev, "CMD allocate failed\n"); + return -ENOMEM; + } + + priv->dvc_nr = nr; + priv->dvc = dvc; + + for_each_rsnd_dvc(dvc, priv, i) { + snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", + DVC_NAME, i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + dvc->info = &info->dvc_info[i]; + dvc->clk = clk; + + rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops, RSND_MOD_DVC, i); + + dev_dbg(dev, "CMD%d probed\n", i); + } + + return 0; +} diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 50a1ef3eb1c..1dd2b7d38c2 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -156,6 +156,101 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, } /* + * DMA read/write register offset + * + * RSND_xxx_I_N for Audio DMAC input + * RSND_xxx_O_N for Audio DMAC output + * RSND_xxx_I_P for Audio DMAC peri peri input + * RSND_xxx_O_P for Audio DMAC peri peri output + * + * ex) R-Car H2 case + * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out + * SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000 + * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 + * CMD : 0xec500000 / 0xec008000 0xec308000 + */ +#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) +#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) + +#define RDMA_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) + +#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) +#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) + +#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) +#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) + +#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) +#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) + +void rsnd_gen_dma_addr(struct rsnd_priv *priv, + struct rsnd_dma *dma, + struct dma_slave_config *cfg, + int is_play, int slave_id) +{ + struct platform_device *pdev = rsnd_priv_to_pdev(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + dma_addr_t ssi_reg = platform_get_resource(pdev, + IORESOURCE_MEM, RSND_GEN2_SSI)->start; + dma_addr_t src_reg = platform_get_resource(pdev, + IORESOURCE_MEM, RSND_GEN2_SCU)->start; + int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); + int use_src = !!rsnd_io_to_mod_src(io); + int use_dvc = !!rsnd_io_to_mod_dvc(io); + int id = rsnd_mod_id(mod); + struct dma_addr { + dma_addr_t src_addr; + dma_addr_t dst_addr; + } dma_addrs[2][2][3] = { + { /* SRC */ + /* Capture */ + {{ 0, 0 }, + { RDMA_SRC_O_N(src, id), 0 }, + { RDMA_CMD_O_N(src, id), 0 }}, + /* Playback */ + {{ 0, 0, }, + { 0, RDMA_SRC_I_N(src, id) }, + { 0, RDMA_SRC_I_N(src, id) }} + }, { /* SSI */ + /* Capture */ + {{ RDMA_SSI_O_N(ssi, id), 0 }, + { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, + { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }}, + /* Playback */ + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) }, + { RDMA_CMD_O_P(src, id), RDMA_SSI_I_P(ssi, id) }} + } + }; + + cfg->slave_id = slave_id; + cfg->src_addr = 0; + cfg->dst_addr = 0; + cfg->direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + + /* + * gen1 uses default DMA addr + */ + if (rsnd_is_gen1(priv)) + return; + + /* it shouldn't happen */ + if (use_dvc & !use_src) { + dev_err(dev, "DVC is selected without SRC\n"); + return; + } + + cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; + cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; + + dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n", + id, cfg->src_addr, cfg->dst_addr); +} + +/* * Gen2 */ @@ -181,6 +276,8 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20), RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20), RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20), + RSND_GEN2_M_REG(gen, SCU, CMD_ROUTE_SLCT, 0x18c, 0x20), + RSND_GEN2_M_REG(gen, SCU, CMD_CTRL, 0x190, 0x20), RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40), RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40), RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40), @@ -189,6 +286,14 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40), RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40), RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40), + RSND_GEN2_M_REG(gen, SCU, DVC_SWRSR, 0xe00, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_DVUIR, 0xe04, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_ADINR, 0xe08, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_DVUCR, 0xe10, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_ZCMCR, 0xe14, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_VOL0R, 0xe28, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_VOL1R, 0xe2c, 0x100), + RSND_GEN2_M_REG(gen, SCU, DVC_DVUER, 0xe48, 0x100), RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), @@ -207,6 +312,7 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50), RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54), RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58), + RSND_GEN2_S_REG(gen, ADG, CMDOUT_TIMSEL, 0x5c), RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), @@ -252,13 +358,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev, return ret; dev_dbg(dev, "Gen2 device probed\n"); - dev_dbg(dev, "SCU : %08x => %p\n", scu_res->start, + dev_dbg(dev, "SCU : %pap => %p\n", &scu_res->start, gen->base[RSND_GEN2_SCU]); - dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, + dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, gen->base[RSND_GEN2_ADG]); - dev_dbg(dev, "SSIU : %08x => %p\n", ssiu_res->start, + dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start, gen->base[RSND_GEN2_SSIU]); - dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, + dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, gen->base[RSND_GEN2_SSI]); return 0; @@ -345,11 +451,11 @@ static int rsnd_gen1_probe(struct platform_device *pdev, return ret; dev_dbg(dev, "Gen1 device probed\n"); - dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start, + dev_dbg(dev, "SRU : %pap => %p\n", &sru_res->start, gen->base[RSND_GEN1_SRU]); - dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, + dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, gen->base[RSND_GEN1_ADG]); - dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, + dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, gen->base[RSND_GEN1_SSI]); return 0; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 619d198c7d2..39d98af5ee0 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -44,6 +44,15 @@ enum rsnd_reg { RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSVR, RSND_REG_SRC_SRCCR, + RSND_REG_CMD_ROUTE_SLCT, + RSND_REG_DVC_SWRSR, + RSND_REG_DVC_DVUIR, + RSND_REG_DVC_ADINR, + RSND_REG_DVC_DVUCR, + RSND_REG_DVC_ZCMCR, + RSND_REG_DVC_VOL0R, + RSND_REG_DVC_VOL1R, + RSND_REG_DVC_DVUER, /* ADG */ RSND_REG_BRRA, @@ -79,6 +88,8 @@ enum rsnd_reg { RSND_REG_SHARE17, RSND_REG_SHARE18, RSND_REG_SHARE19, + RSND_REG_SHARE20, + RSND_REG_SHARE21, RSND_REG_MAX, }; @@ -114,6 +125,8 @@ enum rsnd_reg { #define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17 #define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18 #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 +#define RSND_REG_CMD_CTRL RSND_REG_SHARE20 +#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 struct rsnd_of_data; struct rsnd_priv; @@ -136,6 +149,7 @@ void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); +u32 rsnd_get_adinr(struct rsnd_mod *mod); /* * R-Car DMA @@ -165,29 +179,27 @@ void rsnd_dma_quit(struct rsnd_priv *priv, enum rsnd_mod_type { RSND_MOD_SRC = 0, RSND_MOD_SSI, + RSND_MOD_DVC, RSND_MOD_MAX, }; struct rsnd_mod_ops { char *name; int (*probe)(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); int (*remove)(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); int (*init)(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); int (*quit)(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); int (*start)(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); int (*stop)(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); + int (*pcm_new)(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct snd_soc_pcm_runtime *rtd); }; struct rsnd_dai_stream; @@ -228,6 +240,7 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI]) #define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC]) +#define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC]) struct rsnd_dai { char name[RSND_DAI_NAME_SIZE]; @@ -268,6 +281,11 @@ int rsnd_gen_probe(struct platform_device *pdev, void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); +void rsnd_gen_dma_addr(struct rsnd_priv *priv, + struct rsnd_dma *dma, + struct dma_slave_config *cfg, + int is_play, int slave_id); + #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) @@ -291,6 +309,9 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io); +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai, + struct rsnd_mod *mod, + struct rsnd_dai_stream *io); /* * R-Car sound priv @@ -301,7 +322,7 @@ struct rsnd_of_data { struct rsnd_priv { - struct device *dev; + struct platform_device *pdev; struct rcar_snd_info *info; spinlock_t lock; @@ -328,6 +349,12 @@ struct rsnd_priv { int ssi_nr; /* + * below value will be filled on rsnd_dvc_probe() + */ + void *dvc; + int dvc_nr; + + /* * below value will be filled on rsnd_dai_probe() */ struct snd_soc_dai_driver *daidrv; @@ -335,7 +362,8 @@ struct rsnd_priv { int rdai_nr; }; -#define rsnd_priv_to_dev(priv) ((priv)->dev) +#define rsnd_priv_to_pdev(priv) ((priv)->pdev) +#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) #define rsnd_priv_to_info(priv) ((priv)->info) #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) @@ -364,11 +392,9 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct snd_pcm_runtime *runtime); int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); + struct rsnd_dai *rdai); #define rsnd_src_nr(priv) ((priv)->src_nr) @@ -379,9 +405,19 @@ int rsnd_ssi_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); -struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, - int dai_id, int is_play); int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); -int rsnd_ssi_is_play(struct rsnd_mod *mod); + +/* + * R-Car DVC + */ +int rsnd_dvc_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); +void rsnd_dvc_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); + +#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) + #endif diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 6232b7d307a..200eda019bc 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -10,6 +10,8 @@ */ #include "rsnd.h" +#define SRC_NAME "src" + struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; @@ -18,21 +20,9 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 -/* - * ADINR - */ -#define OTBL_24 (0 << 16) -#define OTBL_22 (2 << 16) -#define OTBL_20 (4 << 16) -#define OTBL_18 (6 << 16) -#define OTBL_16 (8 << 16) - -#define rsnd_src_mode_flags(p) ((p)->info->flags) #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) -#define rsnd_src_hpbif_is_enable(src) \ - (rsnd_src_mode_flags(src) & RSND_SCU_USE_HPBIF) #define rsnd_src_dma_available(src) \ rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod)) @@ -80,34 +70,35 @@ struct rsnd_src { * * This driver request * struct rsnd_src_platform_info { - * u32 flags; * u32 convert_rate; + * int dma_id; * } * - * rsnd_src_hpbif_is_enable() will be true - * if flags had RSND_SRC_USE_HPBIF, - * and it controls whether SSIU is used or not. - * * rsnd_src_convert_rate() indicates * above convert_rate, and it controls * whether SRC is used or not. * * ex) doesn't use SRC - * struct rsnd_src_platform_info info = { - * .flags = 0, - * .convert_rate = 0, + * static struct rsnd_dai_platform_info rsnd_dai = { + * .playback = { .ssi = &rsnd_ssi[0], }, * }; * * ex) uses SRC - * struct rsnd_src_platform_info info = { - * .flags = RSND_SRC_USE_HPBIF, - * .convert_rate = 48000, + * static struct rsnd_src_platform_info rsnd_src[] = { + * RSND_SCU(48000, 0), + * ... + * }; + * static struct rsnd_dai_platform_info rsnd_dai = { + * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, * }; * * ex) uses SRC bypass mode - * struct rsnd_src_platform_info info = { - * .flags = RSND_SRC_USE_HPBIF, - * .convert_rate = 0, + * static struct rsnd_src_platform_info rsnd_src[] = { + * RSND_SCU(0, 0), + * ... + * }; + * static struct rsnd_dai_platform_info rsnd_dai = { + * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, * }; * */ @@ -116,27 +107,17 @@ struct rsnd_src { * Gen1/Gen2 common functions */ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct rcar_snd_info *info = rsnd_priv_to_info(priv); int ssi_id = rsnd_mod_id(ssi_mod); - int has_src = 0; /* * SSI_MODE0 */ - if (info->dai_info) { - has_src = !!src_mod; - } else { - struct rsnd_src *src = rsnd_mod_to_src(src_mod); - has_src = rsnd_src_hpbif_is_enable(src); - } - rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), - has_src ? 0 : (1 << ssi_id)); + src_mod ? 0 : (1 << ssi_id)); /* * SSI_MODE1 @@ -166,8 +147,7 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, } int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); @@ -203,13 +183,12 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, } static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_src *src = rsnd_mod_to_src(mod); u32 convert_rate = rsnd_src_convert_rate(src); - u32 adinr = runtime->channels; u32 fsrate = 0; if (convert_rate) @@ -226,17 +205,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, rsnd_mod_write(mod, SRC_SRCIR, 1); /* Set channel number and output bit length */ - switch (runtime->sample_bits) { - case 16: - adinr |= OTBL_16; - break; - case 32: - adinr |= OTBL_24; - break; - default: - return -EIO; - } - rsnd_mod_write(mod, SRC_ADINR, adinr); + rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); /* Enable the initial value of IFS */ if (fsrate) { @@ -253,30 +222,27 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, } static int rsnd_src_init(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_src *src = rsnd_mod_to_src(mod); - clk_enable(src->clk); + clk_prepare_enable(src->clk); return 0; } static int rsnd_src_quit(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_src *src = rsnd_mod_to_src(mod); - clk_disable(src->clk); + clk_disable_unprepare(src->clk); return 0; } static int rsnd_src_start(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_src *src = rsnd_mod_to_src(mod); @@ -294,8 +260,7 @@ static int rsnd_src_start(struct rsnd_mod *mod, static int rsnd_src_stop(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_src *src = rsnd_mod_to_src(mod); @@ -305,17 +270,13 @@ static int rsnd_src_stop(struct rsnd_mod *mod, return 0; } -static struct rsnd_mod_ops rsnd_src_non_ops = { - .name = "src (non)", -}; - /* * Gen1 functions */ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct src_route_config { u32 mask; int shift; @@ -351,9 +312,9 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod, } static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_src *src = rsnd_mod_to_src(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); @@ -410,12 +371,11 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, } static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { int ret; - ret = rsnd_src_set_convert_rate(mod, rdai, io); + ret = rsnd_src_set_convert_rate(mod, rdai); if (ret < 0) return ret; @@ -431,25 +391,35 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, return 0; } +static int rsnd_src_probe_gen1(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod)); + + return 0; +} + static int rsnd_src_init_gen1(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { int ret; - ret = rsnd_src_init(mod, rdai, io); + ret = rsnd_src_init(mod, rdai); if (ret < 0) return ret; - ret = rsnd_src_set_route_gen1(mod, rdai, io); + ret = rsnd_src_set_route_gen1(mod, rdai); if (ret < 0) return ret; - ret = rsnd_src_set_convert_rate_gen1(mod, rdai, io); + ret = rsnd_src_set_convert_rate_gen1(mod, rdai); if (ret < 0) return ret; - ret = rsnd_src_set_convert_timing_gen1(mod, rdai, io); + ret = rsnd_src_set_convert_timing_gen1(mod, rdai); if (ret < 0) return ret; @@ -457,29 +427,28 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod, } static int rsnd_src_start_gen1(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { int id = rsnd_mod_id(mod); rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); - return rsnd_src_start(mod, rdai, io); + return rsnd_src_start(mod, rdai); } static int rsnd_src_stop_gen1(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { int id = rsnd_mod_id(mod); rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); - return rsnd_src_stop(mod, rdai, io); + return rsnd_src_stop(mod, rdai); } static struct rsnd_mod_ops rsnd_src_gen1_ops = { - .name = "sru (gen1)", + .name = SRC_NAME, + .probe = rsnd_src_probe_gen1, .init = rsnd_src_init_gen1, .quit = rsnd_src_quit, .start = rsnd_src_start_gen1, @@ -490,17 +459,16 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { * Gen2 functions */ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { int ret; - ret = rsnd_src_set_convert_rate(mod, rdai, io); + ret = rsnd_src_set_convert_rate(mod, rdai); if (ret < 0) return ret; - rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR)); - rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_mod_read(mod, SRC_BUSIF_MODE)); + rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr(mod)); + rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); @@ -511,9 +479,9 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, } static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_src *src = rsnd_mod_to_src(mod); u32 convert_rate = rsnd_src_convert_rate(src); @@ -530,35 +498,27 @@ static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod, } static int rsnd_src_probe_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct rsnd_src *src = rsnd_mod_to_src(mod); - struct rsnd_mod *ssi = rsnd_ssi_mod_get(priv, rsnd_mod_id(mod)); struct device *dev = rsnd_priv_to_dev(priv); int ret; - int is_play; - - if (info->dai_info) - is_play = rsnd_info_is_playback(priv, src); - else - is_play = rsnd_ssi_is_play(ssi); ret = rsnd_dma_init(priv, rsnd_mod_to_dma(mod), - is_play, + rsnd_info_is_playback(priv, src), src->info->dma_id); if (ret < 0) dev_err(dev, "SRC DMA failed\n"); + dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); + return ret; } static int rsnd_src_remove_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); @@ -566,20 +526,19 @@ static int rsnd_src_remove_gen2(struct rsnd_mod *mod, } static int rsnd_src_init_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { int ret; - ret = rsnd_src_init(mod, rdai, io); + ret = rsnd_src_init(mod, rdai); if (ret < 0) return ret; - ret = rsnd_src_set_convert_rate_gen2(mod, rdai, io); + ret = rsnd_src_set_convert_rate_gen2(mod, rdai); if (ret < 0) return ret; - ret = rsnd_src_set_convert_timing_gen2(mod, rdai, io); + ret = rsnd_src_set_convert_timing_gen2(mod, rdai); if (ret < 0) return ret; @@ -587,22 +546,22 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, } static int rsnd_src_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); rsnd_mod_write(mod, SSI_CTRL, 0x1); - rsnd_mod_write(mod, SRC_CTRL, 0x11); + rsnd_mod_write(mod, SRC_CTRL, val); - return rsnd_src_start(mod, rdai, io); + return rsnd_src_start(mod, rdai); } static int rsnd_src_stop_gen2(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_src *src = rsnd_mod_to_src(mod); @@ -611,11 +570,11 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); - return rsnd_src_stop(mod, rdai, io); + return rsnd_src_stop(mod, rdai); } static struct rsnd_mod_ops rsnd_src_gen2_ops = { - .name = "src (gen2)", + .name = SRC_NAME, .probe = rsnd_src_probe_gen2, .remove = rsnd_src_remove_gen2, .init = rsnd_src_init_gen2, @@ -651,18 +610,21 @@ static void rsnd_of_parse_src(struct platform_device *pdev, nr = of_get_child_count(src_node); if (!nr) - return; + goto rsnd_of_parse_src_end; src_info = devm_kzalloc(dev, sizeof(struct rsnd_src_platform_info) * nr, GFP_KERNEL); if (!src_info) { dev_err(dev, "src info allocation error\n"); - return; + goto rsnd_of_parse_src_end; } info->src_info = src_info; info->src_info_nr = nr; + +rsnd_of_parse_src_end: + of_node_put(src_node); } int rsnd_src_probe(struct platform_device *pdev, @@ -677,6 +639,16 @@ int rsnd_src_probe(struct platform_device *pdev, char name[RSND_SRC_NAME_SIZE]; int i, nr; + ops = NULL; + if (rsnd_is_gen1(priv)) + ops = &rsnd_src_gen1_ops; + if (rsnd_is_gen2(priv)) + ops = &rsnd_src_gen2_ops; + if (!ops) { + dev_err(dev, "unknown Generation\n"); + return -EIO; + } + rsnd_of_parse_src(pdev, of_data, priv); /* @@ -696,28 +668,16 @@ int rsnd_src_probe(struct platform_device *pdev, priv->src = src; for_each_rsnd_src(src, priv, i) { - snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i); + snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", + SRC_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - snprintf(name, RSND_SRC_NAME_SIZE, "scu.%d", i); - clk = devm_clk_get(dev, name); - } - if (IS_ERR(clk)) return PTR_ERR(clk); src->info = &info->src_info[i]; src->clk = clk; - ops = &rsnd_src_non_ops; - if (rsnd_src_hpbif_is_enable(src)) { - if (rsnd_is_gen1(priv)) - ops = &rsnd_src_gen1_ops; - if (rsnd_is_gen2(priv)) - ops = &rsnd_src_gen2_ops; - } - rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i); dev_dbg(dev, "SRC%d probed\n", i); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4b7e20603dd..2df723df5d1 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -57,6 +57,8 @@ */ #define CONT (1 << 8) /* WS Continue Function */ +#define SSI_NAME "ssi" + struct rsnd_ssi { struct clk *clk; struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ @@ -171,7 +173,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, u32 cr; if (0 == ssi->usrcnt) { - clk_enable(ssi->clk); + clk_prepare_enable(ssi->clk); if (rsnd_dai_is_clk_master(rdai)) { if (rsnd_ssi_clk_from_parent(ssi)) @@ -230,7 +232,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, rsnd_ssi_master_clk_stop(ssi); } - clk_disable(ssi->clk); + clk_disable_unprepare(ssi->clk); } dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); @@ -240,10 +242,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, * SSI mod common functions */ static int rsnd_ssi_init(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 cr; @@ -287,14 +289,13 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, ssi->cr_own = cr; ssi->err = -1; /* ignore 1st error */ - rsnd_src_ssi_mode_init(mod, rdai, io); + rsnd_src_ssi_mode_init(mod, rdai); return 0; } static int rsnd_ssi_quit(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); @@ -359,8 +360,7 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) } static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); @@ -375,19 +375,21 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, if (ret) dev_err(dev, "SSI request interrupt failed\n"); + dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod)); + return ret; } static int rsnd_ssi_pio_start(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); /* enable PIO IRQ */ ssi->cr_etc = UIEN | OIEN | DIEN; - rsnd_src_enable_ssi_irq(mod, rdai, io); + rsnd_src_enable_ssi_irq(mod, rdai); rsnd_ssi_hw_start(ssi, rdai, io); @@ -395,8 +397,7 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, } static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); @@ -408,7 +409,7 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_ssi_pio_ops = { - .name = "ssi (pio)", + .name = SSI_NAME, .probe = rsnd_ssi_pio_probe, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, @@ -417,36 +418,29 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { }; static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = rsnd_priv_to_dev(priv); int dma_id = ssi->info->dma_id; - int is_play; int ret; - if (info->dai_info) - is_play = rsnd_info_is_playback(priv, ssi); - else - is_play = rsnd_ssi_is_play(&ssi->mod); - ret = rsnd_dma_init( priv, rsnd_mod_to_dma(mod), - is_play, + rsnd_info_is_playback(priv, ssi), dma_id); if (ret < 0) dev_err(dev, "SSI DMA failed\n"); + dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod)); + return ret; } static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); @@ -454,11 +448,11 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, } static int rsnd_ssi_dma_start(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); /* enable DMA transfer */ ssi->cr_etc = DMEN; @@ -475,8 +469,7 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, } static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) + struct rsnd_dai *rdai) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); @@ -493,7 +486,7 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_ssi_dma_ops = { - .name = "ssi (dma)", + .name = SSI_NAME, .probe = rsnd_ssi_dma_probe, .remove = rsnd_ssi_dma_remove, .init = rsnd_ssi_init, @@ -506,47 +499,12 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { * Non SSI */ static struct rsnd_mod_ops rsnd_ssi_non_ops = { - .name = "ssi (non)", + .name = SSI_NAME, }; /* * ssi mod function */ -struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, - int dai_id, int is_play) -{ - struct rsnd_dai_platform_info *dai_info = NULL; - struct rsnd_dai_path_info *path_info = NULL; - struct rsnd_ssi_platform_info *target_info = NULL; - struct rsnd_ssi *ssi; - int i, has_play; - - if (priv->rdai) - dai_info = priv->rdai[dai_id].info; - if (dai_info) - path_info = (is_play) ? &dai_info->playback : &dai_info->capture; - if (path_info) - target_info = path_info->ssi; - - is_play = !!is_play; - - for_each_rsnd_ssi(ssi, priv, i) { - if (target_info == ssi->info) - return &ssi->mod; - - /* for compatible */ - if (rsnd_ssi_dai_id(ssi) != dai_id) - continue; - - has_play = rsnd_ssi_is_play(&ssi->mod); - - if (is_play == has_play) - return &ssi->mod; - } - - return NULL; -} - struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) { if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) @@ -562,13 +520,6 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -int rsnd_ssi_is_play(struct rsnd_mod *mod) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); -} - static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) { if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) @@ -609,14 +560,14 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, nr = of_get_child_count(node); if (!nr) - return; + goto rsnd_of_parse_ssi_end; ssi_info = devm_kzalloc(dev, sizeof(struct rsnd_ssi_platform_info) * nr, GFP_KERNEL); if (!ssi_info) { dev_err(dev, "ssi info allocation error\n"); - return; + goto rsnd_of_parse_ssi_end; } info->ssi_info = ssi_info; @@ -638,7 +589,16 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, * irq */ ssi_info->pio_irq = irq_of_parse_and_map(np, 0); + + /* + * DMA + */ + ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? + 0 : 1; } + +rsnd_of_parse_ssi_end: + of_node_put(node); } int rsnd_ssi_probe(struct platform_device *pdev, @@ -672,7 +632,8 @@ int rsnd_ssi_probe(struct platform_device *pdev, for_each_rsnd_ssi(ssi, priv, i) { pinfo = &info->ssi_info[i]; - snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); + snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", + SSI_NAME, i); clk = devm_clk_get(dev, name); if (IS_ERR(clk)) |