diff options
Diffstat (limited to 'sound/soc/fsl/fsl_sai.c')
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 55 |
1 files changed, 43 insertions, 12 deletions
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d430eece1d6b..81f89f6767a2 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -114,11 +114,8 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) if (flags & FSL_SAI_CSR_SEF) dev_dbg(dev, "isr: Tx Frame sync error detected\n"); - if (flags & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) dev_dbg(dev, "isr: Transmit underrun detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n"); @@ -148,11 +145,8 @@ irq_rx: if (flags & FSL_SAI_CSR_SEF) dev_dbg(dev, "isr: Rx Frame sync error detected\n"); - if (flags & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) dev_dbg(dev, "isr: Receive overflow detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled receive FIFO is full\n"); @@ -533,14 +527,17 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, u32 slot_width = word_width; int adir = tx ? RX : TX; u32 pins, bclk; + u32 watermark; int ret, i; - if (sai->slots) - slots = sai->slots; - if (sai->slot_width) slot_width = sai->slot_width; + if (sai->slots) + slots = sai->slots; + else if (sai->bclk_ratio) + slots = sai->bclk_ratio / slot_width; + pins = DIV_ROUND_UP(channels, slots); /* @@ -625,7 +622,15 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, FSL_SAI_CR5_FBT_MASK, val_cr5); } - if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1) + /* + * Combine mode has limation: + * - Can't used for singel dataline/FIFO case except the FIFO0 + * - Can't used for multi dataline/FIFO case except the enabled FIFOs + * are successive and start from FIFO0 + * + * So for common usage, all multi fifo case disable the combine mode. + */ + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1 || sai->is_multi_fifo_dma) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FCOMB_MASK, 0); else @@ -636,6 +641,26 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + dl_cfg[dl_cfg_idx].start_off[tx] * 0x4; + if (sai->is_multi_fifo_dma) { + sai->audio_config[tx].words_per_fifo = min(slots, channels); + if (tx) { + sai->audio_config[tx].n_fifos_dst = pins; + sai->audio_config[tx].stride_fifos_dst = dl_cfg[dl_cfg_idx].next_off[tx]; + } else { + sai->audio_config[tx].n_fifos_src = pins; + sai->audio_config[tx].stride_fifos_src = dl_cfg[dl_cfg_idx].next_off[tx]; + } + dma_params->maxburst = sai->audio_config[tx].words_per_fifo * pins; + dma_params->peripheral_config = &sai->audio_config[tx]; + dma_params->peripheral_size = sizeof(sai->audio_config[tx]); + + watermark = tx ? (sai->soc_data->fifo_depth - dma_params->maxburst) : + (dma_params->maxburst - 1); + regmap_update_bits(sai->regmap, FSL_SAI_xCR1(tx, ofs), + FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), + watermark); + } + /* Find a proper tcre setting */ for (i = 0; i < sai->soc_data->pins; i++) { trce_mask = (1 << (i + 1)) - 1; @@ -1263,6 +1288,7 @@ static int fsl_sai_probe(struct platform_device *pdev) char tmp[8]; int irq, ret, i; int index; + u32 dmas[4]; sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); if (!sai) @@ -1319,6 +1345,11 @@ static int fsl_sai_probe(struct platform_device *pdev) fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk, &sai->pll11k_clk); + /* Use Multi FIFO mode depending on the support from SDMA script */ + ret = of_property_read_u32_array(np, "dmas", dmas, 4); + if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI) + sai->is_multi_fifo_dma = true; + /* read dataline mask for rx and tx*/ ret = fsl_sai_read_dlcfg(sai); if (ret < 0) { |