diff options
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/Kconfig | 2 | ||||
-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 | 168 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 273 | ||||
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 25 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 68 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 194 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 89 |
9 files changed, 538 insertions, 340 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index ff60e11ecb56..b43fdf0d08af 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -56,7 +56,7 @@ config SND_SH7760_AC97 config SND_SIU_MIGOR tristate "SIU sound support on Migo-R" - depends on SH_MIGOR + depends on SH_MIGOR && I2C select SND_SOC_SH4_SIU select SND_SOC_WM8978 help diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 7d0051ced838..9ac536429800 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 69c44269ebdb..fc41a0e8b09f 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 215b668166be..964463dada87 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) @@ -310,23 +309,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 +359,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 +493,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 +509,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 +601,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 +633,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 +743,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 +768,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 +789,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 +798,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 +873,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 +926,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, }; @@ -956,11 +970,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 +1017,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 000000000000..74769b1be005 --- /dev/null +++ b/sound/soc/sh/rcar/dvc.c @@ -0,0 +1,273 @@ +/* + * 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 +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_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 (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, "dvc.%d", 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 50a1ef3eb1c6..a1583b57bf8d 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -181,6 +181,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 +191,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 +217,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 +263,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 +356,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 619d198c7d2e..5aa790170b01 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]; @@ -291,6 +304,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 @@ -328,6 +344,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; @@ -364,11 +386,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 +399,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 6232b7d307aa..e3b078e7c3aa 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -18,21 +18,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 +68,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 +105,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 +145,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 +181,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 +203,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 |