forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/sound/soc/fsl/fsl_esai.c
....@@ -9,6 +9,7 @@
99 #include <linux/module.h>
1010 #include <linux/of_irq.h>
1111 #include <linux/of_platform.h>
12
+#include <linux/pm_runtime.h>
1213 #include <sound/dmaengine_pcm.h>
1314 #include <sound/pcm_params.h>
1415
....@@ -21,8 +22,17 @@
2122 SNDRV_PCM_FMTBIT_S24_LE)
2223
2324 /**
24
- * fsl_esai: ESAI private data
25
- *
25
+ * struct fsl_esai_soc_data - soc specific data
26
+ * @imx: for imx platform
27
+ * @reset_at_xrun: flags for enable reset operaton
28
+ */
29
+struct fsl_esai_soc_data {
30
+ bool imx;
31
+ bool reset_at_xrun;
32
+};
33
+
34
+/**
35
+ * struct fsl_esai - ESAI private data
2636 * @dma_params_rx: DMA parameters for receive channel
2737 * @dma_params_tx: DMA parameters for transmit channel
2838 * @pdev: platform device pointer
....@@ -31,9 +41,15 @@
3141 * @extalclk: esai clock source to derive HCK, SCK and FS
3242 * @fsysclk: system clock source to derive HCK, SCK and FS
3343 * @spbaclk: SPBA clock (optional, depending on SoC design)
44
+ * @work: work to handle the reset operation
45
+ * @soc: soc specific data
46
+ * @lock: spin lock between hw_reset() and trigger()
3447 * @fifo_depth: depth of tx/rx FIFO
3548 * @slot_width: width of each DAI slot
3649 * @slots: number of slots
50
+ * @tx_mask: slot mask for TX
51
+ * @rx_mask: slot mask for RX
52
+ * @channels: channel num for tx or rx
3753 * @hck_rate: clock rate of desired HCKx clock
3854 * @sck_rate: clock rate of desired SCKx clock
3955 * @hck_dir: the direction of HCKx pads
....@@ -51,11 +67,15 @@
5167 struct clk *extalclk;
5268 struct clk *fsysclk;
5369 struct clk *spbaclk;
70
+ struct work_struct work;
71
+ const struct fsl_esai_soc_data *soc;
72
+ spinlock_t lock; /* Protect hw_reset and trigger */
5473 u32 fifo_depth;
5574 u32 slot_width;
5675 u32 slots;
5776 u32 tx_mask;
5877 u32 rx_mask;
78
+ u32 channels[2];
5979 u32 hck_rate[2];
6080 u32 sck_rate[2];
6181 bool hck_dir[2];
....@@ -65,13 +85,40 @@
6585 char name[32];
6686 };
6787
88
+static struct fsl_esai_soc_data fsl_esai_vf610 = {
89
+ .imx = false,
90
+ .reset_at_xrun = true,
91
+};
92
+
93
+static struct fsl_esai_soc_data fsl_esai_imx35 = {
94
+ .imx = true,
95
+ .reset_at_xrun = true,
96
+};
97
+
98
+static struct fsl_esai_soc_data fsl_esai_imx6ull = {
99
+ .imx = true,
100
+ .reset_at_xrun = false,
101
+};
102
+
68103 static irqreturn_t esai_isr(int irq, void *devid)
69104 {
70105 struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
71106 struct platform_device *pdev = esai_priv->pdev;
72107 u32 esr;
108
+ u32 saisr;
73109
74110 regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
111
+ regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr);
112
+
113
+ if ((saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE)) &&
114
+ esai_priv->soc->reset_at_xrun) {
115
+ dev_dbg(&pdev->dev, "reset module for xrun\n");
116
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
117
+ ESAI_xCR_xEIE_MASK, 0);
118
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,
119
+ ESAI_xCR_xEIE_MASK, 0);
120
+ schedule_work(&esai_priv->work);
121
+ }
75122
76123 if (esr & ESAI_ESR_TINIT_MASK)
77124 dev_dbg(&pdev->dev, "isr: Transmission Initialized\n");
....@@ -110,13 +157,15 @@
110157 }
111158
112159 /**
113
- * This function is used to calculate the divisors of psr, pm, fp and it is
114
- * supposed to be called in set_dai_sysclk() and set_bclk().
160
+ * fsl_esai_divisor_cal - This function is used to calculate the
161
+ * divisors of psr, pm, fp and it is supposed to be called in
162
+ * set_dai_sysclk() and set_bclk().
115163 *
164
+ * @dai: pointer to DAI
165
+ * @tx: current setting is for playback or capture
116166 * @ratio: desired overall ratio for the paticipating dividers
117167 * @usefp: for HCK setting, there is no need to set fp divider
118168 * @fp: bypass other dividers by setting fp directly if fp != 0
119
- * @tx: current setting is for playback or capture
120169 */
121170 static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,
122171 bool usefp, u32 fp)
....@@ -203,13 +252,12 @@
203252 }
204253
205254 /**
206
- * This function mainly configures the clock frequency of MCLK (HCKT/HCKR)
207
- *
208
- * @Parameters:
209
- * clk_id: The clock source of HCKT/HCKR
255
+ * fsl_esai_set_dai_sysclk - configure the clock frequency of MCLK (HCKT/HCKR)
256
+ * @dai: pointer to DAI
257
+ * @clk_id: The clock source of HCKT/HCKR
210258 * (Input from outside; output from inside, FSYS or EXTAL)
211
- * freq: The required clock rate of HCKT/HCKR
212
- * dir: The clock direction of HCKT/HCKR
259
+ * @freq: The required clock rate of HCKT/HCKR
260
+ * @dir: The clock direction of HCKT/HCKR
213261 *
214262 * Note: If the direction is input, we do not care about clk_id.
215263 */
....@@ -218,7 +266,7 @@
218266 {
219267 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
220268 struct clk *clksrc = esai_priv->extalclk;
221
- bool tx = clk_id <= ESAI_HCKT_EXTAL;
269
+ bool tx = (clk_id <= ESAI_HCKT_EXTAL || esai_priv->synchronous);
222270 bool in = dir == SND_SOC_CLOCK_IN;
223271 u32 ratio, ecr = 0;
224272 unsigned long clk_rate;
....@@ -253,7 +301,7 @@
253301 ecr |= ESAI_ECR_ETI;
254302 break;
255303 case ESAI_HCKR_EXTAL:
256
- ecr |= ESAI_ECR_ERI;
304
+ ecr |= esai_priv->synchronous ? ESAI_ECR_ETI : ESAI_ECR_ERI;
257305 break;
258306 default:
259307 return -EINVAL;
....@@ -311,7 +359,10 @@
311359 }
312360
313361 /**
314
- * This function configures the related dividers according to the bclk rate
362
+ * fsl_esai_set_bclk - configure the related dividers according to the bclk rate
363
+ * @dai: pointer to DAI
364
+ * @tx: direction boolean
365
+ * @freq: bclk freq
315366 */
316367 static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
317368 {
....@@ -466,32 +517,8 @@
466517 struct snd_soc_dai *dai)
467518 {
468519 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
469
- int ret;
470520
471
- /*
472
- * Some platforms might use the same bit to gate all three or two of
473
- * clocks, so keep all clocks open/close at the same time for safety
474
- */
475
- ret = clk_prepare_enable(esai_priv->coreclk);
476
- if (ret)
477
- return ret;
478
- if (!IS_ERR(esai_priv->spbaclk)) {
479
- ret = clk_prepare_enable(esai_priv->spbaclk);
480
- if (ret)
481
- goto err_spbaclk;
482
- }
483
- if (!IS_ERR(esai_priv->extalclk)) {
484
- ret = clk_prepare_enable(esai_priv->extalclk);
485
- if (ret)
486
- goto err_extalck;
487
- }
488
- if (!IS_ERR(esai_priv->fsysclk)) {
489
- ret = clk_prepare_enable(esai_priv->fsysclk);
490
- if (ret)
491
- goto err_fsysclk;
492
- }
493
-
494
- if (!dai->active) {
521
+ if (!snd_soc_dai_active(dai)) {
495522 /* Set synchronous mode */
496523 regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
497524 ESAI_SAICR_SYNC, esai_priv->synchronous ?
....@@ -508,16 +535,6 @@
508535
509536 return 0;
510537
511
-err_fsysclk:
512
- if (!IS_ERR(esai_priv->extalclk))
513
- clk_disable_unprepare(esai_priv->extalclk);
514
-err_extalck:
515
- if (!IS_ERR(esai_priv->spbaclk))
516
- clk_disable_unprepare(esai_priv->spbaclk);
517
-err_spbaclk:
518
- clk_disable_unprepare(esai_priv->coreclk);
519
-
520
- return ret;
521538 }
522539
523540 static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
....@@ -539,9 +556,17 @@
539556
540557 bclk = params_rate(params) * slot_width * esai_priv->slots;
541558
542
- ret = fsl_esai_set_bclk(dai, tx, bclk);
559
+ ret = fsl_esai_set_bclk(dai, esai_priv->synchronous || tx, bclk);
543560 if (ret)
544561 return ret;
562
+
563
+ mask = ESAI_xCR_xSWS_MASK;
564
+ val = ESAI_xCR_xSWS(slot_width, width);
565
+
566
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
567
+ /* Recording in synchronous mode needs to set TCR also */
568
+ if (!tx && esai_priv->synchronous)
569
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, val);
545570
546571 /* Use Normal mode to support monaural audio */
547572 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
....@@ -558,10 +583,9 @@
558583
559584 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
560585
561
- mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
562
- val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
563
-
564
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
586
+ if (tx)
587
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
588
+ ESAI_xCR_PADC, ESAI_xCR_PADC);
565589
566590 /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */
567591 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
....@@ -571,18 +595,168 @@
571595 return 0;
572596 }
573597
574
-static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
575
- struct snd_soc_dai *dai)
598
+static int fsl_esai_hw_init(struct fsl_esai *esai_priv)
576599 {
577
- struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
600
+ struct platform_device *pdev = esai_priv->pdev;
601
+ int ret;
578602
579
- if (!IS_ERR(esai_priv->fsysclk))
580
- clk_disable_unprepare(esai_priv->fsysclk);
581
- if (!IS_ERR(esai_priv->extalclk))
582
- clk_disable_unprepare(esai_priv->extalclk);
583
- if (!IS_ERR(esai_priv->spbaclk))
584
- clk_disable_unprepare(esai_priv->spbaclk);
585
- clk_disable_unprepare(esai_priv->coreclk);
603
+ /* Reset ESAI unit */
604
+ ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
605
+ ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK,
606
+ ESAI_ECR_ESAIEN | ESAI_ECR_ERST);
607
+ if (ret) {
608
+ dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);
609
+ return ret;
610
+ }
611
+
612
+ /*
613
+ * We need to enable ESAI so as to access some of its registers.
614
+ * Otherwise, we would fail to dump regmap from user space.
615
+ */
616
+ ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
617
+ ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK,
618
+ ESAI_ECR_ESAIEN);
619
+ if (ret) {
620
+ dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);
621
+ return ret;
622
+ }
623
+
624
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
625
+ ESAI_PRRC_PDC_MASK, 0);
626
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
627
+ ESAI_PCRC_PC_MASK, 0);
628
+
629
+ return 0;
630
+}
631
+
632
+static int fsl_esai_register_restore(struct fsl_esai *esai_priv)
633
+{
634
+ int ret;
635
+
636
+ /* FIFO reset for safety */
637
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR,
638
+ ESAI_xFCR_xFR, ESAI_xFCR_xFR);
639
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR,
640
+ ESAI_xFCR_xFR, ESAI_xFCR_xFR);
641
+
642
+ regcache_mark_dirty(esai_priv->regmap);
643
+ ret = regcache_sync(esai_priv->regmap);
644
+ if (ret)
645
+ return ret;
646
+
647
+ /* FIFO reset done */
648
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);
649
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);
650
+
651
+ return 0;
652
+}
653
+
654
+static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx)
655
+{
656
+ u8 i, channels = esai_priv->channels[tx];
657
+ u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
658
+ u32 mask;
659
+
660
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
661
+ ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
662
+
663
+ /* Write initial words reqiured by ESAI as normal procedure */
664
+ for (i = 0; tx && i < channels; i++)
665
+ regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
666
+
667
+ /*
668
+ * When set the TE/RE in the end of enablement flow, there
669
+ * will be channel swap issue for multi data line case.
670
+ * In order to workaround this issue, we switch the bit
671
+ * enablement sequence to below sequence
672
+ * 1) clear the xSMB & xSMA: which is done in probe and
673
+ * stop state.
674
+ * 2) set TE/RE
675
+ * 3) set xSMB
676
+ * 4) set xSMA: xSMA is the last one in this flow, which
677
+ * will trigger esai to start.
678
+ */
679
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
680
+ tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
681
+ tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
682
+ mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask;
683
+
684
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),
685
+ ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask));
686
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),
687
+ ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask));
688
+
689
+ /* Enable Exception interrupt */
690
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
691
+ ESAI_xCR_xEIE_MASK, ESAI_xCR_xEIE);
692
+}
693
+
694
+static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx)
695
+{
696
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
697
+ ESAI_xCR_xEIE_MASK, 0);
698
+
699
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
700
+ tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
701
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),
702
+ ESAI_xSMA_xS_MASK, 0);
703
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),
704
+ ESAI_xSMB_xS_MASK, 0);
705
+
706
+ /* Disable and reset FIFO */
707
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
708
+ ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
709
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
710
+ ESAI_xFCR_xFR, 0);
711
+}
712
+
713
+static void fsl_esai_hw_reset(struct work_struct *work)
714
+{
715
+ struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work);
716
+ bool tx = true, rx = false, enabled[2];
717
+ unsigned long lock_flags;
718
+ u32 tfcr, rfcr;
719
+
720
+ spin_lock_irqsave(&esai_priv->lock, lock_flags);
721
+ /* Save the registers */
722
+ regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr);
723
+ regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr);
724
+ enabled[tx] = tfcr & ESAI_xFCR_xFEN;
725
+ enabled[rx] = rfcr & ESAI_xFCR_xFEN;
726
+
727
+ /* Stop the tx & rx */
728
+ fsl_esai_trigger_stop(esai_priv, tx);
729
+ fsl_esai_trigger_stop(esai_priv, rx);
730
+
731
+ /* Reset the esai, and ignore return value */
732
+ fsl_esai_hw_init(esai_priv);
733
+
734
+ /* Enforce ESAI personal resets for both TX and RX */
735
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
736
+ ESAI_xCR_xPR_MASK, ESAI_xCR_xPR);
737
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,
738
+ ESAI_xCR_xPR_MASK, ESAI_xCR_xPR);
739
+
740
+ /* Restore registers by regcache_sync, and ignore return value */
741
+ fsl_esai_register_restore(esai_priv);
742
+
743
+ /* Remove ESAI personal resets by configuring PCRC and PRRC also */
744
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
745
+ ESAI_xCR_xPR_MASK, 0);
746
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,
747
+ ESAI_xCR_xPR_MASK, 0);
748
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
749
+ ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
750
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
751
+ ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
752
+
753
+ /* Restart tx / rx, if they already enabled */
754
+ if (enabled[tx])
755
+ fsl_esai_trigger_start(esai_priv, tx);
756
+ if (enabled[rx])
757
+ fsl_esai_trigger_start(esai_priv, rx);
758
+
759
+ spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
586760 }
587761
588762 static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
....@@ -590,59 +764,24 @@
590764 {
591765 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
592766 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
593
- u8 i, channels = substream->runtime->channels;
594
- u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
595
- u32 mask;
767
+ unsigned long lock_flags;
768
+
769
+ esai_priv->channels[tx] = substream->runtime->channels;
596770
597771 switch (cmd) {
598772 case SNDRV_PCM_TRIGGER_START:
599773 case SNDRV_PCM_TRIGGER_RESUME:
600774 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
601
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
602
- ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
603
-
604
- /* Write initial words reqiured by ESAI as normal procedure */
605
- for (i = 0; tx && i < channels; i++)
606
- regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
607
-
608
- /*
609
- * When set the TE/RE in the end of enablement flow, there
610
- * will be channel swap issue for multi data line case.
611
- * In order to workaround this issue, we switch the bit
612
- * enablement sequence to below sequence
613
- * 1) clear the xSMB & xSMA: which is done in probe and
614
- * stop state.
615
- * 2) set TE/RE
616
- * 3) set xSMB
617
- * 4) set xSMA: xSMA is the last one in this flow, which
618
- * will trigger esai to start.
619
- */
620
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
621
- tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
622
- tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
623
- mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask;
624
-
625
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),
626
- ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask));
627
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),
628
- ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask));
629
-
775
+ spin_lock_irqsave(&esai_priv->lock, lock_flags);
776
+ fsl_esai_trigger_start(esai_priv, tx);
777
+ spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
630778 break;
631779 case SNDRV_PCM_TRIGGER_SUSPEND:
632780 case SNDRV_PCM_TRIGGER_STOP:
633781 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
634
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
635
- tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
636
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),
637
- ESAI_xSMA_xS_MASK, 0);
638
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),
639
- ESAI_xSMB_xS_MASK, 0);
640
-
641
- /* Disable and reset FIFO */
642
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
643
- ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
644
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
645
- ESAI_xFCR_xFR, 0);
782
+ spin_lock_irqsave(&esai_priv->lock, lock_flags);
783
+ fsl_esai_trigger_stop(esai_priv, tx);
784
+ spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
646785 break;
647786 default:
648787 return -EINVAL;
....@@ -653,7 +792,6 @@
653792
654793 static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
655794 .startup = fsl_esai_startup,
656
- .shutdown = fsl_esai_shutdown,
657795 .trigger = fsl_esai_trigger,
658796 .hw_params = fsl_esai_hw_params,
659797 .set_sysclk = fsl_esai_set_dai_sysclk,
....@@ -828,7 +966,13 @@
828966 return -ENOMEM;
829967
830968 esai_priv->pdev = pdev;
831
- strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1);
969
+ snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np);
970
+
971
+ esai_priv->soc = of_device_get_match_data(&pdev->dev);
972
+ if (!esai_priv->soc) {
973
+ dev_err(&pdev->dev, "failed to get soc data\n");
974
+ return -ENODEV;
975
+ }
832976
833977 /* Get the addresses and IRQ */
834978 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
....@@ -867,12 +1011,10 @@
8671011 PTR_ERR(esai_priv->spbaclk));
8681012
8691013 irq = platform_get_irq(pdev, 0);
870
- if (irq < 0) {
871
- dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
1014
+ if (irq < 0)
8721015 return irq;
873
- }
8741016
875
- ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
1017
+ ret = devm_request_irq(&pdev->dev, irq, esai_isr, IRQF_SHARED,
8761018 esai_priv->name, esai_priv);
8771019 if (ret) {
8781020 dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
....@@ -909,22 +1051,10 @@
9091051
9101052 dev_set_drvdata(&pdev->dev, esai_priv);
9111053
912
- /* Reset ESAI unit */
913
- ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
914
- if (ret) {
915
- dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);
1054
+ spin_lock_init(&esai_priv->lock);
1055
+ ret = fsl_esai_hw_init(esai_priv);
1056
+ if (ret)
9161057 return ret;
917
- }
918
-
919
- /*
920
- * We need to enable ESAI so as to access some of its registers.
921
- * Otherwise, we would fail to dump regmap from user space.
922
- */
923
- ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
924
- if (ret) {
925
- dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);
926
- return ret;
927
- }
9281058
9291059 esai_priv->tx_mask = 0xFFFFFFFF;
9301060 esai_priv->rx_mask = 0xFFFFFFFF;
....@@ -942,6 +1072,12 @@
9421072 return ret;
9431073 }
9441074
1075
+ INIT_WORK(&esai_priv->work, fsl_esai_hw_reset);
1076
+
1077
+ pm_runtime_enable(&pdev->dev);
1078
+
1079
+ regcache_cache_only(esai_priv->regmap, true);
1080
+
9451081 ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE);
9461082 if (ret)
9471083 dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
....@@ -949,55 +1085,105 @@
9491085 return ret;
9501086 }
9511087
1088
+static int fsl_esai_remove(struct platform_device *pdev)
1089
+{
1090
+ struct fsl_esai *esai_priv = platform_get_drvdata(pdev);
1091
+
1092
+ pm_runtime_disable(&pdev->dev);
1093
+ cancel_work_sync(&esai_priv->work);
1094
+
1095
+ return 0;
1096
+}
1097
+
9521098 static const struct of_device_id fsl_esai_dt_ids[] = {
953
- { .compatible = "fsl,imx35-esai", },
954
- { .compatible = "fsl,vf610-esai", },
1099
+ { .compatible = "fsl,imx35-esai", .data = &fsl_esai_imx35 },
1100
+ { .compatible = "fsl,vf610-esai", .data = &fsl_esai_vf610 },
1101
+ { .compatible = "fsl,imx6ull-esai", .data = &fsl_esai_imx6ull },
9551102 {}
9561103 };
9571104 MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
9581105
959
-#ifdef CONFIG_PM_SLEEP
960
-static int fsl_esai_suspend(struct device *dev)
961
-{
962
- struct fsl_esai *esai = dev_get_drvdata(dev);
963
-
964
- regcache_cache_only(esai->regmap, true);
965
- regcache_mark_dirty(esai->regmap);
966
-
967
- return 0;
968
-}
969
-
970
-static int fsl_esai_resume(struct device *dev)
1106
+#ifdef CONFIG_PM
1107
+static int fsl_esai_runtime_resume(struct device *dev)
9711108 {
9721109 struct fsl_esai *esai = dev_get_drvdata(dev);
9731110 int ret;
9741111
975
- regcache_cache_only(esai->regmap, false);
976
-
977
- /* FIFO reset for safety */
978
- regmap_update_bits(esai->regmap, REG_ESAI_TFCR,
979
- ESAI_xFCR_xFR, ESAI_xFCR_xFR);
980
- regmap_update_bits(esai->regmap, REG_ESAI_RFCR,
981
- ESAI_xFCR_xFR, ESAI_xFCR_xFR);
982
-
983
- ret = regcache_sync(esai->regmap);
1112
+ /*
1113
+ * Some platforms might use the same bit to gate all three or two of
1114
+ * clocks, so keep all clocks open/close at the same time for safety
1115
+ */
1116
+ ret = clk_prepare_enable(esai->coreclk);
9841117 if (ret)
9851118 return ret;
1119
+ if (!IS_ERR(esai->spbaclk)) {
1120
+ ret = clk_prepare_enable(esai->spbaclk);
1121
+ if (ret)
1122
+ goto err_spbaclk;
1123
+ }
1124
+ if (!IS_ERR(esai->extalclk)) {
1125
+ ret = clk_prepare_enable(esai->extalclk);
1126
+ if (ret)
1127
+ goto err_extalclk;
1128
+ }
1129
+ if (!IS_ERR(esai->fsysclk)) {
1130
+ ret = clk_prepare_enable(esai->fsysclk);
1131
+ if (ret)
1132
+ goto err_fsysclk;
1133
+ }
9861134
987
- /* FIFO reset done */
988
- regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);
989
- regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);
1135
+ regcache_cache_only(esai->regmap, false);
1136
+
1137
+ ret = fsl_esai_register_restore(esai);
1138
+ if (ret)
1139
+ goto err_regcache_sync;
1140
+
1141
+ return 0;
1142
+
1143
+err_regcache_sync:
1144
+ if (!IS_ERR(esai->fsysclk))
1145
+ clk_disable_unprepare(esai->fsysclk);
1146
+err_fsysclk:
1147
+ if (!IS_ERR(esai->extalclk))
1148
+ clk_disable_unprepare(esai->extalclk);
1149
+err_extalclk:
1150
+ if (!IS_ERR(esai->spbaclk))
1151
+ clk_disable_unprepare(esai->spbaclk);
1152
+err_spbaclk:
1153
+ clk_disable_unprepare(esai->coreclk);
1154
+
1155
+ return ret;
1156
+}
1157
+
1158
+static int fsl_esai_runtime_suspend(struct device *dev)
1159
+{
1160
+ struct fsl_esai *esai = dev_get_drvdata(dev);
1161
+
1162
+ regcache_cache_only(esai->regmap, true);
1163
+
1164
+ if (!IS_ERR(esai->fsysclk))
1165
+ clk_disable_unprepare(esai->fsysclk);
1166
+ if (!IS_ERR(esai->extalclk))
1167
+ clk_disable_unprepare(esai->extalclk);
1168
+ if (!IS_ERR(esai->spbaclk))
1169
+ clk_disable_unprepare(esai->spbaclk);
1170
+ clk_disable_unprepare(esai->coreclk);
9901171
9911172 return 0;
9921173 }
993
-#endif /* CONFIG_PM_SLEEP */
1174
+#endif /* CONFIG_PM */
9941175
9951176 static const struct dev_pm_ops fsl_esai_pm_ops = {
996
- SET_SYSTEM_SLEEP_PM_OPS(fsl_esai_suspend, fsl_esai_resume)
1177
+ SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend,
1178
+ fsl_esai_runtime_resume,
1179
+ NULL)
1180
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1181
+ pm_runtime_force_resume)
9971182 };
9981183
9991184 static struct platform_driver fsl_esai_driver = {
10001185 .probe = fsl_esai_probe,
1186
+ .remove = fsl_esai_remove,
10011187 .driver = {
10021188 .name = "fsl-esai-dai",
10031189 .pm = &fsl_esai_pm_ops,