diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2012-11-05 21:30:38 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-11-06 03:54:42 -0500 |
commit | ab6f6d85210c4d0265cf48e9958c04e08595055a (patch) | |
tree | 95a3371ac6700bc5b7d351b93a2190ec48e65416 /sound/soc/sh | |
parent | 80b4addc9c697c8d515afdaf671b948b3de6801c (diff) |
ASoC: fsi: add master clock control functions
Current FSI driver required set_rate() platform callback function
to set audio clock if it was master mode,
because it seemed that CPG/FSI-DIV clocks calculation depend on
platform/board/cpu.
But it was calculable regardless of platform.
This patch supports audio clock calculation method,
but the sampling rate under 32kHz is not supported at this point.
Old type set_rate() is still supported now,
but it will be deleted on next version
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/fsi.c | 378 |
1 files changed, 372 insertions, 6 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ef257bcb5341..bdaca356aaad 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/pcm_params.h> | ||
24 | #include <sound/sh_fsi.h> | 25 | #include <sound/sh_fsi.h> |
25 | 26 | ||
26 | /* PortA/PortB register */ | 27 | /* PortA/PortB register */ |
@@ -188,6 +189,14 @@ typedef int (*set_rate_func)(struct device *dev, int rate, int enable); | |||
188 | */ | 189 | */ |
189 | 190 | ||
190 | /* | 191 | /* |
192 | * FSI clock | ||
193 | * | ||
194 | * FSIxCLK [CPG] (ick) -------> | | ||
195 | * |-> FSI_DIV (div)-> FSI2 | ||
196 | * FSIxCK [external] (xck) ---> | | ||
197 | */ | ||
198 | |||
199 | /* | ||
191 | * struct | 200 | * struct |
192 | */ | 201 | */ |
193 | 202 | ||
@@ -227,6 +236,20 @@ struct fsi_stream { | |||
227 | dma_addr_t dma; | 236 | dma_addr_t dma; |
228 | }; | 237 | }; |
229 | 238 | ||
239 | struct fsi_clk { | ||
240 | /* see [FSI clock] */ | ||
241 | struct clk *own; | ||
242 | struct clk *xck; | ||
243 | struct clk *ick; | ||
244 | struct clk *div; | ||
245 | int (*set_rate)(struct device *dev, | ||
246 | struct fsi_priv *fsi, | ||
247 | unsigned long rate); | ||
248 | |||
249 | unsigned long rate; | ||
250 | unsigned int count; | ||
251 | }; | ||
252 | |||
230 | struct fsi_priv { | 253 | struct fsi_priv { |
231 | void __iomem *base; | 254 | void __iomem *base; |
232 | struct fsi_master *master; | 255 | struct fsi_master *master; |
@@ -235,6 +258,8 @@ struct fsi_priv { | |||
235 | struct fsi_stream playback; | 258 | struct fsi_stream playback; |
236 | struct fsi_stream capture; | 259 | struct fsi_stream capture; |
237 | 260 | ||
261 | struct fsi_clk clock; | ||
262 | |||
238 | u32 fmt; | 263 | u32 fmt; |
239 | 264 | ||
240 | int chan_num:16; | 265 | int chan_num:16; |
@@ -716,14 +741,335 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
716 | /* | 741 | /* |
717 | * clock function | 742 | * clock function |
718 | */ | 743 | */ |
744 | static int fsi_clk_init(struct device *dev, | ||
745 | struct fsi_priv *fsi, | ||
746 | int xck, | ||
747 | int ick, | ||
748 | int div, | ||
749 | int (*set_rate)(struct device *dev, | ||
750 | struct fsi_priv *fsi, | ||
751 | unsigned long rate)) | ||
752 | { | ||
753 | struct fsi_clk *clock = &fsi->clock; | ||
754 | int is_porta = fsi_is_port_a(fsi); | ||
755 | |||
756 | clock->xck = NULL; | ||
757 | clock->ick = NULL; | ||
758 | clock->div = NULL; | ||
759 | clock->rate = 0; | ||
760 | clock->count = 0; | ||
761 | clock->set_rate = set_rate; | ||
762 | |||
763 | clock->own = devm_clk_get(dev, NULL); | ||
764 | if (IS_ERR(clock->own)) | ||
765 | return -EINVAL; | ||
766 | |||
767 | /* external clock */ | ||
768 | if (xck) { | ||
769 | clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb"); | ||
770 | if (IS_ERR(clock->xck)) { | ||
771 | dev_err(dev, "can't get xck clock\n"); | ||
772 | return -EINVAL; | ||
773 | } | ||
774 | if (clock->xck == clock->own) { | ||
775 | dev_err(dev, "cpu doesn't support xck clock\n"); | ||
776 | return -EINVAL; | ||
777 | } | ||
778 | } | ||
779 | |||
780 | /* FSIACLK/FSIBCLK */ | ||
781 | if (ick) { | ||
782 | clock->ick = devm_clk_get(dev, is_porta ? "icka" : "ickb"); | ||
783 | if (IS_ERR(clock->ick)) { | ||
784 | dev_err(dev, "can't get ick clock\n"); | ||
785 | return -EINVAL; | ||
786 | } | ||
787 | if (clock->ick == clock->own) { | ||
788 | dev_err(dev, "cpu doesn't support ick clock\n"); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | /* FSI-DIV */ | ||
794 | if (div) { | ||
795 | clock->div = devm_clk_get(dev, is_porta ? "diva" : "divb"); | ||
796 | if (IS_ERR(clock->div)) { | ||
797 | dev_err(dev, "can't get div clock\n"); | ||
798 | return -EINVAL; | ||
799 | } | ||
800 | if (clock->div == clock->own) { | ||
801 | dev_err(dev, "cpu doens't support div clock\n"); | ||
802 | return -EINVAL; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | #define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0) | ||
810 | static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate) | ||
811 | { | ||
812 | fsi->clock.rate = rate; | ||
813 | } | ||
814 | |||
815 | static int fsi_clk_is_valid(struct fsi_priv *fsi) | ||
816 | { | ||
817 | return fsi->clock.set_rate && | ||
818 | fsi->clock.rate; | ||
819 | } | ||
820 | |||
821 | static int fsi_clk_enable(struct device *dev, | ||
822 | struct fsi_priv *fsi, | ||
823 | unsigned long rate) | ||
824 | { | ||
825 | struct fsi_clk *clock = &fsi->clock; | ||
826 | int ret = -EINVAL; | ||
827 | |||
828 | if (!fsi_clk_is_valid(fsi)) | ||
829 | return ret; | ||
830 | |||
831 | if (0 == clock->count) { | ||
832 | ret = clock->set_rate(dev, fsi, rate); | ||
833 | if (ret < 0) { | ||
834 | fsi_clk_invalid(fsi); | ||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | if (clock->xck) | ||
839 | clk_enable(clock->xck); | ||
840 | if (clock->ick) | ||
841 | clk_enable(clock->ick); | ||
842 | if (clock->div) | ||
843 | clk_enable(clock->div); | ||
844 | |||
845 | clock->count++; | ||
846 | } | ||
847 | |||
848 | return ret; | ||
849 | } | ||
850 | |||
851 | static int fsi_clk_disable(struct device *dev, | ||
852 | struct fsi_priv *fsi) | ||
853 | { | ||
854 | struct fsi_clk *clock = &fsi->clock; | ||
855 | |||
856 | if (!fsi_clk_is_valid(fsi)) | ||
857 | return -EINVAL; | ||
858 | |||
859 | if (1 == clock->count--) { | ||
860 | if (clock->xck) | ||
861 | clk_disable(clock->xck); | ||
862 | if (clock->ick) | ||
863 | clk_disable(clock->ick); | ||
864 | if (clock->div) | ||
865 | clk_disable(clock->div); | ||
866 | } | ||
867 | |||
868 | return 0; | ||
869 | } | ||
870 | |||
871 | static int fsi_clk_set_ackbpf(struct device *dev, | ||
872 | struct fsi_priv *fsi, | ||
873 | int ackmd, int bpfmd) | ||
874 | { | ||
875 | u32 data = 0; | ||
876 | |||
877 | /* check ackmd/bpfmd relationship */ | ||
878 | if (bpfmd > ackmd) { | ||
879 | dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd); | ||
880 | return -EINVAL; | ||
881 | } | ||
882 | |||
883 | /* ACKMD */ | ||
884 | switch (ackmd) { | ||
885 | case 512: | ||
886 | data |= (0x0 << 12); | ||
887 | break; | ||
888 | case 256: | ||
889 | data |= (0x1 << 12); | ||
890 | break; | ||
891 | case 128: | ||
892 | data |= (0x2 << 12); | ||
893 | break; | ||
894 | case 64: | ||
895 | data |= (0x3 << 12); | ||
896 | break; | ||
897 | case 32: | ||
898 | data |= (0x4 << 12); | ||
899 | break; | ||
900 | default: | ||
901 | dev_err(dev, "unsupported ackmd (%d)\n", ackmd); | ||
902 | return -EINVAL; | ||
903 | } | ||
904 | |||
905 | /* BPFMD */ | ||
906 | switch (bpfmd) { | ||
907 | case 32: | ||
908 | data |= (0x0 << 8); | ||
909 | break; | ||
910 | case 64: | ||
911 | data |= (0x1 << 8); | ||
912 | break; | ||
913 | case 128: | ||
914 | data |= (0x2 << 8); | ||
915 | break; | ||
916 | case 256: | ||
917 | data |= (0x3 << 8); | ||
918 | break; | ||
919 | case 512: | ||
920 | data |= (0x4 << 8); | ||
921 | break; | ||
922 | case 16: | ||
923 | data |= (0x7 << 8); | ||
924 | break; | ||
925 | default: | ||
926 | dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd); | ||
927 | return -EINVAL; | ||
928 | } | ||
929 | |||
930 | dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd); | ||
931 | |||
932 | fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); | ||
933 | udelay(10); | ||
934 | |||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static int fsi_clk_set_rate_external(struct device *dev, | ||
939 | struct fsi_priv *fsi, | ||
940 | unsigned long rate) | ||
941 | { | ||
942 | struct clk *xck = fsi->clock.xck; | ||
943 | struct clk *ick = fsi->clock.ick; | ||
944 | unsigned long xrate; | ||
945 | int ackmd, bpfmd; | ||
946 | int ret = 0; | ||
947 | |||
948 | /* check clock rate */ | ||
949 | xrate = clk_get_rate(xck); | ||
950 | if (xrate % rate) { | ||
951 | dev_err(dev, "unsupported clock rate\n"); | ||
952 | return -EINVAL; | ||
953 | } | ||
954 | |||
955 | clk_set_parent(ick, xck); | ||
956 | clk_set_rate(ick, xrate); | ||
957 | |||
958 | bpfmd = fsi->chan_num * 32; | ||
959 | ackmd = xrate / rate; | ||
960 | |||
961 | dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate); | ||
962 | |||
963 | ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); | ||
964 | if (ret < 0) | ||
965 | dev_err(dev, "%s failed", __func__); | ||
966 | |||
967 | return ret; | ||
968 | } | ||
969 | |||
970 | static int fsi_clk_set_rate_cpg(struct device *dev, | ||
971 | struct fsi_priv *fsi, | ||
972 | unsigned long rate) | ||
973 | { | ||
974 | struct clk *ick = fsi->clock.ick; | ||
975 | struct clk *div = fsi->clock.div; | ||
976 | unsigned long target = 0; /* 12288000 or 11289600 */ | ||
977 | unsigned long actual, cout; | ||
978 | unsigned long diff, min; | ||
979 | unsigned long best_cout, best_act; | ||
980 | int adj; | ||
981 | int ackmd, bpfmd; | ||
982 | int ret = -EINVAL; | ||
983 | |||
984 | if (!(12288000 % rate)) | ||
985 | target = 12288000; | ||
986 | if (!(11289600 % rate)) | ||
987 | target = 11289600; | ||
988 | if (!target) { | ||
989 | dev_err(dev, "unsupported rate\n"); | ||
990 | return ret; | ||
991 | } | ||
992 | |||
993 | bpfmd = fsi->chan_num * 32; | ||
994 | ackmd = target / rate; | ||
995 | ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); | ||
996 | if (ret < 0) { | ||
997 | dev_err(dev, "%s failed", __func__); | ||
998 | return ret; | ||
999 | } | ||
1000 | |||
1001 | /* | ||
1002 | * The clock flow is | ||
1003 | * | ||
1004 | * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec] | ||
1005 | * | ||
1006 | * But, it needs to find best match of CPG and FSI_DIV | ||
1007 | * combination, since it is difficult to generate correct | ||
1008 | * frequency of audio clock from ick clock only. | ||
1009 | * Because ick is created from its parent clock. | ||
1010 | * | ||
1011 | * target = rate x [512/256/128/64]fs | ||
1012 | * cout = round(target x adjustment) | ||
1013 | * actual = cout / adjustment (by FSI-DIV) ~= target | ||
1014 | * audio = actual | ||
1015 | */ | ||
1016 | min = ~0; | ||
1017 | best_cout = 0; | ||
1018 | best_act = 0; | ||
1019 | for (adj = 1; adj < 0xffff; adj++) { | ||
1020 | |||
1021 | cout = target * adj; | ||
1022 | if (cout > 100000000) /* max clock = 100MHz */ | ||
1023 | break; | ||
1024 | |||
1025 | /* cout/actual audio clock */ | ||
1026 | cout = clk_round_rate(ick, cout); | ||
1027 | actual = cout / adj; | ||
1028 | |||
1029 | /* find best frequency */ | ||
1030 | diff = abs(actual - target); | ||
1031 | if (diff < min) { | ||
1032 | min = diff; | ||
1033 | best_cout = cout; | ||
1034 | best_act = actual; | ||
1035 | } | ||
1036 | } | ||
1037 | |||
1038 | ret = clk_set_rate(ick, best_cout); | ||
1039 | if (ret < 0) { | ||
1040 | dev_err(dev, "ick clock failed\n"); | ||
1041 | return -EIO; | ||
1042 | } | ||
1043 | |||
1044 | ret = clk_set_rate(div, clk_round_rate(div, best_act)); | ||
1045 | if (ret < 0) { | ||
1046 | dev_err(dev, "div clock failed\n"); | ||
1047 | return -EIO; | ||
1048 | } | ||
1049 | |||
1050 | dev_dbg(dev, "ick/div = %ld/%ld\n", | ||
1051 | clk_get_rate(ick), clk_get_rate(div)); | ||
1052 | |||
1053 | return ret; | ||
1054 | } | ||
1055 | |||
719 | static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | 1056 | static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, |
720 | long rate, int enable) | 1057 | long rate, int enable) |
721 | { | 1058 | { |
722 | set_rate_func set_rate = fsi_get_info_set_rate(fsi); | 1059 | set_rate_func set_rate = fsi_get_info_set_rate(fsi); |
723 | int ret; | 1060 | int ret; |
724 | 1061 | ||
725 | if (!set_rate) | 1062 | /* |
726 | return 0; | 1063 | * CAUTION |
1064 | * | ||
1065 | * set_rate will be deleted | ||
1066 | */ | ||
1067 | if (!set_rate) { | ||
1068 | if (enable) | ||
1069 | return fsi_clk_enable(dev, fsi, rate); | ||
1070 | else | ||
1071 | return fsi_clk_disable(dev, fsi); | ||
1072 | } | ||
727 | 1073 | ||
728 | ret = set_rate(dev, rate, enable); | 1074 | ret = set_rate(dev, rate, enable); |
729 | if (ret < 0) /* error */ | 1075 | if (ret < 0) /* error */ |
@@ -1355,6 +1701,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
1355 | { | 1701 | { |
1356 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1702 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1357 | 1703 | ||
1704 | fsi_clk_invalid(fsi); | ||
1358 | fsi->rate = 0; | 1705 | fsi->rate = 0; |
1359 | 1706 | ||
1360 | return 0; | 1707 | return 0; |
@@ -1365,6 +1712,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
1365 | { | 1712 | { |
1366 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1713 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1367 | 1714 | ||
1715 | fsi_clk_invalid(fsi); | ||
1368 | fsi->rate = 0; | 1716 | fsi->rate = 0; |
1369 | } | 1717 | } |
1370 | 1718 | ||
@@ -1446,9 +1794,25 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1446 | return -EINVAL; | 1794 | return -EINVAL; |
1447 | } | 1795 | } |
1448 | 1796 | ||
1449 | if (fsi_is_clk_master(fsi) && !set_rate) { | 1797 | if (fsi_is_clk_master(fsi)) { |
1450 | dev_err(dai->dev, "platform doesn't have set_rate\n"); | 1798 | /* |
1451 | return -EINVAL; | 1799 | * CAUTION |
1800 | * | ||
1801 | * set_rate will be deleted | ||
1802 | */ | ||
1803 | if (set_rate) | ||
1804 | dev_warn(dai->dev, "set_rate will be removed soon\n"); | ||
1805 | |||
1806 | switch (flags & SH_FSI_CLK_MASK) { | ||
1807 | case SH_FSI_CLK_EXTERNAL: | ||
1808 | fsi_clk_init(dai->dev, fsi, 1, 1, 0, | ||
1809 | fsi_clk_set_rate_external); | ||
1810 | break; | ||
1811 | case SH_FSI_CLK_CPG: | ||
1812 | fsi_clk_init(dai->dev, fsi, 0, 1, 1, | ||
1813 | fsi_clk_set_rate_cpg); | ||
1814 | break; | ||
1815 | } | ||
1452 | } | 1816 | } |
1453 | 1817 | ||
1454 | /* set format */ | 1818 | /* set format */ |
@@ -1472,8 +1836,10 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | |||
1472 | { | 1836 | { |
1473 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1837 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1474 | 1838 | ||
1475 | if (fsi_is_clk_master(fsi)) | 1839 | if (fsi_is_clk_master(fsi)) { |
1476 | fsi->rate = params_rate(params); | 1840 | fsi->rate = params_rate(params); |
1841 | fsi_clk_valid(fsi, fsi->rate); | ||
1842 | } | ||
1477 | 1843 | ||
1478 | return 0; | 1844 | return 0; |
1479 | } | 1845 | } |