| From b4fba81581fa57de8e1f1fab501e9c5c9f38ac47 Mon Sep 17 00:00:00 2001 |
| From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
| Date: Wed, 29 Nov 2017 03:07:51 +0000 |
| Subject: [PATCH 0561/1795] ASoC: rsnd: TDM 6ch needs 8ch clock for hw refine |
| |
| Renesas sound needs 8ch clock if TDM 6ch mode, and needs 2ch clock for |
| 6ch or 8ch sound if Multi SSI mode. And these are related to before/after |
| CTU (= Channel Transfer Unit). |
| To calculate these we already has rsnd_runtime_channel_for_ssi() which |
| returns runtime necessary channels. |
| But, it based on runtime->channels which is not yet set when hw refine. |
| We need to use hw_params instead of runtime->xxx when hw refine, |
| and it is not needed after runtime was set. |
| This patch adds new hw_params on rsnd_dai_stream, and it will be removed |
| on rsnd_hw_params(). |
| This is very temporary durty code, but it seems no choice at this point. |
| |
| Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com> |
| Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| (cherry picked from commit b2fb31bb7454d5479b1c7214ccd10c1af85a6245) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| sound/soc/sh/rcar/core.c | 92 +++++++++++++++++++++++++++++----------- |
| sound/soc/sh/rcar/rsnd.h | 15 +++++-- |
| 2 files changed, 80 insertions(+), 27 deletions(-) |
| |
| diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c |
| index bd64dc6ec1c3..d76ad46a6fd9 100644 |
| --- a/sound/soc/sh/rcar/core.c |
| +++ b/sound/soc/sh/rcar/core.c |
| @@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) |
| return 0; |
| } |
| |
| -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) |
| +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, |
| + struct snd_pcm_hw_params *params) |
| { |
| struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
| |
| - return runtime->channels; |
| + /* |
| + * params will be added when refine |
| + * see |
| + * __rsnd_soc_hw_rule_rate() |
| + * __rsnd_soc_hw_rule_channels() |
| + */ |
| + if (params) |
| + return params_channels(params); |
| + else |
| + return runtime->channels; |
| } |
| |
| -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) |
| +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, |
| + struct snd_pcm_hw_params *params) |
| { |
| - int chan = rsnd_runtime_channel_original(io); |
| + int chan = rsnd_runtime_channel_original_with_params(io, params); |
| struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); |
| |
| if (ctu_mod) { |
| @@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) |
| return chan; |
| } |
| |
| -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) |
| +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, |
| + struct snd_pcm_hw_params *params) |
| { |
| struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
| int chan = rsnd_io_is_play(io) ? |
| - rsnd_runtime_channel_after_ctu(io) : |
| - rsnd_runtime_channel_original(io); |
| + rsnd_runtime_channel_after_ctu_with_params(io, params) : |
| + rsnd_runtime_channel_original_with_params(io, params); |
| |
| /* Use Multi SSI */ |
| if (rsnd_runtime_is_ssi_multi(io)) |
| @@ -616,8 +628,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
| switch (cmd) { |
| case SNDRV_PCM_TRIGGER_START: |
| case SNDRV_PCM_TRIGGER_RESUME: |
| - rsnd_dai_stream_init(io, substream); |
| - |
| ret = rsnd_dai_call(init, io, priv); |
| if (ret < 0) |
| goto dai_trigger_end; |
| @@ -639,7 +649,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
| |
| ret |= rsnd_dai_call(quit, io, priv); |
| |
| - rsnd_dai_stream_quit(io); |
| break; |
| default: |
| ret = -EINVAL; |
| @@ -784,8 +793,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, |
| return snd_interval_refine(iv, &p); |
| } |
| |
| -static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
| - struct snd_pcm_hw_rule *rule) |
| +static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
| + struct snd_pcm_hw_rule *rule, |
| + int is_play) |
| { |
| struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
| struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
| @@ -793,25 +803,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
| struct snd_soc_dai *dai = rule->private; |
| struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
| struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
| + struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; |
| |
| /* |
| * possible sampling rate limitation is same as |
| * 2ch if it supports multi ssi |
| + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) |
| */ |
| ic = *ic_; |
| - if (1 < rsnd_rdai_ssi_lane_get(rdai)) { |
| - ic.min = 2; |
| - ic.max = 2; |
| - } |
| + ic.min = |
| + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); |
| |
| return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, |
| ARRAY_SIZE(rsnd_soc_hw_rate_list), |
| &ic, ir); |
| } |
| |
| +static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, |
| + struct snd_pcm_hw_rule *rule) |
| +{ |
| + return __rsnd_soc_hw_rule_rate(params, rule, 1); |
| +} |
| + |
| +static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, |
| + struct snd_pcm_hw_rule *rule) |
| +{ |
| + return __rsnd_soc_hw_rule_rate(params, rule, 0); |
| +} |
| |
| -static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
| - struct snd_pcm_hw_rule *rule) |
| +static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
| + struct snd_pcm_hw_rule *rule, |
| + int is_play) |
| { |
| struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
| struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
| @@ -819,22 +841,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
| struct snd_soc_dai *dai = rule->private; |
| struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
| struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
| + struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; |
| |
| /* |
| * possible sampling rate limitation is same as |
| * 2ch if it supports multi ssi |
| + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) |
| */ |
| ic = *ic_; |
| - if (1 < rsnd_rdai_ssi_lane_get(rdai)) { |
| - ic.min = 2; |
| - ic.max = 2; |
| - } |
| + ic.min = |
| + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); |
| |
| return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, |
| ARRAY_SIZE(rsnd_soc_hw_channels_list), |
| ir, &ic); |
| } |
| |
| +static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, |
| + struct snd_pcm_hw_rule *rule) |
| +{ |
| + return __rsnd_soc_hw_rule_channels(params, rule, 1); |
| +} |
| + |
| +static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, |
| + struct snd_pcm_hw_rule *rule) |
| +{ |
| + return __rsnd_soc_hw_rule_channels(params, rule, 0); |
| +} |
| + |
| static const struct snd_pcm_hardware rsnd_pcm_hardware = { |
| .info = SNDRV_PCM_INFO_INTERLEAVED | |
| SNDRV_PCM_INFO_MMAP | |
| @@ -859,6 +893,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, |
| int ret; |
| int i; |
| |
| + rsnd_dai_stream_init(io, substream); |
| + |
| /* |
| * Channel Limitation |
| * It depends on Platform design |
| @@ -886,11 +922,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, |
| * It depends on Clock Master Mode |
| */ |
| if (rsnd_rdai_is_clk_master(rdai)) { |
| + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
| + |
| snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
| - rsnd_soc_hw_rule_rate, dai, |
| + is_play ? rsnd_soc_hw_rule_rate_playback : |
| + rsnd_soc_hw_rule_rate_capture, |
| + dai, |
| SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
| snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
| - rsnd_soc_hw_rule_channels, dai, |
| + is_play ? rsnd_soc_hw_rule_channels_playback : |
| + rsnd_soc_hw_rule_channels_capture, |
| + dai, |
| SNDRV_PCM_HW_PARAM_RATE, -1); |
| } |
| |
| @@ -915,6 +957,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, |
| * call rsnd_dai_call without spinlock |
| */ |
| rsnd_dai_call(nolock_stop, io, priv); |
| + |
| + rsnd_dai_stream_quit(io); |
| } |
| |
| static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { |
| diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h |
| index 57cd2bc773c2..ad6523595b0a 100644 |
| --- a/sound/soc/sh/rcar/rsnd.h |
| +++ b/sound/soc/sh/rcar/rsnd.h |
| @@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, |
| struct device_node *playback, |
| struct device_node *capture); |
| |
| -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); |
| -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); |
| -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); |
| +#define rsnd_runtime_channel_original(io) \ |
| + rsnd_runtime_channel_original_with_params(io, NULL) |
| +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, |
| + struct snd_pcm_hw_params *params); |
| +#define rsnd_runtime_channel_after_ctu(io) \ |
| + rsnd_runtime_channel_after_ctu_with_params(io, NULL) |
| +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, |
| + struct snd_pcm_hw_params *params); |
| +#define rsnd_runtime_channel_for_ssi(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); |
| |
| -- |
| 2.19.0 |
| |