From c516c261c49d0ce9509d6b9623dec6a4e9f919c3 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 30 Mar 2020 16:21:00 +0800 Subject: [PATCH] MLK-13574-2: ASoC: fsl_sai: refine driver for ip upgrade In imx7ulp1, the sai can support two TX channel and two RX channels, So the usage need to be updated. Signed-off-by: Shengjiu Wang [rebase] Signed-off-by: Yangbo Lu --- sound/soc/fsl/fsl_sai.c | 145 ++++++++++++++++++++++++++++++++++++++++-------- sound/soc/fsl/fsl_sai.h | 37 ++++++++++-- 2 files changed, 156 insertions(+), 26 deletions(-) --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -8,16 +8,19 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #include "fsl_sai.h" #include "imx-pcm.h" @@ -25,6 +28,39 @@ #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ FSL_SAI_CSR_FEIE) +static struct fsl_sai_soc_data fsl_sai_vf610 = { + .imx = false, + /*dataline is mask, not index*/ + .dataline = 0x1, + .fifos = 1, + .fifo_depth = 32, + .flags = 0, +}; + +static struct fsl_sai_soc_data fsl_sai_imx6sx = { + .imx = true, + .dataline = 0x1, + .fifos = 1, + .fifo_depth = 32, + .flags = 0, +}; + +static struct fsl_sai_soc_data fsl_sai_imx6ul = { + .imx = true, + .dataline = 0x1, + .fifos = 1, + .fifo_depth = 32, + .flags = 0, +}; + +static struct fsl_sai_soc_data fsl_sai_imx7ulp = { + .imx = true, + .dataline = 0x3, + .fifos = 2, + .fifo_depth = 16, + .flags = SAI_FLAG_PMQOS, +}; + static const unsigned int fsl_sai_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, @@ -506,6 +542,29 @@ static int fsl_sai_hw_params(struct snd_ } } + if (sai->soc->dataline != 0x1) { + switch (sai->dataline[tx]) { + case 0x0: + break; + case 0x1: + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT, 0); + break; + case 0x2: + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT, + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT); + break; + case 0x3: + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT, + FSL_SAI_CR4_FCOMB_SOFT); + break; + default: + break; + } + } + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); @@ -564,14 +623,16 @@ static int fsl_sai_trigger(struct snd_pc FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); for (i = 0; tx && i < channels; i++) - regmap_write(sai->regmap, FSL_SAI_TDR, 0x0); + regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0); if (tx) udelay(10); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); regmap_update_bits(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + FSL_SAI_CSR_SE, FSL_SAI_CSR_SE); regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); @@ -642,8 +703,8 @@ static int fsl_sai_startup(struct snd_pc else sai->is_stream_opened[tx] = true; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, - FSL_SAI_CR3_TRCE); + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0|FSL_SAI_CR3_TRCE1, + FSL_SAI_CR3_TRCE(sai->dataline[tx])); ret = snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints); @@ -660,7 +721,7 @@ static void fsl_sai_shutdown(struct snd_ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); if (sai->is_stream_opened[tx]) { - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0 | FSL_SAI_CR3_TRCE1, 0); sai->is_stream_opened[tx] = false; } } @@ -688,7 +749,7 @@ static int fsl_sai_dai_probe(struct snd_ regmap_write(sai->regmap, FSL_SAI_RCSR, 0); regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, - FSL_SAI_MAXBURST_TX * 2); + sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_RX - 1); @@ -733,7 +794,8 @@ static struct reg_default fsl_sai_reg_de {FSL_SAI_TCR3, 0}, {FSL_SAI_TCR4, 0}, {FSL_SAI_TCR5, 0}, - {FSL_SAI_TDR, 0}, + {FSL_SAI_TDR0, 0}, + {FSL_SAI_TDR1, 0}, {FSL_SAI_TMR, 0}, {FSL_SAI_RCR1, 0}, {FSL_SAI_RCR2, 0}, @@ -752,7 +814,8 @@ static bool fsl_sai_readable_reg(struct case FSL_SAI_TCR3: case FSL_SAI_TCR4: case FSL_SAI_TCR5: - case FSL_SAI_TFR: + case FSL_SAI_TFR0: + case FSL_SAI_TFR1: case FSL_SAI_TMR: case FSL_SAI_RCSR: case FSL_SAI_RCR1: @@ -760,8 +823,10 @@ static bool fsl_sai_readable_reg(struct case FSL_SAI_RCR3: case FSL_SAI_RCR4: case FSL_SAI_RCR5: - case FSL_SAI_RDR: - case FSL_SAI_RFR: + case FSL_SAI_RDR0: + case FSL_SAI_RDR1: + case FSL_SAI_RFR0: + case FSL_SAI_RFR1: case FSL_SAI_RMR: return true; default: @@ -774,9 +839,12 @@ static bool fsl_sai_volatile_reg(struct switch (reg) { case FSL_SAI_TCSR: case FSL_SAI_RCSR: - case FSL_SAI_TFR: - case FSL_SAI_RFR: - case FSL_SAI_RDR: + case FSL_SAI_TFR0: + case FSL_SAI_TFR1: + case FSL_SAI_RFR0: + case FSL_SAI_RFR1: + case FSL_SAI_RDR0: + case FSL_SAI_RDR1: return true; default: return false; @@ -792,7 +860,8 @@ static bool fsl_sai_writeable_reg(struct case FSL_SAI_TCR3: case FSL_SAI_TCR4: case FSL_SAI_TCR5: - case FSL_SAI_TDR: + case FSL_SAI_TDR0: + case FSL_SAI_TDR1: case FSL_SAI_TMR: case FSL_SAI_RCSR: case FSL_SAI_RCR1: @@ -821,9 +890,19 @@ static const struct regmap_config fsl_sa .cache_type = REGCACHE_FLAT, }; +static const struct of_device_id fsl_sai_ids[] = { + { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610 }, + { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx }, + { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6ul }, + { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_sai_ids); + static int fsl_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; struct fsl_sai *sai; struct regmap *gpr; struct resource *res; @@ -838,11 +917,12 @@ static int fsl_sai_probe(struct platform sai->pdev = pdev; - if (of_device_is_compatible(np, "fsl,imx6sx-sai") || - of_device_is_compatible(np, "fsl,imx6ul-sai")) - sai->sai_on_imx = true; + of_id = of_match_device(fsl_sai_ids, &pdev->dev); + if (!of_id || !of_id->data) + return -EINVAL; sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); + sai->soc = of_id->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); @@ -874,11 +954,25 @@ static int fsl_sai_probe(struct platform sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", - i + 1, PTR_ERR(sai->mclk_clk[i])); + i, PTR_ERR(sai->mclk_clk[i])); sai->mclk_clk[i] = NULL; } } + /*dataline mask for rx and tx*/ + ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]); + if (ret) + sai->dataline[0] = 1; + + ret = of_property_read_u32_index(np, "fsl,dataline", 1, &sai->dataline[1]); + if (ret) + sai->dataline[1] = 1; + + if ((sai->dataline[0] & (~sai->soc->dataline)) || sai->dataline[1] & (~sai->soc->dataline)) { + dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline); + return -EINVAL; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); @@ -937,8 +1031,8 @@ static int fsl_sai_probe(struct platform MCLK_DIR(index)); } - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0; + sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; @@ -951,7 +1045,7 @@ static int fsl_sai_probe(struct platform if (ret) goto err_pm_disable; - if (sai->sai_on_imx) + if (sai->soc->imx) ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE); if (ret) goto err_pm_disable; @@ -997,6 +1091,9 @@ static int fsl_sai_runtime_suspend(struc clk_disable_unprepare(sai->bus_clk); + if (sai->soc->flags & SAI_FLAG_PMQOS) + pm_qos_remove_request(&sai->pm_qos_req); + regcache_cache_only(sai->regmap, true); regcache_mark_dirty(sai->regmap); @@ -1026,6 +1123,10 @@ static int fsl_sai_runtime_resume(struct goto disable_tx_clk; } + if (sai->soc->flags & SAI_FLAG_PMQOS) + pm_qos_add_request(&sai->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, 0); + regcache_cache_only(sai->regmap, false); regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -1,11 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2012-2016 Freescale Semiconductor, Inc. */ #ifndef __FSL_SAI_H #define __FSL_SAI_H +#include #include #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ @@ -20,7 +21,10 @@ #define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ #define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ #define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ -#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */ +#define FSL_SAI_TDR0 0x20 /* SAI Transmit Data */ +#define FSL_SAI_TDR1 0x24 /* SAI Transmit Data */ +#define FSL_SAI_TFR0 0x40 /* SAI Transmit FIFO */ +#define FSL_SAI_TFR1 0x44 /* SAI Transmit FIFO */ #define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */ #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ #define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ @@ -29,7 +33,10 @@ #define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ #define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ #define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ -#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */ +#define FSL_SAI_RDR0 0xa0 /* SAI Receive Data */ +#define FSL_SAI_RDR1 0xa4 /* SAI Receive Data */ +#define FSL_SAI_RFR0 0xc0 /* SAI Receive FIFO */ +#define FSL_SAI_RFR1 0xc4 /* SAI Receive FIFO */ #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ @@ -45,6 +52,7 @@ /* SAI Transmit/Receive Control Register */ #define FSL_SAI_CSR_TERE BIT(31) +#define FSL_SAI_CSR_SE BIT(30) #define FSL_SAI_CSR_FR BIT(25) #define FSL_SAI_CSR_SR BIT(24) #define FSL_SAI_CSR_xF_SHIFT 16 @@ -81,11 +89,19 @@ #define FSL_SAI_CR2_DIV_MASK 0xff /* SAI Transmit and Receive Configuration 3 Register */ -#define FSL_SAI_CR3_TRCE BIT(16) +#define FSL_SAI_CR3_TRCE0 BIT(16) +#define FSL_SAI_CR3_TRCE1 BIT(17) +#define FSL_SAI_CR3_TRCE(x) (x << 16) #define FSL_SAI_CR3_WDFL(x) (x) #define FSL_SAI_CR3_WDFL_MASK 0x1f /* SAI Transmit and Receive Configuration 4 Register */ + +#define FSL_SAI_CR4_FCONT BIT(28) +#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26) +#define FSL_SAI_CR4_FCOMB_SOFT BIT(27) +#define FSL_SAI_CR4_FPACK_8 (0x2 << 24) +#define FSL_SAI_CR4_FPACK_16 (0x3 << 24) #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) @@ -126,6 +142,16 @@ #define FSL_SAI_MAXBURST_TX 6 #define FSL_SAI_MAXBURST_RX 6 +#define SAI_FLAG_PMQOS BIT(0) + +struct fsl_sai_soc_data { + unsigned int fifo_depth; + unsigned int fifos; + unsigned int dataline; + unsigned int flags; + bool imx; +}; + struct fsl_sai { struct platform_device *pdev; struct regmap *regmap; @@ -138,6 +164,7 @@ struct fsl_sai { bool sai_on_imx; bool synchronous[2]; bool is_stream_opened[2]; + unsigned int dataline[2]; unsigned int mclk_id[2]; unsigned int mclk_streams; @@ -147,6 +174,8 @@ struct fsl_sai { struct snd_soc_dai_driver cpu_dai_drv; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; + const struct fsl_sai_soc_data *soc; + struct pm_qos_request pm_qos_req; }; #define TX 1