aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Lee <ryans.lee@maximintegrated.com>2017-09-14 20:30:39 -0400
committerMark Brown <broonie@kernel.org>2017-09-25 15:48:14 -0400
commitd4a8bce81cbd53420988f5db0d096ad04960f189 (patch)
tree608cee91e2c2011b65da6bd0cc79f9f3397d2ead
parent4eee20246c0fa77a7a7b189ac806d5f78d675546 (diff)
ASoC: max98927: Added max98927_dai_tdm_slot function
Signed-off-by: Ryan Lee <ryans.lee@maximintegrated.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/max98927.c120
-rw-r--r--sound/soc/codecs/max98927.h1
2 files changed, 105 insertions, 16 deletions
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 6f7b3ef48e25..a1d39353719d 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -250,6 +250,21 @@ static const int rate_table[] = {
250 13000000, 19200000, 250 13000000, 19200000,
251}; 251};
252 252
253/* BCLKs per LRCLK */
254static const int bclk_sel_table[] = {
255 32, 48, 64, 96, 128, 192, 256, 384, 512,
256};
257
258static int max98927_get_bclk_sel(int bclk)
259{
260 int i;
261 /* match BCLKs per LRCLK */
262 for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
263 if (bclk_sel_table[i] == bclk)
264 return i + 2;
265 }
266 return 0;
267}
253static int max98927_set_clock(struct max98927_priv *max98927, 268static int max98927_set_clock(struct max98927_priv *max98927,
254 struct snd_pcm_hw_params *params) 269 struct snd_pcm_hw_params *params)
255{ 270{
@@ -275,23 +290,20 @@ static int max98927_set_clock(struct max98927_priv *max98927,
275 i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); 290 i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
276 } 291 }
277 292
278 switch (blr_clk_ratio) { 293 if (!max98927->tdm_mode) {
279 case 32: 294 /* BCLK configuration */
280 value = 2; 295 value = max98927_get_bclk_sel(blr_clk_ratio);
281 break; 296 if (!value) {
282 case 48: 297 dev_err(codec->dev, "format unsupported %d\n",
283 value = 3; 298 params_format(params));
284 break; 299 return -EINVAL;
285 case 64: 300 }
286 value = 4; 301
287 break; 302 regmap_update_bits(max98927->regmap,
288 default: 303 MAX98927_R0022_PCM_CLK_SETUP,
289 return -EINVAL; 304 MAX98927_PCM_CLK_SETUP_BSEL_MASK,
305 value);
290 } 306 }
291 regmap_update_bits(max98927->regmap,
292 MAX98927_R0022_PCM_CLK_SETUP,
293 MAX98927_PCM_CLK_SETUP_BSEL_MASK,
294 value);
295 return 0; 307 return 0;
296} 308}
297 309
@@ -391,6 +403,78 @@ err:
391 return -EINVAL; 403 return -EINVAL;
392} 404}
393 405
406static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
407 unsigned int tx_mask, unsigned int rx_mask,
408 int slots, int slot_width)
409{
410 struct snd_soc_codec *codec = dai->codec;
411 struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
412 int bsel = 0;
413 unsigned int chan_sz = 0;
414
415 max98927->tdm_mode = true;
416
417 /* BCLK configuration */
418 bsel = max98927_get_bclk_sel(slots * slot_width);
419 if (bsel == 0) {
420 dev_err(codec->dev, "BCLK %d not supported\n",
421 slots * slot_width);
422 return -EINVAL;
423 }
424
425 regmap_update_bits(max98927->regmap,
426 MAX98927_R0022_PCM_CLK_SETUP,
427 MAX98927_PCM_CLK_SETUP_BSEL_MASK,
428 bsel);
429
430 /* Channel size configuration */
431 switch (slot_width) {
432 case 16:
433 chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
434 break;
435 case 24:
436 chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
437 break;
438 case 32:
439 chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
440 break;
441 default:
442 dev_err(codec->dev, "format unsupported %d\n",
443 slot_width);
444 return -EINVAL;
445 }
446
447 regmap_update_bits(max98927->regmap,
448 MAX98927_R0020_PCM_MODE_CFG,
449 MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
450
451 /* Rx slot configuration */
452 regmap_write(max98927->regmap,
453 MAX98927_R0018_PCM_RX_EN_A,
454 rx_mask & 0xFF);
455 regmap_write(max98927->regmap,
456 MAX98927_R0019_PCM_RX_EN_B,
457 (rx_mask & 0xFF00) >> 8);
458
459 /* Tx slot configuration */
460 regmap_write(max98927->regmap,
461 MAX98927_R001A_PCM_TX_EN_A,
462 tx_mask & 0xFF);
463 regmap_write(max98927->regmap,
464 MAX98927_R001B_PCM_TX_EN_B,
465 (tx_mask & 0xFF00) >> 8);
466
467 /* Tx slot Hi-Z configuration */
468 regmap_write(max98927->regmap,
469 MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
470 ~tx_mask & 0xFF);
471 regmap_write(max98927->regmap,
472 MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
473 (~tx_mask & 0xFF00) >> 8);
474
475 return 0;
476}
477
394#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000 478#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
395 479
396#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 480#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -410,6 +494,7 @@ static const struct snd_soc_dai_ops max98927_dai_ops = {
410 .set_sysclk = max98927_dai_set_sysclk, 494 .set_sysclk = max98927_dai_set_sysclk,
411 .set_fmt = max98927_dai_set_fmt, 495 .set_fmt = max98927_dai_set_fmt,
412 .hw_params = max98927_dai_hw_params, 496 .hw_params = max98927_dai_hw_params,
497 .set_tdm_slot = max98927_dai_tdm_slot,
413}; 498};
414 499
415static int max98927_dac_event(struct snd_soc_dapm_widget *w, 500static int max98927_dac_event(struct snd_soc_dapm_widget *w,
@@ -419,6 +504,9 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
419 struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); 504 struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
420 505
421 switch (event) { 506 switch (event) {
507 case SND_SOC_DAPM_PRE_PMU:
508 max98927->tdm_mode = 0;
509 break;
422 case SND_SOC_DAPM_POST_PMU: 510 case SND_SOC_DAPM_POST_PMU:
423 regmap_update_bits(max98927->regmap, 511 regmap_update_bits(max98927->regmap,
424 MAX98927_R003A_AMP_EN, 512 MAX98927_R003A_AMP_EN,
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
index bf7a6f92562a..9ea839735433 100644
--- a/sound/soc/codecs/max98927.h
+++ b/sound/soc/codecs/max98927.h
@@ -270,5 +270,6 @@ struct max98927_priv {
270 unsigned int iface; 270 unsigned int iface;
271 unsigned int master; 271 unsigned int master;
272 unsigned int digital_gain; 272 unsigned int digital_gain;
273 bool tdm_mode;
273}; 274};
274#endif 275#endif