diff options
author | Maxime Ripard <maxime.ripard@bootlin.com> | 2019-08-19 15:25:16 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-08-20 13:31:42 -0400 |
commit | c1d3a921d72bd21f266ca28c15213fbe78160a4b (patch) | |
tree | 2b203dbabb3c9cfa74988b11385efb0294b88e80 /sound | |
parent | fb19739d7f688142b61d0fca476188c4fd9e937a (diff) |
ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
From: Marcus Cooper <codekipper@gmail.com>
The clock division dividers have changed between the older (A10/A31) and
newer (H3, A64, etc) SoCs.
While this was addressed through an offset on some SoCs, it was missing
some dividers as well, so the support wasn't perfect. Let's introduce a
pointer in the quirk structure for the divider calculation functions to use
so we can have the proper range now.
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
[Maxime: Fix the commit log, use a field in the quirk structure]
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://lore.kernel.org/r/0e5b4abf06cd3202354315201c6af44caeb20236.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/sunxi/sun4i-i2s.c | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index acfcdb26086a..0a7f1d0f7371 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c | |||
@@ -129,8 +129,6 @@ struct sun4i_i2s; | |||
129 | * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. | 129 | * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. |
130 | * @reg_offset_txdata: offset of the tx fifo. | 130 | * @reg_offset_txdata: offset of the tx fifo. |
131 | * @sun4i_i2s_regmap: regmap config to use. | 131 | * @sun4i_i2s_regmap: regmap config to use. |
132 | * @mclk_offset: Value by which mclkdiv needs to be adjusted. | ||
133 | * @bclk_offset: Value by which bclkdiv needs to be adjusted. | ||
134 | * @field_clkdiv_mclk_en: regmap field to enable mclk output. | 132 | * @field_clkdiv_mclk_en: regmap field to enable mclk output. |
135 | * @field_fmt_wss: regmap field to set word select size. | 133 | * @field_fmt_wss: regmap field to set word select size. |
136 | * @field_fmt_sr: regmap field to set sample resolution. | 134 | * @field_fmt_sr: regmap field to set sample resolution. |
@@ -142,8 +140,6 @@ struct sun4i_i2s_quirks { | |||
142 | bool has_fmt_set_lrck_period; | 140 | bool has_fmt_set_lrck_period; |
143 | unsigned int reg_offset_txdata; /* TX FIFO */ | 141 | unsigned int reg_offset_txdata; /* TX FIFO */ |
144 | const struct regmap_config *sun4i_i2s_regmap; | 142 | const struct regmap_config *sun4i_i2s_regmap; |
145 | unsigned int mclk_offset; | ||
146 | unsigned int bclk_offset; | ||
147 | 143 | ||
148 | /* Register fields for i2s */ | 144 | /* Register fields for i2s */ |
149 | struct reg_field field_clkdiv_mclk_en; | 145 | struct reg_field field_clkdiv_mclk_en; |
@@ -152,6 +148,11 @@ struct sun4i_i2s_quirks { | |||
152 | struct reg_field field_fmt_bclk; | 148 | struct reg_field field_fmt_bclk; |
153 | struct reg_field field_fmt_lrclk; | 149 | struct reg_field field_fmt_lrclk; |
154 | 150 | ||
151 | const struct sun4i_i2s_clk_div *bclk_dividers; | ||
152 | unsigned int num_bclk_dividers; | ||
153 | const struct sun4i_i2s_clk_div *mclk_dividers; | ||
154 | unsigned int num_mclk_dividers; | ||
155 | |||
155 | unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); | 156 | unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); |
156 | s8 (*get_sr)(const struct sun4i_i2s *, int); | 157 | s8 (*get_sr)(const struct sun4i_i2s *, int); |
157 | s8 (*get_wss)(const struct sun4i_i2s *, int); | 158 | s8 (*get_wss)(const struct sun4i_i2s *, int); |
@@ -208,6 +209,24 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { | |||
208 | /* TODO - extend divide ratio supported by newer SoCs */ | 209 | /* TODO - extend divide ratio supported by newer SoCs */ |
209 | }; | 210 | }; |
210 | 211 | ||
212 | static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { | ||
213 | { .div = 1, .val = 1 }, | ||
214 | { .div = 2, .val = 2 }, | ||
215 | { .div = 4, .val = 3 }, | ||
216 | { .div = 6, .val = 4 }, | ||
217 | { .div = 8, .val = 5 }, | ||
218 | { .div = 12, .val = 6 }, | ||
219 | { .div = 16, .val = 7 }, | ||
220 | { .div = 24, .val = 8 }, | ||
221 | { .div = 32, .val = 9 }, | ||
222 | { .div = 48, .val = 10 }, | ||
223 | { .div = 64, .val = 11 }, | ||
224 | { .div = 96, .val = 12 }, | ||
225 | { .div = 128, .val = 13 }, | ||
226 | { .div = 176, .val = 14 }, | ||
227 | { .div = 192, .val = 15 }, | ||
228 | }; | ||
229 | |||
211 | static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) | 230 | static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) |
212 | { | 231 | { |
213 | return i2s->mclk_freq; | 232 | return i2s->mclk_freq; |
@@ -223,11 +242,12 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, | |||
223 | unsigned int sampling_rate, | 242 | unsigned int sampling_rate, |
224 | unsigned int word_size) | 243 | unsigned int word_size) |
225 | { | 244 | { |
245 | const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; | ||
226 | int div = parent_rate / sampling_rate / word_size / 2; | 246 | int div = parent_rate / sampling_rate / word_size / 2; |
227 | int i; | 247 | int i; |
228 | 248 | ||
229 | for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { | 249 | for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { |
230 | const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; | 250 | const struct sun4i_i2s_clk_div *bdiv = ÷rs[i]; |
231 | 251 | ||
232 | if (bdiv->div == div) | 252 | if (bdiv->div == div) |
233 | return bdiv->val; | 253 | return bdiv->val; |
@@ -240,11 +260,12 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, | |||
240 | unsigned long parent_rate, | 260 | unsigned long parent_rate, |
241 | unsigned long mclk_rate) | 261 | unsigned long mclk_rate) |
242 | { | 262 | { |
263 | const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; | ||
243 | int div = parent_rate / mclk_rate; | 264 | int div = parent_rate / mclk_rate; |
244 | int i; | 265 | int i; |
245 | 266 | ||
246 | for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { | 267 | for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { |
247 | const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; | 268 | const struct sun4i_i2s_clk_div *mdiv = ÷rs[i]; |
248 | 269 | ||
249 | if (mdiv->div == div) | 270 | if (mdiv->div == div) |
250 | return mdiv->val; | 271 | return mdiv->val; |
@@ -326,10 +347,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, | |||
326 | return -EINVAL; | 347 | return -EINVAL; |
327 | } | 348 | } |
328 | 349 | ||
329 | /* Adjust the clock division values if needed */ | ||
330 | bclk_div += i2s->variant->bclk_offset; | ||
331 | mclk_div += i2s->variant->mclk_offset; | ||
332 | |||
333 | regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, | 350 | regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, |
334 | SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | | 351 | SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | |
335 | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); | 352 | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); |
@@ -969,6 +986,10 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { | |||
969 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), | 986 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
970 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), | 987 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
971 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), | 988 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
989 | .bclk_dividers = sun4i_i2s_bclk_div, | ||
990 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), | ||
991 | .mclk_dividers = sun4i_i2s_mclk_div, | ||
992 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), | ||
972 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, | 993 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
973 | .get_sr = sun4i_i2s_get_sr, | 994 | .get_sr = sun4i_i2s_get_sr, |
974 | .get_wss = sun4i_i2s_get_wss, | 995 | .get_wss = sun4i_i2s_get_wss, |
@@ -985,6 +1006,10 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { | |||
985 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), | 1006 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
986 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), | 1007 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
987 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), | 1008 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
1009 | .bclk_dividers = sun4i_i2s_bclk_div, | ||
1010 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), | ||
1011 | .mclk_dividers = sun4i_i2s_mclk_div, | ||
1012 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), | ||
988 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, | 1013 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
989 | .get_sr = sun4i_i2s_get_sr, | 1014 | .get_sr = sun4i_i2s_get_sr, |
990 | .get_wss = sun4i_i2s_get_wss, | 1015 | .get_wss = sun4i_i2s_get_wss, |
@@ -1001,6 +1026,10 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { | |||
1001 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), | 1026 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
1002 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), | 1027 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
1003 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), | 1028 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
1029 | .bclk_dividers = sun8i_i2s_clk_div, | ||
1030 | .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), | ||
1031 | .mclk_dividers = sun8i_i2s_clk_div, | ||
1032 | .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), | ||
1004 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, | 1033 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, |
1005 | .get_sr = sun8i_i2s_get_sr_wss, | 1034 | .get_sr = sun8i_i2s_get_sr_wss, |
1006 | .get_wss = sun8i_i2s_get_sr_wss, | 1035 | .get_wss = sun8i_i2s_get_sr_wss, |
@@ -1012,14 +1041,16 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { | |||
1012 | .has_reset = true, | 1041 | .has_reset = true, |
1013 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, | 1042 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
1014 | .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, | 1043 | .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, |
1015 | .mclk_offset = 1, | ||
1016 | .bclk_offset = 2, | ||
1017 | .has_fmt_set_lrck_period = true, | 1044 | .has_fmt_set_lrck_period = true, |
1018 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), | 1045 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), |
1019 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), | 1046 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), |
1020 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), | 1047 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), |
1021 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), | 1048 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
1022 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), | 1049 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), |
1050 | .bclk_dividers = sun8i_i2s_clk_div, | ||
1051 | .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), | ||
1052 | .mclk_dividers = sun8i_i2s_clk_div, | ||
1053 | .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), | ||
1023 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, | 1054 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, |
1024 | .get_sr = sun8i_i2s_get_sr_wss, | 1055 | .get_sr = sun8i_i2s_get_sr_wss, |
1025 | .get_wss = sun8i_i2s_get_sr_wss, | 1056 | .get_wss = sun8i_i2s_get_sr_wss, |
@@ -1036,6 +1067,10 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { | |||
1036 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), | 1067 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
1037 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), | 1068 | .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
1038 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), | 1069 | .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
1070 | .bclk_dividers = sun4i_i2s_bclk_div, | ||
1071 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), | ||
1072 | .mclk_dividers = sun4i_i2s_mclk_div, | ||
1073 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), | ||
1039 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, | 1074 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
1040 | .get_sr = sun4i_i2s_get_sr, | 1075 | .get_sr = sun4i_i2s_get_sr, |
1041 | .get_wss = sun4i_i2s_get_wss, | 1076 | .get_wss = sun4i_i2s_get_wss, |