diff options
Diffstat (limited to 'sound/soc/sh/rcar/core.c')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 124 |
1 files changed, 60 insertions, 64 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d23c2bbff0cf..f930f51b686f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -102,7 +102,9 @@ #include "rsnd.h" #define RSND_RATES SNDRV_PCM_RATE_8000_192000 -#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) +#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) static const struct of_device_id rsnd_of_match[] = { { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, @@ -280,6 +282,8 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct device *dev = rsnd_priv_to_dev(priv); switch (snd_pcm_format_width(runtime->format)) { + case 8: + return 16 << 16; case 16: return 8 << 16; case 24: @@ -331,7 +335,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) target = cmd ? cmd : ssiu; } - /* Non target mod or 24bit data needs normal DALIGN */ + /* Non target mod or non 16bit needs normal DALIGN */ if ((snd_pcm_format_width(runtime->format) != 16) || (mod != target)) return 0x76543210; @@ -367,7 +371,7 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) * HW 24bit data is located as 0x******00 * */ - if (snd_pcm_format_width(runtime->format) == 16) + if (snd_pcm_format_width(runtime->format) != 24) return 0; for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { @@ -540,6 +544,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, return rdai->ssi_lane; } +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) +{ + if (width > 0) + rdai->chan_width = width; + + return rdai->chan_width; +} + struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) { if ((id < 0) || (id >= rsnd_rdai_nr(priv))) @@ -681,6 +693,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) rdai->frm_clk_inv = 0; break; case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_B: rdai->sys_delay = 1; rdai->data_alignment = 0; rdai->frm_clk_inv = 1; @@ -690,6 +703,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) rdai->data_alignment = 1; rdai->frm_clk_inv = 1; break; + case SND_SOC_DAIFMT_DSP_A: + rdai->sys_delay = 0; + rdai->data_alignment = 0; + rdai->frm_clk_inv = 1; + break; } /* set clock inversion */ @@ -720,6 +738,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct device *dev = rsnd_priv_to_dev(priv); + switch (slot_width) { + case 16: + case 24: + case 32: + break; + default: + /* use default */ + slot_width = 32; + } + switch (slots) { case 2: case 6: @@ -727,6 +755,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, /* TDM Extend Mode */ rsnd_rdai_channels_set(rdai, slots); rsnd_rdai_ssi_lane_set(rdai, 1); + rsnd_rdai_width_set(rdai, slot_width); break; default: dev_err(dev, "unsupported TDM slots (%d)\n", slots); @@ -755,7 +784,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = { 192000, }; -static int rsnd_soc_hw_rule(struct rsnd_priv *priv, +static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, unsigned int *list, int list_num, struct snd_interval *baseline, struct snd_interval *iv) { @@ -772,14 +801,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, if (!snd_interval_test(iv, list[i])) continue; - rate = rsnd_ssi_clk_query(priv, + rate = rsnd_ssi_clk_query(rdai, baseline->min, list[i], NULL); if (rate > 0) { p.min = min(p.min, list[i]); p.max = max(p.max, list[i]); } - rate = rsnd_ssi_clk_query(priv, + rate = rsnd_ssi_clk_query(rdai, baseline->max, list[i], NULL); if (rate > 0) { p.min = min(p.min, list[i]); @@ -790,17 +819,14 @@ 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, - int is_play) +static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { 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); struct snd_interval ic; - 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; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); /* * possible sampling rate limitation is same as @@ -811,34 +837,19 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, ic.min = ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, + return rsnd_soc_hw_rule(rdai, 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, - int is_play) +static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { 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); struct snd_interval ic; - 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; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); /* * possible sampling rate limitation is same as @@ -849,23 +860,11 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ic.min = ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, + return rsnd_soc_hw_rule(rdai, 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 | @@ -882,12 +881,10 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int max_channels = rsnd_rdai_channels_get(rdai); - int ret; int i; rsnd_dai_stream_init(io, substream); @@ -922,25 +919,16 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - is_play ? rsnd_soc_hw_rule_rate_playback : - rsnd_soc_hw_rule_rate_capture, - dai, + rsnd_soc_hw_rule_rate, + is_play ? &rdai->playback : &rdai->capture, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - is_play ? rsnd_soc_hw_rule_channels_playback : - rsnd_soc_hw_rule_channels_capture, - dai, + rsnd_soc_hw_rule_channels, + is_play ? &rdai->playback : &rdai->capture, SNDRV_PCM_HW_PARAM_RATE, -1); } - /* - * call rsnd_dai_call without spinlock - */ - ret = rsnd_dai_call(nolock_start, io, priv); - if (ret < 0) - rsnd_dai_call(nolock_stop, io, priv); - - return ret; + return 0; } static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, @@ -953,7 +941,7 @@ 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_call(cleanup, io, priv); rsnd_dai_stream_quit(io); } @@ -1083,6 +1071,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->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 */ for (io_i = 0;; io_i++) { playback = of_parse_phandle(dai_np, "playback", io_i); @@ -1274,8 +1263,15 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + + if (!runtime) { + dev_warn(dev, "Can't update kctrl when idle\n"); + return 0; + } - return !!runtime; + return 1; } struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) |