diff options
author | Mark Brown <broonie@kernel.org> | 2018-01-18 06:55:37 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-01-18 06:55:37 -0500 |
commit | 078b3a0205cba12302d40ce04a24c0edaa6842ce (patch) | |
tree | 69d5b79691fd894866b89798329c42efc7c641b5 | |
parent | 5f7a0ea9fe0e1874ff339ab42fdde89f0ccee411 (diff) | |
parent | 2ca69d73bc05a55edb95689d436ce87974a3162e (diff) |
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
-rw-r--r-- | Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 15 | ||||
-rw-r--r-- | include/sound/soc.h | 2 | ||||
-rw-r--r-- | sound/soc/rockchip/rk3399_gru_sound.c | 3 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 143 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dma.c | 18 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 15 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 163 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 10 |
8 files changed, 197 insertions, 172 deletions
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 085bec364caf..5bed9a595772 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt | |||
@@ -4,7 +4,7 @@ Renesas R-Car sound | |||
4 | * Modules | 4 | * Modules |
5 | ============================================= | 5 | ============================================= |
6 | 6 | ||
7 | Renesas R-Car sound is constructed from below modules | 7 | Renesas R-Car and RZ/G sound is constructed from below modules |
8 | (for Gen2 or later) | 8 | (for Gen2 or later) |
9 | 9 | ||
10 | SCU : Sampling Rate Converter Unit | 10 | SCU : Sampling Rate Converter Unit |
@@ -197,12 +197,17 @@ Ex) | |||
197 | [MEM] -> [SRC2] -> [CTU03] -+ | 197 | [MEM] -> [SRC2] -> [CTU03] -+ |
198 | 198 | ||
199 | sound { | 199 | sound { |
200 | #address-cells = <1>; | ||
201 | #size-cells = <0>; | ||
202 | |||
200 | compatible = "simple-scu-audio-card"; | 203 | compatible = "simple-scu-audio-card"; |
201 | ... | 204 | ... |
202 | simple-audio-card,cpu-0 { | 205 | simple-audio-card,cpu@0 { |
206 | reg = <0>; | ||
203 | sound-dai = <&rcar_sound 0>; | 207 | sound-dai = <&rcar_sound 0>; |
204 | }; | 208 | }; |
205 | simple-audio-card,cpu-1 { | 209 | simple-audio-card,cpu@1 { |
210 | reg = <1>; | ||
206 | sound-dai = <&rcar_sound 1>; | 211 | sound-dai = <&rcar_sound 1>; |
207 | }; | 212 | }; |
208 | simple-audio-card,codec { | 213 | simple-audio-card,codec { |
@@ -334,9 +339,11 @@ Required properties: | |||
334 | 339 | ||
335 | - compatible : "renesas,rcar_sound-<soctype>", fallbacks | 340 | - compatible : "renesas,rcar_sound-<soctype>", fallbacks |
336 | "renesas,rcar_sound-gen1" if generation1, and | 341 | "renesas,rcar_sound-gen1" if generation1, and |
337 | "renesas,rcar_sound-gen2" if generation2 | 342 | "renesas,rcar_sound-gen2" if generation2 (or RZ/G1) |
338 | "renesas,rcar_sound-gen3" if generation3 | 343 | "renesas,rcar_sound-gen3" if generation3 |
339 | Examples with soctypes are: | 344 | Examples with soctypes are: |
345 | - "renesas,rcar_sound-r8a7743" (RZ/G1M) | ||
346 | - "renesas,rcar_sound-r8a7745" (RZ/G1E) | ||
340 | - "renesas,rcar_sound-r8a7778" (R-Car M1A) | 347 | - "renesas,rcar_sound-r8a7778" (R-Car M1A) |
341 | - "renesas,rcar_sound-r8a7779" (R-Car H1) | 348 | - "renesas,rcar_sound-r8a7779" (R-Car H1) |
342 | - "renesas,rcar_sound-r8a7790" (R-Car H2) | 349 | - "renesas,rcar_sound-r8a7790" (R-Car H2) |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 6e865c2bcffe..8fd59dadaf01 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -494,6 +494,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); | |||
494 | int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num); | 494 | int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num); |
495 | #endif | 495 | #endif |
496 | 496 | ||
497 | void snd_soc_disconnect_sync(struct device *dev); | ||
498 | |||
497 | struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, | 499 | struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, |
498 | const char *dai_link, int stream); | 500 | const char *dai_link, int stream); |
499 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, | 501 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, |
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index d64fbbd50544..fa6cd1de828b 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c | |||
@@ -206,7 +206,8 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) | |||
206 | return ret; | 206 | return ret; |
207 | } | 207 | } |
208 | 208 | ||
209 | snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA); | 209 | snd_jack_set_key( |
210 | rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); | ||
210 | snd_jack_set_key( | 211 | snd_jack_set_key( |
211 | rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); | 212 | rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); |
212 | snd_jack_set_key( | 213 | snd_jack_set_key( |
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f12a88a21dfa..64d5ecb86528 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) | |||
197 | return 0; | 197 | return 0; |
198 | } | 198 | } |
199 | 199 | ||
200 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) | 200 | int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, |
201 | struct snd_pcm_hw_params *params) | ||
201 | { | 202 | { |
202 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 203 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
203 | 204 | ||
204 | return runtime->channels; | 205 | /* |
206 | * params will be added when refine | ||
207 | * see | ||
208 | * __rsnd_soc_hw_rule_rate() | ||
209 | * __rsnd_soc_hw_rule_channels() | ||
210 | */ | ||
211 | if (params) | ||
212 | return params_channels(params); | ||
213 | else | ||
214 | return runtime->channels; | ||
205 | } | 215 | } |
206 | 216 | ||
207 | int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) | 217 | int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, |
218 | struct snd_pcm_hw_params *params) | ||
208 | { | 219 | { |
209 | int chan = rsnd_runtime_channel_original(io); | 220 | int chan = rsnd_runtime_channel_original_with_params(io, params); |
210 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); | 221 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); |
211 | 222 | ||
212 | if (ctu_mod) { | 223 | if (ctu_mod) { |
@@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) | |||
219 | return chan; | 230 | return chan; |
220 | } | 231 | } |
221 | 232 | ||
222 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) | 233 | int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, |
234 | struct snd_pcm_hw_params *params) | ||
223 | { | 235 | { |
224 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 236 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
225 | int chan = rsnd_io_is_play(io) ? | 237 | int chan = rsnd_io_is_play(io) ? |
226 | rsnd_runtime_channel_after_ctu(io) : | 238 | rsnd_runtime_channel_after_ctu_with_params(io, params) : |
227 | rsnd_runtime_channel_original(io); | 239 | rsnd_runtime_channel_original_with_params(io, params); |
228 | 240 | ||
229 | /* Use Multi SSI */ | 241 | /* Use Multi SSI */ |
230 | if (rsnd_runtime_is_ssi_multi(io)) | 242 | if (rsnd_runtime_is_ssi_multi(io)) |
@@ -262,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
262 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 274 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
263 | struct device *dev = rsnd_priv_to_dev(priv); | 275 | struct device *dev = rsnd_priv_to_dev(priv); |
264 | 276 | ||
265 | switch (runtime->sample_bits) { | 277 | switch (snd_pcm_format_width(runtime->format)) { |
266 | case 16: | 278 | case 16: |
267 | return 8 << 16; | 279 | return 8 << 16; |
268 | case 32: | 280 | case 24: |
269 | return 0 << 16; | 281 | return 0 << 16; |
270 | } | 282 | } |
271 | 283 | ||
@@ -282,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
282 | struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); | 294 | struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); |
283 | struct rsnd_mod *target; | 295 | struct rsnd_mod *target; |
284 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 296 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
285 | u32 val = 0x76543210; | ||
286 | u32 mask = ~0; | ||
287 | 297 | ||
288 | /* | 298 | /* |
289 | * *Hardware* L/R and *Software* L/R are inverted. | 299 | * *Hardware* L/R and *Software* L/R are inverted for 16bit data. |
300 | * 31..16 15...0 | ||
301 | * HW: [L ch] [R ch] | ||
302 | * SW: [R ch] [L ch] | ||
290 | * We need to care about inversion timing to control | 303 | * We need to care about inversion timing to control |
291 | * Playback/Capture correctly. | 304 | * Playback/Capture correctly. |
292 | * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R | 305 | * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R |
@@ -313,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
313 | target = cmd ? cmd : ssiu; | 326 | target = cmd ? cmd : ssiu; |
314 | } | 327 | } |
315 | 328 | ||
316 | mask <<= runtime->channels * 4; | 329 | /* Non target mod or 24bit data needs normal DALIGN */ |
317 | val = val & mask; | 330 | if ((snd_pcm_format_width(runtime->format) != 16) || |
318 | 331 | (mod != target)) | |
319 | switch (runtime->sample_bits) { | ||
320 | case 16: | ||
321 | val |= 0x67452301 & ~mask; | ||
322 | break; | ||
323 | case 32: | ||
324 | val |= 0x76543210 & ~mask; | ||
325 | break; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * exchange channeles on SRC if possible, | ||
330 | * otherwise, R/L volume settings on DVC | ||
331 | * changes inverted channels | ||
332 | */ | ||
333 | if (mod == target) | ||
334 | return val; | ||
335 | else | ||
336 | return 0x76543210; | 332 | return 0x76543210; |
333 | /* Target mod needs inverted DALIGN when 16bit */ | ||
334 | else | ||
335 | return 0x67452301; | ||
337 | } | 336 | } |
338 | 337 | ||
339 | u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) | 338 | u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) |
@@ -363,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) | |||
363 | * HW 24bit data is located as 0x******00 | 362 | * HW 24bit data is located as 0x******00 |
364 | * | 363 | * |
365 | */ | 364 | */ |
366 | switch (runtime->sample_bits) { | 365 | if (snd_pcm_format_width(runtime->format) == 16) |
367 | case 16: | ||
368 | return 0; | 366 | return 0; |
369 | case 32: | ||
370 | break; | ||
371 | } | ||
372 | 367 | ||
373 | for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { | 368 | for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { |
374 | tmod = rsnd_io_to_mod(io, mods[i]); | 369 | tmod = rsnd_io_to_mod(io, mods[i]); |
@@ -616,8 +611,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
616 | switch (cmd) { | 611 | switch (cmd) { |
617 | case SNDRV_PCM_TRIGGER_START: | 612 | case SNDRV_PCM_TRIGGER_START: |
618 | case SNDRV_PCM_TRIGGER_RESUME: | 613 | case SNDRV_PCM_TRIGGER_RESUME: |
619 | rsnd_dai_stream_init(io, substream); | ||
620 | |||
621 | ret = rsnd_dai_call(init, io, priv); | 614 | ret = rsnd_dai_call(init, io, priv); |
622 | if (ret < 0) | 615 | if (ret < 0) |
623 | goto dai_trigger_end; | 616 | goto dai_trigger_end; |
@@ -639,7 +632,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
639 | 632 | ||
640 | ret |= rsnd_dai_call(quit, io, priv); | 633 | ret |= rsnd_dai_call(quit, io, priv); |
641 | 634 | ||
642 | rsnd_dai_stream_quit(io); | ||
643 | break; | 635 | break; |
644 | default: | 636 | default: |
645 | ret = -EINVAL; | 637 | ret = -EINVAL; |
@@ -784,8 +776,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, | |||
784 | return snd_interval_refine(iv, &p); | 776 | return snd_interval_refine(iv, &p); |
785 | } | 777 | } |
786 | 778 | ||
787 | static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, | 779 | static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
788 | struct snd_pcm_hw_rule *rule) | 780 | struct snd_pcm_hw_rule *rule, |
781 | int is_play) | ||
789 | { | 782 | { |
790 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | 783 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
791 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | 784 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
@@ -793,25 +786,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, | |||
793 | struct snd_soc_dai *dai = rule->private; | 786 | struct snd_soc_dai *dai = rule->private; |
794 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 787 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
795 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | 788 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
789 | struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; | ||
796 | 790 | ||
797 | /* | 791 | /* |
798 | * possible sampling rate limitation is same as | 792 | * possible sampling rate limitation is same as |
799 | * 2ch if it supports multi ssi | 793 | * 2ch if it supports multi ssi |
794 | * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) | ||
800 | */ | 795 | */ |
801 | ic = *ic_; | 796 | ic = *ic_; |
802 | if (1 < rsnd_rdai_ssi_lane_get(rdai)) { | 797 | ic.min = |
803 | ic.min = 2; | 798 | ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); |
804 | ic.max = 2; | ||
805 | } | ||
806 | 799 | ||
807 | return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, | 800 | return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, |
808 | ARRAY_SIZE(rsnd_soc_hw_rate_list), | 801 | ARRAY_SIZE(rsnd_soc_hw_rate_list), |
809 | &ic, ir); | 802 | &ic, ir); |
810 | } | 803 | } |
811 | 804 | ||
805 | static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, | ||
806 | struct snd_pcm_hw_rule *rule) | ||
807 | { | ||
808 | return __rsnd_soc_hw_rule_rate(params, rule, 1); | ||
809 | } | ||
810 | |||
811 | static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, | ||
812 | struct snd_pcm_hw_rule *rule) | ||
813 | { | ||
814 | return __rsnd_soc_hw_rule_rate(params, rule, 0); | ||
815 | } | ||
812 | 816 | ||
813 | static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, | 817 | static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
814 | struct snd_pcm_hw_rule *rule) | 818 | struct snd_pcm_hw_rule *rule, |
819 | int is_play) | ||
815 | { | 820 | { |
816 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | 821 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
817 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | 822 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
@@ -819,22 +824,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, | |||
819 | struct snd_soc_dai *dai = rule->private; | 824 | struct snd_soc_dai *dai = rule->private; |
820 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 825 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
821 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | 826 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
827 | struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; | ||
822 | 828 | ||
823 | /* | 829 | /* |
824 | * possible sampling rate limitation is same as | 830 | * possible sampling rate limitation is same as |
825 | * 2ch if it supports multi ssi | 831 | * 2ch if it supports multi ssi |
832 | * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) | ||
826 | */ | 833 | */ |
827 | ic = *ic_; | 834 | ic = *ic_; |
828 | if (1 < rsnd_rdai_ssi_lane_get(rdai)) { | 835 | ic.min = |
829 | ic.min = 2; | 836 | ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); |
830 | ic.max = 2; | ||
831 | } | ||
832 | 837 | ||
833 | return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, | 838 | return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, |
834 | ARRAY_SIZE(rsnd_soc_hw_channels_list), | 839 | ARRAY_SIZE(rsnd_soc_hw_channels_list), |
835 | ir, &ic); | 840 | ir, &ic); |
836 | } | 841 | } |
837 | 842 | ||
843 | static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, | ||
844 | struct snd_pcm_hw_rule *rule) | ||
845 | { | ||
846 | return __rsnd_soc_hw_rule_channels(params, rule, 1); | ||
847 | } | ||
848 | |||
849 | static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, | ||
850 | struct snd_pcm_hw_rule *rule) | ||
851 | { | ||
852 | return __rsnd_soc_hw_rule_channels(params, rule, 0); | ||
853 | } | ||
854 | |||
838 | static const struct snd_pcm_hardware rsnd_pcm_hardware = { | 855 | static const struct snd_pcm_hardware rsnd_pcm_hardware = { |
839 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 856 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
840 | SNDRV_PCM_INFO_MMAP | | 857 | SNDRV_PCM_INFO_MMAP | |
@@ -859,6 +876,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, | |||
859 | int ret; | 876 | int ret; |
860 | int i; | 877 | int i; |
861 | 878 | ||
879 | rsnd_dai_stream_init(io, substream); | ||
880 | |||
862 | /* | 881 | /* |
863 | * Channel Limitation | 882 | * Channel Limitation |
864 | * It depends on Platform design | 883 | * It depends on Platform design |
@@ -886,11 +905,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, | |||
886 | * It depends on Clock Master Mode | 905 | * It depends on Clock Master Mode |
887 | */ | 906 | */ |
888 | if (rsnd_rdai_is_clk_master(rdai)) { | 907 | if (rsnd_rdai_is_clk_master(rdai)) { |
908 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
909 | |||
889 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 910 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
890 | rsnd_soc_hw_rule_rate, dai, | 911 | is_play ? rsnd_soc_hw_rule_rate_playback : |
912 | rsnd_soc_hw_rule_rate_capture, | ||
913 | dai, | ||
891 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | 914 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
892 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 915 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
893 | rsnd_soc_hw_rule_channels, dai, | 916 | is_play ? rsnd_soc_hw_rule_channels_playback : |
917 | rsnd_soc_hw_rule_channels_capture, | ||
918 | dai, | ||
894 | SNDRV_PCM_HW_PARAM_RATE, -1); | 919 | SNDRV_PCM_HW_PARAM_RATE, -1); |
895 | } | 920 | } |
896 | 921 | ||
@@ -915,6 +940,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, | |||
915 | * call rsnd_dai_call without spinlock | 940 | * call rsnd_dai_call without spinlock |
916 | */ | 941 | */ |
917 | rsnd_dai_call(nolock_stop, io, priv); | 942 | rsnd_dai_call(nolock_stop, io, priv); |
943 | |||
944 | rsnd_dai_stream_quit(io); | ||
918 | } | 945 | } |
919 | 946 | ||
920 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | 947 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { |
@@ -990,7 +1017,7 @@ of_node_compatible: | |||
990 | 1017 | ||
991 | static void __rsnd_dai_probe(struct rsnd_priv *priv, | 1018 | static void __rsnd_dai_probe(struct rsnd_priv *priv, |
992 | struct device_node *dai_np, | 1019 | struct device_node *dai_np, |
993 | int dai_i, int is_graph) | 1020 | int dai_i) |
994 | { | 1021 | { |
995 | struct device_node *playback, *capture; | 1022 | struct device_node *playback, *capture; |
996 | struct rsnd_dai_stream *io_playback; | 1023 | struct rsnd_dai_stream *io_playback; |
@@ -1089,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) | |||
1089 | dai_i = 0; | 1116 | dai_i = 0; |
1090 | if (is_graph) { | 1117 | if (is_graph) { |
1091 | for_each_endpoint_of_node(dai_node, dai_np) { | 1118 | for_each_endpoint_of_node(dai_node, dai_np) { |
1092 | __rsnd_dai_probe(priv, dai_np, dai_i, is_graph); | 1119 | __rsnd_dai_probe(priv, dai_np, dai_i); |
1093 | rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); | 1120 | rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); |
1094 | dai_i++; | 1121 | dai_i++; |
1095 | } | 1122 | } |
1096 | } else { | 1123 | } else { |
1097 | for_each_child_of_node(dai_node, dai_np) | 1124 | for_each_child_of_node(dai_node, dai_np) |
1098 | __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); | 1125 | __rsnd_dai_probe(priv, dai_np, dai_i++); |
1099 | } | 1126 | } |
1100 | 1127 | ||
1101 | return 0; | 1128 | return 0; |
@@ -1496,6 +1523,8 @@ static int rsnd_remove(struct platform_device *pdev) | |||
1496 | }; | 1523 | }; |
1497 | int ret = 0, i; | 1524 | int ret = 0, i; |
1498 | 1525 | ||
1526 | snd_soc_disconnect_sync(&pdev->dev); | ||
1527 | |||
1499 | pm_runtime_disable(&pdev->dev); | 1528 | pm_runtime_disable(&pdev->dev); |
1500 | 1529 | ||
1501 | for_each_rsnd_dai(rdai, priv, i) { | 1530 | for_each_rsnd_dai(rdai, priv, i) { |
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 4d750bdf8e24..41de23417c4a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
@@ -71,25 +71,7 @@ static struct rsnd_mod mem = { | |||
71 | static void __rsnd_dmaen_complete(struct rsnd_mod *mod, | 71 | static void __rsnd_dmaen_complete(struct rsnd_mod *mod, |
72 | struct rsnd_dai_stream *io) | 72 | struct rsnd_dai_stream *io) |
73 | { | 73 | { |
74 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
75 | bool elapsed = false; | ||
76 | unsigned long flags; | ||
77 | |||
78 | /* | ||
79 | * Renesas sound Gen1 needs 1 DMAC, | ||
80 | * Gen2 needs 2 DMAC. | ||
81 | * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. | ||
82 | * But, Audio-DMAC-peri-peri doesn't have interrupt, | ||
83 | * and this driver is assuming that here. | ||
84 | */ | ||
85 | spin_lock_irqsave(&priv->lock, flags); | ||
86 | |||
87 | if (rsnd_io_is_working(io)) | 74 | if (rsnd_io_is_working(io)) |
88 | elapsed = true; | ||
89 | |||
90 | spin_unlock_irqrestore(&priv->lock, flags); | ||
91 | |||
92 | if (elapsed) | ||
93 | rsnd_dai_period_elapsed(io); | 75 | rsnd_dai_period_elapsed(io); |
94 | } | 76 | } |
95 | 77 | ||
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, | |||
399 | struct device_node *playback, | 399 | struct device_node *playback, |
400 | struct device_node *capture); | 400 | struct device_node *capture); |
401 | 401 | ||
402 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); | 402 | #define rsnd_runtime_channel_original(io) \ |
403 | int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); | 403 | rsnd_runtime_channel_original_with_params(io, NULL) |
404 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); | 404 | int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, |
405 | struct snd_pcm_hw_params *params); | ||
406 | #define rsnd_runtime_channel_after_ctu(io) \ | ||
407 | rsnd_runtime_channel_after_ctu_with_params(io, NULL) | ||
408 | int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, | ||
409 | struct snd_pcm_hw_params *params); | ||
410 | #define rsnd_runtime_channel_for_ssi(io) \ | ||
411 | rsnd_runtime_channel_for_ssi_with_params(io, NULL) | ||
412 | int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, | ||
413 | struct snd_pcm_hw_params *params); | ||
405 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); | 414 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); |
406 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); | 415 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); |
407 | 416 | ||
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index cbf3bf312d23..97a9db892a8f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -79,8 +79,8 @@ struct rsnd_ssi { | |||
79 | int irq; | 79 | int irq; |
80 | unsigned int usrcnt; | 80 | unsigned int usrcnt; |
81 | 81 | ||
82 | /* for PIO */ | ||
82 | int byte_pos; | 83 | int byte_pos; |
83 | int period_pos; | ||
84 | int byte_per_period; | 84 | int byte_per_period; |
85 | int next_period_byte; | 85 | int next_period_byte; |
86 | }; | 86 | }; |
@@ -371,11 +371,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, | |||
371 | if (rsnd_io_is_play(io)) | 371 | if (rsnd_io_is_play(io)) |
372 | cr_own |= TRMD; | 372 | cr_own |= TRMD; |
373 | 373 | ||
374 | switch (runtime->sample_bits) { | 374 | switch (snd_pcm_format_width(runtime->format)) { |
375 | case 16: | 375 | case 16: |
376 | cr_own |= DWL_16; | 376 | cr_own |= DWL_16; |
377 | break; | 377 | break; |
378 | case 32: | 378 | case 24: |
379 | cr_own |= DWL_24; | 379 | cr_own |= DWL_24; |
380 | break; | 380 | break; |
381 | } | 381 | } |
@@ -414,63 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod) | |||
414 | ssi->cr_en); | 414 | ssi->cr_en); |
415 | } | 415 | } |
416 | 416 | ||
417 | static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, | ||
418 | struct rsnd_dai_stream *io) | ||
419 | { | ||
420 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
421 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
422 | |||
423 | ssi->byte_pos = 0; | ||
424 | ssi->period_pos = 0; | ||
425 | ssi->byte_per_period = runtime->period_size * | ||
426 | runtime->channels * | ||
427 | samples_to_bytes(runtime, 1); | ||
428 | ssi->next_period_byte = ssi->byte_per_period; | ||
429 | } | ||
430 | |||
431 | static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod, | ||
432 | struct rsnd_dai_stream *io, | ||
433 | int additional) | ||
434 | { | ||
435 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
436 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
437 | int pos = ssi->byte_pos + additional; | ||
438 | |||
439 | pos %= (runtime->periods * ssi->byte_per_period); | ||
440 | |||
441 | return pos; | ||
442 | } | ||
443 | |||
444 | static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, | ||
445 | struct rsnd_dai_stream *io, | ||
446 | int byte) | ||
447 | { | ||
448 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
449 | bool ret = false; | ||
450 | int byte_pos; | ||
451 | |||
452 | byte_pos = ssi->byte_pos + byte; | ||
453 | |||
454 | if (byte_pos >= ssi->next_period_byte) { | ||
455 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
456 | |||
457 | ssi->period_pos++; | ||
458 | ssi->next_period_byte += ssi->byte_per_period; | ||
459 | |||
460 | if (ssi->period_pos >= runtime->periods) { | ||
461 | byte_pos = 0; | ||
462 | ssi->period_pos = 0; | ||
463 | ssi->next_period_byte = ssi->byte_per_period; | ||
464 | } | ||
465 | |||
466 | ret = true; | ||
467 | } | ||
468 | |||
469 | WRITE_ONCE(ssi->byte_pos, byte_pos); | ||
470 | |||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | /* | 417 | /* |
475 | * SSI mod common functions | 418 | * SSI mod common functions |
476 | */ | 419 | */ |
@@ -484,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
484 | if (!rsnd_ssi_is_run_mods(mod, io)) | 427 | if (!rsnd_ssi_is_run_mods(mod, io)) |
485 | return 0; | 428 | return 0; |
486 | 429 | ||
487 | rsnd_ssi_pointer_init(mod, io); | ||
488 | |||
489 | ssi->usrcnt++; | 430 | ssi->usrcnt++; |
490 | 431 | ||
491 | rsnd_mod_power_on(mod); | 432 | rsnd_mod_power_on(mod); |
@@ -656,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod, | |||
656 | return 0; | 597 | return 0; |
657 | } | 598 | } |
658 | 599 | ||
600 | static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, | ||
601 | struct rsnd_dai_stream *io); | ||
659 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | 602 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, |
660 | struct rsnd_dai_stream *io) | 603 | struct rsnd_dai_stream *io) |
661 | { | 604 | { |
@@ -674,30 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
674 | status = rsnd_ssi_status_get(mod); | 617 | status = rsnd_ssi_status_get(mod); |
675 | 618 | ||
676 | /* PIO only */ | 619 | /* PIO only */ |
677 | if (!is_dma && (status & DIRQ)) { | 620 | if (!is_dma && (status & DIRQ)) |
678 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 621 | elapsed = rsnd_ssi_pio_interrupt(mod, io); |
679 | u32 *buf = (u32 *)(runtime->dma_area + | ||
680 | rsnd_ssi_pointer_offset(mod, io, 0)); | ||
681 | int shift = 0; | ||
682 | |||
683 | switch (runtime->sample_bits) { | ||
684 | case 32: | ||
685 | shift = 8; | ||
686 | break; | ||
687 | } | ||
688 | |||
689 | /* | ||
690 | * 8/16/32 data can be assesse to TDR/RDR register | ||
691 | * directly as 32bit data | ||
692 | * see rsnd_ssi_init() | ||
693 | */ | ||
694 | if (rsnd_io_is_play(io)) | ||
695 | rsnd_mod_write(mod, SSITDR, (*buf) << shift); | ||
696 | else | ||
697 | *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); | ||
698 | |||
699 | elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf)); | ||
700 | } | ||
701 | 622 | ||
702 | /* DMA only */ | 623 | /* DMA only */ |
703 | if (is_dma && (status & (UIRQ | OIRQ))) | 624 | if (is_dma && (status & (UIRQ | OIRQ))) |
@@ -835,7 +756,71 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod, | |||
835 | return 0; | 756 | return 0; |
836 | } | 757 | } |
837 | 758 | ||
838 | static int rsnd_ssi_pointer(struct rsnd_mod *mod, | 759 | /* |
760 | * SSI PIO functions | ||
761 | */ | ||
762 | static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, | ||
763 | struct rsnd_dai_stream *io) | ||
764 | { | ||
765 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
766 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
767 | u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); | ||
768 | int shift = 0; | ||
769 | int byte_pos; | ||
770 | bool elapsed = false; | ||
771 | |||
772 | if (snd_pcm_format_width(runtime->format) == 24) | ||
773 | shift = 8; | ||
774 | |||
775 | /* | ||
776 | * 8/16/32 data can be assesse to TDR/RDR register | ||
777 | * directly as 32bit data | ||
778 | * see rsnd_ssi_init() | ||
779 | */ | ||
780 | if (rsnd_io_is_play(io)) | ||
781 | rsnd_mod_write(mod, SSITDR, (*buf) << shift); | ||
782 | else | ||
783 | *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); | ||
784 | |||
785 | byte_pos = ssi->byte_pos + sizeof(*buf); | ||
786 | |||
787 | if (byte_pos >= ssi->next_period_byte) { | ||
788 | int period_pos = byte_pos / ssi->byte_per_period; | ||
789 | |||
790 | if (period_pos >= runtime->periods) { | ||
791 | byte_pos = 0; | ||
792 | period_pos = 0; | ||
793 | } | ||
794 | |||
795 | ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; | ||
796 | |||
797 | elapsed = true; | ||
798 | } | ||
799 | |||
800 | WRITE_ONCE(ssi->byte_pos, byte_pos); | ||
801 | |||
802 | return elapsed; | ||
803 | } | ||
804 | |||
805 | static int rsnd_ssi_pio_init(struct rsnd_mod *mod, | ||
806 | struct rsnd_dai_stream *io, | ||
807 | struct rsnd_priv *priv) | ||
808 | { | ||
809 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
810 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
811 | |||
812 | if (!rsnd_ssi_is_parent(mod, io)) { | ||
813 | ssi->byte_pos = 0; | ||
814 | ssi->byte_per_period = runtime->period_size * | ||
815 | runtime->channels * | ||
816 | samples_to_bytes(runtime, 1); | ||
817 | ssi->next_period_byte = ssi->byte_per_period; | ||
818 | } | ||
819 | |||
820 | return rsnd_ssi_init(mod, io, priv); | ||
821 | } | ||
822 | |||
823 | static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, | ||
839 | struct rsnd_dai_stream *io, | 824 | struct rsnd_dai_stream *io, |
840 | snd_pcm_uframes_t *pointer) | 825 | snd_pcm_uframes_t *pointer) |
841 | { | 826 | { |
@@ -851,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | |||
851 | .name = SSI_NAME, | 836 | .name = SSI_NAME, |
852 | .probe = rsnd_ssi_common_probe, | 837 | .probe = rsnd_ssi_common_probe, |
853 | .remove = rsnd_ssi_common_remove, | 838 | .remove = rsnd_ssi_common_remove, |
854 | .init = rsnd_ssi_init, | 839 | .init = rsnd_ssi_pio_init, |
855 | .quit = rsnd_ssi_quit, | 840 | .quit = rsnd_ssi_quit, |
856 | .start = rsnd_ssi_start, | 841 | .start = rsnd_ssi_start, |
857 | .stop = rsnd_ssi_stop, | 842 | .stop = rsnd_ssi_stop, |
858 | .irq = rsnd_ssi_irq, | 843 | .irq = rsnd_ssi_irq, |
859 | .pointer= rsnd_ssi_pointer, | 844 | .pointer = rsnd_ssi_pio_pointer, |
860 | .pcm_new = rsnd_ssi_pcm_new, | 845 | .pcm_new = rsnd_ssi_pcm_new, |
861 | .hw_params = rsnd_ssi_hw_params, | 846 | .hw_params = rsnd_ssi_hw_params, |
862 | }; | 847 | }; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9b79c2199781..e018a2badfde 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1393,6 +1393,16 @@ static int soc_init_dai_link(struct snd_soc_card *card, | |||
1393 | return 0; | 1393 | return 0; |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | void snd_soc_disconnect_sync(struct device *dev) | ||
1397 | { | ||
1398 | struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL); | ||
1399 | |||
1400 | if (!component || !component->card) | ||
1401 | return; | ||
1402 | |||
1403 | snd_card_disconnect_sync(component->card->snd_card); | ||
1404 | } | ||
1405 | |||
1396 | /** | 1406 | /** |
1397 | * snd_soc_add_dai_link - Add a DAI link dynamically | 1407 | * snd_soc_add_dai_link - Add a DAI link dynamically |
1398 | * @card: The ASoC card to which the DAI link is added | 1408 | * @card: The ASoC card to which the DAI link is added |