aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShengjiu Wang <b02247@freescale.com>2014-04-14 03:19:54 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:20 -0400
commit440fbeee5bba4d4356a392ff35fe262774c48ea1 (patch)
tree39bdb1ee74dffff73fc6b96ee8e91b832ce3eab0
parent405588f31e432e5c6634a0817e4d804ead87882b (diff)
ENGR00307835-3 ASoC: fsl: implement the ESAI xrun handler.
When esai xrun happened, there is possibility of channel swap. So ESAI need to be reset. Signed-off-by: Shengjiu Wang <b02247@freescale.com>
-rw-r--r--sound/soc/fsl/fsl_esai.c136
-rw-r--r--sound/soc/fsl/fsl_esai.h5
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c20
3 files changed, 160 insertions, 1 deletions
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 6f6adcec7d41..762ac316fa32 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -35,6 +35,13 @@
35#define IMX_ESAI_NET (1 << 0) 35#define IMX_ESAI_NET (1 << 0)
36#define IMX_ESAI_SYN (1 << 1) 36#define IMX_ESAI_SYN (1 << 1)
37 37
38static inline void write_esai_mask(u32 __iomem *addr, u32 clear, u32 set)
39{
40 u32 val = readl(addr);
41 val = (val & ~clear) | set;
42 writel(val, addr);
43}
44
38static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 45static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
39 int clk_id, unsigned int freq, int dir) 46 int clk_id, unsigned int freq, int dir)
40{ 47{
@@ -308,6 +315,8 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
308 clk_enable(esai->clk); 315 clk_enable(esai->clk);
309 clk_prepare_enable(esai->dmaclk); 316 clk_prepare_enable(esai->dmaclk);
310 317
318 esai->substream[substream->stream] = substream;
319
311 ESAI_DUMP(); 320 ESAI_DUMP();
312 return 0; 321 return 0;
313} 322}
@@ -463,6 +472,8 @@ static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
463 writel(0, esai->base + ESAI_PCRC); 472 writel(0, esai->base + ESAI_PCRC);
464 } 473 }
465 474
475 esai->substream[substream->stream] = NULL;
476
466 clk_disable_unprepare(esai->dmaclk); 477 clk_disable_unprepare(esai->dmaclk);
467 clk_disable(esai->clk); 478 clk_disable(esai->clk);
468} 479}
@@ -578,6 +589,126 @@ static const struct snd_soc_component_driver fsl_esai_component = {
578 .name = "fsl-esai", 589 .name = "fsl-esai",
579}; 590};
580 591
592static bool fsl_esai_check_xrun(struct snd_pcm_substream *substream)
593{
594 struct snd_soc_pcm_runtime *rtd = substream->private_data;
595 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
596 struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
597 u32 saisr = readl(esai->base + ESAI_SAISR);
598
599 return saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE) ;
600}
601
602static int store_reg(struct snd_soc_dai *cpu_dai)
603{
604 struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
605
606 esai->reg_cache[0] = readl(esai->base + ESAI_ECR);
607 esai->reg_cache[2] = readl(esai->base + ESAI_TFCR);
608 esai->reg_cache[4] = readl(esai->base + ESAI_RFCR);
609 esai->reg_cache[8] = readl(esai->base + ESAI_SAICR);
610 esai->reg_cache[9] = readl(esai->base + ESAI_TCR);
611 esai->reg_cache[10] = readl(esai->base + ESAI_TCCR);
612 esai->reg_cache[11] = readl(esai->base + ESAI_RCR);
613 esai->reg_cache[12] = readl(esai->base + ESAI_RCCR);
614 esai->reg_cache[13] = readl(esai->base + ESAI_TSMA);
615 esai->reg_cache[14] = readl(esai->base + ESAI_TSMB);
616 esai->reg_cache[15] = readl(esai->base + ESAI_RSMA);
617 esai->reg_cache[16] = readl(esai->base + ESAI_RSMB);
618 return 0;
619}
620
621static int restore_reg(struct snd_soc_dai *cpu_dai)
622{
623 struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
624
625 writel(esai->reg_cache[0], esai->base + ESAI_ECR);
626 writel(esai->reg_cache[2] & ~ESAI_TFCR_TFEN, esai->base + ESAI_TFCR);
627 writel(esai->reg_cache[4] & ~ESAI_RFCR_RFEN, esai->base + ESAI_RFCR);
628 writel(esai->reg_cache[8], esai->base + ESAI_SAICR);
629 writel(esai->reg_cache[9] & ~ESAI_TCR_TE(12), esai->base + ESAI_TCR);
630 writel(esai->reg_cache[10], esai->base + ESAI_TCCR);
631 writel(esai->reg_cache[11] & ~ESAI_RCR_RE(8), esai->base + ESAI_RCR);
632 writel(esai->reg_cache[12], esai->base + ESAI_RCCR);
633 writel(esai->reg_cache[13], esai->base + ESAI_TSMA);
634 writel(esai->reg_cache[14], esai->base + ESAI_TSMB);
635 writel(esai->reg_cache[15], esai->base + ESAI_RSMA);
636 writel(esai->reg_cache[16], esai->base + ESAI_RSMB);
637 return 0;
638}
639
640static int stop_lock_stream(struct snd_pcm_substream *substream)
641{
642 if (substream) {
643 snd_pcm_stream_lock_irq(substream);
644 if (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING)
645 substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
646 }
647 return 0;
648}
649
650static int start_unlock_stream(struct snd_pcm_substream *substream)
651{
652 if (substream) {
653 if (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING)
654 substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
655 snd_pcm_stream_unlock_irq(substream);
656 }
657 return 0;
658}
659
660/*
661 *Here is ESAI underrun reset step:
662 *1. Read "TUE" and got TUE=1
663 *2. stop DMA.
664 *3. stop ESAI TX section.
665 *4. Set the transmitter section individual reset "TPR=1"
666 *5. Reset the ESAI Transmit FIFO (set ESAI_TFCR[1]=1).
667 *6. Config the control registers ESAI_TCCR and ESAI_TCR.config the Transmit FIFO register.
668 *7. clear "TPR"
669 *8. read "TUE"
670 *9. Prefill ESAI TX FIFO.
671 *10.Start DMA.
672 *11 Enable the ESAI
673 */
674static void fsl_esai_reset(struct snd_pcm_substream *substream, bool stop)
675{
676 struct snd_soc_pcm_runtime *rtd = substream->private_data;
677 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
678 struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
679 ESAI_DUMP();
680
681 if (stop) {
682 stop_lock_stream(esai->substream[0]);
683 stop_lock_stream(esai->substream[1]);
684 }
685
686 store_reg(cpu_dai);
687
688 writel(ESAI_ECR_ESAIEN | ESAI_ECR_ERST, esai->base + ESAI_ECR);
689 writel(ESAI_ECR_ESAIEN, esai->base + ESAI_ECR);
690
691 write_esai_mask(esai->base+ESAI_TCR, 0, ESAI_TCR_TPR);
692 write_esai_mask(esai->base+ESAI_RCR, 0, ESAI_RCR_RPR);
693
694 restore_reg(cpu_dai);
695
696 write_esai_mask(esai->base+ESAI_TCR, ESAI_TCR_TPR, 0);
697 write_esai_mask(esai->base+ESAI_RCR, ESAI_RCR_RPR, 0);
698
699 writel(ESAI_GPIO_ESAI, esai->base + ESAI_PRRC);
700 writel(ESAI_GPIO_ESAI, esai->base + ESAI_PCRC);
701
702 /* read "TUE" flag.*/
703 readl(esai->base + ESAI_SAISR);
704
705 if (stop) {
706 start_unlock_stream(esai->substream[1]);
707 start_unlock_stream(esai->substream[0]);
708 }
709 ESAI_DUMP();
710}
711
581static int fsl_esai_reg_init(struct fsl_esai *esai) 712static int fsl_esai_reg_init(struct fsl_esai *esai)
582{ 713{
583 u32 xccr, slots = 2; 714 u32 xccr, slots = 2;
@@ -674,6 +805,11 @@ static int fsl_esai_probe(struct platform_device *pdev)
674 esai->dma_params_tx.filter_data = &esai->filter_data_tx; 805 esai->dma_params_tx.filter_data = &esai->filter_data_tx;
675 esai->dma_params_rx.filter_data = &esai->filter_data_rx; 806 esai->dma_params_rx.filter_data = &esai->filter_data_rx;
676 807
808 esai->dma_params_tx.check_xrun = fsl_esai_check_xrun;
809 esai->dma_params_rx.check_xrun = fsl_esai_check_xrun;
810 esai->dma_params_tx.device_reset = fsl_esai_reset;
811 esai->dma_params_rx.device_reset = fsl_esai_reset;
812
677 ret = of_property_read_u32_array(pdev->dev.of_node, 813 ret = of_property_read_u32_array(pdev->dev.of_node,
678 "fsl,esai-dma-events", dma_events, 2); 814 "fsl,esai-dma-events", dma_events, 2);
679 if (ret) { 815 if (ret) {
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
index f0b6198a69a6..daf080641277 100644
--- a/sound/soc/fsl/fsl_esai.h
+++ b/sound/soc/fsl/fsl_esai.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * imx-esai.h -- ESAI driver header file for Freescale IMX 2 * imx-esai.h -- ESAI driver header file for Freescale IMX
3 * 3 *
4 * Copyright 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved. 4 * Copyright 2008-2014 Freescale Semiconductor, Inc. All Rights Reserved.
5 */ 5 */
6 6
7/* 7/*
@@ -315,6 +315,7 @@
315#define IMX_DAI_ESAI_TX 0x04 315#define IMX_DAI_ESAI_TX 0x04
316#define IMX_DAI_ESAI_RX 0x08 316#define IMX_DAI_ESAI_RX 0x08
317#define IMX_DAI_ESAI_TXRX (IMX_DAI_ESAI_TX | IMX_DAI_ESAI_RX) 317#define IMX_DAI_ESAI_TXRX (IMX_DAI_ESAI_TX | IMX_DAI_ESAI_RX)
318#define REG_CACHE_NUM 20
318 319
319struct fsl_esai { 320struct fsl_esai {
320 struct clk *clk; 321 struct clk *clk;
@@ -328,8 +329,10 @@ struct fsl_esai {
328 struct snd_dmaengine_dai_dma_data dma_params_tx; 329 struct snd_dmaengine_dai_dma_data dma_params_tx;
329 struct imx_dma_data filter_data_tx; 330 struct imx_dma_data filter_data_tx;
330 struct imx_dma_data filter_data_rx; 331 struct imx_dma_data filter_data_rx;
332 struct snd_pcm_substream *substream[2];
331 333
332 char name[32]; 334 char name[32];
335 u32 reg_cache[REG_CACHE_NUM];
333}; 336};
334 337
335#endif 338#endif
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 33752da05482..aa74383daa82 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -94,14 +94,34 @@ static void imx_pcm_dma_set_config_from_dai_data(
94 } 94 }
95} 95}
96 96
97static void imx_pcm_dma_complete(void *arg)
98{
99 struct snd_pcm_substream *substream = arg;
100 struct snd_soc_pcm_runtime *rtd = substream->private_data;
101 struct dmaengine_pcm_runtime_data *prtd = substream->runtime->private_data;
102 struct snd_dmaengine_dai_dma_data *dma_data;
103
104 prtd->pos += snd_pcm_lib_period_bytes(substream);
105 if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
106 prtd->pos = 0;
107
108 snd_pcm_period_elapsed(substream);
109
110 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
111 if (dma_data->check_xrun && dma_data->check_xrun(substream))
112 dma_data->device_reset(substream, 1);
113}
114
97static int imx_pcm_dma_prepare_slave_config(struct snd_pcm_substream *substream, 115static int imx_pcm_dma_prepare_slave_config(struct snd_pcm_substream *substream,
98 struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config) 116 struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
99{ 117{
100 struct snd_soc_pcm_runtime *rtd = substream->private_data; 118 struct snd_soc_pcm_runtime *rtd = substream->private_data;
101 struct snd_dmaengine_dai_dma_data *dma_data; 119 struct snd_dmaengine_dai_dma_data *dma_data;
120 struct dmaengine_pcm_runtime_data *prtd = substream->runtime->private_data;
102 int ret; 121 int ret;
103 122
104 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 123 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
124 prtd->callback = imx_pcm_dma_complete;
105 125
106 ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); 126 ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
107 if (ret) 127 if (ret)