aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolin Chen <b42378@freescale.com>2013-12-12 05:44:45 -0500
committerMark Brown <broonie@linaro.org>2013-12-19 10:03:52 -0500
commitaafa85e71a75fdea9076c5e0f7fe09e12568c9a4 (patch)
tree6aa529ebee0651b3e3489344484e42b6e1896bc6
parent05004cb4cd06127bb8ff70d5ab5a915103828e9d (diff)
ASoC: fsl_ssi: Add DAI master mode support for SSI on i.MX series
This patch adds three main functions for DAI master mode: set_dai_fmt(), set_dai_sysclk() and set_dai_tdm_slot(), and one essential baud clock accordingly. After appending this patch, the fsl_ssi driver on i.MX series has the ability to derive LRCLK and BCLK from baud clock source so as to support some audio Codecs which can only be used in slave mode. Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--sound/soc/fsl/fsl_ssi.c280
-rw-r--r--sound/soc/fsl/fsl_ssi.h2
2 files changed, 278 insertions, 4 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index f9f4569417ed..b2ebaf811599 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -38,6 +38,7 @@
38#include <linux/device.h> 38#include <linux/device.h>
39#include <linux/delay.h> 39#include <linux/delay.h>
40#include <linux/slab.h> 40#include <linux/slab.h>
41#include <linux/spinlock.h>
41#include <linux/of_address.h> 42#include <linux/of_address.h>
42#include <linux/of_irq.h> 43#include <linux/of_irq.h>
43#include <linux/of_platform.h> 44#include <linux/of_platform.h>
@@ -139,7 +140,10 @@ struct fsl_ssi_private {
139 bool ssi_on_imx; 140 bool ssi_on_imx;
140 bool imx_ac97; 141 bool imx_ac97;
141 bool use_dma; 142 bool use_dma;
143 bool baudclk_locked;
142 u8 i2s_mode; 144 u8 i2s_mode;
145 spinlock_t baudclk_lock;
146 struct clk *baudclk;
143 struct clk *clk; 147 struct clk *clk;
144 struct snd_dmaengine_dai_dma_data dma_params_tx; 148 struct snd_dmaengine_dai_dma_data dma_params_tx;
145 struct snd_dmaengine_dai_dma_data dma_params_rx; 149 struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -434,13 +438,18 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
434 struct snd_soc_pcm_runtime *rtd = substream->private_data; 438 struct snd_soc_pcm_runtime *rtd = substream->private_data;
435 struct fsl_ssi_private *ssi_private = 439 struct fsl_ssi_private *ssi_private =
436 snd_soc_dai_get_drvdata(rtd->cpu_dai); 440 snd_soc_dai_get_drvdata(rtd->cpu_dai);
441 unsigned long flags;
437 442
438 /* First, we only do fsl_ssi_setup() when SSI is going to be active. 443 /* First, we only do fsl_ssi_setup() when SSI is going to be active.
439 * Second, fsl_ssi_setup was already called by ac97_init earlier if 444 * Second, fsl_ssi_setup was already called by ac97_init earlier if
440 * the driver is in ac97 mode. 445 * the driver is in ac97 mode.
441 */ 446 */
442 if (!dai->active && !ssi_private->imx_ac97) 447 if (!dai->active && !ssi_private->imx_ac97) {
443 fsl_ssi_setup(ssi_private); 448 fsl_ssi_setup(ssi_private);
449 spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
450 ssi_private->baudclk_locked = false;
451 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
452 }
444 453
445 return 0; 454 return 0;
446} 455}
@@ -502,6 +511,243 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
502} 511}
503 512
504/** 513/**
514 * fsl_ssi_set_dai_fmt - configure Digital Audio Interface Format.
515 */
516static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
517{
518 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
519 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
520 u32 strcr = 0, stcr, srcr, scr, mask;
521
522 scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
523 scr |= CCSR_SSI_SCR_NET;
524
525 mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
526 CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
527 CCSR_SSI_STCR_TEFS;
528 stcr = read_ssi(&ssi->stcr) & ~mask;
529 srcr = read_ssi(&ssi->srcr) & ~mask;
530
531 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
532 case SND_SOC_DAIFMT_I2S:
533 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
534 case SND_SOC_DAIFMT_CBS_CFS:
535 ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_MASTER;
536 break;
537 case SND_SOC_DAIFMT_CBM_CFM:
538 ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
539 break;
540 default:
541 return -EINVAL;
542 }
543 scr |= ssi_private->i2s_mode;
544
545 /* Data on rising edge of bclk, frame low, 1clk before data */
546 strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
547 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
548 break;
549 case SND_SOC_DAIFMT_LEFT_J:
550 /* Data on rising edge of bclk, frame high */
551 strcr |= CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TSCKP;
552 break;
553 case SND_SOC_DAIFMT_DSP_A:
554 /* Data on rising edge of bclk, frame high, 1clk before data */
555 strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
556 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
557 break;
558 case SND_SOC_DAIFMT_DSP_B:
559 /* Data on rising edge of bclk, frame high */
560 strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
561 CCSR_SSI_STCR_TXBIT0;
562 break;
563 default:
564 return -EINVAL;
565 }
566
567 /* DAI clock inversion */
568 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
569 case SND_SOC_DAIFMT_NB_NF:
570 /* Nothing to do for both normal cases */
571 break;
572 case SND_SOC_DAIFMT_IB_NF:
573 /* Invert bit clock */
574 strcr ^= CCSR_SSI_STCR_TSCKP;
575 break;
576 case SND_SOC_DAIFMT_NB_IF:
577 /* Invert frame clock */
578 strcr ^= CCSR_SSI_STCR_TFSI;
579 break;
580 case SND_SOC_DAIFMT_IB_IF:
581 /* Invert both clocks */
582 strcr ^= CCSR_SSI_STCR_TSCKP;
583 strcr ^= CCSR_SSI_STCR_TFSI;
584 break;
585 default:
586 return -EINVAL;
587 }
588
589 /* DAI clock master masks */
590 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
591 case SND_SOC_DAIFMT_CBS_CFS:
592 strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR;
593 scr |= CCSR_SSI_SCR_SYS_CLK_EN;
594 break;
595 case SND_SOC_DAIFMT_CBM_CFM:
596 scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
597 break;
598 default:
599 return -EINVAL;
600 }
601
602 stcr |= strcr;
603 srcr |= strcr;
604
605 if (ssi_private->cpu_dai_drv.symmetric_rates) {
606 /* Need to clear RXDIR when using SYNC mode */
607 srcr &= ~CCSR_SSI_SRCR_RXDIR;
608 scr |= CCSR_SSI_SCR_SYN;
609 }
610
611 write_ssi(stcr, &ssi->stcr);
612 write_ssi(srcr, &ssi->srcr);
613 write_ssi(scr, &ssi->scr);
614
615 return 0;
616}
617
618/**
619 * fsl_ssi_set_dai_sysclk - configure Digital Audio Interface bit clock
620 *
621 * Note: This function can be only called when using SSI as DAI master
622 *
623 * Quick instruction for parameters:
624 * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
625 * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
626 */
627static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
628 int clk_id, unsigned int freq, int dir)
629{
630 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
631 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
632 int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
633 u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
634 unsigned long flags, clkrate, baudrate, tmprate;
635 u64 sub, savesub = 100000;
636
637 /* Don't apply it to any non-baudclk circumstance */
638 if (IS_ERR(ssi_private->baudclk))
639 return -EINVAL;
640
641 /* It should be already enough to divide clock by setting pm alone */
642 psr = 0;
643 div2 = 0;
644
645 factor = (div2 + 1) * (7 * psr + 1) * 2;
646
647 for (i = 0; i < 255; i++) {
648 /* The bclk rate must be smaller than 1/5 sysclk rate */
649 if (factor * (i + 1) < 5)
650 continue;
651
652 tmprate = freq * factor * (i + 2);
653 clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
654
655 do_div(clkrate, factor);
656 afreq = (u32)clkrate / (i + 1);
657
658 if (freq == afreq)
659 sub = 0;
660 else if (freq / afreq == 1)
661 sub = freq - afreq;
662 else if (afreq / freq == 1)
663 sub = afreq - freq;
664 else
665 continue;
666
667 /* Calculate the fraction */
668 sub *= 100000;
669 do_div(sub, freq);
670
671 if (sub < savesub) {
672 baudrate = tmprate;
673 savesub = sub;
674 pm = i;
675 }
676
677 /* We are lucky */
678 if (savesub == 0)
679 break;
680 }
681
682 /* No proper pm found if it is still remaining the initial value */
683 if (pm == 999) {
684 dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
685 return -EINVAL;
686 }
687
688 stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
689 (psr ? CCSR_SSI_SxCCR_PSR : 0);
690 mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 | CCSR_SSI_SxCCR_PSR;
691
692 if (dir == SND_SOC_CLOCK_OUT || synchronous)
693 write_ssi_mask(&ssi->stccr, mask, stccr);
694 else
695 write_ssi_mask(&ssi->srccr, mask, stccr);
696
697 spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
698 if (!ssi_private->baudclk_locked) {
699 ret = clk_set_rate(ssi_private->baudclk, baudrate);
700 if (ret) {
701 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
702 dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
703 return -EINVAL;
704 }
705 ssi_private->baudclk_locked = true;
706 }
707 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
708
709 return 0;
710}
711
712/**
713 * fsl_ssi_set_dai_tdm_slot - set TDM slot number
714 *
715 * Note: This function can be only called when using SSI as DAI master
716 */
717static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
718 u32 rx_mask, int slots, int slot_width)
719{
720 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
721 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
722 u32 val;
723
724 /* The slot number should be >= 2 if using Network mode or I2S mode */
725 val = read_ssi(&ssi->scr) & (CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET);
726 if (val && slots < 2) {
727 dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n");
728 return -EINVAL;
729 }
730
731 write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
732 CCSR_SSI_SxCCR_DC(slots));
733 write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
734 CCSR_SSI_SxCCR_DC(slots));
735
736 /* The register SxMSKs needs SSI to provide essential clock due to
737 * hardware design. So we here temporarily enable SSI to set them.
738 */
739 val = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
740 write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN);
741
742 write_ssi(tx_mask, &ssi->stmsk);
743 write_ssi(rx_mask, &ssi->srmsk);
744
745 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, val);
746
747 return 0;
748}
749
750/**
505 * fsl_ssi_trigger: start and stop the DMA transfer. 751 * fsl_ssi_trigger: start and stop the DMA transfer.
506 * 752 *
507 * This function is called by ALSA to start, stop, pause, and resume the DMA 753 * This function is called by ALSA to start, stop, pause, and resume the DMA
@@ -517,6 +763,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
517 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); 763 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
518 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 764 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
519 unsigned int sier_bits; 765 unsigned int sier_bits;
766 unsigned long flags;
520 767
521 /* 768 /*
522 * Enable only the interrupts and DMA requests 769 * Enable only the interrupts and DMA requests
@@ -557,8 +804,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
557 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); 804 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
558 805
559 if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) & 806 if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
560 (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) 807 (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
561 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); 808 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
809 spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
810 ssi_private->baudclk_locked = false;
811 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
812 }
562 break; 813 break;
563 814
564 default: 815 default:
@@ -585,6 +836,9 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
585static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { 836static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
586 .startup = fsl_ssi_startup, 837 .startup = fsl_ssi_startup,
587 .hw_params = fsl_ssi_hw_params, 838 .hw_params = fsl_ssi_hw_params,
839 .set_fmt = fsl_ssi_set_dai_fmt,
840 .set_sysclk = fsl_ssi_set_dai_sysclk,
841 .set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
588 .trigger = fsl_ssi_trigger, 842 .trigger = fsl_ssi_trigger,
589}; 843};
590 844
@@ -897,6 +1151,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
897 /* Older 8610 DTs didn't have the fifo-depth property */ 1151 /* Older 8610 DTs didn't have the fifo-depth property */
898 ssi_private->fifo_depth = 8; 1152 ssi_private->fifo_depth = 8;
899 1153
1154 ssi_private->baudclk_locked = false;
1155 spin_lock_init(&ssi_private->baudclk_lock);
1156
900 if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) { 1157 if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
901 u32 dma_events[2]; 1158 u32 dma_events[2];
902 ssi_private->ssi_on_imx = true; 1159 ssi_private->ssi_on_imx = true;
@@ -914,6 +1171,15 @@ static int fsl_ssi_probe(struct platform_device *pdev)
914 goto error_irqmap; 1171 goto error_irqmap;
915 } 1172 }
916 1173
1174 /* For those SLAVE implementations, we ingore non-baudclk cases
1175 * and, instead, abandon MASTER mode that needs baud clock.
1176 */
1177 ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
1178 if (IS_ERR(ssi_private->baudclk))
1179 dev_warn(&pdev->dev, "could not get baud clock: %d\n", ret);
1180 else
1181 clk_prepare_enable(ssi_private->baudclk);
1182
917 /* 1183 /*
918 * We have burstsize be "fifo_depth - 2" to match the SSI 1184 * We have burstsize be "fifo_depth - 2" to match the SSI
919 * watermark setting in fsl_ssi_startup(). 1185 * watermark setting in fsl_ssi_startup().
@@ -1059,8 +1325,11 @@ error_dev:
1059 device_remove_file(&pdev->dev, dev_attr); 1325 device_remove_file(&pdev->dev, dev_attr);
1060 1326
1061error_clk: 1327error_clk:
1062 if (ssi_private->ssi_on_imx) 1328 if (ssi_private->ssi_on_imx) {
1329 if (!IS_ERR(ssi_private->baudclk))
1330 clk_disable_unprepare(ssi_private->baudclk);
1063 clk_disable_unprepare(ssi_private->clk); 1331 clk_disable_unprepare(ssi_private->clk);
1332 }
1064 1333
1065error_irqmap: 1334error_irqmap:
1066 irq_dispose_mapping(ssi_private->irq); 1335 irq_dispose_mapping(ssi_private->irq);
@@ -1076,8 +1345,11 @@ static int fsl_ssi_remove(struct platform_device *pdev)
1076 platform_device_unregister(ssi_private->pdev); 1345 platform_device_unregister(ssi_private->pdev);
1077 snd_soc_unregister_component(&pdev->dev); 1346 snd_soc_unregister_component(&pdev->dev);
1078 device_remove_file(&pdev->dev, &ssi_private->dev_attr); 1347 device_remove_file(&pdev->dev, &ssi_private->dev_attr);
1079 if (ssi_private->ssi_on_imx) 1348 if (ssi_private->ssi_on_imx) {
1349 if (!IS_ERR(ssi_private->baudclk))
1350 clk_disable_unprepare(ssi_private->baudclk);
1080 clk_disable_unprepare(ssi_private->clk); 1351 clk_disable_unprepare(ssi_private->clk);
1352 }
1081 irq_dispose_mapping(ssi_private->irq); 1353 irq_dispose_mapping(ssi_private->irq);
1082 1354
1083 return 0; 1355 return 0;
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index e6b9a69e2a68..e6b63240a3d7 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -125,7 +125,9 @@ struct ccsr_ssi {
125#define CCSR_SSI_SRCR_REFS 0x00000001 125#define CCSR_SSI_SRCR_REFS 0x00000001
126 126
127/* STCCR and SRCCR */ 127/* STCCR and SRCCR */
128#define CCSR_SSI_SxCCR_DIV2_SHIFT 18
128#define CCSR_SSI_SxCCR_DIV2 0x00040000 129#define CCSR_SSI_SxCCR_DIV2 0x00040000
130#define CCSR_SSI_SxCCR_PSR_SHIFT 17
129#define CCSR_SSI_SxCCR_PSR 0x00020000 131#define CCSR_SSI_SxCCR_PSR 0x00020000
130#define CCSR_SSI_SxCCR_WL_SHIFT 13 132#define CCSR_SSI_SxCCR_WL_SHIFT 13
131#define CCSR_SSI_SxCCR_WL_MASK 0x0001E000 133#define CCSR_SSI_SxCCR_WL_MASK 0x0001E000