aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2017-11-10 16:30:45 -0500
committerMark Brown <broonie@kernel.org>2017-11-10 16:30:45 -0500
commit4d0210e6d0aec4b95c762e2af1afa688cc512547 (patch)
tree2f91017daa464223883d9295786ea1c20de0633c
parent60190e46df7fc6e9fe558e3c0aa8af8d70ebc8fa (diff)
parent316b7758c998fb13371d14bb6c9e45ab129c19a7 (diff)
Merge remote-tracking branch 'asoc/fix/sunxi' into asoc-linus
-rw-r--r--sound/soc/sunxi/sun8i-codec.c59
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
77struct sun8i_codec { 78struct 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
230struct sun8i_codec_clk_div {
231 u8 div;
232 u8 val;
233};
234
235static 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
252static 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
229static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, 274static 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);