diff options
author | Peter Rosin <peda@axentia.se> | 2016-11-15 13:38:13 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-11-16 06:02:31 -0500 |
commit | a85787edaaf7bc77ed011c89e23d52b3ff352c51 (patch) | |
tree | d705da6cfaf803fb1988a1f6778c41b35bc031f9 | |
parent | 28549313da65cc8711401ee5466c526bd67de5f1 (diff) |
ASoC: atmel_ssc_dai: if not provided, default to sensible dividers
When this driver masters BCLK and/or LRCLK, and noone has stated
differently, assume that all the bits of a frame are used.
This relieves the cpu dai users from the duty to fill in the dividers for
the common case.
Signed-off-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/atmel/atmel_ssc_dai.c | 83 | ||||
-rw-r--r-- | sound/soc/atmel/atmel_ssc_dai.h | 1 |
2 files changed, 77 insertions, 7 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 16e459aedffe..a1e2c5682dcd 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, | |||
380 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); | 380 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); |
381 | /* Clear the SSC dividers */ | 381 | /* Clear the SSC dividers */ |
382 | ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; | 382 | ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; |
383 | ssc_p->forced_divider = 0; | ||
383 | } | 384 | } |
384 | spin_unlock_irq(&ssc_p->lock); | 385 | spin_unlock_irq(&ssc_p->lock); |
385 | 386 | ||
@@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | |||
426 | else | 427 | else |
427 | if (div != ssc_p->cmr_div) | 428 | if (div != ssc_p->cmr_div) |
428 | return -EBUSY; | 429 | return -EBUSY; |
430 | ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV); | ||
429 | break; | 431 | break; |
430 | 432 | ||
431 | case ATMEL_SSC_TCMR_PERIOD: | 433 | case ATMEL_SSC_TCMR_PERIOD: |
432 | ssc_p->tcmr_period = div; | 434 | ssc_p->tcmr_period = div; |
435 | ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD); | ||
433 | break; | 436 | break; |
434 | 437 | ||
435 | case ATMEL_SSC_RCMR_PERIOD: | 438 | case ATMEL_SSC_RCMR_PERIOD: |
436 | ssc_p->rcmr_period = div; | 439 | ssc_p->rcmr_period = div; |
440 | ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD); | ||
437 | break; | 441 | break; |
438 | 442 | ||
439 | default: | 443 | default: |
@@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | |||
443 | return 0; | 447 | return 0; |
444 | } | 448 | } |
445 | 449 | ||
450 | /* Is the cpu-dai master of the frame clock? */ | ||
451 | static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) | ||
452 | { | ||
453 | switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
454 | case SND_SOC_DAIFMT_CBM_CFS: | ||
455 | case SND_SOC_DAIFMT_CBS_CFS: | ||
456 | return 1; | ||
457 | } | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /* Is the cpu-dai master of the bit clock? */ | ||
462 | static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) | ||
463 | { | ||
464 | switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
465 | case SND_SOC_DAIFMT_CBS_CFM: | ||
466 | case SND_SOC_DAIFMT_CBS_CFS: | ||
467 | return 1; | ||
468 | } | ||
469 | return 0; | ||
470 | } | ||
471 | |||
446 | /* | 472 | /* |
447 | * Configure the SSC. | 473 | * Configure the SSC. |
448 | */ | 474 | */ |
@@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
459 | u32 tfmr, rfmr, tcmr, rcmr; | 485 | u32 tfmr, rfmr, tcmr, rcmr; |
460 | int ret; | 486 | int ret; |
461 | int fslen, fslen_ext; | 487 | int fslen, fslen_ext; |
488 | u32 cmr_div; | ||
489 | u32 tcmr_period; | ||
490 | u32 rcmr_period; | ||
462 | 491 | ||
463 | /* | 492 | /* |
464 | * Currently, there is only one set of dma params for | 493 | * Currently, there is only one set of dma params for |
@@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
470 | else | 499 | else |
471 | dir = 1; | 500 | dir = 1; |
472 | 501 | ||
502 | /* | ||
503 | * If the cpu dai should provide BCLK, but noone has provided the | ||
504 | * divider needed for that to work, fall back to something sensible. | ||
505 | */ | ||
506 | cmr_div = ssc_p->cmr_div; | ||
507 | if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) && | ||
508 | atmel_ssc_cbs(ssc_p)) { | ||
509 | int bclk_rate = snd_soc_params_to_bclk(params); | ||
510 | |||
511 | if (bclk_rate < 0) { | ||
512 | dev_err(dai->dev, "unable to calculate cmr_div: %d\n", | ||
513 | bclk_rate); | ||
514 | return bclk_rate; | ||
515 | } | ||
516 | |||
517 | cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate); | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * If the cpu dai should provide LRCLK, but noone has provided the | ||
522 | * dividers needed for that to work, fall back to something sensible. | ||
523 | */ | ||
524 | tcmr_period = ssc_p->tcmr_period; | ||
525 | rcmr_period = ssc_p->rcmr_period; | ||
526 | if (atmel_ssc_cfs(ssc_p)) { | ||
527 | int frame_size = snd_soc_params_to_frame_size(params); | ||
528 | |||
529 | if (frame_size < 0) { | ||
530 | dev_err(dai->dev, | ||
531 | "unable to calculate tx/rx cmr_period: %d\n", | ||
532 | frame_size); | ||
533 | return frame_size; | ||
534 | } | ||
535 | |||
536 | if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD))) | ||
537 | tcmr_period = frame_size / 2 - 1; | ||
538 | if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD))) | ||
539 | rcmr_period = frame_size / 2 - 1; | ||
540 | } | ||
541 | |||
473 | dma_params = ssc_p->dma_params[dir]; | 542 | dma_params = ssc_p->dma_params[dir]; |
474 | 543 | ||
475 | channels = params_channels(params); | 544 | channels = params_channels(params); |
@@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
524 | fslen_ext = (bits - 1) / 16; | 593 | fslen_ext = (bits - 1) / 16; |
525 | fslen = (bits - 1) % 16; | 594 | fslen = (bits - 1) % 16; |
526 | 595 | ||
527 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | 596 | rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) |
528 | | SSC_BF(RCMR_STTDLY, START_DELAY) | 597 | | SSC_BF(RCMR_STTDLY, START_DELAY) |
529 | | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | 598 | | SSC_BF(RCMR_START, SSC_START_FALLING_RF) |
530 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 599 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
@@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
540 | | SSC_BF(RFMR_LOOP, 0) | 609 | | SSC_BF(RFMR_LOOP, 0) |
541 | | SSC_BF(RFMR_DATLEN, (bits - 1)); | 610 | | SSC_BF(RFMR_DATLEN, (bits - 1)); |
542 | 611 | ||
543 | tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | 612 | tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) |
544 | | SSC_BF(TCMR_STTDLY, START_DELAY) | 613 | | SSC_BF(TCMR_STTDLY, START_DELAY) |
545 | | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | 614 | | SSC_BF(TCMR_START, SSC_START_FALLING_RF) |
546 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 615 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
@@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
606 | fslen_ext = (bits - 1) / 16; | 675 | fslen_ext = (bits - 1) / 16; |
607 | fslen = (bits - 1) % 16; | 676 | fslen = (bits - 1) % 16; |
608 | 677 | ||
609 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | 678 | rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) |
610 | | SSC_BF(RCMR_STTDLY, START_DELAY) | 679 | | SSC_BF(RCMR_STTDLY, START_DELAY) |
611 | | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | 680 | | SSC_BF(RCMR_START, SSC_START_FALLING_RF) |
612 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 681 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
@@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
623 | | SSC_BF(RFMR_LOOP, 0) | 692 | | SSC_BF(RFMR_LOOP, 0) |
624 | | SSC_BF(RFMR_DATLEN, (bits - 1)); | 693 | | SSC_BF(RFMR_DATLEN, (bits - 1)); |
625 | 694 | ||
626 | tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | 695 | tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) |
627 | | SSC_BF(TCMR_STTDLY, START_DELAY) | 696 | | SSC_BF(TCMR_STTDLY, START_DELAY) |
628 | | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | 697 | | SSC_BF(TCMR_START, SSC_START_FALLING_RF) |
629 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 698 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
@@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
650 | * MCK divider, and the BCLK signal is output | 719 | * MCK divider, and the BCLK signal is output |
651 | * on the SSC TK line. | 720 | * on the SSC TK line. |
652 | */ | 721 | */ |
653 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | 722 | rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) |
654 | | SSC_BF(RCMR_STTDLY, 1) | 723 | | SSC_BF(RCMR_STTDLY, 1) |
655 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 724 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
656 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 725 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
@@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
665 | | SSC_BF(RFMR_LOOP, 0) | 734 | | SSC_BF(RFMR_LOOP, 0) |
666 | | SSC_BF(RFMR_DATLEN, (bits - 1)); | 735 | | SSC_BF(RFMR_DATLEN, (bits - 1)); |
667 | 736 | ||
668 | tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | 737 | tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) |
669 | | SSC_BF(TCMR_STTDLY, 1) | 738 | | SSC_BF(TCMR_STTDLY, 1) |
670 | | SSC_BF(TCMR_START, SSC_START_RISING_RF) | 739 | | SSC_BF(TCMR_START, SSC_START_RISING_RF) |
671 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 740 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
@@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
760 | } | 829 | } |
761 | 830 | ||
762 | /* set SSC clock mode register */ | 831 | /* set SSC clock mode register */ |
763 | ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); | 832 | ssc_writel(ssc_p->ssc->regs, CMR, cmr_div); |
764 | 833 | ||
765 | /* set receive clock mode and format */ | 834 | /* set receive clock mode and format */ |
766 | ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); | 835 | ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); |
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index 80b153857a88..75194f582131 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h | |||
@@ -113,6 +113,7 @@ struct atmel_ssc_info { | |||
113 | unsigned short cmr_div; | 113 | unsigned short cmr_div; |
114 | unsigned short tcmr_period; | 114 | unsigned short tcmr_period; |
115 | unsigned short rcmr_period; | 115 | unsigned short rcmr_period; |
116 | unsigned int forced_divider; | ||
116 | struct atmel_pcm_dma_params *dma_params[2]; | 117 | struct atmel_pcm_dma_params *dma_params[2]; |
117 | struct atmel_ssc_state ssc_state; | 118 | struct atmel_ssc_state ssc_state; |
118 | unsigned long mck_rate; | 119 | unsigned long mck_rate; |