aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl/fsl_sai.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl/fsl_sai.c')
-rw-r--r--sound/soc/fsl/fsl_sai.c255
1 files changed, 138 insertions, 117 deletions
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 56da8c8c5960..c5a0e8af8226 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -22,6 +22,7 @@
22#include <sound/pcm_params.h> 22#include <sound/pcm_params.h>
23 23
24#include "fsl_sai.h" 24#include "fsl_sai.h"
25#include "imx-pcm.h"
25 26
26#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ 27#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
27 FSL_SAI_CSR_FEIE) 28 FSL_SAI_CSR_FEIE)
@@ -30,78 +31,96 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
30{ 31{
31 struct fsl_sai *sai = (struct fsl_sai *)devid; 32 struct fsl_sai *sai = (struct fsl_sai *)devid;
32 struct device *dev = &sai->pdev->dev; 33 struct device *dev = &sai->pdev->dev;
33 u32 xcsr, mask; 34 u32 flags, xcsr, mask;
35 bool irq_none = true;
34 36
35 /* Only handle those what we enabled */ 37 /*
38 * Both IRQ status bits and IRQ mask bits are in the xCSR but
39 * different shifts. And we here create a mask only for those
40 * IRQs that we activated.
41 */
36 mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT; 42 mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
37 43
38 /* Tx IRQ */ 44 /* Tx IRQ */
39 regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr); 45 regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
40 xcsr &= mask; 46 flags = xcsr & mask;
47
48 if (flags)
49 irq_none = false;
50 else
51 goto irq_rx;
41 52
42 if (xcsr & FSL_SAI_CSR_WSF) 53 if (flags & FSL_SAI_CSR_WSF)
43 dev_dbg(dev, "isr: Start of Tx word detected\n"); 54 dev_dbg(dev, "isr: Start of Tx word detected\n");
44 55
45 if (xcsr & FSL_SAI_CSR_SEF) 56 if (flags & FSL_SAI_CSR_SEF)
46 dev_warn(dev, "isr: Tx Frame sync error detected\n"); 57 dev_warn(dev, "isr: Tx Frame sync error detected\n");
47 58
48 if (xcsr & FSL_SAI_CSR_FEF) { 59 if (flags & FSL_SAI_CSR_FEF) {
49 dev_warn(dev, "isr: Transmit underrun detected\n"); 60 dev_warn(dev, "isr: Transmit underrun detected\n");
50 /* FIFO reset for safety */ 61 /* FIFO reset for safety */
51 xcsr |= FSL_SAI_CSR_FR; 62 xcsr |= FSL_SAI_CSR_FR;
52 } 63 }
53 64
54 if (xcsr & FSL_SAI_CSR_FWF) 65 if (flags & FSL_SAI_CSR_FWF)
55 dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n"); 66 dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
56 67
57 if (xcsr & FSL_SAI_CSR_FRF) 68 if (flags & FSL_SAI_CSR_FRF)
58 dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n"); 69 dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
59 70
60 regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 71 flags &= FSL_SAI_CSR_xF_W_MASK;
61 FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr); 72 xcsr &= ~FSL_SAI_CSR_xF_MASK;
73
74 if (flags)
75 regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
62 76
77irq_rx:
63 /* Rx IRQ */ 78 /* Rx IRQ */
64 regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr); 79 regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
65 xcsr &= mask; 80 flags = xcsr & mask;
66 81
67 if (xcsr & FSL_SAI_CSR_WSF) 82 if (flags)
83 irq_none = false;
84 else
85 goto out;
86
87 if (flags & FSL_SAI_CSR_WSF)
68 dev_dbg(dev, "isr: Start of Rx word detected\n"); 88 dev_dbg(dev, "isr: Start of Rx word detected\n");
69 89
70 if (xcsr & FSL_SAI_CSR_SEF) 90 if (flags & FSL_SAI_CSR_SEF)
71 dev_warn(dev, "isr: Rx Frame sync error detected\n"); 91 dev_warn(dev, "isr: Rx Frame sync error detected\n");
72 92
73 if (xcsr & FSL_SAI_CSR_FEF) { 93 if (flags & FSL_SAI_CSR_FEF) {
74 dev_warn(dev, "isr: Receive overflow detected\n"); 94 dev_warn(dev, "isr: Receive overflow detected\n");
75 /* FIFO reset for safety */ 95 /* FIFO reset for safety */
76 xcsr |= FSL_SAI_CSR_FR; 96 xcsr |= FSL_SAI_CSR_FR;
77 } 97 }
78 98
79 if (xcsr & FSL_SAI_CSR_FWF) 99 if (flags & FSL_SAI_CSR_FWF)
80 dev_dbg(dev, "isr: Enabled receive FIFO is full\n"); 100 dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
81 101
82 if (xcsr & FSL_SAI_CSR_FRF) 102 if (flags & FSL_SAI_CSR_FRF)
83 dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n"); 103 dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
84 104
85 regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 105 flags &= FSL_SAI_CSR_xF_W_MASK;
86 FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr); 106 xcsr &= ~FSL_SAI_CSR_xF_MASK;
107
108 if (flags)
109 regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
87 110
88 return IRQ_HANDLED; 111out:
112 if (irq_none)
113 return IRQ_NONE;
114 else
115 return IRQ_HANDLED;
89} 116}
90 117
91static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, 118static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
92 int clk_id, unsigned int freq, int fsl_dir) 119 int clk_id, unsigned int freq, int fsl_dir)
93{ 120{
94 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); 121 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
95 u32 val_cr2, reg_cr2; 122 bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
96 123 u32 val_cr2 = 0;
97 if (fsl_dir == FSL_FMT_TRANSMITTER)
98 reg_cr2 = FSL_SAI_TCR2;
99 else
100 reg_cr2 = FSL_SAI_RCR2;
101
102 regmap_read(sai->regmap, reg_cr2, &val_cr2);
103
104 val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
105 124
106 switch (clk_id) { 125 switch (clk_id) {
107 case FSL_SAI_CLK_BUS: 126 case FSL_SAI_CLK_BUS:
@@ -120,7 +139,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
120 return -EINVAL; 139 return -EINVAL;
121 } 140 }
122 141
123 regmap_write(sai->regmap, reg_cr2, val_cr2); 142 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
143 FSL_SAI_CR2_MSEL_MASK, val_cr2);
124 144
125 return 0; 145 return 0;
126} 146}
@@ -152,22 +172,10 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
152 unsigned int fmt, int fsl_dir) 172 unsigned int fmt, int fsl_dir)
153{ 173{
154 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); 174 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
155 u32 val_cr2, val_cr4, reg_cr2, reg_cr4; 175 bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
156 176 u32 val_cr2 = 0, val_cr4 = 0;
157 if (fsl_dir == FSL_FMT_TRANSMITTER) {
158 reg_cr2 = FSL_SAI_TCR2;
159 reg_cr4 = FSL_SAI_TCR4;
160 } else {
161 reg_cr2 = FSL_SAI_RCR2;
162 reg_cr4 = FSL_SAI_RCR4;
163 }
164 177
165 regmap_read(sai->regmap, reg_cr2, &val_cr2); 178 if (!sai->big_endian_data)
166 regmap_read(sai->regmap, reg_cr4, &val_cr4);
167
168 if (sai->big_endian_data)
169 val_cr4 &= ~FSL_SAI_CR4_MF;
170 else
171 val_cr4 |= FSL_SAI_CR4_MF; 179 val_cr4 |= FSL_SAI_CR4_MF;
172 180
173 /* DAI mode */ 181 /* DAI mode */
@@ -188,7 +196,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
188 * frame sync asserts with the first bit of the frame. 196 * frame sync asserts with the first bit of the frame.
189 */ 197 */
190 val_cr2 |= FSL_SAI_CR2_BCP; 198 val_cr2 |= FSL_SAI_CR2_BCP;
191 val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
192 break; 199 break;
193 case SND_SOC_DAIFMT_DSP_A: 200 case SND_SOC_DAIFMT_DSP_A:
194 /* 201 /*
@@ -198,7 +205,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
198 * data word. 205 * data word.
199 */ 206 */
200 val_cr2 |= FSL_SAI_CR2_BCP; 207 val_cr2 |= FSL_SAI_CR2_BCP;
201 val_cr4 &= ~FSL_SAI_CR4_FSP;
202 val_cr4 |= FSL_SAI_CR4_FSE; 208 val_cr4 |= FSL_SAI_CR4_FSE;
203 sai->is_dsp_mode = true; 209 sai->is_dsp_mode = true;
204 break; 210 break;
@@ -208,7 +214,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
208 * frame sync asserts with the first bit of the frame. 214 * frame sync asserts with the first bit of the frame.
209 */ 215 */
210 val_cr2 |= FSL_SAI_CR2_BCP; 216 val_cr2 |= FSL_SAI_CR2_BCP;
211 val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
212 sai->is_dsp_mode = true; 217 sai->is_dsp_mode = true;
213 break; 218 break;
214 case SND_SOC_DAIFMT_RIGHT_J: 219 case SND_SOC_DAIFMT_RIGHT_J:
@@ -246,23 +251,22 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
246 val_cr4 |= FSL_SAI_CR4_FSD_MSTR; 251 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
247 break; 252 break;
248 case SND_SOC_DAIFMT_CBM_CFM: 253 case SND_SOC_DAIFMT_CBM_CFM:
249 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
250 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
251 break; 254 break;
252 case SND_SOC_DAIFMT_CBS_CFM: 255 case SND_SOC_DAIFMT_CBS_CFM:
253 val_cr2 |= FSL_SAI_CR2_BCD_MSTR; 256 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
254 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
255 break; 257 break;
256 case SND_SOC_DAIFMT_CBM_CFS: 258 case SND_SOC_DAIFMT_CBM_CFS:
257 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
258 val_cr4 |= FSL_SAI_CR4_FSD_MSTR; 259 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
259 break; 260 break;
260 default: 261 default:
261 return -EINVAL; 262 return -EINVAL;
262 } 263 }
263 264
264 regmap_write(sai->regmap, reg_cr2, val_cr2); 265 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
265 regmap_write(sai->regmap, reg_cr4, val_cr4); 266 FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
267 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
268 FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
269 FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
266 270
267 return 0; 271 return 0;
268} 272}
@@ -289,29 +293,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
289 struct snd_soc_dai *cpu_dai) 293 struct snd_soc_dai *cpu_dai)
290{ 294{
291 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); 295 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
292 u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr; 296 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
293 unsigned int channels = params_channels(params); 297 unsigned int channels = params_channels(params);
294 u32 word_width = snd_pcm_format_width(params_format(params)); 298 u32 word_width = snd_pcm_format_width(params_format(params));
295 299 u32 val_cr4 = 0, val_cr5 = 0;
296 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
297 reg_cr4 = FSL_SAI_TCR4;
298 reg_cr5 = FSL_SAI_TCR5;
299 reg_mr = FSL_SAI_TMR;
300 } else {
301 reg_cr4 = FSL_SAI_RCR4;
302 reg_cr5 = FSL_SAI_RCR5;
303 reg_mr = FSL_SAI_RMR;
304 }
305
306 regmap_read(sai->regmap, reg_cr4, &val_cr4);
307 regmap_read(sai->regmap, reg_cr4, &val_cr5);
308
309 val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
310 val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
311
312 val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
313 val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
314 val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
315 300
316 if (!sai->is_dsp_mode) 301 if (!sai->is_dsp_mode)
317 val_cr4 |= FSL_SAI_CR4_SYWD(word_width); 302 val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
@@ -319,18 +304,20 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
319 val_cr5 |= FSL_SAI_CR5_WNW(word_width); 304 val_cr5 |= FSL_SAI_CR5_WNW(word_width);
320 val_cr5 |= FSL_SAI_CR5_W0W(word_width); 305 val_cr5 |= FSL_SAI_CR5_W0W(word_width);
321 306
322 val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
323 if (sai->big_endian_data) 307 if (sai->big_endian_data)
324 val_cr5 |= FSL_SAI_CR5_FBT(0); 308 val_cr5 |= FSL_SAI_CR5_FBT(0);
325 else 309 else
326 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); 310 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
327 311
328 val_cr4 |= FSL_SAI_CR4_FRSZ(channels); 312 val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
329 val_mr = ~0UL - ((1 << channels) - 1);
330 313
331 regmap_write(sai->regmap, reg_cr4, val_cr4); 314 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
332 regmap_write(sai->regmap, reg_cr5, val_cr5); 315 FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
333 regmap_write(sai->regmap, reg_mr, val_mr); 316 val_cr4);
317 regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx),
318 FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
319 FSL_SAI_CR5_FBT_MASK, val_cr5);
320 regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
334 321
335 return 0; 322 return 0;
336} 323}
@@ -339,6 +326,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
339 struct snd_soc_dai *cpu_dai) 326 struct snd_soc_dai *cpu_dai)
340{ 327{
341 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); 328 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
329 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
342 u32 tcsr, rcsr; 330 u32 tcsr, rcsr;
343 331
344 /* 332 /*
@@ -353,14 +341,6 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
353 regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); 341 regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
354 regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); 342 regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
355 343
356 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
357 tcsr |= FSL_SAI_CSR_FRDE;
358 rcsr &= ~FSL_SAI_CSR_FRDE;
359 } else {
360 rcsr |= FSL_SAI_CSR_FRDE;
361 tcsr &= ~FSL_SAI_CSR_FRDE;
362 }
363
364 /* 344 /*
365 * It is recommended that the transmitter is the last enabled 345 * It is recommended that the transmitter is the last enabled
366 * and the first disabled. 346 * and the first disabled.
@@ -369,22 +349,33 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
369 case SNDRV_PCM_TRIGGER_START: 349 case SNDRV_PCM_TRIGGER_START:
370 case SNDRV_PCM_TRIGGER_RESUME: 350 case SNDRV_PCM_TRIGGER_RESUME:
371 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 351 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
372 tcsr |= FSL_SAI_CSR_TERE; 352 if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) {
373 rcsr |= FSL_SAI_CSR_TERE; 353 regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
354 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
355 regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
356 FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
357 }
374 358
375 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); 359 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
376 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); 360 FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
361 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
362 FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
377 break; 363 break;
378 case SNDRV_PCM_TRIGGER_STOP: 364 case SNDRV_PCM_TRIGGER_STOP:
379 case SNDRV_PCM_TRIGGER_SUSPEND: 365 case SNDRV_PCM_TRIGGER_SUSPEND:
380 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 366 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
381 if (!(cpu_dai->playback_active || cpu_dai->capture_active)) { 367 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
382 tcsr &= ~FSL_SAI_CSR_TERE; 368 FSL_SAI_CSR_FRDE, 0);
383 rcsr &= ~FSL_SAI_CSR_TERE; 369 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
370 FSL_SAI_CSR_xIE_MASK, 0);
371
372 /* Check if the opposite FRDE is also disabled */
373 if (!(tx ? rcsr & FSL_SAI_CSR_FRDE : tcsr & FSL_SAI_CSR_FRDE)) {
374 regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
375 FSL_SAI_CSR_TERE, 0);
376 regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
377 FSL_SAI_CSR_TERE, 0);
384 } 378 }
385
386 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
387 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
388 break; 379 break;
389 default: 380 default:
390 return -EINVAL; 381 return -EINVAL;
@@ -397,14 +388,17 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
397 struct snd_soc_dai *cpu_dai) 388 struct snd_soc_dai *cpu_dai)
398{ 389{
399 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); 390 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
400 u32 reg; 391 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
392 struct device *dev = &sai->pdev->dev;
393 int ret;
401 394
402 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 395 ret = clk_prepare_enable(sai->bus_clk);
403 reg = FSL_SAI_TCR3; 396 if (ret) {
404 else 397 dev_err(dev, "failed to enable bus clock: %d\n", ret);
405 reg = FSL_SAI_RCR3; 398 return ret;
399 }
406 400
407 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, 401 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
408 FSL_SAI_CR3_TRCE); 402 FSL_SAI_CR3_TRCE);
409 403
410 return 0; 404 return 0;
@@ -414,15 +408,11 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
414 struct snd_soc_dai *cpu_dai) 408 struct snd_soc_dai *cpu_dai)
415{ 409{
416 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); 410 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
417 u32 reg; 411 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
418 412
419 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 413 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
420 reg = FSL_SAI_TCR3;
421 else
422 reg = FSL_SAI_RCR3;
423 414
424 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, 415 clk_disable_unprepare(sai->bus_clk);
425 ~FSL_SAI_CR3_TRCE);
426} 416}
427 417
428static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { 418static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -438,8 +428,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
438{ 428{
439 struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); 429 struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
440 430
441 regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS); 431 regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
442 regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS); 432 regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
443 regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, 433 regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
444 FSL_SAI_MAXBURST_TX * 2); 434 FSL_SAI_MAXBURST_TX * 2);
445 regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, 435 regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -555,7 +545,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
555 struct fsl_sai *sai; 545 struct fsl_sai *sai;
556 struct resource *res; 546 struct resource *res;
557 void __iomem *base; 547 void __iomem *base;
558 int irq, ret; 548 char tmp[8];
549 int irq, ret, i;
559 550
560 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 551 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
561 if (!sai) 552 if (!sai)
@@ -563,6 +554,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
563 554
564 sai->pdev = pdev; 555 sai->pdev = pdev;
565 556
557 if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
558 sai->sai_on_imx = true;
559
566 sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); 560 sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
567 if (sai->big_endian_regs) 561 if (sai->big_endian_regs)
568 fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; 562 fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -575,12 +569,35 @@ static int fsl_sai_probe(struct platform_device *pdev)
575 return PTR_ERR(base); 569 return PTR_ERR(base);
576 570
577 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, 571 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
578 "sai", base, &fsl_sai_regmap_config); 572 "bus", base, &fsl_sai_regmap_config);
573
574 /* Compatible with old DTB cases */
575 if (IS_ERR(sai->regmap))
576 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
577 "sai", base, &fsl_sai_regmap_config);
579 if (IS_ERR(sai->regmap)) { 578 if (IS_ERR(sai->regmap)) {
580 dev_err(&pdev->dev, "regmap init failed\n"); 579 dev_err(&pdev->dev, "regmap init failed\n");
581 return PTR_ERR(sai->regmap); 580 return PTR_ERR(sai->regmap);
582 } 581 }
583 582
583 /* No error out for old DTB cases but only mark the clock NULL */
584 sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
585 if (IS_ERR(sai->bus_clk)) {
586 dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
587 PTR_ERR(sai->bus_clk));
588 sai->bus_clk = NULL;
589 }
590
591 for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
592 sprintf(tmp, "mclk%d", i + 1);
593 sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
594 if (IS_ERR(sai->mclk_clk[i])) {
595 dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
596 i + 1, PTR_ERR(sai->mclk_clk[i]));
597 sai->mclk_clk[i] = NULL;
598 }
599 }
600
584 irq = platform_get_irq(pdev, 0); 601 irq = platform_get_irq(pdev, 0);
585 if (irq < 0) { 602 if (irq < 0) {
586 dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); 603 dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
@@ -605,12 +622,16 @@ static int fsl_sai_probe(struct platform_device *pdev)
605 if (ret) 622 if (ret)
606 return ret; 623 return ret;
607 624
608 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 625 if (sai->sai_on_imx)
609 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); 626 return imx_pcm_dma_init(pdev);
627 else
628 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
629 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
610} 630}
611 631
612static const struct of_device_id fsl_sai_ids[] = { 632static const struct of_device_id fsl_sai_ids[] = {
613 { .compatible = "fsl,vf610-sai", }, 633 { .compatible = "fsl,vf610-sai", },
634 { .compatible = "fsl,imx6sx-sai", },
614 { /* sentinel */ } 635 { /* sentinel */ }
615}; 636};
616 637