diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2015-04-01 00:15:16 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-04-01 16:23:37 -0400 |
commit | 43cb6954f8c8a68fdc354226fa045ff43c7e4d39 (patch) | |
tree | 226b9fefccce33865b68083c1cb16fa1ac90091f /sound/soc/sh | |
parent | 969b8619069f0e4da767c54481dcc10812f949a5 (diff) |
ASoC: rsnd: add Synchronous SRC mode
Renesas R-Car sound SRC (= Sampling Rate Converter) has
Asynchronous/Synchronous SRC mode. Asynchronous mode is already
supported via DPCM. This patch adds Synchronous mode on it.
The condition of enabling Synchronous mode are
- SoC is clock master
- Sound uses SRC
- Sound doesn't use DVC
- Sound card uses DPCM (= rsrc-card card)
amixer set "SRC Out Rate" on
aplay xxx.wav &
amixer set "SRC Out Rate" 48000
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/rcar/src.c | 126 |
1 files changed, 121 insertions, 5 deletions
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index a0a2bdac09d9..3beb32eb412a 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -22,13 +22,15 @@ | |||
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 | struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ | ||
26 | struct rsnd_kctrl_cfg_s sync; /* sync convert */ | ||
25 | u32 convert_rate; /* sampling rate convert */ | 27 | u32 convert_rate; /* sampling rate convert */ |
26 | int err; | 28 | int err; |
27 | }; | 29 | }; |
28 | 30 | ||
29 | #define RSND_SRC_NAME_SIZE 16 | 31 | #define RSND_SRC_NAME_SIZE 16 |
30 | 32 | ||
31 | #define rsnd_src_convert_rate(s) ((s)->convert_rate) | 33 | #define rsnd_enable_sync_convert(src) ((src)->sen.val) |
32 | #define rsnd_src_of_node(priv) \ | 34 | #define rsnd_src_of_node(priv) \ |
33 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") | 35 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") |
34 | 36 | ||
@@ -233,6 +235,30 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) | |||
233 | return 0; | 235 | return 0; |
234 | } | 236 | } |
235 | 237 | ||
238 | static u32 rsnd_src_convert_rate(struct rsnd_src *src) | ||
239 | { | ||
240 | struct rsnd_mod *mod = &src->mod; | ||
241 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
242 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
243 | u32 convert_rate; | ||
244 | |||
245 | if (!runtime) | ||
246 | return 0; | ||
247 | |||
248 | if (!rsnd_enable_sync_convert(src)) | ||
249 | return src->convert_rate; | ||
250 | |||
251 | convert_rate = src->sync.val; | ||
252 | |||
253 | if (!convert_rate) | ||
254 | convert_rate = src->convert_rate; | ||
255 | |||
256 | if (!convert_rate) | ||
257 | convert_rate = runtime->rate; | ||
258 | |||
259 | return convert_rate; | ||
260 | } | ||
261 | |||
236 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | 262 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
237 | struct rsnd_dai_stream *io, | 263 | struct rsnd_dai_stream *io, |
238 | struct snd_pcm_runtime *runtime) | 264 | struct snd_pcm_runtime *runtime) |
@@ -333,6 +359,9 @@ static int rsnd_src_init(struct rsnd_mod *mod, | |||
333 | 359 | ||
334 | src->err = 0; | 360 | src->err = 0; |
335 | 361 | ||
362 | /* reset sync convert_rate */ | ||
363 | src->sync.val = 0; | ||
364 | |||
336 | /* | 365 | /* |
337 | * Initialize the operation of the SRC internal circuits | 366 | * Initialize the operation of the SRC internal circuits |
338 | * see rsnd_src_start() | 367 | * see rsnd_src_start() |
@@ -356,6 +385,9 @@ static int rsnd_src_quit(struct rsnd_mod *mod, | |||
356 | 385 | ||
357 | src->convert_rate = 0; | 386 | src->convert_rate = 0; |
358 | 387 | ||
388 | /* reset sync convert_rate */ | ||
389 | src->sync.val = 0; | ||
390 | |||
359 | return 0; | 391 | return 0; |
360 | } | 392 | } |
361 | 393 | ||
@@ -672,6 +704,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod) | |||
672 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 704 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
673 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 705 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
674 | u32 convert_rate = rsnd_src_convert_rate(src); | 706 | u32 convert_rate = rsnd_src_convert_rate(src); |
707 | u32 cr, route; | ||
675 | uint ratio; | 708 | uint ratio; |
676 | int ret; | 709 | int ret; |
677 | 710 | ||
@@ -692,13 +725,21 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod) | |||
692 | if (ret < 0) | 725 | if (ret < 0) |
693 | return ret; | 726 | return ret; |
694 | 727 | ||
695 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); | 728 | cr = 0x00011110; |
696 | 729 | route = 0x0; | |
697 | if (convert_rate) { | 730 | if (convert_rate) { |
698 | /* Gen1/Gen2 are not compatible */ | 731 | route = 0x1; |
699 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | 732 | |
733 | if (rsnd_enable_sync_convert(src)) { | ||
734 | cr |= 0x1; | ||
735 | route |= rsnd_io_is_play(io) ? | ||
736 | (0x1 << 24) : (0x1 << 25); | ||
737 | } | ||
700 | } | 738 | } |
701 | 739 | ||
740 | rsnd_mod_write(mod, SRC_SRCCR, cr); | ||
741 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); | ||
742 | |||
702 | switch (rsnd_mod_id(mod)) { | 743 | switch (rsnd_mod_id(mod)) { |
703 | case 5: | 744 | case 5: |
704 | case 6: | 745 | case 6: |
@@ -811,6 +852,80 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | |||
811 | return ret; | 852 | return ret; |
812 | } | 853 | } |
813 | 854 | ||
855 | static void rsnd_src_reconvert_update(struct rsnd_mod *mod) | ||
856 | { | ||
857 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
858 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
859 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
860 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
861 | u32 fsrate; | ||
862 | |||
863 | if (!runtime) | ||
864 | return; | ||
865 | |||
866 | if (!convert_rate) | ||
867 | convert_rate = runtime->rate; | ||
868 | |||
869 | fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
870 | |||
871 | /* update IFS */ | ||
872 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
873 | } | ||
874 | |||
875 | static int rsnd_src_pcm_new(struct rsnd_mod *mod, | ||
876 | struct snd_soc_pcm_runtime *rtd) | ||
877 | { | ||
878 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
879 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
880 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
881 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
882 | int ret; | ||
883 | |||
884 | /* | ||
885 | * enable SRC sync convert if possible | ||
886 | */ | ||
887 | |||
888 | /* | ||
889 | * Gen1 is not supported | ||
890 | */ | ||
891 | if (rsnd_is_gen1(priv)) | ||
892 | return 0; | ||
893 | |||
894 | /* | ||
895 | * SRC sync convert needs clock master | ||
896 | */ | ||
897 | if (!rsnd_rdai_is_clk_master(rdai)) | ||
898 | return 0; | ||
899 | |||
900 | /* | ||
901 | * We can't use SRC sync convert | ||
902 | * if it has DVC | ||
903 | */ | ||
904 | if (rsnd_io_to_mod_dvc(io)) | ||
905 | return 0; | ||
906 | |||
907 | /* | ||
908 | * enable sync convert | ||
909 | */ | ||
910 | ret = rsnd_kctrl_new_s(mod, rtd, | ||
911 | rsnd_io_is_play(io) ? | ||
912 | "SRC Out Rate Switch" : | ||
913 | "SRC In Rate Switch", | ||
914 | rsnd_src_reconvert_update, | ||
915 | &src->sen, 1); | ||
916 | if (ret < 0) | ||
917 | return ret; | ||
918 | |||
919 | ret = rsnd_kctrl_new_s(mod, rtd, | ||
920 | rsnd_io_is_play(io) ? | ||
921 | "SRC Out Rate" : | ||
922 | "SRC In Rate", | ||
923 | rsnd_src_reconvert_update, | ||
924 | &src->sync, 192000); | ||
925 | |||
926 | return ret; | ||
927 | } | ||
928 | |||
814 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { | 929 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { |
815 | .name = SRC_NAME, | 930 | .name = SRC_NAME, |
816 | .dma_req = rsnd_src_dma_req, | 931 | .dma_req = rsnd_src_dma_req, |
@@ -821,6 +936,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = { | |||
821 | .start = rsnd_src_start_gen2, | 936 | .start = rsnd_src_start_gen2, |
822 | .stop = rsnd_src_stop_gen2, | 937 | .stop = rsnd_src_stop_gen2, |
823 | .hw_params = rsnd_src_hw_params, | 938 | .hw_params = rsnd_src_hw_params, |
939 | .pcm_new = rsnd_src_pcm_new, | ||
824 | }; | 940 | }; |
825 | 941 | ||
826 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | 942 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) |