1 From c516c261c49d0ce9509d6b9623dec6a4e9f919c3 Mon Sep 17 00:00:00 2001
2 From: Shengjiu Wang <shengjiu.wang@freescale.com>
3 Date: Mon, 30 Mar 2020 16:21:00 +0800
4 Subject: [PATCH] MLK-13574-2: ASoC: fsl_sai: refine driver for ip upgrade
6 In imx7ulp1, the sai can support two TX channel and two RX
7 channels, So the usage need to be updated.
9 Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
11 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
13 sound/soc/fsl/fsl_sai.c | 145 ++++++++++++++++++++++++++++++++++++++++--------
14 sound/soc/fsl/fsl_sai.h | 37 ++++++++++--
15 2 files changed, 156 insertions(+), 26 deletions(-)
17 --- a/sound/soc/fsl/fsl_sai.c
18 +++ b/sound/soc/fsl/fsl_sai.c
20 #include <linux/delay.h>
21 #include <linux/dmaengine.h>
22 #include <linux/module.h>
23 +#include <linux/of_device.h>
24 #include <linux/of_address.h>
25 #include <linux/pm_runtime.h>
26 #include <linux/regmap.h>
27 #include <linux/slab.h>
28 #include <linux/time.h>
29 +#include <linux/pm_qos.h>
30 #include <sound/core.h>
31 #include <sound/dmaengine_pcm.h>
32 #include <sound/pcm_params.h>
33 #include <linux/mfd/syscon.h>
34 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
35 +#include <linux/pm_runtime.h>
40 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
43 +static struct fsl_sai_soc_data fsl_sai_vf610 = {
45 + /*dataline is mask, not index*/
52 +static struct fsl_sai_soc_data fsl_sai_imx6sx = {
60 +static struct fsl_sai_soc_data fsl_sai_imx6ul = {
68 +static struct fsl_sai_soc_data fsl_sai_imx7ulp = {
73 + .flags = SAI_FLAG_PMQOS,
76 static const unsigned int fsl_sai_rates[] = {
77 8000, 11025, 12000, 16000, 22050,
78 24000, 32000, 44100, 48000, 64000,
79 @@ -505,6 +541,29 @@ static int fsl_sai_hw_params(struct snd_
83 + if (sai->soc->dataline != 0x1) {
84 + switch (sai->dataline[tx]) {
88 + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
89 + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT, 0);
92 + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
93 + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT,
94 + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT);
97 + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
98 + FSL_SAI_CR4_FCOMB_SOFT | FSL_SAI_CR4_FCOMB_SHIFT,
99 + FSL_SAI_CR4_FCOMB_SOFT);
106 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
107 FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
109 @@ -563,14 +622,16 @@ static int fsl_sai_trigger(struct snd_pc
110 FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
112 for (i = 0; tx && i < channels; i++)
113 - regmap_write(sai->regmap, FSL_SAI_TDR, 0x0);
114 + regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
118 - regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
119 - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
120 regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
121 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
122 + regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
123 + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
124 + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
125 + FSL_SAI_CSR_SE, FSL_SAI_CSR_SE);
127 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
128 FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
129 @@ -641,8 +702,8 @@ static int fsl_sai_startup(struct snd_pc
131 sai->is_stream_opened[tx] = true;
133 - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
135 + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0|FSL_SAI_CR3_TRCE1,
136 + FSL_SAI_CR3_TRCE(sai->dataline[tx]));
138 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
139 SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
140 @@ -659,7 +720,7 @@ static void fsl_sai_shutdown(struct snd_
141 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
143 if (sai->is_stream_opened[tx]) {
144 - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
145 + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE0 | FSL_SAI_CR3_TRCE1, 0);
146 sai->is_stream_opened[tx] = false;
149 @@ -687,7 +748,7 @@ static int fsl_sai_dai_probe(struct snd_
150 regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
152 regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
153 - FSL_SAI_MAXBURST_TX * 2);
154 + sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
155 regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
156 FSL_SAI_MAXBURST_RX - 1);
158 @@ -732,7 +793,8 @@ static struct reg_default fsl_sai_reg_de
168 @@ -751,7 +813,8 @@ static bool fsl_sai_readable_reg(struct
178 @@ -759,8 +822,10 @@ static bool fsl_sai_readable_reg(struct
191 @@ -773,9 +838,12 @@ static bool fsl_sai_volatile_reg(struct
207 @@ -791,7 +859,8 @@ static bool fsl_sai_writeable_reg(struct
217 @@ -820,9 +889,19 @@ static const struct regmap_config fsl_sa
218 .cache_type = REGCACHE_FLAT,
221 +static const struct of_device_id fsl_sai_ids[] = {
222 + { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610 },
223 + { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx },
224 + { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6ul },
225 + { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp },
228 +MODULE_DEVICE_TABLE(of, fsl_sai_ids);
230 static int fsl_sai_probe(struct platform_device *pdev)
232 struct device_node *np = pdev->dev.of_node;
233 + const struct of_device_id *of_id;
236 struct resource *res;
237 @@ -837,11 +916,12 @@ static int fsl_sai_probe(struct platform
241 - if (of_device_is_compatible(np, "fsl,imx6sx-sai") ||
242 - of_device_is_compatible(np, "fsl,imx6ul-sai"))
243 - sai->sai_on_imx = true;
244 + of_id = of_match_device(fsl_sai_ids, &pdev->dev);
245 + if (!of_id || !of_id->data)
248 sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
249 + sai->soc = of_id->data;
251 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
252 base = devm_ioremap_resource(&pdev->dev, res);
253 @@ -873,11 +953,25 @@ static int fsl_sai_probe(struct platform
254 sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
255 if (IS_ERR(sai->mclk_clk[i])) {
256 dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
257 - i + 1, PTR_ERR(sai->mclk_clk[i]));
258 + i, PTR_ERR(sai->mclk_clk[i]));
259 sai->mclk_clk[i] = NULL;
263 + /*dataline mask for rx and tx*/
264 + ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
266 + sai->dataline[0] = 1;
268 + ret = of_property_read_u32_index(np, "fsl,dataline", 1, &sai->dataline[1]);
270 + sai->dataline[1] = 1;
272 + if ((sai->dataline[0] & (~sai->soc->dataline)) || sai->dataline[1] & (~sai->soc->dataline)) {
273 + dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
277 irq = platform_get_irq(pdev, 0);
279 dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
280 @@ -936,8 +1030,8 @@ static int fsl_sai_probe(struct platform
284 - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
285 - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
286 + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
287 + sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
288 sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
289 sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
291 @@ -950,7 +1044,7 @@ static int fsl_sai_probe(struct platform
295 - if (sai->sai_on_imx)
297 ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
300 @@ -996,6 +1090,9 @@ static int fsl_sai_runtime_suspend(struc
302 clk_disable_unprepare(sai->bus_clk);
304 + if (sai->soc->flags & SAI_FLAG_PMQOS)
305 + pm_qos_remove_request(&sai->pm_qos_req);
307 regcache_cache_only(sai->regmap, true);
308 regcache_mark_dirty(sai->regmap);
310 @@ -1025,6 +1122,10 @@ static int fsl_sai_runtime_resume(struct
314 + if (sai->soc->flags & SAI_FLAG_PMQOS)
315 + pm_qos_add_request(&sai->pm_qos_req,
316 + PM_QOS_CPU_DMA_LATENCY, 0);
318 regcache_cache_only(sai->regmap, false);
319 regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
320 regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
321 --- a/sound/soc/fsl/fsl_sai.h
322 +++ b/sound/soc/fsl/fsl_sai.h
324 /* SPDX-License-Identifier: GPL-2.0 */
326 - * Copyright 2012-2013 Freescale Semiconductor, Inc.
327 + * Copyright 2012-2016 Freescale Semiconductor, Inc.
333 +#include <linux/pm_qos.h>
334 #include <sound/dmaengine_pcm.h>
336 #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
338 #define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */
339 #define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */
340 #define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */
341 -#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */
342 +#define FSL_SAI_TDR0 0x20 /* SAI Transmit Data */
343 +#define FSL_SAI_TDR1 0x24 /* SAI Transmit Data */
344 +#define FSL_SAI_TFR0 0x40 /* SAI Transmit FIFO */
345 +#define FSL_SAI_TFR1 0x44 /* SAI Transmit FIFO */
346 #define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */
347 #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */
348 #define FSL_SAI_RCSR 0x80 /* SAI Receive Control */
350 #define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */
351 #define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */
352 #define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */
353 -#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */
354 +#define FSL_SAI_RDR0 0xa0 /* SAI Receive Data */
355 +#define FSL_SAI_RDR1 0xa4 /* SAI Receive Data */
356 +#define FSL_SAI_RFR0 0xc0 /* SAI Receive FIFO */
357 +#define FSL_SAI_RFR1 0xc4 /* SAI Receive FIFO */
358 #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */
359 #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */
363 /* SAI Transmit/Receive Control Register */
364 #define FSL_SAI_CSR_TERE BIT(31)
365 +#define FSL_SAI_CSR_SE BIT(30)
366 #define FSL_SAI_CSR_FR BIT(25)
367 #define FSL_SAI_CSR_SR BIT(24)
368 #define FSL_SAI_CSR_xF_SHIFT 16
370 #define FSL_SAI_CR2_DIV_MASK 0xff
372 /* SAI Transmit and Receive Configuration 3 Register */
373 -#define FSL_SAI_CR3_TRCE BIT(16)
374 +#define FSL_SAI_CR3_TRCE0 BIT(16)
375 +#define FSL_SAI_CR3_TRCE1 BIT(17)
376 +#define FSL_SAI_CR3_TRCE(x) (x << 16)
377 #define FSL_SAI_CR3_WDFL(x) (x)
378 #define FSL_SAI_CR3_WDFL_MASK 0x1f
380 /* SAI Transmit and Receive Configuration 4 Register */
382 +#define FSL_SAI_CR4_FCONT BIT(28)
383 +#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
384 +#define FSL_SAI_CR4_FCOMB_SOFT BIT(27)
385 +#define FSL_SAI_CR4_FPACK_8 (0x2 << 24)
386 +#define FSL_SAI_CR4_FPACK_16 (0x3 << 24)
387 #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
388 #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
389 #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
391 #define FSL_SAI_MAXBURST_TX 6
392 #define FSL_SAI_MAXBURST_RX 6
394 +#define SAI_FLAG_PMQOS BIT(0)
396 +struct fsl_sai_soc_data {
397 + unsigned int fifo_depth;
398 + unsigned int fifos;
399 + unsigned int dataline;
400 + unsigned int flags;
405 struct platform_device *pdev;
406 struct regmap *regmap;
407 @@ -138,6 +164,7 @@ struct fsl_sai {
410 bool is_stream_opened[2];
411 + unsigned int dataline[2];
413 unsigned int mclk_id[2];
414 unsigned int mclk_streams;
415 @@ -147,6 +174,8 @@ struct fsl_sai {
416 struct snd_soc_dai_driver cpu_dai_drv;
417 struct snd_dmaengine_dai_dma_data dma_params_rx;
418 struct snd_dmaengine_dai_dma_data dma_params_tx;
419 + const struct fsl_sai_soc_data *soc;
420 + struct pm_qos_request pm_qos_req;