aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2019-08-12 05:52:25 -0400
committerMark Brown <broonie@kernel.org>2019-08-12 09:08:35 -0400
commitabe51c351827e0086dad079dfe02918fecdf4830 (patch)
treed9afcd24ff6185e59fecd93c8e724c3c9d096cca /sound
parent79631210fc413546d0ed73632ff904ded5192cc9 (diff)
ASoC: pcm3168a: Retain the independence of DAC and ADC side of the codec
The DAC and ADC path of the codec is independent, have dedicated LRCK (FS) and BCK for DAC/ADC. They can be configured to use different format, TDM slots and slot_width if needed. Move these parameters under dedicated io_params structure and manage them independently based on the dai. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Link: https://lore.kernel.org/r/20190812095226.18870-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/pcm3168a.c125
1 files changed, 54 insertions, 71 deletions
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index e84a1509fe65..75fa8e9ee894 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
44 "VCCDA2" 44 "VCCDA2"
45}; 45};
46 46
47#define PCM3168A_DAI_DAC 0
48#define PCM3168A_DAI_ADC 1
49
50/* ADC/DAC side parameters */
51struct pcm3168a_io_params {
52 bool master_mode;
53 unsigned int fmt;
54 int tdm_slots;
55 u32 tdm_mask;
56 int slot_width;
57};
58
47struct pcm3168a_priv { 59struct pcm3168a_priv {
48 struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; 60 struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
49 struct regmap *regmap; 61 struct regmap *regmap;
50 struct clk *scki; 62 struct clk *scki;
51 bool adc_master_mode;
52 bool dac_master_mode;
53 unsigned long sysclk; 63 unsigned long sysclk;
54 unsigned int adc_fmt; 64
55 unsigned int dac_fmt; 65 struct pcm3168a_io_params io_params[2];
56 int tdm_slots;
57 u32 tdm_mask[2];
58 int slot_width;
59}; 66};
60 67
61static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; 68static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
@@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
308 return 0; 315 return 0;
309} 316}
310 317
311static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, 318static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
312 unsigned int format, bool dac)
313{ 319{
314 struct snd_soc_component *component = dai->component; 320 struct snd_soc_component *component = dai->component;
315 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 321 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
@@ -356,43 +362,31 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
356 return -EINVAL; 362 return -EINVAL;
357 } 363 }
358 364
359 if (dac) { 365 if (dai->id == PCM3168A_DAI_DAC) {
360 reg = PCM3168A_DAC_PWR_MST_FMT; 366 reg = PCM3168A_DAC_PWR_MST_FMT;
361 mask = PCM3168A_DAC_FMT_MASK; 367 mask = PCM3168A_DAC_FMT_MASK;
362 shift = PCM3168A_DAC_FMT_SHIFT; 368 shift = PCM3168A_DAC_FMT_SHIFT;
363 pcm3168a->dac_master_mode = master_mode;
364 pcm3168a->dac_fmt = fmt;
365 } else { 369 } else {
366 reg = PCM3168A_ADC_MST_FMT; 370 reg = PCM3168A_ADC_MST_FMT;
367 mask = PCM3168A_ADC_FMTAD_MASK; 371 mask = PCM3168A_ADC_FMTAD_MASK;
368 shift = PCM3168A_ADC_FMTAD_SHIFT; 372 shift = PCM3168A_ADC_FMTAD_SHIFT;
369 pcm3168a->adc_master_mode = master_mode;
370 pcm3168a->adc_fmt = fmt;
371 } 373 }
372 374
375 pcm3168a->io_params[dai->id].master_mode = master_mode;
376 pcm3168a->io_params[dai->id].fmt = fmt;
377
373 regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); 378 regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
374 379
375 return 0; 380 return 0;
376} 381}
377 382
378static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
379 unsigned int format)
380{
381 return pcm3168a_set_dai_fmt(dai, format, true);
382}
383
384static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
385 unsigned int format)
386{
387 return pcm3168a_set_dai_fmt(dai, format, false);
388}
389
390static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 383static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
391 unsigned int rx_mask, int slots, 384 unsigned int rx_mask, int slots,
392 int slot_width) 385 int slot_width)
393{ 386{
394 struct snd_soc_component *component = dai->component; 387 struct snd_soc_component *component = dai->component;
395 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 388 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
389 struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
396 390
397 if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { 391 if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
398 dev_err(component->dev, 392 dev_err(component->dev,
@@ -408,22 +402,25 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
408 return -EINVAL; 402 return -EINVAL;
409 } 403 }
410 404
411 if (pcm3168a->tdm_slots && pcm3168a->tdm_slots != slots) { 405 if (io_params->tdm_slots && io_params->tdm_slots != slots) {
412 dev_err(component->dev, "Not matching slots %d vs %d\n", 406 dev_err(component->dev, "Not matching slots %d vs %d\n",
413 pcm3168a->tdm_slots, slots); 407 io_params->tdm_slots, slots);
414 return -EINVAL; 408 return -EINVAL;
415 } 409 }
416 410
417 if (pcm3168a->slot_width && pcm3168a->slot_width != slot_width) { 411 if (io_params->slot_width && io_params->slot_width != slot_width) {
418 dev_err(component->dev, "Not matching slot_width %d vs %d\n", 412 dev_err(component->dev, "Not matching slot_width %d vs %d\n",
419 pcm3168a->slot_width, slot_width); 413 io_params->slot_width, slot_width);
420 return -EINVAL; 414 return -EINVAL;
421 } 415 }
422 416
423 pcm3168a->tdm_slots = slots; 417 io_params->tdm_slots = slots;
424 pcm3168a->slot_width = slot_width; 418 io_params->slot_width = slot_width;
425 pcm3168a->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; 419 /* Ignore the not relevant mask for the DAI/direction */
426 pcm3168a->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; 420 if (dai->id == PCM3168A_DAI_DAC)
421 io_params->tdm_mask = tx_mask;
422 else
423 io_params->tdm_mask = rx_mask;
427 424
428 return 0; 425 return 0;
429} 426}
@@ -434,7 +431,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
434{ 431{
435 struct snd_soc_component *component = dai->component; 432 struct snd_soc_component *component = dai->component;
436 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 433 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
437 bool tx, master_mode; 434 struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
435 bool master_mode;
438 u32 val, mask, shift, reg; 436 u32 val, mask, shift, reg;
439 unsigned int rate, fmt, ratio, max_ratio; 437 unsigned int rate, fmt, ratio, max_ratio;
440 unsigned int tdm_slots; 438 unsigned int tdm_slots;
@@ -444,23 +442,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
444 442
445 ratio = pcm3168a->sysclk / rate; 443 ratio = pcm3168a->sysclk / rate;
446 444
447 tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 445 if (dai->id == PCM3168A_DAI_DAC) {
448 if (tx) {
449 max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; 446 max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
450 reg = PCM3168A_DAC_PWR_MST_FMT; 447 reg = PCM3168A_DAC_PWR_MST_FMT;
451 mask = PCM3168A_DAC_MSDA_MASK; 448 mask = PCM3168A_DAC_MSDA_MASK;
452 shift = PCM3168A_DAC_MSDA_SHIFT; 449 shift = PCM3168A_DAC_MSDA_SHIFT;
453 master_mode = pcm3168a->dac_master_mode;
454 fmt = pcm3168a->dac_fmt;
455 } else { 450 } else {
456 max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; 451 max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
457 reg = PCM3168A_ADC_MST_FMT; 452 reg = PCM3168A_ADC_MST_FMT;
458 mask = PCM3168A_ADC_MSAD_MASK; 453 mask = PCM3168A_ADC_MSAD_MASK;
459 shift = PCM3168A_ADC_MSAD_SHIFT; 454 shift = PCM3168A_ADC_MSAD_SHIFT;
460 master_mode = pcm3168a->adc_master_mode;
461 fmt = pcm3168a->adc_fmt;
462 } 455 }
463 456
457 master_mode = io_params->master_mode;
458 fmt = io_params->fmt;
459
464 for (i = 0; i < max_ratio; i++) { 460 for (i = 0; i < max_ratio; i++) {
465 if (pcm3168a_scki_ratios[i] == ratio) 461 if (pcm3168a_scki_ratios[i] == ratio)
466 break; 462 break;
@@ -471,8 +467,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
471 return -EINVAL; 467 return -EINVAL;
472 } 468 }
473 469
474 if (pcm3168a->slot_width) 470 if (io_params->slot_width)
475 slot_width = pcm3168a->slot_width; 471 slot_width = io_params->slot_width;
476 else 472 else
477 slot_width = params_width(params); 473 slot_width = params_width(params);
478 474
@@ -497,8 +493,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
497 return -EINVAL; 493 return -EINVAL;
498 } 494 }
499 495
500 if (pcm3168a->tdm_slots) 496 if (io_params->tdm_slots)
501 tdm_slots = pcm3168a->tdm_slots; 497 tdm_slots = io_params->tdm_slots;
502 else 498 else
503 tdm_slots = params_channels(params); 499 tdm_slots = params_channels(params);
504 500
@@ -534,7 +530,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
534 530
535 regmap_update_bits(pcm3168a->regmap, reg, mask, val); 531 regmap_update_bits(pcm3168a->regmap, reg, mask, val);
536 532
537 if (tx) { 533 if (dai->id == PCM3168A_DAI_DAC) {
538 mask = PCM3168A_DAC_FMT_MASK; 534 mask = PCM3168A_DAC_FMT_MASK;
539 shift = PCM3168A_DAC_FMT_SHIFT; 535 shift = PCM3168A_DAC_FMT_SHIFT;
540 } else { 536 } else {
@@ -552,20 +548,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
552{ 548{
553 struct snd_soc_component *component = dai->component; 549 struct snd_soc_component *component = dai->component;
554 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 550 struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
555 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
556 unsigned int fmt;
557 unsigned int sample_min; 551 unsigned int sample_min;
558 unsigned int channel_max; 552 unsigned int channel_max;
559 unsigned int channel_maxs[] = { 553 unsigned int channel_maxs[] = {
560 6, /* rx */ 554 8, /* DAC */
561 8 /* tx */ 555 6 /* ADC */
562 }; 556 };
563 557
564 if (tx)
565 fmt = pcm3168a->dac_fmt;
566 else
567 fmt = pcm3168a->adc_fmt;
568
569 /* 558 /*
570 * Available Data Bits 559 * Available Data Bits
571 * 560 *
@@ -578,7 +567,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
578 * I2S 567 * I2S
579 * LEFT_J 568 * LEFT_J
580 */ 569 */
581 switch (fmt) { 570 switch (pcm3168a->io_params[dai->id].fmt) {
582 case PCM3168A_FMT_RIGHT_J: 571 case PCM3168A_FMT_RIGHT_J:
583 sample_min = 16; 572 sample_min = 16;
584 channel_max = 2; 573 channel_max = 2;
@@ -588,7 +577,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
588 case PCM3168A_FMT_DSP_A: 577 case PCM3168A_FMT_DSP_A:
589 case PCM3168A_FMT_DSP_B: 578 case PCM3168A_FMT_DSP_B:
590 sample_min = 24; 579 sample_min = 24;
591 channel_max = channel_maxs[tx]; 580 channel_max = channel_maxs[dai->id];
592 break; 581 break;
593 default: 582 default:
594 sample_min = 24; 583 sample_min = 24;
@@ -600,8 +589,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
600 sample_min, 32); 589 sample_min, 32);
601 590
602 /* Allow all channels in multi DIN/DOUT mode */ 591 /* Allow all channels in multi DIN/DOUT mode */
603 if (pcm3168a->tdm_slots == 2) 592 if (pcm3168a->io_params[dai->id].tdm_slots == 2)
604 channel_max = channel_maxs[tx]; 593 channel_max = channel_maxs[dai->id];
605 594
606 snd_pcm_hw_constraint_minmax(substream->runtime, 595 snd_pcm_hw_constraint_minmax(substream->runtime,
607 SNDRV_PCM_HW_PARAM_CHANNELS, 596 SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -609,26 +598,19 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
609 598
610 return 0; 599 return 0;
611} 600}
612static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { 601static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
613 .startup = pcm3168a_startup, 602 .startup = pcm3168a_startup,
614 .set_fmt = pcm3168a_set_dai_fmt_dac, 603 .set_fmt = pcm3168a_set_dai_fmt,
615 .set_sysclk = pcm3168a_set_dai_sysclk, 604 .set_sysclk = pcm3168a_set_dai_sysclk,
616 .hw_params = pcm3168a_hw_params, 605 .hw_params = pcm3168a_hw_params,
617 .digital_mute = pcm3168a_digital_mute, 606 .digital_mute = pcm3168a_digital_mute,
618 .set_tdm_slot = pcm3168a_set_tdm_slot, 607 .set_tdm_slot = pcm3168a_set_tdm_slot,
619}; 608};
620 609
621static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
622 .startup = pcm3168a_startup,
623 .set_fmt = pcm3168a_set_dai_fmt_adc,
624 .set_sysclk = pcm3168a_set_dai_sysclk,
625 .hw_params = pcm3168a_hw_params,
626 .set_tdm_slot = pcm3168a_set_tdm_slot,
627};
628
629static struct snd_soc_dai_driver pcm3168a_dais[] = { 610static struct snd_soc_dai_driver pcm3168a_dais[] = {
630 { 611 {
631 .name = "pcm3168a-dac", 612 .name = "pcm3168a-dac",
613 .id = PCM3168A_DAI_DAC,
632 .playback = { 614 .playback = {
633 .stream_name = "Playback", 615 .stream_name = "Playback",
634 .channels_min = 1, 616 .channels_min = 1,
@@ -636,10 +618,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
636 .rates = SNDRV_PCM_RATE_8000_192000, 618 .rates = SNDRV_PCM_RATE_8000_192000,
637 .formats = PCM3168A_FORMATS 619 .formats = PCM3168A_FORMATS
638 }, 620 },
639 .ops = &pcm3168a_dac_dai_ops 621 .ops = &pcm3168a_dai_ops
640 }, 622 },
641 { 623 {
642 .name = "pcm3168a-adc", 624 .name = "pcm3168a-adc",
625 .id = PCM3168A_DAI_ADC,
643 .capture = { 626 .capture = {
644 .stream_name = "Capture", 627 .stream_name = "Capture",
645 .channels_min = 1, 628 .channels_min = 1,
@@ -647,7 +630,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
647 .rates = SNDRV_PCM_RATE_8000_96000, 630 .rates = SNDRV_PCM_RATE_8000_96000,
648 .formats = PCM3168A_FORMATS 631 .formats = PCM3168A_FORMATS
649 }, 632 },
650 .ops = &pcm3168a_adc_dai_ops 633 .ops = &pcm3168a_dai_ops
651 }, 634 },
652}; 635};
653 636