diff options
| -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) |
