aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/davinci
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2015-03-20 07:31:08 -0400
committerMark Brown <broonie@kernel.org>2015-03-24 13:19:43 -0400
commita75a053f1eefbbbbae0f7d6bf1ed12ce012112b7 (patch)
tree12d884faf49d96e56b577061fabba3d10f28898b /sound/soc/davinci
parent66e618857ca46433741bf97ceca1b425387400b1 (diff)
ASoC: davinci-mcasp: Set rule constraints if implicit BCLK divider is used
Set rule constraints to allow only combinations of sample-rate, sample-format, and channels counts that can be played/captured with reasonable sample-rate accuracy. The logic with tdm-slots and serializers (=i2s data wires) goes like this: The first wire will take all channels up to number of tdm-slots, before following wires (if any) are used. If the first wire is used fully, the remaining wires share the same clocks and the divider can be calculated for the first wire. Also, takes the number of tdm-slots into account when implicitly selecting the BLCK divider. Signed-off-by: Jyri Sarha <jsarha@ti.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/davinci')
-rw-r--r--sound/soc/davinci/davinci-mcasp.c207
1 files changed, 197 insertions, 10 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index d40b392b3da2..76156d18ed46 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -27,6 +27,7 @@
27#include <linux/of_platform.h> 27#include <linux/of_platform.h>
28#include <linux/of_device.h> 28#include <linux/of_device.h>
29#include <linux/platform_data/davinci_asp.h> 29#include <linux/platform_data/davinci_asp.h>
30#include <linux/math64.h>
30 31
31#include <sound/asoundef.h> 32#include <sound/asoundef.h>
32#include <sound/core.h> 33#include <sound/core.h>
@@ -65,6 +66,11 @@ struct davinci_mcasp_context {
65 bool pm_state; 66 bool pm_state;
66}; 67};
67 68
69struct davinci_mcasp_ruledata {
70 struct davinci_mcasp *mcasp;
71 int serializers;
72};
73
68struct davinci_mcasp { 74struct davinci_mcasp {
69 struct snd_dmaengine_dai_dma_data dma_data[2]; 75 struct snd_dmaengine_dai_dma_data dma_data[2];
70 void __iomem *base; 76 void __iomem *base;
@@ -99,6 +105,8 @@ struct davinci_mcasp {
99#ifdef CONFIG_PM_SLEEP 105#ifdef CONFIG_PM_SLEEP
100 struct davinci_mcasp_context context; 106 struct davinci_mcasp_context context;
101#endif 107#endif
108
109 struct davinci_mcasp_ruledata ruledata[2];
102}; 110};
103 111
104static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset, 112static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
@@ -868,6 +876,30 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
868 return 0; 876 return 0;
869} 877}
870 878
879static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
880 unsigned int bclk_freq,
881 int *error_ppm)
882{
883 int div = mcasp->sysclk_freq / bclk_freq;
884 int rem = mcasp->sysclk_freq % bclk_freq;
885
886 if (rem != 0) {
887 if (div == 0 ||
888 ((mcasp->sysclk_freq / div) - bclk_freq) >
889 (bclk_freq - (mcasp->sysclk_freq / (div+1)))) {
890 div++;
891 rem = rem - bclk_freq;
892 }
893 }
894 if (error_ppm)
895 *error_ppm =
896 (div*1000000 + (int)div64_long(1000000LL*rem,
897 (int)bclk_freq))
898 /div - 1000000;
899
900 return div;
901}
902
871static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, 903static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
872 struct snd_pcm_hw_params *params, 904 struct snd_pcm_hw_params *params,
873 struct snd_soc_dai *cpu_dai) 905 struct snd_soc_dai *cpu_dai)
@@ -883,16 +915,20 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
883 * the machine driver, we need to calculate the ratio. 915 * the machine driver, we need to calculate the ratio.
884 */ 916 */
885 if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { 917 if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
886 unsigned int bclk_freq = snd_soc_params_to_bclk(params); 918 int channels = params_channels(params);
887 unsigned int div = mcasp->sysclk_freq / bclk_freq; 919 int rate = params_rate(params);
888 if (mcasp->sysclk_freq % bclk_freq != 0) { 920 int sbits = params_width(params);
889 if (((mcasp->sysclk_freq / div) - bclk_freq) > 921 int ppm, div;
890 (bclk_freq - (mcasp->sysclk_freq / (div+1)))) 922
891 div++; 923 if (channels > mcasp->tdm_slots)
892 dev_warn(mcasp->dev, 924 channels = mcasp->tdm_slots;
893 "Inaccurate BCLK: %u Hz / %u != %u Hz\n", 925
894 mcasp->sysclk_freq, div, bclk_freq); 926 div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*channels,
895 } 927 &ppm);
928 if (ppm)
929 dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
930 ppm);
931
896 __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0); 932 __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);
897 } 933 }
898 934
@@ -974,6 +1010,120 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
974 return ret; 1010 return ret;
975} 1011}
976 1012
1013static const unsigned int davinci_mcasp_dai_rates[] = {
1014 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
1015 88200, 96000, 176400, 192000,
1016};
1017
1018#define DAVINCI_MAX_RATE_ERROR_PPM 1000
1019
1020static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
1021 struct snd_pcm_hw_rule *rule)
1022{
1023 struct davinci_mcasp_ruledata *rd = rule->private;
1024 struct snd_interval *ri =
1025 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
1026 int sbits = params_width(params);
1027 int channels = params_channels(params);
1028 unsigned int list[ARRAY_SIZE(davinci_mcasp_dai_rates)];
1029 int i, count = 0;
1030
1031 if (channels > rd->mcasp->tdm_slots)
1032 channels = rd->mcasp->tdm_slots;
1033
1034 for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
1035 if (ri->min <= davinci_mcasp_dai_rates[i] &&
1036 ri->max >= davinci_mcasp_dai_rates[i]) {
1037 uint bclk_freq = sbits*channels*
1038 davinci_mcasp_dai_rates[i];
1039 int ppm;
1040
1041 davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
1042 if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM)
1043 list[count++] = davinci_mcasp_dai_rates[i];
1044 }
1045 }
1046 dev_dbg(rd->mcasp->dev,
1047 "%d frequencies (%d-%d) for %d sbits and %d channels\n",
1048 count, ri->min, ri->max, sbits, channels);
1049
1050 return snd_interval_list(hw_param_interval(params, rule->var),
1051 count, list, 0);
1052}
1053
1054static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
1055 struct snd_pcm_hw_rule *rule)
1056{
1057 struct davinci_mcasp_ruledata *rd = rule->private;
1058 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1059 struct snd_mask nfmt;
1060 int rate = params_rate(params);
1061 int channels = params_channels(params);
1062 int i, count = 0;
1063
1064 snd_mask_none(&nfmt);
1065
1066 if (channels > rd->mcasp->tdm_slots)
1067 channels = rd->mcasp->tdm_slots;
1068
1069 for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
1070 if (snd_mask_test(fmt, i)) {
1071 uint bclk_freq = snd_pcm_format_width(i)*channels*rate;
1072 int ppm;
1073
1074 davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
1075 if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
1076 snd_mask_set(&nfmt, i);
1077 count++;
1078 }
1079 }
1080 }
1081 dev_dbg(rd->mcasp->dev,
1082 "%d possible sample format for %d Hz and %d channels\n",
1083 count, rate, channels);
1084
1085 return snd_mask_refine(fmt, &nfmt);
1086}
1087
1088static int davinci_mcasp_hw_rule_channels(struct snd_pcm_hw_params *params,
1089 struct snd_pcm_hw_rule *rule)
1090{
1091 struct davinci_mcasp_ruledata *rd = rule->private;
1092 struct snd_interval *ci =
1093 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
1094 int sbits = params_width(params);
1095 int rate = params_rate(params);
1096 int max_chan_per_wire = rd->mcasp->tdm_slots < ci->max ?
1097 rd->mcasp->tdm_slots : ci->max;
1098 unsigned int list[ci->max - ci->min + 1];
1099 int c1, c, count = 0;
1100
1101 for (c1 = ci->min; c1 <= max_chan_per_wire; c1++) {
1102 uint bclk_freq = c1*sbits*rate;
1103 int ppm;
1104
1105 davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
1106 if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
1107 /* If we can use all tdm_slots, we can put any
1108 amount of channels to remaining wires as
1109 long as they fit in. */
1110 if (c1 == rd->mcasp->tdm_slots) {
1111 for (c = c1; c <= rd->serializers*c1 &&
1112 c <= ci->max; c++)
1113 list[count++] = c;
1114 } else {
1115 list[count++] = c1;
1116 }
1117 }
1118 }
1119 dev_dbg(rd->mcasp->dev,
1120 "%d possible channel counts (%d-%d) for %d Hz and %d sbits\n",
1121 count, ci->min, ci->max, rate, sbits);
1122
1123 return snd_interval_list(hw_param_interval(params, rule->var),
1124 count, list, 0);
1125}
1126
977static int davinci_mcasp_startup(struct snd_pcm_substream *substream, 1127static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
978 struct snd_soc_dai *cpu_dai) 1128 struct snd_soc_dai *cpu_dai)
979{ 1129{
@@ -999,6 +1149,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
999 if (mcasp->serial_dir[i] == dir) 1149 if (mcasp->serial_dir[i] == dir)
1000 max_channels++; 1150 max_channels++;
1001 } 1151 }
1152 mcasp->ruledata[dir].serializers = max_channels;
1002 max_channels *= mcasp->tdm_slots; 1153 max_channels *= mcasp->tdm_slots;
1003 /* 1154 /*
1004 * If the already active stream has less channels than the calculated 1155 * If the already active stream has less channels than the calculated
@@ -1013,6 +1164,42 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
1013 snd_pcm_hw_constraint_minmax(substream->runtime, 1164 snd_pcm_hw_constraint_minmax(substream->runtime,
1014 SNDRV_PCM_HW_PARAM_CHANNELS, 1165 SNDRV_PCM_HW_PARAM_CHANNELS,
1015 2, max_channels); 1166 2, max_channels);
1167
1168 /*
1169 * If we rely on implicit BCLK divider setting we should
1170 * set constraints based on what we can provide.
1171 */
1172 if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
1173 int ret;
1174
1175 mcasp->ruledata[dir].mcasp = mcasp;
1176
1177 ret = snd_pcm_hw_rule_add(substream->runtime, 0,
1178 SNDRV_PCM_HW_PARAM_RATE,
1179 davinci_mcasp_hw_rule_rate,
1180 &mcasp->ruledata[dir],
1181 SNDRV_PCM_HW_PARAM_FORMAT,
1182 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
1183 if (ret)
1184 return ret;
1185 ret = snd_pcm_hw_rule_add(substream->runtime, 0,
1186 SNDRV_PCM_HW_PARAM_FORMAT,
1187 davinci_mcasp_hw_rule_format,
1188 &mcasp->ruledata[dir],
1189 SNDRV_PCM_HW_PARAM_RATE,
1190 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
1191 if (ret)
1192 return ret;
1193 ret = snd_pcm_hw_rule_add(substream->runtime, 0,
1194 SNDRV_PCM_HW_PARAM_CHANNELS,
1195 davinci_mcasp_hw_rule_channels,
1196 &mcasp->ruledata[dir],
1197 SNDRV_PCM_HW_PARAM_RATE,
1198 SNDRV_PCM_HW_PARAM_FORMAT, -1);
1199 if (ret)
1200 return ret;
1201 }
1202
1016 return 0; 1203 return 0;
1017} 1204}
1018 1205