1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Freescale ALSA SoC Digital Audio Interface (SAI) driver. |
4 | // |
5 | // Copyright 2012-2015 Freescale Semiconductor, Inc. |
6 | |
7 | #include <linux/clk.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/dmaengine.h> |
10 | #include <linux/module.h> |
11 | #include <linux/of.h> |
12 | #include <linux/pinctrl/consumer.h> |
13 | #include <linux/pm_qos.h> |
14 | #include <linux/pm_runtime.h> |
15 | #include <linux/regmap.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/time.h> |
18 | #include <sound/core.h> |
19 | #include <sound/dmaengine_pcm.h> |
20 | #include <sound/pcm_params.h> |
21 | #include <linux/mfd/syscon.h> |
22 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> |
23 | |
24 | #include "fsl_sai.h" |
25 | #include "fsl_utils.h" |
26 | #include "imx-pcm.h" |
27 | |
28 | #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ |
29 | FSL_SAI_CSR_FEIE) |
30 | |
31 | static const unsigned int fsl_sai_rates[] = { |
32 | 8000, 11025, 12000, 16000, 22050, |
33 | 24000, 32000, 44100, 48000, 64000, |
34 | 88200, 96000, 176400, 192000, 352800, |
35 | 384000, 705600, 768000, 1411200, 2822400, |
36 | }; |
37 | |
38 | static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { |
39 | .count = ARRAY_SIZE(fsl_sai_rates), |
40 | .list = fsl_sai_rates, |
41 | }; |
42 | |
43 | /** |
44 | * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream |
45 | * |
46 | * SAI supports synchronous mode using bit/frame clocks of either Transmitter's |
47 | * or Receiver's for both streams. This function is used to check if clocks of |
48 | * the stream's are synced by the opposite stream. |
49 | * |
50 | * @sai: SAI context |
51 | * @dir: stream direction |
52 | */ |
53 | static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) |
54 | { |
55 | int adir = (dir == TX) ? RX : TX; |
56 | |
57 | /* current dir in async mode while opposite dir in sync mode */ |
58 | return !sai->synchronous[dir] && sai->synchronous[adir]; |
59 | } |
60 | |
61 | static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk) |
62 | { |
63 | struct pinctrl_state *state = NULL; |
64 | |
65 | if (sai->is_pdm_mode) { |
66 | /* DSD512@44.1kHz, DSD512@48kHz */ |
67 | if (bclk >= 22579200) |
68 | state = pinctrl_lookup_state(p: sai->pinctrl, name: "dsd512" ); |
69 | |
70 | /* Get default DSD state */ |
71 | if (IS_ERR_OR_NULL(ptr: state)) |
72 | state = pinctrl_lookup_state(p: sai->pinctrl, name: "dsd" ); |
73 | } else { |
74 | /* 706k32b2c, 768k32b2c, etc */ |
75 | if (bclk >= 45158400) |
76 | state = pinctrl_lookup_state(p: sai->pinctrl, name: "pcm_b2m" ); |
77 | } |
78 | |
79 | /* Get default state */ |
80 | if (IS_ERR_OR_NULL(ptr: state)) |
81 | state = pinctrl_lookup_state(p: sai->pinctrl, name: "default" ); |
82 | |
83 | return state; |
84 | } |
85 | |
86 | static irqreturn_t fsl_sai_isr(int irq, void *devid) |
87 | { |
88 | struct fsl_sai *sai = (struct fsl_sai *)devid; |
89 | unsigned int ofs = sai->soc_data->reg_offset; |
90 | struct device *dev = &sai->pdev->dev; |
91 | u32 flags, xcsr, mask; |
92 | irqreturn_t iret = IRQ_NONE; |
93 | |
94 | /* |
95 | * Both IRQ status bits and IRQ mask bits are in the xCSR but |
96 | * different shifts. And we here create a mask only for those |
97 | * IRQs that we activated. |
98 | */ |
99 | mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT; |
100 | |
101 | /* Tx IRQ */ |
102 | regmap_read(map: sai->regmap, FSL_SAI_TCSR(ofs), val: &xcsr); |
103 | flags = xcsr & mask; |
104 | |
105 | if (flags) |
106 | iret = IRQ_HANDLED; |
107 | else |
108 | goto irq_rx; |
109 | |
110 | if (flags & FSL_SAI_CSR_WSF) |
111 | dev_dbg(dev, "isr: Start of Tx word detected\n" ); |
112 | |
113 | if (flags & FSL_SAI_CSR_SEF) |
114 | dev_dbg(dev, "isr: Tx Frame sync error detected\n" ); |
115 | |
116 | if (flags & FSL_SAI_CSR_FEF) |
117 | dev_dbg(dev, "isr: Transmit underrun detected\n" ); |
118 | |
119 | if (flags & FSL_SAI_CSR_FWF) |
120 | dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n" ); |
121 | |
122 | if (flags & FSL_SAI_CSR_FRF) |
123 | dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n" ); |
124 | |
125 | flags &= FSL_SAI_CSR_xF_W_MASK; |
126 | xcsr &= ~FSL_SAI_CSR_xF_MASK; |
127 | |
128 | if (flags) |
129 | regmap_write(map: sai->regmap, FSL_SAI_TCSR(ofs), val: flags | xcsr); |
130 | |
131 | irq_rx: |
132 | /* Rx IRQ */ |
133 | regmap_read(map: sai->regmap, FSL_SAI_RCSR(ofs), val: &xcsr); |
134 | flags = xcsr & mask; |
135 | |
136 | if (flags) |
137 | iret = IRQ_HANDLED; |
138 | else |
139 | goto out; |
140 | |
141 | if (flags & FSL_SAI_CSR_WSF) |
142 | dev_dbg(dev, "isr: Start of Rx word detected\n" ); |
143 | |
144 | if (flags & FSL_SAI_CSR_SEF) |
145 | dev_dbg(dev, "isr: Rx Frame sync error detected\n" ); |
146 | |
147 | if (flags & FSL_SAI_CSR_FEF) |
148 | dev_dbg(dev, "isr: Receive overflow detected\n" ); |
149 | |
150 | if (flags & FSL_SAI_CSR_FWF) |
151 | dev_dbg(dev, "isr: Enabled receive FIFO is full\n" ); |
152 | |
153 | if (flags & FSL_SAI_CSR_FRF) |
154 | dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n" ); |
155 | |
156 | flags &= FSL_SAI_CSR_xF_W_MASK; |
157 | xcsr &= ~FSL_SAI_CSR_xF_MASK; |
158 | |
159 | if (flags) |
160 | regmap_write(map: sai->regmap, FSL_SAI_RCSR(ofs), val: flags | xcsr); |
161 | |
162 | out: |
163 | return iret; |
164 | } |
165 | |
166 | static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, |
167 | u32 rx_mask, int slots, int slot_width) |
168 | { |
169 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
170 | |
171 | sai->slots = slots; |
172 | sai->slot_width = slot_width; |
173 | |
174 | return 0; |
175 | } |
176 | |
177 | static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai, |
178 | unsigned int ratio) |
179 | { |
180 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); |
181 | |
182 | sai->bclk_ratio = ratio; |
183 | |
184 | return 0; |
185 | } |
186 | |
187 | static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, |
188 | int clk_id, unsigned int freq, bool tx) |
189 | { |
190 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
191 | unsigned int ofs = sai->soc_data->reg_offset; |
192 | u32 val_cr2 = 0; |
193 | |
194 | switch (clk_id) { |
195 | case FSL_SAI_CLK_BUS: |
196 | val_cr2 |= FSL_SAI_CR2_MSEL_BUS; |
197 | break; |
198 | case FSL_SAI_CLK_MAST1: |
199 | val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1; |
200 | break; |
201 | case FSL_SAI_CLK_MAST2: |
202 | val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2; |
203 | break; |
204 | case FSL_SAI_CLK_MAST3: |
205 | val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3; |
206 | break; |
207 | default: |
208 | return -EINVAL; |
209 | } |
210 | |
211 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR2(tx, ofs), |
212 | FSL_SAI_CR2_MSEL_MASK, val: val_cr2); |
213 | |
214 | return 0; |
215 | } |
216 | |
217 | static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id, unsigned int freq) |
218 | { |
219 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); |
220 | int ret; |
221 | |
222 | fsl_asoc_reparent_pll_clocks(dev: dai->dev, clk: sai->mclk_clk[clk_id], |
223 | pll8k_clk: sai->pll8k_clk, pll11k_clk: sai->pll11k_clk, ratio: freq); |
224 | |
225 | ret = clk_set_rate(clk: sai->mclk_clk[clk_id], rate: freq); |
226 | if (ret < 0) |
227 | dev_err(dai->dev, "failed to set clock rate (%u): %d\n" , freq, ret); |
228 | |
229 | return ret; |
230 | } |
231 | |
232 | static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
233 | int clk_id, unsigned int freq, int dir) |
234 | { |
235 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
236 | int ret; |
237 | |
238 | if (dir == SND_SOC_CLOCK_IN) |
239 | return 0; |
240 | |
241 | if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) { |
242 | if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) { |
243 | dev_err(cpu_dai->dev, "Unknown clock id: %d\n" , clk_id); |
244 | return -EINVAL; |
245 | } |
246 | |
247 | if (IS_ERR_OR_NULL(ptr: sai->mclk_clk[clk_id])) { |
248 | dev_err(cpu_dai->dev, "Unassigned clock: %d\n" , clk_id); |
249 | return -EINVAL; |
250 | } |
251 | |
252 | if (sai->mclk_streams == 0) { |
253 | ret = fsl_sai_set_mclk_rate(dai: cpu_dai, clk_id, freq); |
254 | if (ret < 0) |
255 | return ret; |
256 | } |
257 | } |
258 | |
259 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, tx: true); |
260 | if (ret) { |
261 | dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n" , ret); |
262 | return ret; |
263 | } |
264 | |
265 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, tx: false); |
266 | if (ret) |
267 | dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n" , ret); |
268 | |
269 | return ret; |
270 | } |
271 | |
272 | static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, |
273 | unsigned int fmt, bool tx) |
274 | { |
275 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
276 | unsigned int ofs = sai->soc_data->reg_offset; |
277 | u32 val_cr2 = 0, val_cr4 = 0; |
278 | |
279 | if (!sai->is_lsb_first) |
280 | val_cr4 |= FSL_SAI_CR4_MF; |
281 | |
282 | sai->is_pdm_mode = false; |
283 | sai->is_dsp_mode = false; |
284 | /* DAI mode */ |
285 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
286 | case SND_SOC_DAIFMT_I2S: |
287 | /* |
288 | * Frame low, 1clk before data, one word length for frame sync, |
289 | * frame sync starts one serial clock cycle earlier, |
290 | * that is, together with the last bit of the previous |
291 | * data word. |
292 | */ |
293 | val_cr2 |= FSL_SAI_CR2_BCP; |
294 | val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; |
295 | break; |
296 | case SND_SOC_DAIFMT_LEFT_J: |
297 | /* |
298 | * Frame high, one word length for frame sync, |
299 | * frame sync asserts with the first bit of the frame. |
300 | */ |
301 | val_cr2 |= FSL_SAI_CR2_BCP; |
302 | break; |
303 | case SND_SOC_DAIFMT_DSP_A: |
304 | /* |
305 | * Frame high, 1clk before data, one bit for frame sync, |
306 | * frame sync starts one serial clock cycle earlier, |
307 | * that is, together with the last bit of the previous |
308 | * data word. |
309 | */ |
310 | val_cr2 |= FSL_SAI_CR2_BCP; |
311 | val_cr4 |= FSL_SAI_CR4_FSE; |
312 | sai->is_dsp_mode = true; |
313 | break; |
314 | case SND_SOC_DAIFMT_DSP_B: |
315 | /* |
316 | * Frame high, one bit for frame sync, |
317 | * frame sync asserts with the first bit of the frame. |
318 | */ |
319 | val_cr2 |= FSL_SAI_CR2_BCP; |
320 | sai->is_dsp_mode = true; |
321 | break; |
322 | case SND_SOC_DAIFMT_PDM: |
323 | val_cr2 |= FSL_SAI_CR2_BCP; |
324 | val_cr4 &= ~FSL_SAI_CR4_MF; |
325 | sai->is_pdm_mode = true; |
326 | break; |
327 | case SND_SOC_DAIFMT_RIGHT_J: |
328 | /* To be done */ |
329 | default: |
330 | return -EINVAL; |
331 | } |
332 | |
333 | /* DAI clock inversion */ |
334 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
335 | case SND_SOC_DAIFMT_IB_IF: |
336 | /* Invert both clocks */ |
337 | val_cr2 ^= FSL_SAI_CR2_BCP; |
338 | val_cr4 ^= FSL_SAI_CR4_FSP; |
339 | break; |
340 | case SND_SOC_DAIFMT_IB_NF: |
341 | /* Invert bit clock */ |
342 | val_cr2 ^= FSL_SAI_CR2_BCP; |
343 | break; |
344 | case SND_SOC_DAIFMT_NB_IF: |
345 | /* Invert frame clock */ |
346 | val_cr4 ^= FSL_SAI_CR4_FSP; |
347 | break; |
348 | case SND_SOC_DAIFMT_NB_NF: |
349 | /* Nothing to do for both normal cases */ |
350 | break; |
351 | default: |
352 | return -EINVAL; |
353 | } |
354 | |
355 | /* DAI clock provider masks */ |
356 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
357 | case SND_SOC_DAIFMT_BP_FP: |
358 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; |
359 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; |
360 | sai->is_consumer_mode = false; |
361 | break; |
362 | case SND_SOC_DAIFMT_BC_FC: |
363 | sai->is_consumer_mode = true; |
364 | break; |
365 | case SND_SOC_DAIFMT_BP_FC: |
366 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; |
367 | sai->is_consumer_mode = false; |
368 | break; |
369 | case SND_SOC_DAIFMT_BC_FP: |
370 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; |
371 | sai->is_consumer_mode = true; |
372 | break; |
373 | default: |
374 | return -EINVAL; |
375 | } |
376 | |
377 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR2(tx, ofs), |
378 | FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val: val_cr2); |
379 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(tx, ofs), |
380 | FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE | |
381 | FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val: val_cr4); |
382 | |
383 | return 0; |
384 | } |
385 | |
386 | static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) |
387 | { |
388 | int ret; |
389 | |
390 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, tx: true); |
391 | if (ret) { |
392 | dev_err(cpu_dai->dev, "Cannot set tx format: %d\n" , ret); |
393 | return ret; |
394 | } |
395 | |
396 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, tx: false); |
397 | if (ret) |
398 | dev_err(cpu_dai->dev, "Cannot set rx format: %d\n" , ret); |
399 | |
400 | return ret; |
401 | } |
402 | |
403 | static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) |
404 | { |
405 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); |
406 | unsigned int reg, ofs = sai->soc_data->reg_offset; |
407 | unsigned long clk_rate; |
408 | u32 savediv = 0, ratio, bestdiff = freq; |
409 | int adir = tx ? RX : TX; |
410 | int dir = tx ? TX : RX; |
411 | u32 id; |
412 | bool support_1_1_ratio = sai->verid.version >= 0x0301; |
413 | |
414 | /* Don't apply to consumer mode */ |
415 | if (sai->is_consumer_mode) |
416 | return 0; |
417 | |
418 | /* |
419 | * There is no point in polling MCLK0 if it is identical to MCLK1. |
420 | * And given that MQS use case has to use MCLK1 though two clocks |
421 | * are the same, we simply skip MCLK0 and start to find from MCLK1. |
422 | */ |
423 | id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0; |
424 | |
425 | for (; id < FSL_SAI_MCLK_MAX; id++) { |
426 | int diff; |
427 | |
428 | clk_rate = clk_get_rate(clk: sai->mclk_clk[id]); |
429 | if (!clk_rate) |
430 | continue; |
431 | |
432 | ratio = DIV_ROUND_CLOSEST(clk_rate, freq); |
433 | if (!ratio || ratio > 512) |
434 | continue; |
435 | if (ratio == 1 && !support_1_1_ratio) |
436 | continue; |
437 | if ((ratio & 1) && ratio > 1) |
438 | continue; |
439 | |
440 | diff = abs((long)clk_rate - ratio * freq); |
441 | |
442 | /* |
443 | * Drop the source that can not be |
444 | * divided into the required rate. |
445 | */ |
446 | if (diff != 0 && clk_rate / diff < 1000) |
447 | continue; |
448 | |
449 | dev_dbg(dai->dev, |
450 | "ratio %d for freq %dHz based on clock %ldHz\n" , |
451 | ratio, freq, clk_rate); |
452 | |
453 | |
454 | if (diff < bestdiff) { |
455 | savediv = ratio; |
456 | sai->mclk_id[tx] = id; |
457 | bestdiff = diff; |
458 | } |
459 | |
460 | if (diff == 0) |
461 | break; |
462 | } |
463 | |
464 | if (savediv == 0) { |
465 | dev_err(dai->dev, "failed to derive required %cx rate: %d\n" , |
466 | tx ? 'T' : 'R', freq); |
467 | return -EINVAL; |
468 | } |
469 | |
470 | dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n" , |
471 | sai->mclk_id[tx], savediv, bestdiff); |
472 | |
473 | /* |
474 | * 1) For Asynchronous mode, we must set RCR2 register for capture, and |
475 | * set TCR2 register for playback. |
476 | * 2) For Tx sync with Rx clock, we must set RCR2 register for playback |
477 | * and capture. |
478 | * 3) For Rx sync with Tx clock, we must set TCR2 register for playback |
479 | * and capture. |
480 | * 4) For Tx and Rx are both Synchronous with another SAI, we just |
481 | * ignore it. |
482 | */ |
483 | if (fsl_sai_dir_is_synced(sai, dir: adir)) |
484 | reg = FSL_SAI_xCR2(!tx, ofs); |
485 | else if (!sai->synchronous[dir]) |
486 | reg = FSL_SAI_xCR2(tx, ofs); |
487 | else |
488 | return 0; |
489 | |
490 | regmap_update_bits(map: sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK, |
491 | FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); |
492 | |
493 | if (savediv == 1) { |
494 | regmap_update_bits(map: sai->regmap, reg, |
495 | FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, |
496 | FSL_SAI_CR2_BYP); |
497 | if (fsl_sai_dir_is_synced(sai, dir: adir)) |
498 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR2(tx, ofs), |
499 | FSL_SAI_CR2_BCI, FSL_SAI_CR2_BCI); |
500 | else |
501 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR2(tx, ofs), |
502 | FSL_SAI_CR2_BCI, val: 0); |
503 | } else { |
504 | regmap_update_bits(map: sai->regmap, reg, |
505 | FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, |
506 | val: savediv / 2 - 1); |
507 | } |
508 | |
509 | return 0; |
510 | } |
511 | |
512 | static int fsl_sai_hw_params(struct snd_pcm_substream *substream, |
513 | struct snd_pcm_hw_params *params, |
514 | struct snd_soc_dai *cpu_dai) |
515 | { |
516 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
517 | unsigned int ofs = sai->soc_data->reg_offset; |
518 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
519 | unsigned int channels = params_channels(p: params); |
520 | struct snd_dmaengine_dai_dma_data *dma_params; |
521 | struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg; |
522 | u32 word_width = params_width(p: params); |
523 | int trce_mask = 0, dl_cfg_idx = 0; |
524 | int dl_cfg_cnt = sai->dl_cfg_cnt; |
525 | u32 dl_type = FSL_SAI_DL_I2S; |
526 | u32 val_cr4 = 0, val_cr5 = 0; |
527 | u32 slots = (channels == 1) ? 2 : channels; |
528 | u32 slot_width = word_width; |
529 | int adir = tx ? RX : TX; |
530 | u32 pins, bclk; |
531 | u32 watermark; |
532 | int ret, i; |
533 | |
534 | if (sai->slot_width) |
535 | slot_width = sai->slot_width; |
536 | |
537 | if (sai->slots) |
538 | slots = sai->slots; |
539 | else if (sai->bclk_ratio) |
540 | slots = sai->bclk_ratio / slot_width; |
541 | |
542 | pins = DIV_ROUND_UP(channels, slots); |
543 | |
544 | /* |
545 | * PDM mode, channels are independent |
546 | * each channels are on one dataline/FIFO. |
547 | */ |
548 | if (sai->is_pdm_mode) { |
549 | pins = channels; |
550 | dl_type = FSL_SAI_DL_PDM; |
551 | } |
552 | |
553 | for (i = 0; i < dl_cfg_cnt; i++) { |
554 | if (dl_cfg[i].type == dl_type && dl_cfg[i].pins[tx] == pins) { |
555 | dl_cfg_idx = i; |
556 | break; |
557 | } |
558 | } |
559 | |
560 | if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) < pins) { |
561 | dev_err(cpu_dai->dev, "channel not supported\n" ); |
562 | return -EINVAL; |
563 | } |
564 | |
565 | bclk = params_rate(p: params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width); |
566 | |
567 | if (!IS_ERR_OR_NULL(ptr: sai->pinctrl)) { |
568 | sai->pins_state = fsl_sai_get_pins_state(sai, bclk); |
569 | if (!IS_ERR_OR_NULL(ptr: sai->pins_state)) { |
570 | ret = pinctrl_select_state(p: sai->pinctrl, s: sai->pins_state); |
571 | if (ret) { |
572 | dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n" , ret); |
573 | return ret; |
574 | } |
575 | } |
576 | } |
577 | |
578 | if (!sai->is_consumer_mode) { |
579 | ret = fsl_sai_set_bclk(dai: cpu_dai, tx, freq: bclk); |
580 | if (ret) |
581 | return ret; |
582 | |
583 | /* Do not enable the clock if it is already enabled */ |
584 | if (!(sai->mclk_streams & BIT(substream->stream))) { |
585 | ret = clk_prepare_enable(clk: sai->mclk_clk[sai->mclk_id[tx]]); |
586 | if (ret) |
587 | return ret; |
588 | |
589 | sai->mclk_streams |= BIT(substream->stream); |
590 | } |
591 | } |
592 | |
593 | if (!sai->is_dsp_mode && !sai->is_pdm_mode) |
594 | val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); |
595 | |
596 | val_cr5 |= FSL_SAI_CR5_WNW(slot_width); |
597 | val_cr5 |= FSL_SAI_CR5_W0W(slot_width); |
598 | |
599 | if (sai->is_lsb_first || sai->is_pdm_mode) |
600 | val_cr5 |= FSL_SAI_CR5_FBT(0); |
601 | else |
602 | val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); |
603 | |
604 | val_cr4 |= FSL_SAI_CR4_FRSZ(slots); |
605 | |
606 | /* Set to output mode to avoid tri-stated data pins */ |
607 | if (tx) |
608 | val_cr4 |= FSL_SAI_CR4_CHMOD; |
609 | |
610 | /* |
611 | * For SAI provider mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will |
612 | * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), |
613 | * RCR5(TCR5) for playback(capture), or there will be sync error. |
614 | */ |
615 | |
616 | if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, dir: adir)) { |
617 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(!tx, ofs), |
618 | FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | |
619 | FSL_SAI_CR4_CHMOD_MASK, |
620 | val: val_cr4); |
621 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR5(!tx, ofs), |
622 | FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | |
623 | FSL_SAI_CR5_FBT_MASK, val: val_cr5); |
624 | } |
625 | |
626 | /* |
627 | * Combine mode has limation: |
628 | * - Can't used for singel dataline/FIFO case except the FIFO0 |
629 | * - Can't used for multi dataline/FIFO case except the enabled FIFOs |
630 | * are successive and start from FIFO0 |
631 | * |
632 | * So for common usage, all multi fifo case disable the combine mode. |
633 | */ |
634 | if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1 || sai->is_multi_fifo_dma) |
635 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(tx, ofs), |
636 | FSL_SAI_CR4_FCOMB_MASK, val: 0); |
637 | else |
638 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(tx, ofs), |
639 | FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT); |
640 | |
641 | dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx; |
642 | dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + |
643 | dl_cfg[dl_cfg_idx].start_off[tx] * 0x4; |
644 | |
645 | if (sai->is_multi_fifo_dma) { |
646 | sai->audio_config[tx].words_per_fifo = min(slots, channels); |
647 | if (tx) { |
648 | sai->audio_config[tx].n_fifos_dst = pins; |
649 | sai->audio_config[tx].stride_fifos_dst = dl_cfg[dl_cfg_idx].next_off[tx]; |
650 | } else { |
651 | sai->audio_config[tx].n_fifos_src = pins; |
652 | sai->audio_config[tx].stride_fifos_src = dl_cfg[dl_cfg_idx].next_off[tx]; |
653 | } |
654 | dma_params->maxburst = sai->audio_config[tx].words_per_fifo * pins; |
655 | dma_params->peripheral_config = &sai->audio_config[tx]; |
656 | dma_params->peripheral_size = sizeof(sai->audio_config[tx]); |
657 | |
658 | watermark = tx ? (sai->soc_data->fifo_depth - dma_params->maxburst) : |
659 | (dma_params->maxburst - 1); |
660 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR1(tx, ofs), |
661 | FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), |
662 | val: watermark); |
663 | } |
664 | |
665 | /* Find a proper tcre setting */ |
666 | for (i = 0; i < sai->soc_data->pins; i++) { |
667 | trce_mask = (1 << (i + 1)) - 1; |
668 | if (hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins) |
669 | break; |
670 | } |
671 | |
672 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR3(tx, ofs), |
673 | FSL_SAI_CR3_TRCE_MASK, |
674 | FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask))); |
675 | |
676 | /* |
677 | * When the TERE and FSD_MSTR enabled before configuring the word width |
678 | * There will be no frame sync clock issue, because word width impact |
679 | * the generation of frame sync clock. |
680 | * |
681 | * TERE enabled earlier only for i.MX8MP case for the hardware limitation, |
682 | * We need to disable FSD_MSTR before configuring word width, then enable |
683 | * FSD_MSTR bit for this specific case. |
684 | */ |
685 | if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && |
686 | !sai->is_consumer_mode) |
687 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(tx, ofs), |
688 | FSL_SAI_CR4_FSD_MSTR, val: 0); |
689 | |
690 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(tx, ofs), |
691 | FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | |
692 | FSL_SAI_CR4_CHMOD_MASK, |
693 | val: val_cr4); |
694 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR5(tx, ofs), |
695 | FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | |
696 | FSL_SAI_CR5_FBT_MASK, val: val_cr5); |
697 | |
698 | /* Enable FSD_MSTR after configuring word width */ |
699 | if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && |
700 | !sai->is_consumer_mode) |
701 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR4(tx, ofs), |
702 | FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR); |
703 | |
704 | regmap_write(map: sai->regmap, FSL_SAI_xMR(tx), |
705 | val: ~0UL - ((1 << min(channels, slots)) - 1)); |
706 | |
707 | return 0; |
708 | } |
709 | |
710 | static int fsl_sai_hw_free(struct snd_pcm_substream *substream, |
711 | struct snd_soc_dai *cpu_dai) |
712 | { |
713 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
714 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
715 | unsigned int ofs = sai->soc_data->reg_offset; |
716 | |
717 | /* Clear xMR to avoid channel swap with mclk_with_tere enabled case */ |
718 | regmap_write(map: sai->regmap, FSL_SAI_xMR(tx), val: 0); |
719 | |
720 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCR3(tx, ofs), |
721 | FSL_SAI_CR3_TRCE_MASK, val: 0); |
722 | |
723 | if (!sai->is_consumer_mode && |
724 | sai->mclk_streams & BIT(substream->stream)) { |
725 | clk_disable_unprepare(clk: sai->mclk_clk[sai->mclk_id[tx]]); |
726 | sai->mclk_streams &= ~BIT(substream->stream); |
727 | } |
728 | |
729 | return 0; |
730 | } |
731 | |
732 | static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) |
733 | { |
734 | unsigned int ofs = sai->soc_data->reg_offset; |
735 | bool tx = dir == TX; |
736 | u32 xcsr, count = 100, mask; |
737 | |
738 | if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output) |
739 | mask = FSL_SAI_CSR_TERE; |
740 | else |
741 | mask = FSL_SAI_CSR_TERE | FSL_SAI_CSR_BCE; |
742 | |
743 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
744 | mask, val: 0); |
745 | |
746 | /* TERE will remain set till the end of current frame */ |
747 | do { |
748 | udelay(10); |
749 | regmap_read(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), val: &xcsr); |
750 | } while (--count && xcsr & FSL_SAI_CSR_TERE); |
751 | |
752 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
753 | FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); |
754 | |
755 | /* |
756 | * For sai master mode, after several open/close sai, |
757 | * there will be no frame clock, and can't recover |
758 | * anymore. Add software reset to fix this issue. |
759 | * This is a hardware bug, and will be fix in the |
760 | * next sai version. |
761 | */ |
762 | if (!sai->is_consumer_mode) { |
763 | /* Software Reset */ |
764 | regmap_write(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); |
765 | /* Clear SR bit to finish the reset */ |
766 | regmap_write(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), val: 0); |
767 | } |
768 | } |
769 | |
770 | static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, |
771 | struct snd_soc_dai *cpu_dai) |
772 | { |
773 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
774 | unsigned int ofs = sai->soc_data->reg_offset; |
775 | |
776 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
777 | int adir = tx ? RX : TX; |
778 | int dir = tx ? TX : RX; |
779 | u32 xcsr; |
780 | |
781 | /* |
782 | * Asynchronous mode: Clear SYNC for both Tx and Rx. |
783 | * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. |
784 | * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. |
785 | */ |
786 | regmap_update_bits(map: sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC, |
787 | val: sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); |
788 | regmap_update_bits(map: sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC, |
789 | val: sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); |
790 | |
791 | /* |
792 | * It is recommended that the transmitter is the last enabled |
793 | * and the first disabled. |
794 | */ |
795 | switch (cmd) { |
796 | case SNDRV_PCM_TRIGGER_START: |
797 | case SNDRV_PCM_TRIGGER_RESUME: |
798 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
799 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
800 | FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); |
801 | |
802 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
803 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); |
804 | /* |
805 | * Enable the opposite direction for synchronous mode |
806 | * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx |
807 | * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx |
808 | * |
809 | * RM recommends to enable RE after TE for case 1 and to enable |
810 | * TE after RE for case 2, but we here may not always guarantee |
811 | * that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables |
812 | * TE after RE, which is against what RM recommends but should |
813 | * be safe to do, judging by years of testing results. |
814 | */ |
815 | if (fsl_sai_dir_is_synced(sai, dir: adir)) |
816 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR((!tx), ofs), |
817 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); |
818 | |
819 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
820 | FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); |
821 | break; |
822 | case SNDRV_PCM_TRIGGER_STOP: |
823 | case SNDRV_PCM_TRIGGER_SUSPEND: |
824 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
825 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
826 | FSL_SAI_CSR_FRDE, val: 0); |
827 | regmap_update_bits(map: sai->regmap, FSL_SAI_xCSR(tx, ofs), |
828 | FSL_SAI_CSR_xIE_MASK, val: 0); |
829 | |
830 | /* Check if the opposite FRDE is also disabled */ |
831 | regmap_read(map: sai->regmap, FSL_SAI_xCSR(!tx, ofs), val: &xcsr); |
832 | |
833 | /* |
834 | * If opposite stream provides clocks for synchronous mode and |
835 | * it is inactive, disable it before disabling the current one |
836 | */ |
837 | if (fsl_sai_dir_is_synced(sai, dir: adir) && !(xcsr & FSL_SAI_CSR_FRDE)) |
838 | fsl_sai_config_disable(sai, dir: adir); |
839 | |
840 | /* |
841 | * Disable current stream if either of: |
842 | * 1. current stream doesn't provide clocks for synchronous mode |
843 | * 2. current stream provides clocks for synchronous mode but no |
844 | * more stream is active. |
845 | */ |
846 | if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE)) |
847 | fsl_sai_config_disable(sai, dir); |
848 | |
849 | break; |
850 | default: |
851 | return -EINVAL; |
852 | } |
853 | |
854 | return 0; |
855 | } |
856 | |
857 | static int fsl_sai_startup(struct snd_pcm_substream *substream, |
858 | struct snd_soc_dai *cpu_dai) |
859 | { |
860 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai: cpu_dai); |
861 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
862 | int ret; |
863 | |
864 | /* |
865 | * EDMA controller needs period size to be a multiple of |
866 | * tx/rx maxburst |
867 | */ |
868 | if (sai->soc_data->use_edma) |
869 | snd_pcm_hw_constraint_step(runtime: substream->runtime, cond: 0, |
870 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
871 | step: tx ? sai->dma_params_tx.maxburst : |
872 | sai->dma_params_rx.maxburst); |
873 | |
874 | ret = snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0, |
875 | SNDRV_PCM_HW_PARAM_RATE, l: &fsl_sai_rate_constraints); |
876 | |
877 | return ret; |
878 | } |
879 | |
880 | static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) |
881 | { |
882 | struct fsl_sai *sai = dev_get_drvdata(dev: cpu_dai->dev); |
883 | unsigned int ofs = sai->soc_data->reg_offset; |
884 | |
885 | /* Software Reset for both Tx and Rx */ |
886 | regmap_write(map: sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); |
887 | regmap_write(map: sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); |
888 | /* Clear SR bit to finish the reset */ |
889 | regmap_write(map: sai->regmap, FSL_SAI_TCSR(ofs), val: 0); |
890 | regmap_write(map: sai->regmap, FSL_SAI_RCSR(ofs), val: 0); |
891 | |
892 | regmap_update_bits(map: sai->regmap, FSL_SAI_TCR1(ofs), |
893 | FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), |
894 | val: sai->soc_data->fifo_depth - sai->dma_params_tx.maxburst); |
895 | regmap_update_bits(map: sai->regmap, FSL_SAI_RCR1(ofs), |
896 | FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), |
897 | val: sai->dma_params_rx.maxburst - 1); |
898 | |
899 | snd_soc_dai_init_dma_data(dai: cpu_dai, playback: &sai->dma_params_tx, |
900 | capture: &sai->dma_params_rx); |
901 | |
902 | return 0; |
903 | } |
904 | |
905 | static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { |
906 | .probe = fsl_sai_dai_probe, |
907 | .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, |
908 | .set_sysclk = fsl_sai_set_dai_sysclk, |
909 | .set_fmt = fsl_sai_set_dai_fmt, |
910 | .set_tdm_slot = fsl_sai_set_dai_tdm_slot, |
911 | .hw_params = fsl_sai_hw_params, |
912 | .hw_free = fsl_sai_hw_free, |
913 | .trigger = fsl_sai_trigger, |
914 | .startup = fsl_sai_startup, |
915 | }; |
916 | |
917 | static int fsl_sai_dai_resume(struct snd_soc_component *component) |
918 | { |
919 | struct fsl_sai *sai = snd_soc_component_get_drvdata(c: component); |
920 | struct device *dev = &sai->pdev->dev; |
921 | int ret; |
922 | |
923 | if (!IS_ERR_OR_NULL(ptr: sai->pinctrl) && !IS_ERR_OR_NULL(ptr: sai->pins_state)) { |
924 | ret = pinctrl_select_state(p: sai->pinctrl, s: sai->pins_state); |
925 | if (ret) { |
926 | dev_err(dev, "failed to set proper pins state: %d\n" , ret); |
927 | return ret; |
928 | } |
929 | } |
930 | |
931 | return 0; |
932 | } |
933 | |
934 | static struct snd_soc_dai_driver fsl_sai_dai_template = { |
935 | .playback = { |
936 | .stream_name = "CPU-Playback" , |
937 | .channels_min = 1, |
938 | .channels_max = 32, |
939 | .rate_min = 8000, |
940 | .rate_max = 2822400, |
941 | .rates = SNDRV_PCM_RATE_KNOT, |
942 | .formats = FSL_SAI_FORMATS, |
943 | }, |
944 | .capture = { |
945 | .stream_name = "CPU-Capture" , |
946 | .channels_min = 1, |
947 | .channels_max = 32, |
948 | .rate_min = 8000, |
949 | .rate_max = 2822400, |
950 | .rates = SNDRV_PCM_RATE_KNOT, |
951 | .formats = FSL_SAI_FORMATS, |
952 | }, |
953 | .ops = &fsl_sai_pcm_dai_ops, |
954 | }; |
955 | |
956 | static const struct snd_soc_component_driver fsl_component = { |
957 | .name = "fsl-sai" , |
958 | .resume = fsl_sai_dai_resume, |
959 | .legacy_dai_naming = 1, |
960 | }; |
961 | |
962 | static struct reg_default fsl_sai_reg_defaults_ofs0[] = { |
963 | {FSL_SAI_TCR1(0), 0}, |
964 | {FSL_SAI_TCR2(0), 0}, |
965 | {FSL_SAI_TCR3(0), 0}, |
966 | {FSL_SAI_TCR4(0), 0}, |
967 | {FSL_SAI_TCR5(0), 0}, |
968 | {FSL_SAI_TDR0, 0}, |
969 | {FSL_SAI_TDR1, 0}, |
970 | {FSL_SAI_TDR2, 0}, |
971 | {FSL_SAI_TDR3, 0}, |
972 | {FSL_SAI_TDR4, 0}, |
973 | {FSL_SAI_TDR5, 0}, |
974 | {FSL_SAI_TDR6, 0}, |
975 | {FSL_SAI_TDR7, 0}, |
976 | {FSL_SAI_TMR, 0}, |
977 | {FSL_SAI_RCR1(0), 0}, |
978 | {FSL_SAI_RCR2(0), 0}, |
979 | {FSL_SAI_RCR3(0), 0}, |
980 | {FSL_SAI_RCR4(0), 0}, |
981 | {FSL_SAI_RCR5(0), 0}, |
982 | {FSL_SAI_RMR, 0}, |
983 | }; |
984 | |
985 | static struct reg_default fsl_sai_reg_defaults_ofs8[] = { |
986 | {FSL_SAI_TCR1(8), 0}, |
987 | {FSL_SAI_TCR2(8), 0}, |
988 | {FSL_SAI_TCR3(8), 0}, |
989 | {FSL_SAI_TCR4(8), 0}, |
990 | {FSL_SAI_TCR5(8), 0}, |
991 | {FSL_SAI_TDR0, 0}, |
992 | {FSL_SAI_TDR1, 0}, |
993 | {FSL_SAI_TDR2, 0}, |
994 | {FSL_SAI_TDR3, 0}, |
995 | {FSL_SAI_TDR4, 0}, |
996 | {FSL_SAI_TDR5, 0}, |
997 | {FSL_SAI_TDR6, 0}, |
998 | {FSL_SAI_TDR7, 0}, |
999 | {FSL_SAI_TMR, 0}, |
1000 | {FSL_SAI_RCR1(8), 0}, |
1001 | {FSL_SAI_RCR2(8), 0}, |
1002 | {FSL_SAI_RCR3(8), 0}, |
1003 | {FSL_SAI_RCR4(8), 0}, |
1004 | {FSL_SAI_RCR5(8), 0}, |
1005 | {FSL_SAI_RMR, 0}, |
1006 | {FSL_SAI_MCTL, 0}, |
1007 | {FSL_SAI_MDIV, 0}, |
1008 | }; |
1009 | |
1010 | static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) |
1011 | { |
1012 | struct fsl_sai *sai = dev_get_drvdata(dev); |
1013 | unsigned int ofs = sai->soc_data->reg_offset; |
1014 | |
1015 | if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs)) |
1016 | return true; |
1017 | |
1018 | if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs)) |
1019 | return true; |
1020 | |
1021 | switch (reg) { |
1022 | case FSL_SAI_TFR0: |
1023 | case FSL_SAI_TFR1: |
1024 | case FSL_SAI_TFR2: |
1025 | case FSL_SAI_TFR3: |
1026 | case FSL_SAI_TFR4: |
1027 | case FSL_SAI_TFR5: |
1028 | case FSL_SAI_TFR6: |
1029 | case FSL_SAI_TFR7: |
1030 | case FSL_SAI_TMR: |
1031 | case FSL_SAI_RDR0: |
1032 | case FSL_SAI_RDR1: |
1033 | case FSL_SAI_RDR2: |
1034 | case FSL_SAI_RDR3: |
1035 | case FSL_SAI_RDR4: |
1036 | case FSL_SAI_RDR5: |
1037 | case FSL_SAI_RDR6: |
1038 | case FSL_SAI_RDR7: |
1039 | case FSL_SAI_RFR0: |
1040 | case FSL_SAI_RFR1: |
1041 | case FSL_SAI_RFR2: |
1042 | case FSL_SAI_RFR3: |
1043 | case FSL_SAI_RFR4: |
1044 | case FSL_SAI_RFR5: |
1045 | case FSL_SAI_RFR6: |
1046 | case FSL_SAI_RFR7: |
1047 | case FSL_SAI_RMR: |
1048 | case FSL_SAI_MCTL: |
1049 | case FSL_SAI_MDIV: |
1050 | case FSL_SAI_VERID: |
1051 | case FSL_SAI_PARAM: |
1052 | case FSL_SAI_TTCTN: |
1053 | case FSL_SAI_RTCTN: |
1054 | case FSL_SAI_TTCTL: |
1055 | case FSL_SAI_TBCTN: |
1056 | case FSL_SAI_TTCAP: |
1057 | case FSL_SAI_RTCTL: |
1058 | case FSL_SAI_RBCTN: |
1059 | case FSL_SAI_RTCAP: |
1060 | return true; |
1061 | default: |
1062 | return false; |
1063 | } |
1064 | } |
1065 | |
1066 | static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) |
1067 | { |
1068 | struct fsl_sai *sai = dev_get_drvdata(dev); |
1069 | unsigned int ofs = sai->soc_data->reg_offset; |
1070 | |
1071 | if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs)) |
1072 | return true; |
1073 | |
1074 | /* Set VERID and PARAM be volatile for reading value in probe */ |
1075 | if (ofs == 8 && (reg == FSL_SAI_VERID || reg == FSL_SAI_PARAM)) |
1076 | return true; |
1077 | |
1078 | switch (reg) { |
1079 | case FSL_SAI_TFR0: |
1080 | case FSL_SAI_TFR1: |
1081 | case FSL_SAI_TFR2: |
1082 | case FSL_SAI_TFR3: |
1083 | case FSL_SAI_TFR4: |
1084 | case FSL_SAI_TFR5: |
1085 | case FSL_SAI_TFR6: |
1086 | case FSL_SAI_TFR7: |
1087 | case FSL_SAI_RFR0: |
1088 | case FSL_SAI_RFR1: |
1089 | case FSL_SAI_RFR2: |
1090 | case FSL_SAI_RFR3: |
1091 | case FSL_SAI_RFR4: |
1092 | case FSL_SAI_RFR5: |
1093 | case FSL_SAI_RFR6: |
1094 | case FSL_SAI_RFR7: |
1095 | case FSL_SAI_RDR0: |
1096 | case FSL_SAI_RDR1: |
1097 | case FSL_SAI_RDR2: |
1098 | case FSL_SAI_RDR3: |
1099 | case FSL_SAI_RDR4: |
1100 | case FSL_SAI_RDR5: |
1101 | case FSL_SAI_RDR6: |
1102 | case FSL_SAI_RDR7: |
1103 | return true; |
1104 | default: |
1105 | return false; |
1106 | } |
1107 | } |
1108 | |
1109 | static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) |
1110 | { |
1111 | struct fsl_sai *sai = dev_get_drvdata(dev); |
1112 | unsigned int ofs = sai->soc_data->reg_offset; |
1113 | |
1114 | if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs)) |
1115 | return true; |
1116 | |
1117 | if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs)) |
1118 | return true; |
1119 | |
1120 | switch (reg) { |
1121 | case FSL_SAI_TDR0: |
1122 | case FSL_SAI_TDR1: |
1123 | case FSL_SAI_TDR2: |
1124 | case FSL_SAI_TDR3: |
1125 | case FSL_SAI_TDR4: |
1126 | case FSL_SAI_TDR5: |
1127 | case FSL_SAI_TDR6: |
1128 | case FSL_SAI_TDR7: |
1129 | case FSL_SAI_TMR: |
1130 | case FSL_SAI_RMR: |
1131 | case FSL_SAI_MCTL: |
1132 | case FSL_SAI_MDIV: |
1133 | case FSL_SAI_TTCTL: |
1134 | case FSL_SAI_RTCTL: |
1135 | return true; |
1136 | default: |
1137 | return false; |
1138 | } |
1139 | } |
1140 | |
1141 | static struct regmap_config fsl_sai_regmap_config = { |
1142 | .reg_bits = 32, |
1143 | .reg_stride = 4, |
1144 | .val_bits = 32, |
1145 | .fast_io = true, |
1146 | |
1147 | .max_register = FSL_SAI_RMR, |
1148 | .reg_defaults = fsl_sai_reg_defaults_ofs0, |
1149 | .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0), |
1150 | .readable_reg = fsl_sai_readable_reg, |
1151 | .volatile_reg = fsl_sai_volatile_reg, |
1152 | .writeable_reg = fsl_sai_writeable_reg, |
1153 | .cache_type = REGCACHE_FLAT, |
1154 | }; |
1155 | |
1156 | static int fsl_sai_check_version(struct device *dev) |
1157 | { |
1158 | struct fsl_sai *sai = dev_get_drvdata(dev); |
1159 | unsigned char ofs = sai->soc_data->reg_offset; |
1160 | unsigned int val; |
1161 | int ret; |
1162 | |
1163 | if (FSL_SAI_TCSR(ofs) == FSL_SAI_VERID) |
1164 | return 0; |
1165 | |
1166 | ret = regmap_read(map: sai->regmap, FSL_SAI_VERID, val: &val); |
1167 | if (ret < 0) |
1168 | return ret; |
1169 | |
1170 | dev_dbg(dev, "VERID: 0x%016X\n" , val); |
1171 | |
1172 | sai->verid.version = val & |
1173 | (FSL_SAI_VERID_MAJOR_MASK | FSL_SAI_VERID_MINOR_MASK); |
1174 | sai->verid.version >>= FSL_SAI_VERID_MINOR_SHIFT; |
1175 | sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK; |
1176 | |
1177 | ret = regmap_read(map: sai->regmap, FSL_SAI_PARAM, val: &val); |
1178 | if (ret < 0) |
1179 | return ret; |
1180 | |
1181 | dev_dbg(dev, "PARAM: 0x%016X\n" , val); |
1182 | |
1183 | /* Max slots per frame, power of 2 */ |
1184 | sai->param.slot_num = 1 << |
1185 | ((val & FSL_SAI_PARAM_SPF_MASK) >> FSL_SAI_PARAM_SPF_SHIFT); |
1186 | |
1187 | /* Words per fifo, power of 2 */ |
1188 | sai->param.fifo_depth = 1 << |
1189 | ((val & FSL_SAI_PARAM_WPF_MASK) >> FSL_SAI_PARAM_WPF_SHIFT); |
1190 | |
1191 | /* Number of datalines implemented */ |
1192 | sai->param.dataline = val & FSL_SAI_PARAM_DLN_MASK; |
1193 | |
1194 | return 0; |
1195 | } |
1196 | |
1197 | /* |
1198 | * Calculate the offset between first two datalines, don't |
1199 | * different offset in one case. |
1200 | */ |
1201 | static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask) |
1202 | { |
1203 | int fbidx, nbidx, offset; |
1204 | |
1205 | fbidx = find_first_bit(addr: &dl_mask, FSL_SAI_DL_NUM); |
1206 | nbidx = find_next_bit(addr: &dl_mask, FSL_SAI_DL_NUM, offset: fbidx + 1); |
1207 | offset = nbidx - fbidx - 1; |
1208 | |
1209 | return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset); |
1210 | } |
1211 | |
1212 | /* |
1213 | * read the fsl,dataline property from dts file. |
1214 | * It has 3 value for each configuration, first one means the type: |
1215 | * I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is |
1216 | * dataline mask for 'tx'. for example |
1217 | * |
1218 | * fsl,dataline = <1 0xff 0xff 2 0xff 0x11>, |
1219 | * |
1220 | * It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type |
1221 | * rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled). |
1222 | * |
1223 | */ |
1224 | static int fsl_sai_read_dlcfg(struct fsl_sai *sai) |
1225 | { |
1226 | struct platform_device *pdev = sai->pdev; |
1227 | struct device_node *np = pdev->dev.of_node; |
1228 | struct device *dev = &pdev->dev; |
1229 | int ret, elems, i, index, num_cfg; |
1230 | char *propname = "fsl,dataline" ; |
1231 | struct fsl_sai_dl_cfg *cfg; |
1232 | unsigned long dl_mask; |
1233 | unsigned int soc_dl; |
1234 | u32 rx, tx, type; |
1235 | |
1236 | elems = of_property_count_u32_elems(np, propname); |
1237 | |
1238 | if (elems <= 0) { |
1239 | elems = 0; |
1240 | } else if (elems % 3) { |
1241 | dev_err(dev, "Number of elements must be divisible to 3.\n" ); |
1242 | return -EINVAL; |
1243 | } |
1244 | |
1245 | num_cfg = elems / 3; |
1246 | /* Add one more for default value */ |
1247 | cfg = devm_kzalloc(dev: &pdev->dev, size: (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL); |
1248 | if (!cfg) |
1249 | return -ENOMEM; |
1250 | |
1251 | /* Consider default value "0 0xFF 0xFF" if property is missing */ |
1252 | soc_dl = BIT(sai->soc_data->pins) - 1; |
1253 | cfg[0].type = FSL_SAI_DL_DEFAULT; |
1254 | cfg[0].pins[0] = sai->soc_data->pins; |
1255 | cfg[0].mask[0] = soc_dl; |
1256 | cfg[0].start_off[0] = 0; |
1257 | cfg[0].next_off[0] = 0; |
1258 | |
1259 | cfg[0].pins[1] = sai->soc_data->pins; |
1260 | cfg[0].mask[1] = soc_dl; |
1261 | cfg[0].start_off[1] = 0; |
1262 | cfg[0].next_off[1] = 0; |
1263 | for (i = 1, index = 0; i < num_cfg + 1; i++) { |
1264 | /* |
1265 | * type of dataline |
1266 | * 0 means default mode |
1267 | * 1 means I2S mode |
1268 | * 2 means PDM mode |
1269 | */ |
1270 | ret = of_property_read_u32_index(np, propname, index: index++, out_value: &type); |
1271 | if (ret) |
1272 | return -EINVAL; |
1273 | |
1274 | ret = of_property_read_u32_index(np, propname, index: index++, out_value: &rx); |
1275 | if (ret) |
1276 | return -EINVAL; |
1277 | |
1278 | ret = of_property_read_u32_index(np, propname, index: index++, out_value: &tx); |
1279 | if (ret) |
1280 | return -EINVAL; |
1281 | |
1282 | if ((rx & ~soc_dl) || (tx & ~soc_dl)) { |
1283 | dev_err(dev, "dataline cfg[%d] setting error, mask is 0x%x\n" , i, soc_dl); |
1284 | return -EINVAL; |
1285 | } |
1286 | |
1287 | rx = rx & soc_dl; |
1288 | tx = tx & soc_dl; |
1289 | |
1290 | cfg[i].type = type; |
1291 | cfg[i].pins[0] = hweight8(rx); |
1292 | cfg[i].mask[0] = rx; |
1293 | dl_mask = rx; |
1294 | cfg[i].start_off[0] = find_first_bit(addr: &dl_mask, FSL_SAI_DL_NUM); |
1295 | cfg[i].next_off[0] = fsl_sai_calc_dl_off(dl_mask: rx); |
1296 | |
1297 | cfg[i].pins[1] = hweight8(tx); |
1298 | cfg[i].mask[1] = tx; |
1299 | dl_mask = tx; |
1300 | cfg[i].start_off[1] = find_first_bit(addr: &dl_mask, FSL_SAI_DL_NUM); |
1301 | cfg[i].next_off[1] = fsl_sai_calc_dl_off(dl_mask: tx); |
1302 | } |
1303 | |
1304 | sai->dl_cfg = cfg; |
1305 | sai->dl_cfg_cnt = num_cfg + 1; |
1306 | return 0; |
1307 | } |
1308 | |
1309 | static int fsl_sai_runtime_suspend(struct device *dev); |
1310 | static int fsl_sai_runtime_resume(struct device *dev); |
1311 | |
1312 | static int fsl_sai_probe(struct platform_device *pdev) |
1313 | { |
1314 | struct device_node *np = pdev->dev.of_node; |
1315 | struct device *dev = &pdev->dev; |
1316 | struct fsl_sai *sai; |
1317 | struct regmap *gpr; |
1318 | void __iomem *base; |
1319 | char tmp[8]; |
1320 | int irq, ret, i; |
1321 | int index; |
1322 | u32 dmas[4]; |
1323 | |
1324 | sai = devm_kzalloc(dev, size: sizeof(*sai), GFP_KERNEL); |
1325 | if (!sai) |
1326 | return -ENOMEM; |
1327 | |
1328 | sai->pdev = pdev; |
1329 | sai->soc_data = of_device_get_match_data(dev); |
1330 | |
1331 | sai->is_lsb_first = of_property_read_bool(np, propname: "lsb-first" ); |
1332 | |
1333 | base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &sai->res); |
1334 | if (IS_ERR(ptr: base)) |
1335 | return PTR_ERR(ptr: base); |
1336 | |
1337 | if (sai->soc_data->reg_offset == 8) { |
1338 | fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8; |
1339 | fsl_sai_regmap_config.max_register = FSL_SAI_MDIV; |
1340 | fsl_sai_regmap_config.num_reg_defaults = |
1341 | ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); |
1342 | } |
1343 | |
1344 | sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config); |
1345 | if (IS_ERR(ptr: sai->regmap)) { |
1346 | dev_err(dev, "regmap init failed\n" ); |
1347 | return PTR_ERR(ptr: sai->regmap); |
1348 | } |
1349 | |
1350 | sai->bus_clk = devm_clk_get(dev, id: "bus" ); |
1351 | /* Compatible with old DTB cases */ |
1352 | if (IS_ERR(ptr: sai->bus_clk) && PTR_ERR(ptr: sai->bus_clk) != -EPROBE_DEFER) |
1353 | sai->bus_clk = devm_clk_get(dev, id: "sai" ); |
1354 | if (IS_ERR(ptr: sai->bus_clk)) { |
1355 | dev_err(dev, "failed to get bus clock: %ld\n" , |
1356 | PTR_ERR(sai->bus_clk)); |
1357 | /* -EPROBE_DEFER */ |
1358 | return PTR_ERR(ptr: sai->bus_clk); |
1359 | } |
1360 | |
1361 | for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { |
1362 | sprintf(buf: tmp, fmt: "mclk%d" , i); |
1363 | sai->mclk_clk[i] = devm_clk_get(dev, id: tmp); |
1364 | if (IS_ERR(ptr: sai->mclk_clk[i])) { |
1365 | dev_err(dev, "failed to get mclk%d clock: %ld\n" , |
1366 | i, PTR_ERR(sai->mclk_clk[i])); |
1367 | sai->mclk_clk[i] = NULL; |
1368 | } |
1369 | } |
1370 | |
1371 | if (sai->soc_data->mclk0_is_mclk1) |
1372 | sai->mclk_clk[0] = sai->mclk_clk[1]; |
1373 | else |
1374 | sai->mclk_clk[0] = sai->bus_clk; |
1375 | |
1376 | fsl_asoc_get_pll_clocks(dev: &pdev->dev, pll8k_clk: &sai->pll8k_clk, |
1377 | pll11k_clk: &sai->pll11k_clk); |
1378 | |
1379 | /* Use Multi FIFO mode depending on the support from SDMA script */ |
1380 | ret = of_property_read_u32_array(np, propname: "dmas" , out_values: dmas, sz: 4); |
1381 | if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI) |
1382 | sai->is_multi_fifo_dma = true; |
1383 | |
1384 | /* read dataline mask for rx and tx*/ |
1385 | ret = fsl_sai_read_dlcfg(sai); |
1386 | if (ret < 0) { |
1387 | dev_err(dev, "failed to read dlcfg %d\n" , ret); |
1388 | return ret; |
1389 | } |
1390 | |
1391 | irq = platform_get_irq(pdev, 0); |
1392 | if (irq < 0) |
1393 | return irq; |
1394 | |
1395 | ret = devm_request_irq(dev, irq, handler: fsl_sai_isr, IRQF_SHARED, |
1396 | devname: np->name, dev_id: sai); |
1397 | if (ret) { |
1398 | dev_err(dev, "failed to claim irq %u\n" , irq); |
1399 | return ret; |
1400 | } |
1401 | |
1402 | memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, |
1403 | sizeof(fsl_sai_dai_template)); |
1404 | |
1405 | /* Sync Tx with Rx as default by following old DT binding */ |
1406 | sai->synchronous[RX] = true; |
1407 | sai->synchronous[TX] = false; |
1408 | sai->cpu_dai_drv.symmetric_rate = 1; |
1409 | sai->cpu_dai_drv.symmetric_channels = 1; |
1410 | sai->cpu_dai_drv.symmetric_sample_bits = 1; |
1411 | |
1412 | if (of_property_read_bool(np, propname: "fsl,sai-synchronous-rx" ) && |
1413 | of_property_read_bool(np, propname: "fsl,sai-asynchronous" )) { |
1414 | /* error out if both synchronous and asynchronous are present */ |
1415 | dev_err(dev, "invalid binding for synchronous mode\n" ); |
1416 | return -EINVAL; |
1417 | } |
1418 | |
1419 | if (of_property_read_bool(np, propname: "fsl,sai-synchronous-rx" )) { |
1420 | /* Sync Rx with Tx */ |
1421 | sai->synchronous[RX] = false; |
1422 | sai->synchronous[TX] = true; |
1423 | } else if (of_property_read_bool(np, propname: "fsl,sai-asynchronous" )) { |
1424 | /* Discard all settings for asynchronous mode */ |
1425 | sai->synchronous[RX] = false; |
1426 | sai->synchronous[TX] = false; |
1427 | sai->cpu_dai_drv.symmetric_rate = 0; |
1428 | sai->cpu_dai_drv.symmetric_channels = 0; |
1429 | sai->cpu_dai_drv.symmetric_sample_bits = 0; |
1430 | } |
1431 | |
1432 | sai->mclk_direction_output = of_property_read_bool(np, propname: "fsl,sai-mclk-direction-output" ); |
1433 | |
1434 | if (sai->mclk_direction_output && |
1435 | of_device_is_compatible(device: np, "fsl,imx6ul-sai" )) { |
1436 | gpr = syscon_regmap_lookup_by_compatible(s: "fsl,imx6ul-iomuxc-gpr" ); |
1437 | if (IS_ERR(ptr: gpr)) { |
1438 | dev_err(dev, "cannot find iomuxc registers\n" ); |
1439 | return PTR_ERR(ptr: gpr); |
1440 | } |
1441 | |
1442 | index = of_alias_get_id(np, stem: "sai" ); |
1443 | if (index < 0) |
1444 | return index; |
1445 | |
1446 | regmap_update_bits(map: gpr, IOMUXC_GPR1, MCLK_DIR(index), |
1447 | MCLK_DIR(index)); |
1448 | } |
1449 | |
1450 | sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0; |
1451 | sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0; |
1452 | sai->dma_params_rx.maxburst = |
1453 | sai->soc_data->max_burst[RX] ? sai->soc_data->max_burst[RX] : FSL_SAI_MAXBURST_RX; |
1454 | sai->dma_params_tx.maxburst = |
1455 | sai->soc_data->max_burst[TX] ? sai->soc_data->max_burst[TX] : FSL_SAI_MAXBURST_TX; |
1456 | |
1457 | sai->pinctrl = devm_pinctrl_get(dev: &pdev->dev); |
1458 | |
1459 | platform_set_drvdata(pdev, data: sai); |
1460 | pm_runtime_enable(dev); |
1461 | if (!pm_runtime_enabled(dev)) { |
1462 | ret = fsl_sai_runtime_resume(dev); |
1463 | if (ret) |
1464 | goto err_pm_disable; |
1465 | } |
1466 | |
1467 | ret = pm_runtime_resume_and_get(dev); |
1468 | if (ret < 0) |
1469 | goto err_pm_get_sync; |
1470 | |
1471 | /* Get sai version */ |
1472 | ret = fsl_sai_check_version(dev); |
1473 | if (ret < 0) |
1474 | dev_warn(dev, "Error reading SAI version: %d\n" , ret); |
1475 | |
1476 | /* Select MCLK direction */ |
1477 | if (sai->mclk_direction_output && |
1478 | sai->soc_data->max_register >= FSL_SAI_MCTL) { |
1479 | regmap_update_bits(map: sai->regmap, FSL_SAI_MCTL, |
1480 | FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); |
1481 | } |
1482 | |
1483 | ret = pm_runtime_put_sync(dev); |
1484 | if (ret < 0 && ret != -ENOSYS) |
1485 | goto err_pm_get_sync; |
1486 | |
1487 | /* |
1488 | * Register platform component before registering cpu dai for there |
1489 | * is not defer probe for platform component in snd_soc_add_pcm_runtime(). |
1490 | */ |
1491 | if (sai->soc_data->use_imx_pcm) { |
1492 | ret = imx_pcm_dma_init(pdev); |
1493 | if (ret) { |
1494 | dev_err_probe(dev, err: ret, fmt: "PCM DMA init failed\n" ); |
1495 | if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)) |
1496 | dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n" ); |
1497 | goto err_pm_get_sync; |
1498 | } |
1499 | } else { |
1500 | ret = devm_snd_dmaengine_pcm_register(dev, NULL, flags: 0); |
1501 | if (ret) { |
1502 | dev_err_probe(dev, err: ret, fmt: "Registering PCM dmaengine failed\n" ); |
1503 | goto err_pm_get_sync; |
1504 | } |
1505 | } |
1506 | |
1507 | ret = devm_snd_soc_register_component(dev, component_driver: &fsl_component, |
1508 | dai_drv: &sai->cpu_dai_drv, num_dai: 1); |
1509 | if (ret) |
1510 | goto err_pm_get_sync; |
1511 | |
1512 | return ret; |
1513 | |
1514 | err_pm_get_sync: |
1515 | if (!pm_runtime_status_suspended(dev)) |
1516 | fsl_sai_runtime_suspend(dev); |
1517 | err_pm_disable: |
1518 | pm_runtime_disable(dev); |
1519 | |
1520 | return ret; |
1521 | } |
1522 | |
1523 | static void fsl_sai_remove(struct platform_device *pdev) |
1524 | { |
1525 | pm_runtime_disable(dev: &pdev->dev); |
1526 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
1527 | fsl_sai_runtime_suspend(dev: &pdev->dev); |
1528 | } |
1529 | |
1530 | static const struct fsl_sai_soc_data fsl_sai_vf610_data = { |
1531 | .use_imx_pcm = false, |
1532 | .use_edma = false, |
1533 | .fifo_depth = 32, |
1534 | .pins = 1, |
1535 | .reg_offset = 0, |
1536 | .mclk0_is_mclk1 = false, |
1537 | .flags = 0, |
1538 | .max_register = FSL_SAI_RMR, |
1539 | }; |
1540 | |
1541 | static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { |
1542 | .use_imx_pcm = true, |
1543 | .use_edma = false, |
1544 | .fifo_depth = 32, |
1545 | .pins = 1, |
1546 | .reg_offset = 0, |
1547 | .mclk0_is_mclk1 = true, |
1548 | .flags = 0, |
1549 | .max_register = FSL_SAI_RMR, |
1550 | }; |
1551 | |
1552 | static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { |
1553 | .use_imx_pcm = true, |
1554 | .use_edma = false, |
1555 | .fifo_depth = 16, |
1556 | .pins = 2, |
1557 | .reg_offset = 8, |
1558 | .mclk0_is_mclk1 = false, |
1559 | .flags = PMQOS_CPU_LATENCY, |
1560 | .max_register = FSL_SAI_RMR, |
1561 | }; |
1562 | |
1563 | static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { |
1564 | .use_imx_pcm = true, |
1565 | .use_edma = false, |
1566 | .fifo_depth = 128, |
1567 | .pins = 8, |
1568 | .reg_offset = 8, |
1569 | .mclk0_is_mclk1 = false, |
1570 | .flags = 0, |
1571 | .max_register = FSL_SAI_RMR, |
1572 | }; |
1573 | |
1574 | static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { |
1575 | .use_imx_pcm = true, |
1576 | .use_edma = true, |
1577 | .fifo_depth = 64, |
1578 | .pins = 4, |
1579 | .reg_offset = 0, |
1580 | .mclk0_is_mclk1 = false, |
1581 | .flags = 0, |
1582 | .max_register = FSL_SAI_RMR, |
1583 | }; |
1584 | |
1585 | static const struct fsl_sai_soc_data fsl_sai_imx8mm_data = { |
1586 | .use_imx_pcm = true, |
1587 | .use_edma = false, |
1588 | .fifo_depth = 128, |
1589 | .reg_offset = 8, |
1590 | .mclk0_is_mclk1 = false, |
1591 | .pins = 8, |
1592 | .flags = 0, |
1593 | .max_register = FSL_SAI_MCTL, |
1594 | }; |
1595 | |
1596 | static const struct fsl_sai_soc_data fsl_sai_imx8mn_data = { |
1597 | .use_imx_pcm = true, |
1598 | .use_edma = false, |
1599 | .fifo_depth = 128, |
1600 | .reg_offset = 8, |
1601 | .mclk0_is_mclk1 = false, |
1602 | .pins = 8, |
1603 | .flags = 0, |
1604 | .max_register = FSL_SAI_MDIV, |
1605 | }; |
1606 | |
1607 | static const struct fsl_sai_soc_data fsl_sai_imx8mp_data = { |
1608 | .use_imx_pcm = true, |
1609 | .use_edma = false, |
1610 | .fifo_depth = 128, |
1611 | .reg_offset = 8, |
1612 | .mclk0_is_mclk1 = false, |
1613 | .pins = 8, |
1614 | .flags = 0, |
1615 | .max_register = FSL_SAI_MDIV, |
1616 | .mclk_with_tere = true, |
1617 | }; |
1618 | |
1619 | static const struct fsl_sai_soc_data fsl_sai_imx8ulp_data = { |
1620 | .use_imx_pcm = true, |
1621 | .use_edma = true, |
1622 | .fifo_depth = 16, |
1623 | .reg_offset = 8, |
1624 | .mclk0_is_mclk1 = false, |
1625 | .pins = 4, |
1626 | .flags = PMQOS_CPU_LATENCY, |
1627 | .max_register = FSL_SAI_RTCAP, |
1628 | }; |
1629 | |
1630 | static const struct fsl_sai_soc_data fsl_sai_imx93_data = { |
1631 | .use_imx_pcm = true, |
1632 | .use_edma = true, |
1633 | .fifo_depth = 128, |
1634 | .reg_offset = 8, |
1635 | .mclk0_is_mclk1 = false, |
1636 | .pins = 4, |
1637 | .flags = 0, |
1638 | .max_register = FSL_SAI_MCTL, |
1639 | .max_burst = {8, 8}, |
1640 | }; |
1641 | |
1642 | static const struct fsl_sai_soc_data fsl_sai_imx95_data = { |
1643 | .use_imx_pcm = true, |
1644 | .use_edma = true, |
1645 | .fifo_depth = 128, |
1646 | .reg_offset = 8, |
1647 | .mclk0_is_mclk1 = false, |
1648 | .pins = 8, |
1649 | .flags = 0, |
1650 | .max_register = FSL_SAI_MCTL, |
1651 | .max_burst = {8, 8}, |
1652 | }; |
1653 | |
1654 | static const struct of_device_id fsl_sai_ids[] = { |
1655 | { .compatible = "fsl,vf610-sai" , .data = &fsl_sai_vf610_data }, |
1656 | { .compatible = "fsl,imx6sx-sai" , .data = &fsl_sai_imx6sx_data }, |
1657 | { .compatible = "fsl,imx6ul-sai" , .data = &fsl_sai_imx6sx_data }, |
1658 | { .compatible = "fsl,imx7ulp-sai" , .data = &fsl_sai_imx7ulp_data }, |
1659 | { .compatible = "fsl,imx8mq-sai" , .data = &fsl_sai_imx8mq_data }, |
1660 | { .compatible = "fsl,imx8qm-sai" , .data = &fsl_sai_imx8qm_data }, |
1661 | { .compatible = "fsl,imx8mm-sai" , .data = &fsl_sai_imx8mm_data }, |
1662 | { .compatible = "fsl,imx8mp-sai" , .data = &fsl_sai_imx8mp_data }, |
1663 | { .compatible = "fsl,imx8ulp-sai" , .data = &fsl_sai_imx8ulp_data }, |
1664 | { .compatible = "fsl,imx8mn-sai" , .data = &fsl_sai_imx8mn_data }, |
1665 | { .compatible = "fsl,imx93-sai" , .data = &fsl_sai_imx93_data }, |
1666 | { .compatible = "fsl,imx95-sai" , .data = &fsl_sai_imx95_data }, |
1667 | { /* sentinel */ } |
1668 | }; |
1669 | MODULE_DEVICE_TABLE(of, fsl_sai_ids); |
1670 | |
1671 | static int fsl_sai_runtime_suspend(struct device *dev) |
1672 | { |
1673 | struct fsl_sai *sai = dev_get_drvdata(dev); |
1674 | |
1675 | if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) |
1676 | clk_disable_unprepare(clk: sai->mclk_clk[sai->mclk_id[0]]); |
1677 | |
1678 | if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) |
1679 | clk_disable_unprepare(clk: sai->mclk_clk[sai->mclk_id[1]]); |
1680 | |
1681 | clk_disable_unprepare(clk: sai->bus_clk); |
1682 | |
1683 | if (sai->soc_data->flags & PMQOS_CPU_LATENCY) |
1684 | cpu_latency_qos_remove_request(req: &sai->pm_qos_req); |
1685 | |
1686 | regcache_cache_only(map: sai->regmap, enable: true); |
1687 | |
1688 | return 0; |
1689 | } |
1690 | |
1691 | static int fsl_sai_runtime_resume(struct device *dev) |
1692 | { |
1693 | struct fsl_sai *sai = dev_get_drvdata(dev); |
1694 | unsigned int ofs = sai->soc_data->reg_offset; |
1695 | int ret; |
1696 | |
1697 | ret = clk_prepare_enable(clk: sai->bus_clk); |
1698 | if (ret) { |
1699 | dev_err(dev, "failed to enable bus clock: %d\n" , ret); |
1700 | return ret; |
1701 | } |
1702 | |
1703 | if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) { |
1704 | ret = clk_prepare_enable(clk: sai->mclk_clk[sai->mclk_id[1]]); |
1705 | if (ret) |
1706 | goto disable_bus_clk; |
1707 | } |
1708 | |
1709 | if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) { |
1710 | ret = clk_prepare_enable(clk: sai->mclk_clk[sai->mclk_id[0]]); |
1711 | if (ret) |
1712 | goto disable_tx_clk; |
1713 | } |
1714 | |
1715 | if (sai->soc_data->flags & PMQOS_CPU_LATENCY) |
1716 | cpu_latency_qos_add_request(req: &sai->pm_qos_req, value: 0); |
1717 | |
1718 | regcache_cache_only(map: sai->regmap, enable: false); |
1719 | regcache_mark_dirty(map: sai->regmap); |
1720 | regmap_write(map: sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); |
1721 | regmap_write(map: sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); |
1722 | usleep_range(min: 1000, max: 2000); |
1723 | regmap_write(map: sai->regmap, FSL_SAI_TCSR(ofs), val: 0); |
1724 | regmap_write(map: sai->regmap, FSL_SAI_RCSR(ofs), val: 0); |
1725 | |
1726 | ret = regcache_sync(map: sai->regmap); |
1727 | if (ret) |
1728 | goto disable_rx_clk; |
1729 | |
1730 | if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output) |
1731 | regmap_update_bits(map: sai->regmap, FSL_SAI_TCSR(ofs), |
1732 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); |
1733 | |
1734 | return 0; |
1735 | |
1736 | disable_rx_clk: |
1737 | if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) |
1738 | clk_disable_unprepare(clk: sai->mclk_clk[sai->mclk_id[0]]); |
1739 | disable_tx_clk: |
1740 | if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) |
1741 | clk_disable_unprepare(clk: sai->mclk_clk[sai->mclk_id[1]]); |
1742 | disable_bus_clk: |
1743 | clk_disable_unprepare(clk: sai->bus_clk); |
1744 | |
1745 | return ret; |
1746 | } |
1747 | |
1748 | static const struct dev_pm_ops fsl_sai_pm_ops = { |
1749 | SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend, |
1750 | fsl_sai_runtime_resume, NULL) |
1751 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
1752 | pm_runtime_force_resume) |
1753 | }; |
1754 | |
1755 | static struct platform_driver fsl_sai_driver = { |
1756 | .probe = fsl_sai_probe, |
1757 | .remove_new = fsl_sai_remove, |
1758 | .driver = { |
1759 | .name = "fsl-sai" , |
1760 | .pm = &fsl_sai_pm_ops, |
1761 | .of_match_table = fsl_sai_ids, |
1762 | }, |
1763 | }; |
1764 | module_platform_driver(fsl_sai_driver); |
1765 | |
1766 | MODULE_DESCRIPTION("Freescale Soc SAI Interface" ); |
1767 | MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>" ); |
1768 | MODULE_ALIAS("platform:fsl-sai" ); |
1769 | MODULE_LICENSE("GPL" ); |
1770 | |