diff options
author | Mark Brown <broonie@kernel.org> | 2017-11-10 16:30:45 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-11-10 16:30:45 -0500 |
commit | 4d0210e6d0aec4b95c762e2af1afa688cc512547 (patch) | |
tree | 2f91017daa464223883d9295786ea1c20de0633c | |
parent | 60190e46df7fc6e9fe558e3c0aa8af8d70ebc8fa (diff) | |
parent | 316b7758c998fb13371d14bb6c9e45ab129c19a7 (diff) |
Merge remote-tracking branch 'asoc/fix/sunxi' into asoc-linus
-rw-r--r-- | sound/soc/sunxi/sun8i-codec.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index abfb710df7cb..50a9e077f01b 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c | |||
@@ -73,6 +73,7 @@ | |||
73 | #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) | 73 | #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) |
74 | #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) | 74 | #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) |
75 | #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) | 75 | #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) |
76 | #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) | ||
76 | 77 | ||
77 | struct sun8i_codec { | 78 | struct sun8i_codec { |
78 | struct device *dev; | 79 | struct device *dev; |
@@ -170,11 +171,11 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
170 | 171 | ||
171 | /* clock masters */ | 172 | /* clock masters */ |
172 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 173 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
173 | case SND_SOC_DAIFMT_CBS_CFS: /* DAI Slave */ | 174 | case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */ |
174 | value = 0x0; /* Codec Master */ | 175 | value = 0x1; |
175 | break; | 176 | break; |
176 | case SND_SOC_DAIFMT_CBM_CFM: /* DAI Master */ | 177 | case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */ |
177 | value = 0x1; /* Codec Slave */ | 178 | value = 0x0; |
178 | break; | 179 | break; |
179 | default: | 180 | default: |
180 | return -EINVAL; | 181 | return -EINVAL; |
@@ -226,12 +227,57 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
226 | return 0; | 227 | return 0; |
227 | } | 228 | } |
228 | 229 | ||
230 | struct sun8i_codec_clk_div { | ||
231 | u8 div; | ||
232 | u8 val; | ||
233 | }; | ||
234 | |||
235 | static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { | ||
236 | { .div = 1, .val = 0 }, | ||
237 | { .div = 2, .val = 1 }, | ||
238 | { .div = 4, .val = 2 }, | ||
239 | { .div = 6, .val = 3 }, | ||
240 | { .div = 8, .val = 4 }, | ||
241 | { .div = 12, .val = 5 }, | ||
242 | { .div = 16, .val = 6 }, | ||
243 | { .div = 24, .val = 7 }, | ||
244 | { .div = 32, .val = 8 }, | ||
245 | { .div = 48, .val = 9 }, | ||
246 | { .div = 64, .val = 10 }, | ||
247 | { .div = 96, .val = 11 }, | ||
248 | { .div = 128, .val = 12 }, | ||
249 | { .div = 192, .val = 13 }, | ||
250 | }; | ||
251 | |||
252 | static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, | ||
253 | unsigned int rate, | ||
254 | unsigned int word_size) | ||
255 | { | ||
256 | unsigned long clk_rate = clk_get_rate(scodec->clk_module); | ||
257 | unsigned int div = clk_rate / rate / word_size / 2; | ||
258 | unsigned int best_val = 0, best_diff = ~0; | ||
259 | int i; | ||
260 | |||
261 | for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) { | ||
262 | const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i]; | ||
263 | unsigned int diff = abs(bdiv->div - div); | ||
264 | |||
265 | if (diff < best_diff) { | ||
266 | best_diff = diff; | ||
267 | best_val = bdiv->val; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | return best_val; | ||
272 | } | ||
273 | |||
229 | static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, | 274 | static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, |
230 | struct snd_pcm_hw_params *params, | 275 | struct snd_pcm_hw_params *params, |
231 | struct snd_soc_dai *dai) | 276 | struct snd_soc_dai *dai) |
232 | { | 277 | { |
233 | struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); | 278 | struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); |
234 | int sample_rate; | 279 | int sample_rate; |
280 | u8 bclk_div; | ||
235 | 281 | ||
236 | /* | 282 | /* |
237 | * The CPU DAI handles only a sample of 16 bits. Configure the | 283 | * The CPU DAI handles only a sample of 16 bits. Configure the |
@@ -241,6 +287,11 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, | |||
241 | SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, | 287 | SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, |
242 | SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); | 288 | SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); |
243 | 289 | ||
290 | bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16); | ||
291 | regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, | ||
292 | SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, | ||
293 | bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); | ||
294 | |||
244 | regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, | 295 | regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, |
245 | SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, | 296 | SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, |
246 | SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); | 297 | SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); |