diff options
author | Mark Brown <broonie@kernel.org> | 2018-12-18 12:23:59 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-12-18 12:23:59 +0000 |
commit | a7a850dba82498a1e050d8d153cae67ce0edb3b2 (patch) | |
tree | f2b50444022ad27f407e087a820ae5ff248e0492 /sound/soc/sh | |
parent | c5fd9e77be44360b4827069c59f524815517917b (diff) | |
parent | 0f4967bc21de0bb9e107f9ad3ced852daf66acd2 (diff) | |
download | linux-a7a850dba82498a1e050d8d153cae67ce0edb3b2.tar.bz2 |
Merge branch 'asoc-4.21' into asoc-next
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 38 | ||||
-rw-r--r-- | sound/soc/sh/rcar/cmd.c | 11 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 244 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ctu.c | 138 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dma.c | 84 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 13 | ||||
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 49 | ||||
-rw-r--r-- | sound/soc/sh/rcar/mix.c | 3 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 382 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 67 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 269 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssiu.c | 300 |
12 files changed, 893 insertions, 705 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 28327dd2c6cb..e821ccc70f47 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -249,28 +249,8 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, out = out << shift; mask = 0x0f1f << shift; - switch (id / 2) { - case 0: - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0, mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out); - break; - case 1: - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1, mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out); - break; - case 2: - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2, mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out); - break; - case 3: - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3, mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out); - break; - case 4: - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4, mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out); - break; - } + rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in); + rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out); if (en) rsnd_mod_bset(adg_mod, DIV_EN, en, en); @@ -299,17 +279,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) if (id == 8) return; - switch (id / 4) { - case 0: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val); - break; - case 1: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val); - break; - case 2: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val); - break; - } + rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val); dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val); } @@ -613,7 +583,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) return -ENOMEM; ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, - NULL, NULL, 0, 0); + NULL, 0, 0); if (ret) return ret; diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index cc191cd5fb82..e6bb6a9a0684 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -116,10 +116,11 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_cmd_ops = { - .name = CMD_NAME, - .init = rsnd_cmd_init, - .start = rsnd_cmd_start, - .stop = rsnd_cmd_stop, + .name = CMD_NAME, + .init = rsnd_cmd_init, + .start = rsnd_cmd_start, + .stop = rsnd_cmd_stop, + .get_status = rsnd_mod_get_status, }; static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) @@ -162,7 +163,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv) for_each_rsnd_cmd(cmd, priv, i) { ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), &rsnd_cmd_ops, NULL, - rsnd_mod_get_status, RSND_MOD_CMD, i); + RSND_MOD_CMD, i); if (ret) return ret; } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 114f8f233764..59e250cc2e9d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -123,8 +123,8 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); - dev_warn(dev, "%s[%d] is not your expected module\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + dev_warn(dev, "%s is not your expected module\n", + rsnd_mod_name(mod)); } } @@ -137,20 +137,69 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, return mod->ops->dma_req(io, mod); } -u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, +#define MOD_NAME_NUM 5 +#define MOD_NAME_SIZE 16 +char *rsnd_mod_name(struct rsnd_mod *mod) +{ + static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; + static int num; + char *name = names[num]; + + num++; + if (num >= MOD_NAME_NUM) + num = 0; + + /* + * Let's use same char to avoid pointlessness memory + * Thus, rsnd_mod_name() should be used immediately + * Don't keep pointer + */ + if ((mod)->ops->id_sub) { + snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", + mod->ops->name, + rsnd_mod_id(mod), + rsnd_mod_id_sub(mod)); + } else { + snprintf(name, MOD_NAME_SIZE, "%s[%d]", + mod->ops->name, + rsnd_mod_id(mod)); + } + + return name; +} + +u32 *rsnd_mod_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, enum rsnd_mod_type type) { return &mod->status; } +int rsnd_mod_id_raw(struct rsnd_mod *mod) +{ + return mod->id; +} + +int rsnd_mod_id(struct rsnd_mod *mod) +{ + if ((mod)->ops->id) + return (mod)->ops->id(mod); + + return rsnd_mod_id_raw(mod); +} + +int rsnd_mod_id_sub(struct rsnd_mod *mod) +{ + if ((mod)->ops->id_sub) + return (mod)->ops->id_sub(mod); + + return 0; +} + int rsnd_mod_init(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_mod_ops *ops, struct clk *clk, - u32* (*get_status)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - enum rsnd_mod_type type), enum rsnd_mod_type type, int id) { @@ -164,7 +213,6 @@ int rsnd_mod_init(struct rsnd_priv *priv, mod->type = type; mod->clk = clk; mod->priv = priv; - mod->get_status = get_status; return ret; } @@ -228,7 +276,20 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); if (ctu_mod) { - u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod); + u32 converted_chan = rsnd_io_converted_chan(io); + + /* + * !! Note !! + * + * converted_chan will be used for CTU, + * or TDM Split mode. + * User shouldn't use CTU with TDM Split mode. + */ + if (rsnd_runtime_is_tdm_split(io)) { + struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); + + dev_err(dev, "CTU and TDM Split should be used\n"); + } if (converted_chan) return converted_chan; @@ -246,7 +307,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, rsnd_runtime_channel_original_with_params(io, params); /* Use Multi SSI */ - if (rsnd_runtime_is_ssi_multi(io)) + if (rsnd_runtime_is_multi_ssi(io)) chan /= rsnd_rdai_ssi_lane_get(rdai); /* TDM Extend Mode needs 8ch */ @@ -256,7 +317,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, return chan; } -int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) +int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int lane = rsnd_rdai_ssi_lane_get(rdai); @@ -267,11 +328,16 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) return (chan > 2) && (lane > 1); } -int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) +int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) { return rsnd_runtime_channel_for_ssi(io) >= 6; } +int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) +{ + return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); +} + /* * ADINR function */ @@ -472,20 +538,19 @@ static int rsnd_status_update(u32 *status, enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ int tmp = 0; \ - u32 *status = mod->get_status(io, mod, types[i]); \ + u32 *status = mod->ops->get_status(mod, io, types[i]); \ int func_call = rsnd_status_update(status, \ __rsnd_mod_shift_##fn, \ __rsnd_mod_add_##fn, \ __rsnd_mod_call_##fn); \ - rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ + rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \ + rsnd_mod_name(mod), *status, \ (func_call && (mod)->ops->fn) ? #fn : ""); \ if (func_call && (mod)->ops->fn) \ tmp = (mod)->ops->fn(mod, io, param); \ if (tmp && (tmp != -EPROBE_DEFER)) \ - dev_err(dev, "%s[%d] : %s error %d\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), \ - #fn, tmp); \ + dev_err(dev, "%s : %s error %d\n", \ + rsnd_mod_name(mod), #fn, tmp); \ ret |= tmp; \ } \ ret; \ @@ -512,8 +577,8 @@ int rsnd_dai_connect(struct rsnd_mod *mod, io->mod[type] = mod; - dev_dbg(dev, "%s[%d] is connected to io (%s)\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + dev_dbg(dev, "%s is connected to io (%s)\n", + rsnd_mod_name(mod), rsnd_io_is_play(io) ? "Playback" : "Capture"); return 0; @@ -750,6 +815,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, switch (slots) { case 2: + /* TDM Split Mode */ case 6: case 8: /* TDM Extend Mode */ @@ -965,6 +1031,82 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .prepare = rsnd_soc_dai_prepare, }; +static void rsnd_parse_connect_simple(struct rsnd_priv *priv, + struct device_node *dai_np, + int dai_i, int is_play) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + struct rsnd_dai_stream *io = is_play ? + &rdai->playback : + &rdai->capture; + struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); + struct device_node *np; + int i, j; + + if (!ssiu_np) + return; + + if (!rsnd_io_to_mod_ssi(io)) + return; + + /* + * This driver assumes that it is TDM Split mode + * if it includes ssiu node + */ + for (i = 0;; i++) { + struct device_node *node = is_play ? + of_parse_phandle(dai_np, "playback", i) : + of_parse_phandle(dai_np, "capture", i); + + if (!node) + break; + + j = 0; + for_each_child_of_node(ssiu_np, np) { + if (np == node) { + rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); + dev_dbg(dev, "%s is part of TDM Split\n", io->name); + } + j++; + } + + } +} + +static void rsnd_parse_connect_graph(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *endpoint) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *remote_port = of_graph_get_remote_port(endpoint); + struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); + + if (!rsnd_io_to_mod_ssi(io)) + return; + + /* HDMI0 */ + if (strstr(remote_node->full_name, "hdmi@fead0000")) { + rsnd_flags_set(io, RSND_STREAM_HDMI0); + dev_dbg(dev, "%s connected to HDMI0\n", io->name); + } + + /* HDMI1 */ + if (strstr(remote_node->full_name, "hdmi@feae0000")) { + rsnd_flags_set(io, RSND_STREAM_HDMI1); + dev_dbg(dev, "%s connected to HDMI1\n", io->name); + } + + /* + * This driver assumes that it is TDM Split mode + * if remote node has multi endpoint + */ + if (of_get_child_count(remote_port) > 1) { + rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); + dev_dbg(dev, "%s is part of TDM Split\n", io->name); + } +} + void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), struct device_node *node, @@ -1051,24 +1193,24 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; - snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, + snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i); drv->playback.rates = RSND_RATES; drv->playback.formats = RSND_FMTS; drv->playback.channels_min = 2; drv->playback.channels_max = 8; - drv->playback.stream_name = rdai->playback.name; + drv->playback.stream_name = io_playback->name; - snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, + snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i); drv->capture.rates = RSND_RATES; drv->capture.formats = RSND_FMTS; drv->capture.channels_min = 2; drv->capture.channels_max = 8; - drv->capture.stream_name = rdai->capture.name; + drv->capture.stream_name = io_capture->name; - rdai->playback.rdai = rdai; - rdai->capture.rdai = rdai; + io_playback->rdai = rdai; + io_capture->rdai = rdai; rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ @@ -1081,6 +1223,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, break; rsnd_parse_connect_ssi(rdai, playback, capture); + rsnd_parse_connect_ssiu(rdai, playback, capture); rsnd_parse_connect_src(rdai, playback, capture); rsnd_parse_connect_ctu(rdai, playback, capture); rsnd_parse_connect_mix(rdai, playback, capture); @@ -1137,12 +1280,23 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) if (is_graph) { for_each_endpoint_of_node(dai_node, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_i); - rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); + if (rsnd_is_gen3(priv)) { + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); + rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + } dai_i++; } } else { - for_each_child_of_node(dai_node, dai_np) - __rsnd_dai_probe(priv, dai_np, dai_i++); + for_each_child_of_node(dai_node, dai_np) { + __rsnd_dai_probe(priv, dai_np, dai_i); + if (rsnd_is_gen3(priv)) { + rsnd_parse_connect_simple(priv, dai_np, dai_i, 1); + rsnd_parse_connect_simple(priv, dai_np, dai_i, 0); + } + dai_i++; + } } return 0; @@ -1157,8 +1311,40 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + struct snd_soc_pcm_runtime *fe = substream->private_data; int ret; + /* + * rsnd assumes that it might be used under DPCM if user want to use + * channel / rate convert. Then, rsnd should be FE. + * And then, this function will be called *after* BE settings. + * this means, each BE already has fixuped hw_params. + * see + * dpcm_fe_dai_hw_params() + * dpcm_be_dai_hw_params() + */ + io->converted_rate = 0; + io->converted_chan = 0; + if (fe->dai_link->dynamic) { + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_soc_dpcm *dpcm; + struct snd_pcm_hw_params *be_params; + int stream = substream->stream; + + for_each_dpcm_be(fe, stream, dpcm) { + be_params = &dpcm->hw_params; + if (params_channels(hw_params) != params_channels(be_params)) + io->converted_chan = params_channels(be_params); + if (params_rate(hw_params) != params_rate(be_params)) + io->converted_rate = params_rate(be_params); + } + if (io->converted_chan) + dev_dbg(dev, "convert channels = %d\n", io->converted_chan); + if (io->converted_rate) + dev_dbg(dev, "convert rate = %d\n", io->converted_rate); + } + ret = rsnd_dai_call(hw_params, io, substream, hw_params); if (ret) return ret; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index ad702377a6c3..8cb06dab234e 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -72,10 +72,7 @@ struct rsnd_ctu { struct rsnd_mod mod; struct rsnd_kctrl_cfg_m pass; - struct rsnd_kctrl_cfg_m sv0; - struct rsnd_kctrl_cfg_m sv1; - struct rsnd_kctrl_cfg_m sv2; - struct rsnd_kctrl_cfg_m sv3; + struct rsnd_kctrl_cfg_m sv[4]; struct rsnd_kctrl_cfg_s reset; int channels; u32 flags; @@ -107,13 +104,6 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod) rsnd_mod_write(mod, CTU_SWRSR, 0); } -int rsnd_ctu_converted_channel(struct rsnd_mod *mod) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - - return ctu->channels; -} - static int rsnd_ctu_probe_(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -127,7 +117,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); u32 cpmdr = 0; u32 scmdr = 0; - int i; + int i, j; for (i = 0; i < RSND_MAX_CHANNELS; i++) { u32 val = rsnd_kctrl_valm(ctu->pass, i); @@ -146,45 +136,13 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, rsnd_mod_write(mod, CTU_SCMDR, scmdr); - if (scmdr > 0) { - rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0)); - rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1)); - rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2)); - rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3)); - rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4)); - rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5)); - rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6)); - rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7)); - } - if (scmdr > 1) { - rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0)); - rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1)); - rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2)); - rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3)); - rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4)); - rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5)); - rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6)); - rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7)); - } - if (scmdr > 2) { - rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0)); - rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1)); - rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2)); - rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3)); - rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4)); - rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5)); - rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6)); - rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7)); - } - if (scmdr > 3) { - rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0)); - rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1)); - rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2)); - rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3)); - rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4)); - rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5)); - rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6)); - rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7)); + for (i = 0; i < 4; i++) { + + if (i >= scmdr) + break; + + for (j = 0; j < RSND_MAX_CHANNELS; j++) + rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j)); } rsnd_mod_write(mod, CTU_CTUIR, 0); @@ -201,10 +159,10 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, for (i = 0; i < RSND_MAX_CHANNELS; i++) { rsnd_kctrl_valm(ctu->pass, i) = 0; - rsnd_kctrl_valm(ctu->sv0, i) = 0; - rsnd_kctrl_valm(ctu->sv1, i) = 0; - rsnd_kctrl_valm(ctu->sv2, i) = 0; - rsnd_kctrl_valm(ctu->sv3, i) = 0; + rsnd_kctrl_valm(ctu->sv[0], i) = 0; + rsnd_kctrl_valm(ctu->sv[1], i) = 0; + rsnd_kctrl_valm(ctu->sv[2], i) = 0; + rsnd_kctrl_valm(ctu->sv[3], i) = 0; } rsnd_kctrl_vals(ctu->reset) = 0; } @@ -233,43 +191,6 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, return 0; } -static int rsnd_ctu_hw_params(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *fe_params) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - struct snd_soc_pcm_runtime *fe = substream->private_data; - - /* - * CTU assumes that it is used under DPCM if user want to use - * channel transfer. Then, CTU should be FE. - * And then, this function will be called *after* BE settings. - * this means, each BE already has fixuped hw_params. - * see - * dpcm_fe_dai_hw_params() - * dpcm_be_dai_hw_params() - */ - ctu->channels = 0; - if (fe->dai_link->dynamic) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_soc_dpcm *dpcm; - struct snd_pcm_hw_params *be_params; - int stream = substream->stream; - - for_each_dpcm_be(fe, stream, dpcm) { - be_params = &dpcm->hw_params; - if (params_channels(fe_params) != params_channels(be_params)) - ctu->channels = params_channels(be_params); - } - - dev_dbg(dev, "CTU convert channels %d\n", ctu->channels); - } - - return 0; -} - static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) @@ -291,7 +212,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", rsnd_kctrl_accept_anytime, NULL, - &ctu->sv0, RSND_MAX_CHANNELS, + &ctu->sv[0], RSND_MAX_CHANNELS, 0x00FFFFFF); if (ret < 0) return ret; @@ -300,7 +221,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", rsnd_kctrl_accept_anytime, NULL, - &ctu->sv1, RSND_MAX_CHANNELS, + &ctu->sv[1], RSND_MAX_CHANNELS, 0x00FFFFFF); if (ret < 0) return ret; @@ -309,7 +230,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", rsnd_kctrl_accept_anytime, NULL, - &ctu->sv2, RSND_MAX_CHANNELS, + &ctu->sv[2], RSND_MAX_CHANNELS, 0x00FFFFFF); if (ret < 0) return ret; @@ -318,7 +239,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", rsnd_kctrl_accept_anytime, NULL, - &ctu->sv3, RSND_MAX_CHANNELS, + &ctu->sv[3], RSND_MAX_CHANNELS, 0x00FFFFFF); if (ret < 0) return ret; @@ -334,13 +255,34 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, return ret; } +static int rsnd_ctu_id(struct rsnd_mod *mod) +{ + /* + * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0 + * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1 + */ + return mod->id / 4; +} + +static int rsnd_ctu_id_sub(struct rsnd_mod *mod) +{ + /* + * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3 + * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3 + */ + return mod->id % 4; +} + static struct rsnd_mod_ops rsnd_ctu_ops = { .name = CTU_NAME, .probe = rsnd_ctu_probe_, .init = rsnd_ctu_init, .quit = rsnd_ctu_quit, - .hw_params = rsnd_ctu_hw_params, .pcm_new = rsnd_ctu_pcm_new, + .get_status = rsnd_mod_get_status, + .id = rsnd_ctu_id, + .id_sub = rsnd_ctu_id_sub, + .id_cmd = rsnd_mod_id_raw, }; struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) @@ -404,7 +346,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, - clk, rsnd_mod_get_status, RSND_MOD_CTU, i); + clk, RSND_MOD_CTU, i); if (ret) { of_node_put(np); goto rsnd_ctu_probe_done; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 6d1947515dc8..0324a5c39619 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -174,8 +174,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dev_dbg(dev, "%s[%d] %pad -> %pad\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + dev_dbg(dev, "%s %pad -> %pad\n", + rsnd_mod_name(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); @@ -218,7 +218,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, int i = 0; for_each_child_of_node(of_node, np) { - if (i == rsnd_mod_id(mod) && (!chan)) + if (i == rsnd_mod_id_raw(mod) && (!chan)) chan = of_dma_request_slave_channel(np, name); i++; } @@ -289,12 +289,13 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_dmaen_ops = { - .name = "audmac", - .prepare = rsnd_dmaen_prepare, - .cleanup = rsnd_dmaen_cleanup, - .start = rsnd_dmaen_start, - .stop = rsnd_dmaen_stop, - .pointer= rsnd_dmaen_pointer, + .name = "audmac", + .prepare = rsnd_dmaen_prepare, + .cleanup = rsnd_dmaen_cleanup, + .start = rsnd_dmaen_start, + .stop = rsnd_dmaen_stop, + .pointer = rsnd_dmaen_pointer, + .get_status = rsnd_mod_get_status, }; /* @@ -343,14 +344,16 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); const u8 *entry = NULL; int id = 255; int size = 0; - if (mod == ssi) { - int busif = rsnd_ssi_get_busif(io); + if ((mod == ssi) || + (mod == ssiu)) { + int busif = rsnd_mod_id_sub(ssiu); entry = gen2_id_table_ssiu; size = ARRAY_SIZE(gen2_id_table_ssiu); @@ -368,8 +371,7 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, if ((!entry) || (size <= id)) { struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); - dev_err(dev, "unknown connection (%s[%d])\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod)); /* use non-prohibited SRS number as error */ return 0x00; /* SSI00 */ @@ -477,10 +479,11 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, } static struct rsnd_mod_ops rsnd_dmapp_ops = { - .name = "audmac-pp", - .start = rsnd_dmapp_start, - .stop = rsnd_dmapp_stop, - .quit = rsnd_dmapp_stop, + .name = "audmac-pp", + .start = rsnd_dmapp_start, + .stop = rsnd_dmapp_stop, + .quit = rsnd_dmapp_stop, + .get_status = rsnd_mod_get_status, }; /* @@ -529,13 +532,14 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, struct device *dev = rsnd_priv_to_dev(priv); phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); - int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); + int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) || + !!(rsnd_io_to_mod_ssiu(io) == mod); int use_src = !!rsnd_io_to_mod_src(io); int use_cmd = !!rsnd_io_to_mod_dvc(io) || !!rsnd_io_to_mod_mix(io) || !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); - int busif = rsnd_ssi_get_busif(io); + int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io)); struct dma_addr { dma_addr_t out_addr; dma_addr_t in_addr; @@ -619,7 +623,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, struct rsnd_mod **mod_from, struct rsnd_mod **mod_to) { - struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssi; struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); @@ -630,6 +634,28 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, struct device *dev = rsnd_priv_to_dev(priv); int nr, i, idx; + /* + * It should use "rcar_sound,ssiu" on DT. + * But, we need to keep compatibility for old version. + * + * If it has "rcar_sound.ssiu", it will be used. + * If not, "rcar_sound.ssi" will be used. + * see + * rsnd_ssiu_dma_req() + * rsnd_ssi_dma_req() + */ + if (rsnd_ssiu_of_node(priv)) { + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); + + /* use SSIU */ + ssi = ssiu; + if (this == rsnd_io_to_mod_ssi(io)) + this = ssiu; + } else { + /* keep compatible, use SSI */ + ssi = rsnd_io_to_mod_ssi(io); + } + if (!ssi) return; @@ -690,12 +716,10 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, *mod_to = mod[1]; } - dev_dbg(dev, "module connection (this is %s[%d])\n", - rsnd_mod_name(this), rsnd_mod_id(this)); + dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this)); for (i = 0; i <= idx; i++) { - dev_dbg(dev, " %s[%d]%s\n", + dev_dbg(dev, " %s%s\n", rsnd_mod_name(mod[i] ? mod[i] : &mem), - rsnd_mod_id (mod[i] ? mod[i] : &mem), (mod[i] == *mod_from) ? " from" : (mod[i] == *mod_to) ? " to" : ""); } @@ -756,16 +780,14 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, *dma_mod = rsnd_mod_get(dma); ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, - rsnd_mod_get_status, type, dma_id); + type, dma_id); if (ret < 0) return ret; - dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", - rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod), + dev_dbg(dev, "%s %s -> %s\n", + rsnd_mod_name(*dma_mod), rsnd_mod_name(mod_from ? mod_from : &mem), - rsnd_mod_id (mod_from ? mod_from : &mem), - rsnd_mod_name(mod_to ? mod_to : &mem), - rsnd_mod_id (mod_to ? mod_to : &mem)); + rsnd_mod_name(mod_to ? mod_to : &mem)); ret = attach(io, dma, mod_from, mod_to); if (ret < 0) @@ -823,5 +845,5 @@ int rsnd_dma_probe(struct rsnd_priv *priv) priv->dma = dmac; /* dummy mem mod for debug */ - return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0); + return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0); } diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 024ece46bf68..8d91c0eb0880 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -86,14 +86,8 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, val[i] = rsnd_kctrl_valm(dvc->volume, i); /* Enable Digital Volume */ - rsnd_mod_write(mod, DVC_VOL0R, val[0]); - rsnd_mod_write(mod, DVC_VOL1R, val[1]); - rsnd_mod_write(mod, DVC_VOL2R, val[2]); - rsnd_mod_write(mod, DVC_VOL3R, val[3]); - rsnd_mod_write(mod, DVC_VOL4R, val[4]); - rsnd_mod_write(mod, DVC_VOL5R, val[5]); - rsnd_mod_write(mod, DVC_VOL6R, val[6]); - rsnd_mod_write(mod, DVC_VOL7R, val[7]); + for (i = 0; i < RSND_MAX_CHANNELS; i++) + rsnd_mod_write(mod, DVC_VOLxR(i), val[i]); } static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, @@ -298,6 +292,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = { .init = rsnd_dvc_init, .quit = rsnd_dvc_quit, .pcm_new = rsnd_dvc_pcm_new, + .get_status = rsnd_mod_get_status, }; struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) @@ -357,7 +352,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, - clk, rsnd_mod_get_status, RSND_MOD_DVC, i); + clk, RSND_MOD_DVC, i); if (ret) { of_node_put(np); goto rsnd_dvc_probe_done; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 1f7881cc16b2..7cda60188f41 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -26,8 +26,8 @@ struct rsnd_gen { struct regmap *regmap[RSND_BASE_MAX]; /* RSND_REG_MAX base */ - struct regmap_field *regs[RSND_REG_MAX]; - const char *reg_name[RSND_REG_MAX]; + struct regmap_field *regs[REG_MAX]; + const char *reg_name[REG_MAX]; }; #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) @@ -49,11 +49,11 @@ struct rsnd_regmap_field_conf { } /* single address mapping */ #define RSND_GEN_S_REG(id, offset) \ - RSND_REG_SET(RSND_REG_##id, offset, 0, #id) + RSND_REG_SET(id, offset, 0, #id) /* multi address mapping */ #define RSND_GEN_M_REG(id, offset, _id_offset) \ - RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id) + RSND_REG_SET(id, offset, _id_offset, #id) /* * basic function @@ -71,9 +71,17 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv, return 1; } -u32 rsnd_read(struct rsnd_priv *priv, - struct rsnd_mod *mod, enum rsnd_reg reg) +static int rsnd_mod_id_cmd(struct rsnd_mod *mod) { + if (mod->ops->id_cmd) + return mod->ops->id_cmd(mod); + + return rsnd_mod_id(mod); +} + +u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv); u32 val; @@ -81,35 +89,36 @@ u32 rsnd_read(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return 0; - regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); + regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val); - dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_reg_name(gen, reg), reg, val); return val; } -void rsnd_write(struct rsnd_priv *priv, - struct rsnd_mod *mod, - enum rsnd_reg reg, u32 data) +void rsnd_mod_write(struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv); if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); + regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data); - dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_reg_name(gen, reg), reg, data); } -void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, - enum rsnd_reg reg, u32 mask, u32 data) +void rsnd_mod_bset(struct rsnd_mod *mod, + enum rsnd_reg reg, u32 mask, u32 data) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv); @@ -117,10 +126,10 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, return; regmap_fields_force_update_bits(gen->regs[reg], - rsnd_mod_id(mod), mask, data); + rsnd_mod_id_cmd(mod), mask, data); - dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n", + rsnd_mod_name(mod), rsnd_reg_name(gen, reg), reg, data, mask); } diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 8e3b57eaa708..a3e0370f5704 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -256,6 +256,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = { .init = rsnd_mix_init, .quit = rsnd_mix_quit, .pcm_new = rsnd_mix_pcm_new, + .get_status = rsnd_mod_get_status, }; struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) @@ -315,7 +316,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, - clk, rsnd_mod_get_status, RSND_MOD_MIX, i); + clk, RSND_MOD_MIX, i); if (ret) { of_node_put(np); goto rsnd_mix_probe_done; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4464d1d0a042..605e4b934982 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -42,165 +42,175 @@ */ enum rsnd_reg { /* SCU (MIX/CTU/DVC) */ - RSND_REG_SRC_I_BUSIF_MODE, - RSND_REG_SRC_O_BUSIF_MODE, - RSND_REG_SRC_ROUTE_MODE0, - RSND_REG_SRC_SWRSR, - RSND_REG_SRC_SRCIR, - RSND_REG_SRC_ADINR, - RSND_REG_SRC_IFSCR, - RSND_REG_SRC_IFSVR, - RSND_REG_SRC_SRCCR, - RSND_REG_SRC_CTRL, - RSND_REG_SRC_BSDSR, - RSND_REG_SRC_BSISR, - RSND_REG_SRC_INT_ENABLE0, - RSND_REG_SRC_BUSIF_DALIGN, - RSND_REG_SRCIN_TIMSEL0, - RSND_REG_SRCIN_TIMSEL1, - RSND_REG_SRCIN_TIMSEL2, - RSND_REG_SRCIN_TIMSEL3, - RSND_REG_SRCIN_TIMSEL4, - RSND_REG_SRCOUT_TIMSEL0, - RSND_REG_SRCOUT_TIMSEL1, - RSND_REG_SRCOUT_TIMSEL2, - RSND_REG_SRCOUT_TIMSEL3, - RSND_REG_SRCOUT_TIMSEL4, - RSND_REG_SCU_SYS_STATUS0, - RSND_REG_SCU_SYS_STATUS1, - RSND_REG_SCU_SYS_INT_EN0, - RSND_REG_SCU_SYS_INT_EN1, - RSND_REG_CMD_CTRL, - RSND_REG_CMD_BUSIF_MODE, - RSND_REG_CMD_BUSIF_DALIGN, - RSND_REG_CMD_ROUTE_SLCT, - RSND_REG_CMDOUT_TIMSEL, - RSND_REG_CTU_SWRSR, - RSND_REG_CTU_CTUIR, - RSND_REG_CTU_ADINR, - RSND_REG_CTU_CPMDR, - RSND_REG_CTU_SCMDR, - RSND_REG_CTU_SV00R, - RSND_REG_CTU_SV01R, - RSND_REG_CTU_SV02R, - RSND_REG_CTU_SV03R, - RSND_REG_CTU_SV04R, - RSND_REG_CTU_SV05R, - RSND_REG_CTU_SV06R, - RSND_REG_CTU_SV07R, - RSND_REG_CTU_SV10R, - RSND_REG_CTU_SV11R, - RSND_REG_CTU_SV12R, - RSND_REG_CTU_SV13R, - RSND_REG_CTU_SV14R, - RSND_REG_CTU_SV15R, - RSND_REG_CTU_SV16R, - RSND_REG_CTU_SV17R, - RSND_REG_CTU_SV20R, - RSND_REG_CTU_SV21R, - RSND_REG_CTU_SV22R, - RSND_REG_CTU_SV23R, - RSND_REG_CTU_SV24R, - RSND_REG_CTU_SV25R, - RSND_REG_CTU_SV26R, - RSND_REG_CTU_SV27R, - RSND_REG_CTU_SV30R, - RSND_REG_CTU_SV31R, - RSND_REG_CTU_SV32R, - RSND_REG_CTU_SV33R, - RSND_REG_CTU_SV34R, - RSND_REG_CTU_SV35R, - RSND_REG_CTU_SV36R, - RSND_REG_CTU_SV37R, - RSND_REG_MIX_SWRSR, - RSND_REG_MIX_MIXIR, - RSND_REG_MIX_ADINR, - RSND_REG_MIX_MIXMR, - RSND_REG_MIX_MVPDR, - RSND_REG_MIX_MDBAR, - RSND_REG_MIX_MDBBR, - RSND_REG_MIX_MDBCR, - RSND_REG_MIX_MDBDR, - RSND_REG_MIX_MDBER, - 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_VOL2R, - RSND_REG_DVC_VOL3R, - RSND_REG_DVC_VOL4R, - RSND_REG_DVC_VOL5R, - RSND_REG_DVC_VOL6R, - RSND_REG_DVC_VOL7R, - RSND_REG_DVC_DVUER, - RSND_REG_DVC_VRCTR, - RSND_REG_DVC_VRPDR, - RSND_REG_DVC_VRDBR, + SRC_I_BUSIF_MODE, + SRC_O_BUSIF_MODE, + SRC_ROUTE_MODE0, + SRC_SWRSR, + SRC_SRCIR, + SRC_ADINR, + SRC_IFSCR, + SRC_IFSVR, + SRC_SRCCR, + SRC_CTRL, + SRC_BSDSR, + SRC_BSISR, + SRC_INT_ENABLE0, + SRC_BUSIF_DALIGN, + SRCIN_TIMSEL0, + SRCIN_TIMSEL1, + SRCIN_TIMSEL2, + SRCIN_TIMSEL3, + SRCIN_TIMSEL4, + SRCOUT_TIMSEL0, + SRCOUT_TIMSEL1, + SRCOUT_TIMSEL2, + SRCOUT_TIMSEL3, + SRCOUT_TIMSEL4, + SCU_SYS_STATUS0, + SCU_SYS_STATUS1, + SCU_SYS_INT_EN0, + SCU_SYS_INT_EN1, + CMD_CTRL, + CMD_BUSIF_MODE, + CMD_BUSIF_DALIGN, + CMD_ROUTE_SLCT, + CMDOUT_TIMSEL, + CTU_SWRSR, + CTU_CTUIR, + CTU_ADINR, + CTU_CPMDR, + CTU_SCMDR, + CTU_SV00R, + CTU_SV01R, + CTU_SV02R, + CTU_SV03R, + CTU_SV04R, + CTU_SV05R, + CTU_SV06R, + CTU_SV07R, + CTU_SV10R, + CTU_SV11R, + CTU_SV12R, + CTU_SV13R, + CTU_SV14R, + CTU_SV15R, + CTU_SV16R, + CTU_SV17R, + CTU_SV20R, + CTU_SV21R, + CTU_SV22R, + CTU_SV23R, + CTU_SV24R, + CTU_SV25R, + CTU_SV26R, + CTU_SV27R, + CTU_SV30R, + CTU_SV31R, + CTU_SV32R, + CTU_SV33R, + CTU_SV34R, + CTU_SV35R, + CTU_SV36R, + CTU_SV37R, + MIX_SWRSR, + MIX_MIXIR, + MIX_ADINR, + MIX_MIXMR, + MIX_MVPDR, + MIX_MDBAR, + MIX_MDBBR, + MIX_MDBCR, + MIX_MDBDR, + MIX_MDBER, + DVC_SWRSR, + DVC_DVUIR, + DVC_ADINR, + DVC_DVUCR, + DVC_ZCMCR, + DVC_VOL0R, + DVC_VOL1R, + DVC_VOL2R, + DVC_VOL3R, + DVC_VOL4R, + DVC_VOL5R, + DVC_VOL6R, + DVC_VOL7R, + DVC_DVUER, + DVC_VRCTR, + DVC_VRPDR, + DVC_VRDBR, /* ADG */ - RSND_REG_BRRA, - RSND_REG_BRRB, - RSND_REG_BRGCKR, - RSND_REG_DIV_EN, - RSND_REG_AUDIO_CLK_SEL0, - RSND_REG_AUDIO_CLK_SEL1, - RSND_REG_AUDIO_CLK_SEL2, + BRRA, + BRRB, + BRGCKR, + DIV_EN, + AUDIO_CLK_SEL0, + AUDIO_CLK_SEL1, + AUDIO_CLK_SEL2, /* SSIU */ - RSND_REG_SSI_MODE, - RSND_REG_SSI_MODE0, - RSND_REG_SSI_MODE1, - RSND_REG_SSI_MODE2, - RSND_REG_SSI_CONTROL, - RSND_REG_SSI_CTRL, - RSND_REG_SSI_BUSIF0_MODE, - RSND_REG_SSI_BUSIF0_ADINR, - RSND_REG_SSI_BUSIF0_DALIGN, - RSND_REG_SSI_BUSIF1_MODE, - RSND_REG_SSI_BUSIF1_ADINR, - RSND_REG_SSI_BUSIF1_DALIGN, - RSND_REG_SSI_BUSIF2_MODE, - RSND_REG_SSI_BUSIF2_ADINR, - RSND_REG_SSI_BUSIF2_DALIGN, - RSND_REG_SSI_BUSIF3_MODE, - RSND_REG_SSI_BUSIF3_ADINR, - RSND_REG_SSI_BUSIF3_DALIGN, - RSND_REG_SSI_BUSIF4_MODE, - RSND_REG_SSI_BUSIF4_ADINR, - RSND_REG_SSI_BUSIF4_DALIGN, - RSND_REG_SSI_BUSIF5_MODE, - RSND_REG_SSI_BUSIF5_ADINR, - RSND_REG_SSI_BUSIF5_DALIGN, - RSND_REG_SSI_BUSIF6_MODE, - RSND_REG_SSI_BUSIF6_ADINR, - RSND_REG_SSI_BUSIF6_DALIGN, - RSND_REG_SSI_BUSIF7_MODE, - RSND_REG_SSI_BUSIF7_ADINR, - RSND_REG_SSI_BUSIF7_DALIGN, - RSND_REG_SSI_INT_ENABLE, - RSND_REG_SSI_SYS_STATUS0, - RSND_REG_SSI_SYS_STATUS1, - RSND_REG_SSI_SYS_STATUS2, - RSND_REG_SSI_SYS_STATUS3, - RSND_REG_SSI_SYS_STATUS4, - RSND_REG_SSI_SYS_STATUS5, - RSND_REG_SSI_SYS_STATUS6, - RSND_REG_SSI_SYS_STATUS7, - RSND_REG_HDMI0_SEL, - RSND_REG_HDMI1_SEL, + SSI_MODE, + SSI_MODE0, + SSI_MODE1, + SSI_MODE2, + SSI_CONTROL, + SSI_CTRL, + SSI_BUSIF0_MODE, + SSI_BUSIF1_MODE, + SSI_BUSIF2_MODE, + SSI_BUSIF3_MODE, + SSI_BUSIF4_MODE, + SSI_BUSIF5_MODE, + SSI_BUSIF6_MODE, + SSI_BUSIF7_MODE, + SSI_BUSIF0_ADINR, + SSI_BUSIF1_ADINR, + SSI_BUSIF2_ADINR, + SSI_BUSIF3_ADINR, + SSI_BUSIF4_ADINR, + SSI_BUSIF5_ADINR, + SSI_BUSIF6_ADINR, + SSI_BUSIF7_ADINR, + SSI_BUSIF0_DALIGN, + SSI_BUSIF1_DALIGN, + SSI_BUSIF2_DALIGN, + SSI_BUSIF3_DALIGN, + SSI_BUSIF4_DALIGN, + SSI_BUSIF5_DALIGN, + SSI_BUSIF6_DALIGN, + SSI_BUSIF7_DALIGN, + SSI_INT_ENABLE, + SSI_SYS_STATUS0, + SSI_SYS_STATUS1, + SSI_SYS_STATUS2, + SSI_SYS_STATUS3, + SSI_SYS_STATUS4, + SSI_SYS_STATUS5, + SSI_SYS_STATUS6, + SSI_SYS_STATUS7, + HDMI0_SEL, + HDMI1_SEL, /* SSI */ - RSND_REG_SSICR, - RSND_REG_SSISR, - RSND_REG_SSITDR, - RSND_REG_SSIRDR, - RSND_REG_SSIWSR, + SSICR, + SSISR, + SSITDR, + SSIRDR, + SSIWSR, - RSND_REG_MAX, + REG_MAX, }; +#define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i)) +#define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i)) +#define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j)) +#define DVC_VOLxR(i) (DVC_VOL0R + (i)) +#define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i)) +#define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i)) +#define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i)) +#define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i)) +#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i)) + struct rsnd_priv; struct rsnd_mod; @@ -210,20 +220,9 @@ struct rsnd_dai_stream; /* * R-Car basic functions */ -#define rsnd_mod_read(m, r) \ - rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) -#define rsnd_mod_write(m, r, d) \ - rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) -#define rsnd_mod_bset(m, r, s, d) \ - rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) - -u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); -void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, - enum rsnd_reg reg, u32 data); -void rsnd_force_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_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg); +void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); +void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); @@ -301,6 +300,12 @@ struct rsnd_mod_ops { int (*cleanup)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + u32 *(*get_status)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type); + int (*id)(struct rsnd_mod *mod); + int (*id_sub)(struct rsnd_mod *mod); + int (*id_cmd)(struct rsnd_mod *mod); }; struct rsnd_dai_stream; @@ -310,9 +315,6 @@ struct rsnd_mod { struct rsnd_mod_ops *ops; struct rsnd_priv *priv; struct clk *clk; - u32 *(*get_status)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - enum rsnd_mod_type type); u32 status; }; /* @@ -375,8 +377,6 @@ struct rsnd_mod { #define __rsnd_mod_call_pointer 0 #define rsnd_mod_to_priv(mod) ((mod)->priv) -#define rsnd_mod_name(mod) ((mod)->ops->name) -#define rsnd_mod_id(mod) ((mod)->id) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) #define rsnd_mod_get(ip) (&(ip)->mod) @@ -385,9 +385,6 @@ int rsnd_mod_init(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_mod_ops *ops, struct clk *clk, - u32* (*get_status)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - enum rsnd_mod_type type), enum rsnd_mod_type type, int id); void rsnd_mod_quit(struct rsnd_mod *mod); @@ -396,9 +393,13 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); -u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, +u32 *rsnd_mod_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, enum rsnd_mod_type type); +int rsnd_mod_id(struct rsnd_mod *mod); +int rsnd_mod_id_raw(struct rsnd_mod *mod); +int rsnd_mod_id_sub(struct rsnd_mod *mod); +char *rsnd_mod_name(struct rsnd_mod *mod); struct rsnd_mod *rsnd_mod_next(int *iterator, struct rsnd_dai_stream *io, enum rsnd_mod_type *array, @@ -430,8 +431,9 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, rsnd_runtime_channel_for_ssi_with_params(io, NULL) int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, struct snd_pcm_hw_params *params); -int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); -int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); +int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io); +int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io); +int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io); /* * DT @@ -440,6 +442,7 @@ int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) #define RSND_NODE_DAI "rcar_sound,dai" #define RSND_NODE_SSI "rcar_sound,ssi" +#define RSND_NODE_SSIU "rcar_sound,ssiu" #define RSND_NODE_SRC "rcar_sound,src" #define RSND_NODE_CTU "rcar_sound,ctu" #define RSND_NODE_MIX "rcar_sound,mix" @@ -456,8 +459,17 @@ struct rsnd_dai_stream { struct rsnd_mod *dma; struct rsnd_dai *rdai; struct device *dmac_dev; /* for IPMMU */ + u32 converted_rate; /* converted sampling rate */ + int converted_chan; /* converted channels */ u32 parent_ssi_status; + u32 flags; }; + +/* flags */ +#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */ +#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */ +#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */ + #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) #define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) @@ -472,6 +484,8 @@ struct rsnd_dai_stream { #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) #define rsnd_io_to_runtime(io) ((io)->substream ? \ (io)->substream->runtime : NULL) +#define rsnd_io_converted_rate(io) ((io)->converted_rate) +#define rsnd_io_converted_chan(io) ((io)->converted_chan) int rsnd_io_is_working(struct rsnd_dai_stream *io); struct rsnd_dai { @@ -712,18 +726,9 @@ extern const char * const volume_ramp_rate[]; int rsnd_ssi_probe(struct rsnd_priv *priv); void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); -int rsnd_ssi_get_busif(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); -#define RSND_SSI_HDMI_PORT0 0xf0 -#define RSND_SSI_HDMI_PORT1 0xf1 -int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io); -void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, - struct device_node *endpoint, - int dai_i); - #define rsnd_ssi_is_pin_sharing(io) \ __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); @@ -742,6 +747,10 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod); int rsnd_ssiu_probe(struct rsnd_priv *priv); void rsnd_ssiu_remove(struct rsnd_priv *priv); +void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture); +#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU) /* * R-Car SRC @@ -767,7 +776,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, */ int rsnd_ctu_probe(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv); -int rsnd_ctu_converted_channel(struct rsnd_mod *mod); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) #define rsnd_parse_connect_ctu(rdai, playback, capture) \ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index cd38a43b976f..50348a2c9203 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -25,7 +25,6 @@ struct rsnd_src { struct rsnd_mod *dma; struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ struct rsnd_kctrl_cfg_s sync; /* sync convert */ - u32 convert_rate; /* sampling rate convert */ int irq; }; @@ -89,12 +88,12 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, return 0; if (!rsnd_src_sync_is_enabled(mod)) - return src->convert_rate; + return rsnd_io_converted_rate(io); convert_rate = src->sync.val; if (!convert_rate) - convert_rate = src->convert_rate; + convert_rate = rsnd_io_converted_rate(io); if (!convert_rate) convert_rate = runtime->rate; @@ -135,40 +134,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, return rate; } -static int rsnd_src_hw_params(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *fe_params) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct snd_soc_pcm_runtime *fe = substream->private_data; - - /* - * SRC assumes that it is used under DPCM if user want to use - * sampling rate convert. Then, SRC should be FE. - * And then, this function will be called *after* BE settings. - * this means, each BE already has fixuped hw_params. - * see - * dpcm_fe_dai_hw_params() - * dpcm_be_dai_hw_params() - */ - src->convert_rate = 0; - if (fe->dai_link->dynamic) { - int stream = substream->stream; - struct snd_soc_dpcm *dpcm; - struct snd_pcm_hw_params *be_params; - - for_each_dpcm_be(fe, stream, dpcm) { - be_params = &dpcm->hw_params; - - if (params_rate(fe_params) != params_rate(be_params)) - src->convert_rate = params_rate(be_params); - } - } - - return 0; -} - static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -349,9 +314,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod) status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); if ((status0 & val0) || (status1 & val1)) { - rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x, 0x%08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), - status0, status1); + rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", + rsnd_mod_name(mod), status0, status1); ret = true; } @@ -527,16 +491,16 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_src_ops = { - .name = SRC_NAME, - .dma_req = rsnd_src_dma_req, - .probe = rsnd_src_probe_, - .init = rsnd_src_init, - .quit = rsnd_src_quit, - .start = rsnd_src_start, - .stop = rsnd_src_stop, - .irq = rsnd_src_irq, - .hw_params = rsnd_src_hw_params, - .pcm_new = rsnd_src_pcm_new, + .name = SRC_NAME, + .dma_req = rsnd_src_dma_req, + .probe = rsnd_src_probe_, + .init = rsnd_src_init, + .quit = rsnd_src_quit, + .start = rsnd_src_start, + .stop = rsnd_src_stop, + .irq = rsnd_src_irq, + .pcm_new = rsnd_src_pcm_new, + .get_status = rsnd_mod_get_status, }; struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) @@ -605,8 +569,7 @@ int rsnd_src_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(src), - &rsnd_src_ops, clk, rsnd_mod_get_status, - RSND_MOD_SRC, i); + &rsnd_src_ops, clk, RSND_MOD_SRC, i); if (ret) { of_node_put(np); goto rsnd_src_probe_done; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6ec78f3096dd..45ef295743ec 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -99,9 +99,7 @@ struct rsnd_ssi { /* flags */ #define RSND_SSI_CLK_PIN_SHARE (1 << 0) #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ -#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */ -#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */ -#define RSND_SSI_PROBED (1 << 4) +#define RSND_SSI_PROBED (1 << 2) #define for_each_rsnd_ssi(pos, priv, i) \ for (i = 0; \ @@ -119,19 +117,7 @@ struct rsnd_ssi { (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) #define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) -int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (rsnd_flags_has(ssi, RSND_SSI_HDMI0)) - return RSND_SSI_HDMI_PORT0; - - if (rsnd_flags_has(ssi, RSND_SSI_HDMI1)) - return RSND_SSI_HDMI_PORT1; - - return 0; -} +static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { @@ -150,11 +136,6 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) return use_busif; } -int rsnd_ssi_get_busif(struct rsnd_dai_stream *io) -{ - return 0; /* BUSIF0 only for now */ -} - static void rsnd_ssi_status_clear(struct rsnd_mod *mod) { rsnd_mod_write(mod, SSISR, 0); @@ -181,8 +162,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, udelay(5); } - dev_warn(dev, "%s[%d] status check failed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod)); } static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) @@ -224,7 +204,7 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) { - if (rsnd_runtime_is_ssi_multi(io)) + if (rsnd_runtime_is_multi_ssi(io)) return rsnd_ssi_multi_slaves(io); return 0; @@ -320,6 +300,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return 0; } + if (rsnd_runtime_is_tdm_split(io)) + chan = rsnd_io_converted_chan(io); + main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); if (!main_rate) { dev_err(dev, "unsupported clock rate\n"); @@ -346,9 +329,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, ssi->rate = rate; ssi->chan = chan; - dev_dbg(dev, "%s[%d] outputs %u Hz\n", - rsnd_mod_name(mod), - rsnd_mod_id(mod), rate); + dev_dbg(dev, "%s outputs %d chan %u Hz\n", + rsnd_mod_name(mod), chan, rate); return 0; } @@ -379,14 +361,23 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); u32 cr_own = ssi->cr_own; u32 cr_mode = ssi->cr_mode; u32 wsr = ssi->wsr; - int is_tdm; + int width; + int is_tdm, is_tdm_split; + + is_tdm = rsnd_runtime_is_tdm(io); + is_tdm_split = rsnd_runtime_is_tdm_split(io); - is_tdm = rsnd_runtime_is_ssi_tdm(io); + if (is_tdm) + dev_dbg(dev, "TDM mode\n"); + if (is_tdm_split) + dev_dbg(dev, "TDM Split mode\n"); cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); @@ -405,7 +396,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, * rsnd_ssiu_init_gen2() */ wsr = ssi->wsr; - if (is_tdm) { + if (is_tdm || is_tdm_split) { wsr |= WS_MODE; cr_own |= CHNL_8; } @@ -421,7 +412,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_own |= TRMD; cr_own &= ~DWL_MASK; - switch (snd_pcm_format_width(runtime->format)) { + width = snd_pcm_format_width(runtime->format); + if (is_tdm_split) { + /* + * The SWL and DWL bits in SSICR should be fixed at 32-bit + * setting when TDM split mode. + * see datasheet + * Operation :: TDM Format Split Function (TDM Split Mode) + */ + width = 32; + } + + switch (width) { case 8: cr_own |= DWL_8; break; @@ -431,6 +433,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, case 24: cr_own |= DWL_24; break; + case 32: + cr_own |= DWL_32; + break; } if (rsnd_ssi_is_dma_mode(mod)) { @@ -494,8 +499,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, return 0; if (!ssi->usrcnt) { - dev_err(dev, "%s[%d] usrcnt error\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod)); return -EIO; } @@ -654,8 +658,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) { - rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), status); + rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); stop = true; } @@ -681,6 +685,41 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) return IRQ_HANDLED; } +static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + /* + * SSIP (= SSI parent) needs to be special, otherwise, + * 2nd SSI might doesn't start. see also rsnd_mod_call() + * + * We can't include parent SSI status on SSI, because we don't know + * how many SSI requests parent SSI. Thus, it is localed on "io" now. + * ex) trouble case + * Playback: SSI0 + * Capture : SSI1 (needs SSI0) + * + * 1) start Capture -> SSI0/SSI1 are started. + * 2) start Playback -> SSI0 doesn't work, because it is already + * marked as "started" on 1) + * + * OTOH, using each mod's status is good for MUX case. + * It doesn't need to start in 2nd start + * ex) + * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 + * | + * IO-1: SRC1 -> CTU2 -+ + * + * 1) start IO-0 -> start SSI0 + * 2) start IO-1 -> SSI0 doesn't need to start, because it is + * already started on 1) + */ + if (type == RSND_MOD_SSIP) + return &io->parent_ssi_status; + + return rsnd_mod_get_status(mod, io, type); +} + /* * SSI PIO */ @@ -730,7 +769,7 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int ret; + int ret = 0; /* * SSIP/SSIU/IRQ are not needed on @@ -744,10 +783,6 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, * see rsnd_ssi_pcm_new() */ - ret = rsnd_ssiu_attach(io, mod); - if (ret < 0) - return ret; - /* * SSI might be called again as PIO fallback * It is easy to manual handling for IRQ request/free @@ -876,18 +911,19 @@ static int rsnd_ssi_prepare(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_ssi_pio_ops = { - .name = SSI_NAME, - .probe = rsnd_ssi_common_probe, - .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_pio_init, - .quit = rsnd_ssi_quit, - .start = rsnd_ssi_start, - .stop = rsnd_ssi_stop, - .irq = rsnd_ssi_irq, - .pointer = rsnd_ssi_pio_pointer, - .pcm_new = rsnd_ssi_pcm_new, - .hw_params = rsnd_ssi_hw_params, - .prepare = rsnd_ssi_prepare, + .name = SSI_NAME, + .probe = rsnd_ssi_common_probe, + .remove = rsnd_ssi_common_remove, + .init = rsnd_ssi_pio_init, + .quit = rsnd_ssi_quit, + .start = rsnd_ssi_start, + .stop = rsnd_ssi_stop, + .irq = rsnd_ssi_irq, + .pointer = rsnd_ssi_pio_pointer, + .pcm_new = rsnd_ssi_pcm_new, + .hw_params = rsnd_ssi_hw_params, + .prepare = rsnd_ssi_prepare, + .get_status = rsnd_ssi_get_status, }; static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, @@ -928,8 +964,7 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod, */ mod->ops = &rsnd_ssi_pio_ops; - dev_info(dev, "%s[%d] fallback to PIO mode\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod)); return 0; } @@ -941,6 +976,17 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, int is_play = rsnd_io_is_play(io); char *name; + /* + * It should use "rcar_sound,ssiu" on DT. + * But, we need to keep compatibility for old version. + * + * If it has "rcar_sound.ssiu", it will be used. + * If not, "rcar_sound.ssi" will be used. + * see + * rsnd_ssiu_dma_req() + * rsnd_dma_of_path() + */ + if (rsnd_ssi_use_busif(io)) name = is_play ? "rxu" : "txu"; else @@ -951,27 +997,27 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, } static struct rsnd_mod_ops rsnd_ssi_dma_ops = { - .name = SSI_NAME, - .dma_req = rsnd_ssi_dma_req, - .probe = rsnd_ssi_dma_probe, - .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_init, - .quit = rsnd_ssi_quit, - .start = rsnd_ssi_start, - .stop = rsnd_ssi_stop, - .irq = rsnd_ssi_irq, - .pcm_new = rsnd_ssi_pcm_new, - .fallback = rsnd_ssi_fallback, - .hw_params = rsnd_ssi_hw_params, - .prepare = rsnd_ssi_prepare, + .name = SSI_NAME, + .dma_req = rsnd_ssi_dma_req, + .probe = rsnd_ssi_dma_probe, + .remove = rsnd_ssi_common_remove, + .init = rsnd_ssi_init, + .quit = rsnd_ssi_quit, + .start = rsnd_ssi_start, + .stop = rsnd_ssi_stop, + .irq = rsnd_ssi_irq, + .pcm_new = rsnd_ssi_pcm_new, + .fallback = rsnd_ssi_fallback, + .hw_params = rsnd_ssi_hw_params, + .prepare = rsnd_ssi_prepare, + .get_status = rsnd_ssi_get_status, }; -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) +static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) { return mod->ops == &rsnd_ssi_dma_ops; } - /* * ssi mod function */ @@ -1027,54 +1073,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, of_node_put(node); } -static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *remote_ep) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - struct rsnd_ssi *ssi; - struct device_node *remote_node = of_graph_get_port_parent(remote_ep); - - /* support Gen3 only */ - if (!rsnd_is_gen3(priv)) - return; - - if (!mod) - return; - - ssi = rsnd_mod_to_ssi(mod); - - /* HDMI0 */ - if (strstr(remote_node->full_name, "hdmi@fead0000")) { - rsnd_flags_set(ssi, RSND_SSI_HDMI0); - dev_dbg(dev, "%s[%d] connected to HDMI0\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - } - - /* HDMI1 */ - if (strstr(remote_node->full_name, "hdmi@feae0000")) { - rsnd_flags_set(ssi, RSND_SSI_HDMI1); - dev_dbg(dev, "%s[%d] connected to HDMI1\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - } -} - -void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, - struct device_node *endpoint, - int dai_i) -{ - struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); - struct device_node *remote_ep; - - remote_ep = of_graph_get_remote_endpoint(endpoint); - if (!remote_ep) - return; - - __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep); - __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep); -} - struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) { if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) @@ -1091,41 +1089,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE)); } -static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - enum rsnd_mod_type type) -{ - /* - * SSIP (= SSI parent) needs to be special, otherwise, - * 2nd SSI might doesn't start. see also rsnd_mod_call() - * - * We can't include parent SSI status on SSI, because we don't know - * how many SSI requests parent SSI. Thus, it is localed on "io" now. - * ex) trouble case - * Playback: SSI0 - * Capture : SSI1 (needs SSI0) - * - * 1) start Capture -> SSI0/SSI1 are started. - * 2) start Playback -> SSI0 doesn't work, because it is already - * marked as "started" on 1) - * - * OTOH, using each mod's status is good for MUX case. - * It doesn't need to start in 2nd start - * ex) - * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 - * | - * IO-1: SRC1 -> CTU2 -+ - * - * 1) start IO-0 -> start SSI0 - * 2) start IO-1 -> SSI0 doesn't need to start, because it is - * already started on 1) - */ - if (type == RSND_MOD_SSIP) - return &io->parent_ssi_status; - - return rsnd_mod_get_status(io, mod, type); -} - int rsnd_ssi_probe(struct rsnd_priv *priv) { struct device_node *node; @@ -1192,7 +1155,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ops = &rsnd_ssi_dma_ops; ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, - rsnd_ssi_get_status, RSND_MOD_SSI, i); + RSND_MOD_SSI, i); if (ret) { of_node_put(np); goto rsnd_ssi_probe_done; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 39b67643b5dc..c5934adcfd01 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -12,8 +12,14 @@ struct rsnd_ssiu { struct rsnd_mod mod; u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ unsigned int usrcnt; + int id; + int id_sub; }; +/* SSI_MODE */ +#define TDM_EXT (1 << 0) +#define TDM_SPLIT (1 << 8) + #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) #define for_each_rsnd_ssiu(pos, priv, i) \ @@ -22,6 +28,33 @@ struct rsnd_ssiu { ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ i++) +/* + * SSI Gen2 Gen3 + * 0 BUSIF0-3 BUSIF0-7 + * 1 BUSIF0-3 BUSIF0-7 + * 2 BUSIF0-3 BUSIF0-7 + * 3 BUSIF0 BUSIF0-7 + * 4 BUSIF0 BUSIF0-7 + * 5 BUSIF0 BUSIF0 + * 6 BUSIF0 BUSIF0 + * 7 BUSIF0 BUSIF0 + * 8 BUSIF0 BUSIF0 + * 9 BUSIF0-3 BUSIF0-7 + * total 22 52 + */ +static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; +static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; + +static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + int busif = rsnd_mod_id_sub(mod); + + return &ssiu->busif_status[busif]; +} + static int rsnd_ssiu_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -32,6 +65,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, int id = rsnd_mod_id(mod); u32 mask1, val1; u32 mask2, val2; + int i; /* clear status */ switch (id) { @@ -40,16 +74,12 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, case 2: case 3: case 4: - rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4)); - rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4)); - rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4)); - rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4)); + for (i = 0; i < 4; i++) + rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4)); break; case 9: - rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4); - rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4); - rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4); - rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4); + for (i = 0; i < 4; i++) + rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << (id * 4)); break; } @@ -115,8 +145,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { - .name = SSIU_NAME, - .init = rsnd_ssiu_init, + .name = SSIU_NAME, + .init = rsnd_ssiu_init, + .get_status = rsnd_ssiu_get_status, }; static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, @@ -124,7 +155,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int hdmi = rsnd_ssi_hdmi_port(io); + u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); + u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); int ret; u32 mode = 0; @@ -134,20 +166,21 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, ssiu->usrcnt++; - if (rsnd_runtime_is_ssi_tdm(io)) { - /* - * TDM Extend Mode - * see - * rsnd_ssi_config_init() - */ - mode = 0x1; - } + /* + * TDM Extend/Split Mode + * see + * rsnd_ssi_config_init() + */ + if (rsnd_runtime_is_tdm(io)) + mode = TDM_EXT; + else if (rsnd_runtime_is_tdm_split(io)) + mode = TDM_SPLIT; rsnd_mod_write(mod, SSI_MODE, mode); if (rsnd_ssi_use_busif(io)) { int id = rsnd_mod_id(mod); - int busif = rsnd_ssi_get_busif(io); + int busif = rsnd_mod_id_sub(mod); /* * FIXME @@ -162,46 +195,18 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, id, busif); } -#define RSND_WRITE_BUSIF(i) \ - rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \ - rsnd_get_adinr_bit(mod, io) | \ - (rsnd_io_is_play(io) ? \ - rsnd_runtime_channel_after_ctu(io) : \ - rsnd_runtime_channel_original(io))); \ - rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \ - rsnd_get_busif_shift(io, mod) | 1); \ - rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \ - rsnd_get_dalign(mod, io)) - - switch (busif) { - case 0: - RSND_WRITE_BUSIF(0); - break; - case 1: - RSND_WRITE_BUSIF(1); - break; - case 2: - RSND_WRITE_BUSIF(2); - break; - case 3: - RSND_WRITE_BUSIF(3); - break; - case 4: - RSND_WRITE_BUSIF(4); - break; - case 5: - RSND_WRITE_BUSIF(5); - break; - case 6: - RSND_WRITE_BUSIF(6); - break; - case 7: - RSND_WRITE_BUSIF(7); - break; - } + rsnd_mod_write(mod, SSI_BUSIF_ADINR(busif), + rsnd_get_adinr_bit(mod, io) | + (rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu(io) : + rsnd_runtime_channel_original(io))); + rsnd_mod_write(mod, SSI_BUSIF_MODE(busif), + rsnd_get_busif_shift(io, mod) | 1); + rsnd_mod_write(mod, SSI_BUSIF_DALIGN(busif), + rsnd_get_dalign(mod, io)); } - if (hdmi) { + if (has_hdmi0 || has_hdmi1) { enum rsnd_mod_type rsnd_ssi_array[] = { RSND_MOD_SSIM1, RSND_MOD_SSIM2, @@ -227,14 +232,10 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, rsnd_mod_id(pos) << shift; } - switch (hdmi) { - case RSND_SSI_HDMI_PORT0: + if (has_hdmi0) rsnd_mod_write(mod, HDMI0_SEL, val); - break; - case RSND_SSI_HDMI_PORT1: + if (has_hdmi1) rsnd_mod_write(mod, HDMI1_SEL, val); - break; - } } return 0; @@ -244,7 +245,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - int busif = rsnd_ssi_get_busif(io); + int busif = rsnd_mod_id_sub(mod); if (!rsnd_ssi_use_busif(io)) return 0; @@ -262,7 +263,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int busif = rsnd_ssi_get_busif(io); + int busif = rsnd_mod_id_sub(mod); if (!rsnd_ssi_use_busif(io)) return 0; @@ -278,11 +279,53 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, return 0; } +static int rsnd_ssiu_id(struct rsnd_mod *mod) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + + /* see rsnd_ssiu_probe() */ + return ssiu->id; +} + +static int rsnd_ssiu_id_sub(struct rsnd_mod *mod) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + + /* see rsnd_ssiu_probe() */ + return ssiu->id_sub; +} + +static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + int is_play = rsnd_io_is_play(io); + char *name; + + /* + * It should use "rcar_sound,ssiu" on DT. + * But, we need to keep compatibility for old version. + * + * If it has "rcar_sound.ssiu", it will be used. + * If not, "rcar_sound.ssi" will be used. + * see + * rsnd_ssi_dma_req() + * rsnd_dma_of_path() + */ + + name = is_play ? "rx" : "tx"; + + return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), + mod, name); +} + static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { - .name = SSIU_NAME, - .init = rsnd_ssiu_init_gen2, - .start = rsnd_ssiu_start_gen2, - .stop = rsnd_ssiu_stop_gen2, + .name = SSIU_NAME, + .dma_req = rsnd_ssiu_dma_req, + .init = rsnd_ssiu_init_gen2, + .start = rsnd_ssiu_start_gen2, + .stop = rsnd_ssiu_stop_gen2, + .get_status = rsnd_ssiu_get_status, }; static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) @@ -293,36 +336,85 @@ static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); } -int rsnd_ssiu_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *ssi_mod) +static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, + struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod)); + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *mod; + struct rsnd_ssiu *ssiu; + int i; - rsnd_mod_confirm_ssi(ssi_mod); + if (!ssi_mod) + return; - return rsnd_dai_connect(mod, io, mod->type); + /* select BUSIF0 */ + for_each_rsnd_ssiu(ssiu, priv, i) { + mod = rsnd_mod_get(ssiu); + + if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && + (rsnd_mod_id_sub(mod) == 0)) { + rsnd_dai_connect(mod, io, mod->type); + return; + } + } } -static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - enum rsnd_mod_type type) +void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture) { - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int busif = rsnd_ssi_get_busif(io); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device_node *node = rsnd_ssiu_of_node(priv); + struct device_node *np; + struct rsnd_mod *mod; + struct rsnd_dai_stream *io_p = &rdai->playback; + struct rsnd_dai_stream *io_c = &rdai->capture; + int i; - return &ssiu->busif_status[busif]; + /* use rcar_sound,ssiu if exist */ + if (node) { + i = 0; + for_each_child_of_node(node, np) { + mod = rsnd_ssiu_mod_get(priv, i); + if (np == playback) + rsnd_dai_connect(mod, io_p, mod->type); + if (np == capture) + rsnd_dai_connect(mod, io_c, mod->type); + i++; + } + + of_node_put(node); + } + + /* Keep DT compatibility */ + if (!rsnd_io_to_mod_ssiu(io_p)) + rsnd_parse_connect_ssiu_compatible(priv, io_p); + if (!rsnd_io_to_mod_ssiu(io_c)) + rsnd_parse_connect_ssiu_compatible(priv, io_c); } int rsnd_ssiu_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *node; struct rsnd_ssiu *ssiu; struct rsnd_mod_ops *ops; + const int *list = NULL; int i, nr, ret; - /* same number to SSI */ - nr = priv->ssi_nr; + /* + * Keep DT compatibility. + * if it has "rcar_sound,ssiu", use it. + * if not, use "rcar_sound,ssi" + * see + * rsnd_ssiu_bufsif_to_id() + */ + node = rsnd_ssiu_of_node(priv); + if (node) + nr = of_get_child_count(node); + else + nr = priv->ssi_nr; + ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); if (!ssiu) return -ENOMEM; @@ -335,10 +427,46 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) else ops = &rsnd_ssiu_ops_gen2; + /* Keep compatibility */ + nr = 0; + if ((node) && + (ops == &rsnd_ssiu_ops_gen2)) { + ops->id = rsnd_ssiu_id; + ops->id_sub = rsnd_ssiu_id_sub; + + if (rsnd_is_gen2(priv)) { + list = gen2_id; + nr = ARRAY_SIZE(gen2_id); + } else if (rsnd_is_gen3(priv)) { + list = gen3_id; + nr = ARRAY_SIZE(gen3_id); + } else { + dev_err(dev, "unknown SSIU\n"); + return -ENODEV; + } + } + for_each_rsnd_ssiu(ssiu, priv, i) { + if (node) { + int j; + + /* + * see + * rsnd_ssiu_get_id() + * rsnd_ssiu_get_id_sub() + */ + for (j = 0; j < nr; j++) { + if (list[j] > i) + break; + ssiu->id = j; + ssiu->id_sub = i - list[ssiu->id]; + } + } else { + ssiu->id = i; + } + ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), - ops, NULL, rsnd_ssiu_get_status, - RSND_MOD_SSIU, i); + ops, NULL, RSND_MOD_SSIU, i); if (ret) return ret; } |