diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2015-03-26 00:02:51 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-03-27 19:00:49 -0400 |
commit | 3b7843ff618f63d1776abd71de7eea9130987037 (patch) | |
tree | 1bd63a14b5e8f85d9d5db164c583a49136bc09fd /sound | |
parent | b543b52a44c4e45283cd17721af1299049405136 (diff) |
ASoC: rsnd: add DPCM based sampling rate convert
This patch supports DPCM based sampling rate convert on Renesas sound
driver. It assumes...
1. SRC is implemented as FE
2. BE dai_link supports .be_hw_params_fixup
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 11 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 8 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 49 |
3 files changed, 63 insertions, 5 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 770247cddb6c..9b0de428c45b 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -203,7 +203,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod) | |||
203 | ({ \ | 203 | ({ \ |
204 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ | 204 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
205 | struct device *dev = rsnd_priv_to_dev(priv); \ | 205 | struct device *dev = rsnd_priv_to_dev(priv); \ |
206 | u32 mask = 1 << __rsnd_mod_shift_##func; \ | 206 | u32 mask = (1 << __rsnd_mod_shift_##func) & ~(1 << 31); \ |
207 | u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \ | 207 | u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \ |
208 | int ret = 0; \ | 208 | int ret = 0; \ |
209 | if ((mod->status & mask) == call) { \ | 209 | if ((mod->status & mask) == call) { \ |
@@ -728,6 +728,15 @@ static int rsnd_pcm_open(struct snd_pcm_substream *substream) | |||
728 | static int rsnd_hw_params(struct snd_pcm_substream *substream, | 728 | static int rsnd_hw_params(struct snd_pcm_substream *substream, |
729 | struct snd_pcm_hw_params *hw_params) | 729 | struct snd_pcm_hw_params *hw_params) |
730 | { | 730 | { |
731 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); | ||
732 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
733 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | ||
734 | int ret; | ||
735 | |||
736 | ret = rsnd_dai_call(hw_params, io, substream, hw_params); | ||
737 | if (ret) | ||
738 | return ret; | ||
739 | |||
731 | return snd_pcm_lib_malloc_pages(substream, | 740 | return snd_pcm_lib_malloc_pages(substream, |
732 | params_buffer_bytes(hw_params)); | 741 | params_buffer_bytes(hw_params)); |
733 | } | 742 | } |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f7af0be11558..4e6de6804cfb 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -239,6 +239,9 @@ struct rsnd_mod_ops { | |||
239 | struct rsnd_priv *priv); | 239 | struct rsnd_priv *priv); |
240 | int (*pcm_new)(struct rsnd_mod *mod, | 240 | int (*pcm_new)(struct rsnd_mod *mod, |
241 | struct snd_soc_pcm_runtime *rtd); | 241 | struct snd_soc_pcm_runtime *rtd); |
242 | int (*hw_params)(struct rsnd_mod *mod, | ||
243 | struct snd_pcm_substream *substream, | ||
244 | struct snd_pcm_hw_params *hw_params); | ||
242 | int (*fallback)(struct rsnd_mod *mod, | 245 | int (*fallback)(struct rsnd_mod *mod, |
243 | struct rsnd_priv *priv); | 246 | struct rsnd_priv *priv); |
244 | }; | 247 | }; |
@@ -262,6 +265,9 @@ struct rsnd_mod { | |||
262 | * 2 0: start 1: stop | 265 | * 2 0: start 1: stop |
263 | * 3 0: pcm_new | 266 | * 3 0: pcm_new |
264 | * 4 0: fallback | 267 | * 4 0: fallback |
268 | * | ||
269 | * 31 bit is always called (see __rsnd_mod_call) | ||
270 | * 31 0: hw_params | ||
265 | */ | 271 | */ |
266 | #define __rsnd_mod_shift_probe 0 | 272 | #define __rsnd_mod_shift_probe 0 |
267 | #define __rsnd_mod_shift_remove 0 | 273 | #define __rsnd_mod_shift_remove 0 |
@@ -271,6 +277,7 @@ struct rsnd_mod { | |||
271 | #define __rsnd_mod_shift_stop 2 | 277 | #define __rsnd_mod_shift_stop 2 |
272 | #define __rsnd_mod_shift_pcm_new 3 | 278 | #define __rsnd_mod_shift_pcm_new 3 |
273 | #define __rsnd_mod_shift_fallback 4 | 279 | #define __rsnd_mod_shift_fallback 4 |
280 | #define __rsnd_mod_shift_hw_params 31 /* always called */ | ||
274 | 281 | ||
275 | #define __rsnd_mod_call_probe 0 | 282 | #define __rsnd_mod_call_probe 0 |
276 | #define __rsnd_mod_call_remove 1 | 283 | #define __rsnd_mod_call_remove 1 |
@@ -280,6 +287,7 @@ struct rsnd_mod { | |||
280 | #define __rsnd_mod_call_stop 1 | 287 | #define __rsnd_mod_call_stop 1 |
281 | #define __rsnd_mod_call_pcm_new 0 | 288 | #define __rsnd_mod_call_pcm_new 0 |
282 | #define __rsnd_mod_call_fallback 0 | 289 | #define __rsnd_mod_call_fallback 0 |
290 | #define __rsnd_mod_call_hw_params 0 | ||
283 | 291 | ||
284 | #define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod))) | 292 | #define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod))) |
285 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 293 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 83611fa450bf..a0a2bdac09d9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -22,12 +22,13 @@ | |||
22 | struct rsnd_src { | 22 | struct rsnd_src { |
23 | struct rsnd_src_platform_info *info; /* rcar_snd.h */ | 23 | struct rsnd_src_platform_info *info; /* rcar_snd.h */ |
24 | struct rsnd_mod mod; | 24 | struct rsnd_mod mod; |
25 | u32 convert_rate; /* sampling rate convert */ | ||
25 | int err; | 26 | int err; |
26 | }; | 27 | }; |
27 | 28 | ||
28 | #define RSND_SRC_NAME_SIZE 16 | 29 | #define RSND_SRC_NAME_SIZE 16 |
29 | 30 | ||
30 | #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) | 31 | #define rsnd_src_convert_rate(s) ((s)->convert_rate) |
31 | #define rsnd_src_of_node(priv) \ | 32 | #define rsnd_src_of_node(priv) \ |
32 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") | 33 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") |
33 | 34 | ||
@@ -288,7 +289,43 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod) | |||
288 | return 0; | 289 | return 0; |
289 | } | 290 | } |
290 | 291 | ||
291 | static int rsnd_src_init(struct rsnd_mod *mod) | 292 | static int rsnd_src_hw_params(struct rsnd_mod *mod, |
293 | struct snd_pcm_substream *substream, | ||
294 | struct snd_pcm_hw_params *fe_params) | ||
295 | { | ||
296 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
297 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
298 | |||
299 | /* default value (mainly for non-DT) */ | ||
300 | src->convert_rate = src->info->convert_rate; | ||
301 | |||
302 | /* | ||
303 | * SRC assumes that it is used under DPCM if user want to use | ||
304 | * sampling rate convert. Then, SRC should be FE. | ||
305 | * And then, this function will be called *after* BE settings. | ||
306 | * this means, each BE already has fixuped hw_params. | ||
307 | * see | ||
308 | * dpcm_fe_dai_hw_params() | ||
309 | * dpcm_be_dai_hw_params() | ||
310 | */ | ||
311 | if (fe->dai_link->dynamic) { | ||
312 | int stream = substream->stream; | ||
313 | struct snd_soc_dpcm *dpcm; | ||
314 | struct snd_pcm_hw_params *be_params; | ||
315 | |||
316 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
317 | be_params = &dpcm->hw_params; | ||
318 | |||
319 | if (params_rate(fe_params) != params_rate(be_params)) | ||
320 | src->convert_rate = params_rate(be_params); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int rsnd_src_init(struct rsnd_mod *mod, | ||
328 | struct rsnd_priv *priv) | ||
292 | { | 329 | { |
293 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 330 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
294 | 331 | ||
@@ -317,6 +354,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod, | |||
317 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", | 354 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", |
318 | rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); | 355 | rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); |
319 | 356 | ||
357 | src->convert_rate = 0; | ||
358 | |||
320 | return 0; | 359 | return 0; |
321 | } | 360 | } |
322 | 361 | ||
@@ -465,7 +504,7 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod, | |||
465 | { | 504 | { |
466 | int ret; | 505 | int ret; |
467 | 506 | ||
468 | ret = rsnd_src_init(mod); | 507 | ret = rsnd_src_init(mod, priv); |
469 | if (ret < 0) | 508 | if (ret < 0) |
470 | return ret; | 509 | return ret; |
471 | 510 | ||
@@ -511,6 +550,7 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { | |||
511 | .quit = rsnd_src_quit, | 550 | .quit = rsnd_src_quit, |
512 | .start = rsnd_src_start_gen1, | 551 | .start = rsnd_src_start_gen1, |
513 | .stop = rsnd_src_stop_gen1, | 552 | .stop = rsnd_src_stop_gen1, |
553 | .hw_params = rsnd_src_hw_params, | ||
514 | }; | 554 | }; |
515 | 555 | ||
516 | /* | 556 | /* |
@@ -736,7 +776,7 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, | |||
736 | { | 776 | { |
737 | int ret; | 777 | int ret; |
738 | 778 | ||
739 | ret = rsnd_src_init(mod); | 779 | ret = rsnd_src_init(mod, priv); |
740 | if (ret < 0) | 780 | if (ret < 0) |
741 | return ret; | 781 | return ret; |
742 | 782 | ||
@@ -780,6 +820,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = { | |||
780 | .quit = rsnd_src_quit, | 820 | .quit = rsnd_src_quit, |
781 | .start = rsnd_src_start_gen2, | 821 | .start = rsnd_src_start_gen2, |
782 | .stop = rsnd_src_stop_gen2, | 822 | .stop = rsnd_src_stop_gen2, |
823 | .hw_params = rsnd_src_hw_params, | ||
783 | }; | 824 | }; |
784 | 825 | ||
785 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | 826 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) |