1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver |
4 | // |
5 | // Copyright (C) 2014 Freescale Semiconductor, Inc. |
6 | // |
7 | // Author: Nicolin Chen <nicoleotsuka@gmail.com> |
8 | |
9 | #include <linux/clk.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/dma-mapping.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of_platform.h> |
14 | #include <linux/dma/imx-dma.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <sound/dmaengine_pcm.h> |
17 | #include <sound/pcm_params.h> |
18 | |
19 | #include "fsl_asrc.h" |
20 | |
21 | #define IDEAL_RATIO_DECIMAL_DEPTH 26 |
22 | #define DIVIDER_NUM 64 |
23 | #define INIT_RETRY_NUM 50 |
24 | |
25 | #define pair_err(fmt, ...) \ |
26 | dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) |
27 | |
28 | #define pair_dbg(fmt, ...) \ |
29 | dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) |
30 | |
31 | #define pair_warn(fmt, ...) \ |
32 | dev_warn(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) |
33 | |
34 | /* Corresponding to process_option */ |
35 | static unsigned int supported_asrc_rate[] = { |
36 | 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, |
37 | 64000, 88200, 96000, 128000, 176400, 192000, |
38 | }; |
39 | |
40 | static struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { |
41 | .count = ARRAY_SIZE(supported_asrc_rate), |
42 | .list = supported_asrc_rate, |
43 | }; |
44 | |
45 | /* |
46 | * The following tables map the relationship between asrc_inclk/asrc_outclk in |
47 | * fsl_asrc.h and the registers of ASRCSR |
48 | */ |
49 | static unsigned char input_clk_map_imx35[ASRC_CLK_MAP_LEN] = { |
50 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, |
51 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
52 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
53 | }; |
54 | |
55 | static unsigned char output_clk_map_imx35[ASRC_CLK_MAP_LEN] = { |
56 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, |
57 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
58 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
59 | }; |
60 | |
61 | /* i.MX53 uses the same map for input and output */ |
62 | static unsigned char input_clk_map_imx53[ASRC_CLK_MAP_LEN] = { |
63 | /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ |
64 | 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, |
65 | 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, |
66 | 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, |
67 | }; |
68 | |
69 | static unsigned char output_clk_map_imx53[ASRC_CLK_MAP_LEN] = { |
70 | /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ |
71 | 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, |
72 | 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, |
73 | 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, |
74 | }; |
75 | |
76 | /* |
77 | * i.MX8QM/i.MX8QXP uses the same map for input and output. |
78 | * clk_map_imx8qm[0] is for i.MX8QM asrc0 |
79 | * clk_map_imx8qm[1] is for i.MX8QM asrc1 |
80 | * clk_map_imx8qxp[0] is for i.MX8QXP asrc0 |
81 | * clk_map_imx8qxp[1] is for i.MX8QXP asrc1 |
82 | */ |
83 | static unsigned char clk_map_imx8qm[2][ASRC_CLK_MAP_LEN] = { |
84 | { |
85 | 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, |
86 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, |
87 | 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, |
88 | }, |
89 | { |
90 | 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, |
91 | 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, |
92 | 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, |
93 | }, |
94 | }; |
95 | |
96 | static unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = { |
97 | { |
98 | 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, |
99 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xf, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xf, |
100 | 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, |
101 | }, |
102 | { |
103 | 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, |
104 | 0x0, 0x1, 0x2, 0x3, 0x7, 0x8, 0xf, 0xf, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, |
105 | 0xf, 0xf, 0x6, 0xf, 0xf, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, |
106 | }, |
107 | }; |
108 | |
109 | /* |
110 | * According to RM, the divider range is 1 ~ 8, |
111 | * prescaler is power of 2 from 1 ~ 128. |
112 | */ |
113 | static int asrc_clk_divider[DIVIDER_NUM] = { |
114 | 1, 2, 4, 8, 16, 32, 64, 128, /* divider = 1 */ |
115 | 2, 4, 8, 16, 32, 64, 128, 256, /* divider = 2 */ |
116 | 3, 6, 12, 24, 48, 96, 192, 384, /* divider = 3 */ |
117 | 4, 8, 16, 32, 64, 128, 256, 512, /* divider = 4 */ |
118 | 5, 10, 20, 40, 80, 160, 320, 640, /* divider = 5 */ |
119 | 6, 12, 24, 48, 96, 192, 384, 768, /* divider = 6 */ |
120 | 7, 14, 28, 56, 112, 224, 448, 896, /* divider = 7 */ |
121 | 8, 16, 32, 64, 128, 256, 512, 1024, /* divider = 8 */ |
122 | }; |
123 | |
124 | /* |
125 | * Check if the divider is available for internal ratio mode |
126 | */ |
127 | static bool fsl_asrc_divider_avail(int clk_rate, int rate, int *div) |
128 | { |
129 | u32 rem, i; |
130 | u64 n; |
131 | |
132 | if (div) |
133 | *div = 0; |
134 | |
135 | if (clk_rate == 0 || rate == 0) |
136 | return false; |
137 | |
138 | n = clk_rate; |
139 | rem = do_div(n, rate); |
140 | |
141 | if (div) |
142 | *div = n; |
143 | |
144 | if (rem != 0) |
145 | return false; |
146 | |
147 | for (i = 0; i < DIVIDER_NUM; i++) { |
148 | if (n == asrc_clk_divider[i]) |
149 | break; |
150 | } |
151 | |
152 | if (i == DIVIDER_NUM) |
153 | return false; |
154 | |
155 | return true; |
156 | } |
157 | |
158 | /** |
159 | * fsl_asrc_sel_proc - Select the pre-processing and post-processing options |
160 | * @inrate: input sample rate |
161 | * @outrate: output sample rate |
162 | * @pre_proc: return value for pre-processing option |
163 | * @post_proc: return value for post-processing option |
164 | * |
165 | * Make sure to exclude following unsupported cases before |
166 | * calling this function: |
167 | * 1) inrate > 8.125 * outrate |
168 | * 2) inrate > 16.125 * outrate |
169 | * |
170 | */ |
171 | static void fsl_asrc_sel_proc(int inrate, int outrate, |
172 | int *pre_proc, int *post_proc) |
173 | { |
174 | bool post_proc_cond2; |
175 | bool post_proc_cond0; |
176 | |
177 | /* select pre_proc between [0, 2] */ |
178 | if (inrate * 8 > 33 * outrate) |
179 | *pre_proc = 2; |
180 | else if (inrate * 8 > 15 * outrate) { |
181 | if (inrate > 152000) |
182 | *pre_proc = 2; |
183 | else |
184 | *pre_proc = 1; |
185 | } else if (inrate < 76000) |
186 | *pre_proc = 0; |
187 | else if (inrate > 152000) |
188 | *pre_proc = 2; |
189 | else |
190 | *pre_proc = 1; |
191 | |
192 | /* Condition for selection of post-processing */ |
193 | post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) || |
194 | (inrate > 56000 && outrate < 56000); |
195 | post_proc_cond0 = inrate * 23 < outrate * 8; |
196 | |
197 | if (post_proc_cond2) |
198 | *post_proc = 2; |
199 | else if (post_proc_cond0) |
200 | *post_proc = 0; |
201 | else |
202 | *post_proc = 1; |
203 | } |
204 | |
205 | /** |
206 | * fsl_asrc_request_pair - Request ASRC pair |
207 | * @channels: number of channels |
208 | * @pair: pointer to pair |
209 | * |
210 | * It assigns pair by the order of A->C->B because allocation of pair B, |
211 | * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A |
212 | * while pair A and pair C are comparatively independent. |
213 | */ |
214 | static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) |
215 | { |
216 | enum asrc_pair_index index = ASRC_INVALID_PAIR; |
217 | struct fsl_asrc *asrc = pair->asrc; |
218 | struct device *dev = &asrc->pdev->dev; |
219 | unsigned long lock_flags; |
220 | int i, ret = 0; |
221 | |
222 | spin_lock_irqsave(&asrc->lock, lock_flags); |
223 | |
224 | for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { |
225 | if (asrc->pair[i] != NULL) |
226 | continue; |
227 | |
228 | index = i; |
229 | |
230 | if (i != ASRC_PAIR_B) |
231 | break; |
232 | } |
233 | |
234 | if (index == ASRC_INVALID_PAIR) { |
235 | dev_err(dev, "all pairs are busy now\n" ); |
236 | ret = -EBUSY; |
237 | } else if (asrc->channel_avail < channels) { |
238 | dev_err(dev, "can't afford required channels: %d\n" , channels); |
239 | ret = -EINVAL; |
240 | } else { |
241 | asrc->channel_avail -= channels; |
242 | asrc->pair[index] = pair; |
243 | pair->channels = channels; |
244 | pair->index = index; |
245 | } |
246 | |
247 | spin_unlock_irqrestore(lock: &asrc->lock, flags: lock_flags); |
248 | |
249 | return ret; |
250 | } |
251 | |
252 | /** |
253 | * fsl_asrc_release_pair - Release ASRC pair |
254 | * @pair: pair to release |
255 | * |
256 | * It clears the resource from asrc and releases the occupied channels. |
257 | */ |
258 | static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) |
259 | { |
260 | struct fsl_asrc *asrc = pair->asrc; |
261 | enum asrc_pair_index index = pair->index; |
262 | unsigned long lock_flags; |
263 | |
264 | /* Make sure the pair is disabled */ |
265 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
266 | ASRCTR_ASRCEi_MASK(index), val: 0); |
267 | |
268 | spin_lock_irqsave(&asrc->lock, lock_flags); |
269 | |
270 | asrc->channel_avail += pair->channels; |
271 | asrc->pair[index] = NULL; |
272 | pair->error = 0; |
273 | |
274 | spin_unlock_irqrestore(lock: &asrc->lock, flags: lock_flags); |
275 | } |
276 | |
277 | /** |
278 | * fsl_asrc_set_watermarks- configure input and output thresholds |
279 | * @pair: pointer to pair |
280 | * @in: input threshold |
281 | * @out: output threshold |
282 | */ |
283 | static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) |
284 | { |
285 | struct fsl_asrc *asrc = pair->asrc; |
286 | enum asrc_pair_index index = pair->index; |
287 | |
288 | regmap_update_bits(map: asrc->regmap, REG_ASRMCR(index), |
289 | ASRMCRi_EXTTHRSHi_MASK | |
290 | ASRMCRi_INFIFO_THRESHOLD_MASK | |
291 | ASRMCRi_OUTFIFO_THRESHOLD_MASK, |
292 | ASRMCRi_EXTTHRSHi | |
293 | ASRMCRi_INFIFO_THRESHOLD(in) | |
294 | ASRMCRi_OUTFIFO_THRESHOLD(out)); |
295 | } |
296 | |
297 | /** |
298 | * fsl_asrc_cal_asrck_divisor - Calculate the total divisor between asrck clock rate and sample rate |
299 | * @pair: pointer to pair |
300 | * @div: divider |
301 | * |
302 | * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider |
303 | */ |
304 | static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) |
305 | { |
306 | u32 ps; |
307 | |
308 | /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ |
309 | for (ps = 0; div > 8; ps++) |
310 | div >>= 1; |
311 | |
312 | return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; |
313 | } |
314 | |
315 | /** |
316 | * fsl_asrc_set_ideal_ratio - Calculate and set the ratio for Ideal Ratio mode only |
317 | * @pair: pointer to pair |
318 | * @inrate: input rate |
319 | * @outrate: output rate |
320 | * |
321 | * The ratio is a 32-bit fixed point value with 26 fractional bits. |
322 | */ |
323 | static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, |
324 | int inrate, int outrate) |
325 | { |
326 | struct fsl_asrc *asrc = pair->asrc; |
327 | enum asrc_pair_index index = pair->index; |
328 | unsigned long ratio; |
329 | int i; |
330 | |
331 | if (!outrate) { |
332 | pair_err("output rate should not be zero\n" ); |
333 | return -EINVAL; |
334 | } |
335 | |
336 | /* Calculate the intergal part of the ratio */ |
337 | ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; |
338 | |
339 | /* ... and then the 26 depth decimal part */ |
340 | inrate %= outrate; |
341 | |
342 | for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { |
343 | inrate <<= 1; |
344 | |
345 | if (inrate < outrate) |
346 | continue; |
347 | |
348 | ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); |
349 | inrate -= outrate; |
350 | |
351 | if (!inrate) |
352 | break; |
353 | } |
354 | |
355 | regmap_write(map: asrc->regmap, REG_ASRIDRL(index), val: ratio); |
356 | regmap_write(map: asrc->regmap, REG_ASRIDRH(index), val: ratio >> 24); |
357 | |
358 | return 0; |
359 | } |
360 | |
361 | /** |
362 | * fsl_asrc_config_pair - Configure the assigned ASRC pair |
363 | * @pair: pointer to pair |
364 | * @use_ideal_rate: boolean configuration |
365 | * |
366 | * It configures those ASRC registers according to a configuration instance |
367 | * of struct asrc_config which includes in/output sample rate, width, channel |
368 | * and clock settings. |
369 | * |
370 | * Note: |
371 | * The ideal ratio configuration can work with a flexible clock rate setting. |
372 | * Using IDEAL_RATIO_RATE gives a faster converting speed but overloads ASRC. |
373 | * For a regular audio playback, the clock rate should not be slower than an |
374 | * clock rate aligning with the output sample rate; For a use case requiring |
375 | * faster conversion, set use_ideal_rate to have the faster speed. |
376 | */ |
377 | static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) |
378 | { |
379 | struct fsl_asrc_pair_priv *pair_priv = pair->private; |
380 | struct asrc_config *config = pair_priv->config; |
381 | struct fsl_asrc *asrc = pair->asrc; |
382 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
383 | enum asrc_pair_index index = pair->index; |
384 | enum asrc_word_width input_word_width; |
385 | enum asrc_word_width output_word_width; |
386 | u32 inrate, outrate, indiv, outdiv; |
387 | u32 clk_index[2], div[2]; |
388 | u64 clk_rate; |
389 | int in, out, channels; |
390 | int pre_proc, post_proc; |
391 | struct clk *clk; |
392 | bool ideal, div_avail; |
393 | |
394 | if (!config) { |
395 | pair_err("invalid pair config\n" ); |
396 | return -EINVAL; |
397 | } |
398 | |
399 | /* Validate channels */ |
400 | if (config->channel_num < 1 || config->channel_num > 10) { |
401 | pair_err("does not support %d channels\n" , config->channel_num); |
402 | return -EINVAL; |
403 | } |
404 | |
405 | switch (snd_pcm_format_width(format: config->input_format)) { |
406 | case 8: |
407 | input_word_width = ASRC_WIDTH_8_BIT; |
408 | break; |
409 | case 16: |
410 | input_word_width = ASRC_WIDTH_16_BIT; |
411 | break; |
412 | case 24: |
413 | input_word_width = ASRC_WIDTH_24_BIT; |
414 | break; |
415 | default: |
416 | pair_err("does not support this input format, %d\n" , |
417 | config->input_format); |
418 | return -EINVAL; |
419 | } |
420 | |
421 | switch (snd_pcm_format_width(format: config->output_format)) { |
422 | case 16: |
423 | output_word_width = ASRC_WIDTH_16_BIT; |
424 | break; |
425 | case 24: |
426 | output_word_width = ASRC_WIDTH_24_BIT; |
427 | break; |
428 | default: |
429 | pair_err("does not support this output format, %d\n" , |
430 | config->output_format); |
431 | return -EINVAL; |
432 | } |
433 | |
434 | inrate = config->input_sample_rate; |
435 | outrate = config->output_sample_rate; |
436 | ideal = config->inclk == INCLK_NONE; |
437 | |
438 | /* Validate input and output sample rates */ |
439 | for (in = 0; in < ARRAY_SIZE(supported_asrc_rate); in++) |
440 | if (inrate == supported_asrc_rate[in]) |
441 | break; |
442 | |
443 | if (in == ARRAY_SIZE(supported_asrc_rate)) { |
444 | pair_err("unsupported input sample rate: %dHz\n" , inrate); |
445 | return -EINVAL; |
446 | } |
447 | |
448 | for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) |
449 | if (outrate == supported_asrc_rate[out]) |
450 | break; |
451 | |
452 | if (out == ARRAY_SIZE(supported_asrc_rate)) { |
453 | pair_err("unsupported output sample rate: %dHz\n" , outrate); |
454 | return -EINVAL; |
455 | } |
456 | |
457 | if ((outrate >= 5512 && outrate <= 30000) && |
458 | (outrate > 24 * inrate || inrate > 8 * outrate)) { |
459 | pair_err("exceed supported ratio range [1/24, 8] for \ |
460 | inrate/outrate: %d/%d\n" , inrate, outrate); |
461 | return -EINVAL; |
462 | } |
463 | |
464 | /* Validate input and output clock sources */ |
465 | clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; |
466 | clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk]; |
467 | |
468 | /* We only have output clock for ideal ratio mode */ |
469 | clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; |
470 | |
471 | clk_rate = clk_get_rate(clk); |
472 | div_avail = fsl_asrc_divider_avail(clk_rate, rate: inrate, div: &div[IN]); |
473 | |
474 | /* |
475 | * The divider range is [1, 1024], defined by the hardware. For non- |
476 | * ideal ratio configuration, clock rate has to be strictly aligned |
477 | * with the sample rate. For ideal ratio configuration, clock rates |
478 | * only result in different converting speeds. So remainder does not |
479 | * matter, as long as we keep the divider within its valid range. |
480 | */ |
481 | if (div[IN] == 0 || (!ideal && !div_avail)) { |
482 | pair_err("failed to support input sample rate %dHz by asrck_%x\n" , |
483 | inrate, clk_index[ideal ? OUT : IN]); |
484 | return -EINVAL; |
485 | } |
486 | |
487 | div[IN] = min_t(u32, 1024, div[IN]); |
488 | |
489 | clk = asrc_priv->asrck_clk[clk_index[OUT]]; |
490 | clk_rate = clk_get_rate(clk); |
491 | if (ideal && use_ideal_rate) |
492 | div_avail = fsl_asrc_divider_avail(clk_rate, IDEAL_RATIO_RATE, div: &div[OUT]); |
493 | else |
494 | div_avail = fsl_asrc_divider_avail(clk_rate, rate: outrate, div: &div[OUT]); |
495 | |
496 | /* Output divider has the same limitation as the input one */ |
497 | if (div[OUT] == 0 || (!ideal && !div_avail)) { |
498 | pair_err("failed to support output sample rate %dHz by asrck_%x\n" , |
499 | outrate, clk_index[OUT]); |
500 | return -EINVAL; |
501 | } |
502 | |
503 | div[OUT] = min_t(u32, 1024, div[OUT]); |
504 | |
505 | /* Set the channel number */ |
506 | channels = config->channel_num; |
507 | |
508 | if (asrc_priv->soc->channel_bits < 4) |
509 | channels /= 2; |
510 | |
511 | /* Update channels for current pair */ |
512 | regmap_update_bits(map: asrc->regmap, REG_ASRCNCR, |
513 | ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), |
514 | ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits)); |
515 | |
516 | /* Default setting: Automatic selection for processing mode */ |
517 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
518 | ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); |
519 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
520 | ASRCTR_USRi_MASK(index), val: 0); |
521 | |
522 | /* Set the input and output clock sources */ |
523 | regmap_update_bits(map: asrc->regmap, REG_ASRCSR, |
524 | ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), |
525 | ASRCSR_AICS(index, clk_index[IN]) | |
526 | ASRCSR_AOCS(index, clk_index[OUT])); |
527 | |
528 | /* Calculate the input clock divisors */ |
529 | indiv = fsl_asrc_cal_asrck_divisor(pair, div: div[IN]); |
530 | outdiv = fsl_asrc_cal_asrck_divisor(pair, div: div[OUT]); |
531 | |
532 | /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ |
533 | regmap_update_bits(map: asrc->regmap, REG_ASRCDR(index), |
534 | ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | |
535 | ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), |
536 | ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); |
537 | |
538 | /* Implement word_width configurations */ |
539 | regmap_update_bits(map: asrc->regmap, REG_ASRMCR1(index), |
540 | ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, |
541 | ASRMCR1i_OW16(output_word_width) | |
542 | ASRMCR1i_IWD(input_word_width)); |
543 | |
544 | /* Enable BUFFER STALL */ |
545 | regmap_update_bits(map: asrc->regmap, REG_ASRMCR(index), |
546 | ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); |
547 | |
548 | /* Set default thresholds for input and output FIFO */ |
549 | fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, |
550 | ASRC_INPUTFIFO_THRESHOLD); |
551 | |
552 | /* Configure the following only for Ideal Ratio mode */ |
553 | if (!ideal) |
554 | return 0; |
555 | |
556 | /* Clear ASTSx bit to use Ideal Ratio mode */ |
557 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
558 | ASRCTR_ATSi_MASK(index), val: 0); |
559 | |
560 | /* Enable Ideal Ratio mode */ |
561 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
562 | ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), |
563 | ASRCTR_IDR(index) | ASRCTR_USR(index)); |
564 | |
565 | fsl_asrc_sel_proc(inrate, outrate, pre_proc: &pre_proc, post_proc: &post_proc); |
566 | |
567 | /* Apply configurations for pre- and post-processing */ |
568 | regmap_update_bits(map: asrc->regmap, REG_ASRCFG, |
569 | ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), |
570 | ASRCFG_PREMOD(index, pre_proc) | |
571 | ASRCFG_POSTMOD(index, post_proc)); |
572 | |
573 | return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); |
574 | } |
575 | |
576 | /** |
577 | * fsl_asrc_start_pair - Start the assigned ASRC pair |
578 | * @pair: pointer to pair |
579 | * |
580 | * It enables the assigned pair and makes it stopped at the stall level. |
581 | */ |
582 | static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) |
583 | { |
584 | struct fsl_asrc *asrc = pair->asrc; |
585 | enum asrc_pair_index index = pair->index; |
586 | int reg, retry = INIT_RETRY_NUM, i; |
587 | |
588 | /* Enable the current pair */ |
589 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
590 | ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); |
591 | |
592 | /* Wait for status of initialization */ |
593 | do { |
594 | udelay(5); |
595 | regmap_read(map: asrc->regmap, REG_ASRCFG, val: ®); |
596 | reg &= ASRCFG_INIRQi_MASK(index); |
597 | } while (!reg && --retry); |
598 | |
599 | /* NOTE: Doesn't treat initialization timeout as an error */ |
600 | if (!retry) |
601 | pair_warn("initialization isn't finished\n" ); |
602 | |
603 | /* Make the input fifo to ASRC STALL level */ |
604 | regmap_read(map: asrc->regmap, REG_ASRCNCR, val: ®); |
605 | for (i = 0; i < pair->channels * 4; i++) |
606 | regmap_write(map: asrc->regmap, REG_ASRDI(index), val: 0); |
607 | |
608 | /* Enable overload interrupt */ |
609 | regmap_write(map: asrc->regmap, REG_ASRIER, ASRIER_AOLIE); |
610 | } |
611 | |
612 | /** |
613 | * fsl_asrc_stop_pair - Stop the assigned ASRC pair |
614 | * @pair: pointer to pair |
615 | */ |
616 | static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) |
617 | { |
618 | struct fsl_asrc *asrc = pair->asrc; |
619 | enum asrc_pair_index index = pair->index; |
620 | |
621 | /* Stop the current pair */ |
622 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
623 | ASRCTR_ASRCEi_MASK(index), val: 0); |
624 | } |
625 | |
626 | /** |
627 | * fsl_asrc_get_dma_channel- Get DMA channel according to the pair and direction. |
628 | * @pair: pointer to pair |
629 | * @dir: DMA direction |
630 | */ |
631 | static struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, |
632 | bool dir) |
633 | { |
634 | struct fsl_asrc *asrc = pair->asrc; |
635 | enum asrc_pair_index index = pair->index; |
636 | char name[4]; |
637 | |
638 | sprintf(buf: name, fmt: "%cx%c" , dir == IN ? 'r' : 't', index + 'a'); |
639 | |
640 | return dma_request_slave_channel(dev: &asrc->pdev->dev, name); |
641 | } |
642 | |
643 | static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, |
644 | struct snd_soc_dai *dai) |
645 | { |
646 | struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
647 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
648 | |
649 | /* Odd channel number is not valid for older ASRC (channel_bits==3) */ |
650 | if (asrc_priv->soc->channel_bits == 3) |
651 | snd_pcm_hw_constraint_step(runtime: substream->runtime, cond: 0, |
652 | SNDRV_PCM_HW_PARAM_CHANNELS, step: 2); |
653 | |
654 | |
655 | return snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0, |
656 | SNDRV_PCM_HW_PARAM_RATE, l: &fsl_asrc_rate_constraints); |
657 | } |
658 | |
659 | /* Select proper clock source for internal ratio mode */ |
660 | static void fsl_asrc_select_clk(struct fsl_asrc_priv *asrc_priv, |
661 | struct fsl_asrc_pair *pair, |
662 | int in_rate, |
663 | int out_rate) |
664 | { |
665 | struct fsl_asrc_pair_priv *pair_priv = pair->private; |
666 | struct asrc_config *config = pair_priv->config; |
667 | int rate[2], select_clk[2]; /* Array size 2 means IN and OUT */ |
668 | int clk_rate, clk_index; |
669 | int i, j; |
670 | |
671 | rate[IN] = in_rate; |
672 | rate[OUT] = out_rate; |
673 | |
674 | /* Select proper clock source for internal ratio mode */ |
675 | for (j = 0; j < 2; j++) { |
676 | for (i = 0; i < ASRC_CLK_MAP_LEN; i++) { |
677 | clk_index = asrc_priv->clk_map[j][i]; |
678 | clk_rate = clk_get_rate(clk: asrc_priv->asrck_clk[clk_index]); |
679 | /* Only match a perfect clock source with no remainder */ |
680 | if (fsl_asrc_divider_avail(clk_rate, rate: rate[j], NULL)) |
681 | break; |
682 | } |
683 | |
684 | select_clk[j] = i; |
685 | } |
686 | |
687 | /* Switch to ideal ratio mode if there is no proper clock source */ |
688 | if (select_clk[IN] == ASRC_CLK_MAP_LEN || select_clk[OUT] == ASRC_CLK_MAP_LEN) { |
689 | select_clk[IN] = INCLK_NONE; |
690 | select_clk[OUT] = OUTCLK_ASRCK1_CLK; |
691 | } |
692 | |
693 | config->inclk = select_clk[IN]; |
694 | config->outclk = select_clk[OUT]; |
695 | } |
696 | |
697 | static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, |
698 | struct snd_pcm_hw_params *params, |
699 | struct snd_soc_dai *dai) |
700 | { |
701 | struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
702 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
703 | struct snd_pcm_runtime *runtime = substream->runtime; |
704 | struct fsl_asrc_pair *pair = runtime->private_data; |
705 | struct fsl_asrc_pair_priv *pair_priv = pair->private; |
706 | unsigned int channels = params_channels(p: params); |
707 | unsigned int rate = params_rate(p: params); |
708 | struct asrc_config config; |
709 | int ret; |
710 | |
711 | ret = fsl_asrc_request_pair(channels, pair); |
712 | if (ret) { |
713 | dev_err(dai->dev, "fail to request asrc pair\n" ); |
714 | return ret; |
715 | } |
716 | |
717 | pair_priv->config = &config; |
718 | |
719 | config.pair = pair->index; |
720 | config.channel_num = channels; |
721 | |
722 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
723 | config.input_format = params_format(p: params); |
724 | config.output_format = asrc->asrc_format; |
725 | config.input_sample_rate = rate; |
726 | config.output_sample_rate = asrc->asrc_rate; |
727 | } else { |
728 | config.input_format = asrc->asrc_format; |
729 | config.output_format = params_format(p: params); |
730 | config.input_sample_rate = asrc->asrc_rate; |
731 | config.output_sample_rate = rate; |
732 | } |
733 | |
734 | fsl_asrc_select_clk(asrc_priv, pair, |
735 | in_rate: config.input_sample_rate, |
736 | out_rate: config.output_sample_rate); |
737 | |
738 | ret = fsl_asrc_config_pair(pair, use_ideal_rate: false); |
739 | if (ret) { |
740 | dev_err(dai->dev, "fail to config asrc pair\n" ); |
741 | return ret; |
742 | } |
743 | |
744 | return 0; |
745 | } |
746 | |
747 | static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, |
748 | struct snd_soc_dai *dai) |
749 | { |
750 | struct snd_pcm_runtime *runtime = substream->runtime; |
751 | struct fsl_asrc_pair *pair = runtime->private_data; |
752 | |
753 | if (pair) |
754 | fsl_asrc_release_pair(pair); |
755 | |
756 | return 0; |
757 | } |
758 | |
759 | static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
760 | struct snd_soc_dai *dai) |
761 | { |
762 | struct snd_pcm_runtime *runtime = substream->runtime; |
763 | struct fsl_asrc_pair *pair = runtime->private_data; |
764 | |
765 | switch (cmd) { |
766 | case SNDRV_PCM_TRIGGER_START: |
767 | case SNDRV_PCM_TRIGGER_RESUME: |
768 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
769 | fsl_asrc_start_pair(pair); |
770 | break; |
771 | case SNDRV_PCM_TRIGGER_STOP: |
772 | case SNDRV_PCM_TRIGGER_SUSPEND: |
773 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
774 | fsl_asrc_stop_pair(pair); |
775 | break; |
776 | default: |
777 | return -EINVAL; |
778 | } |
779 | |
780 | return 0; |
781 | } |
782 | |
783 | static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) |
784 | { |
785 | struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
786 | |
787 | snd_soc_dai_init_dma_data(dai, playback: &asrc->dma_params_tx, |
788 | capture: &asrc->dma_params_rx); |
789 | |
790 | return 0; |
791 | } |
792 | |
793 | static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { |
794 | .probe = fsl_asrc_dai_probe, |
795 | .startup = fsl_asrc_dai_startup, |
796 | .hw_params = fsl_asrc_dai_hw_params, |
797 | .hw_free = fsl_asrc_dai_hw_free, |
798 | .trigger = fsl_asrc_dai_trigger, |
799 | }; |
800 | |
801 | #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ |
802 | SNDRV_PCM_FMTBIT_S16_LE | \ |
803 | SNDRV_PCM_FMTBIT_S24_3LE) |
804 | |
805 | static struct snd_soc_dai_driver fsl_asrc_dai = { |
806 | .playback = { |
807 | .stream_name = "ASRC-Playback" , |
808 | .channels_min = 1, |
809 | .channels_max = 10, |
810 | .rate_min = 5512, |
811 | .rate_max = 192000, |
812 | .rates = SNDRV_PCM_RATE_KNOT, |
813 | .formats = FSL_ASRC_FORMATS | |
814 | SNDRV_PCM_FMTBIT_S8, |
815 | }, |
816 | .capture = { |
817 | .stream_name = "ASRC-Capture" , |
818 | .channels_min = 1, |
819 | .channels_max = 10, |
820 | .rate_min = 5512, |
821 | .rate_max = 192000, |
822 | .rates = SNDRV_PCM_RATE_KNOT, |
823 | .formats = FSL_ASRC_FORMATS, |
824 | }, |
825 | .ops = &fsl_asrc_dai_ops, |
826 | }; |
827 | |
828 | static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) |
829 | { |
830 | switch (reg) { |
831 | case REG_ASRCTR: |
832 | case REG_ASRIER: |
833 | case REG_ASRCNCR: |
834 | case REG_ASRCFG: |
835 | case REG_ASRCSR: |
836 | case REG_ASRCDR1: |
837 | case REG_ASRCDR2: |
838 | case REG_ASRSTR: |
839 | case REG_ASRPM1: |
840 | case REG_ASRPM2: |
841 | case REG_ASRPM3: |
842 | case REG_ASRPM4: |
843 | case REG_ASRPM5: |
844 | case REG_ASRTFR1: |
845 | case REG_ASRCCR: |
846 | case REG_ASRDOA: |
847 | case REG_ASRDOB: |
848 | case REG_ASRDOC: |
849 | case REG_ASRIDRHA: |
850 | case REG_ASRIDRLA: |
851 | case REG_ASRIDRHB: |
852 | case REG_ASRIDRLB: |
853 | case REG_ASRIDRHC: |
854 | case REG_ASRIDRLC: |
855 | case REG_ASR76K: |
856 | case REG_ASR56K: |
857 | case REG_ASRMCRA: |
858 | case REG_ASRFSTA: |
859 | case REG_ASRMCRB: |
860 | case REG_ASRFSTB: |
861 | case REG_ASRMCRC: |
862 | case REG_ASRFSTC: |
863 | case REG_ASRMCR1A: |
864 | case REG_ASRMCR1B: |
865 | case REG_ASRMCR1C: |
866 | return true; |
867 | default: |
868 | return false; |
869 | } |
870 | } |
871 | |
872 | static bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) |
873 | { |
874 | switch (reg) { |
875 | case REG_ASRSTR: |
876 | case REG_ASRDIA: |
877 | case REG_ASRDIB: |
878 | case REG_ASRDIC: |
879 | case REG_ASRDOA: |
880 | case REG_ASRDOB: |
881 | case REG_ASRDOC: |
882 | case REG_ASRFSTA: |
883 | case REG_ASRFSTB: |
884 | case REG_ASRFSTC: |
885 | case REG_ASRCFG: |
886 | return true; |
887 | default: |
888 | return false; |
889 | } |
890 | } |
891 | |
892 | static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) |
893 | { |
894 | switch (reg) { |
895 | case REG_ASRCTR: |
896 | case REG_ASRIER: |
897 | case REG_ASRCNCR: |
898 | case REG_ASRCFG: |
899 | case REG_ASRCSR: |
900 | case REG_ASRCDR1: |
901 | case REG_ASRCDR2: |
902 | case REG_ASRSTR: |
903 | case REG_ASRPM1: |
904 | case REG_ASRPM2: |
905 | case REG_ASRPM3: |
906 | case REG_ASRPM4: |
907 | case REG_ASRPM5: |
908 | case REG_ASRTFR1: |
909 | case REG_ASRCCR: |
910 | case REG_ASRDIA: |
911 | case REG_ASRDIB: |
912 | case REG_ASRDIC: |
913 | case REG_ASRIDRHA: |
914 | case REG_ASRIDRLA: |
915 | case REG_ASRIDRHB: |
916 | case REG_ASRIDRLB: |
917 | case REG_ASRIDRHC: |
918 | case REG_ASRIDRLC: |
919 | case REG_ASR76K: |
920 | case REG_ASR56K: |
921 | case REG_ASRMCRA: |
922 | case REG_ASRMCRB: |
923 | case REG_ASRMCRC: |
924 | case REG_ASRMCR1A: |
925 | case REG_ASRMCR1B: |
926 | case REG_ASRMCR1C: |
927 | return true; |
928 | default: |
929 | return false; |
930 | } |
931 | } |
932 | |
933 | static struct reg_default fsl_asrc_reg[] = { |
934 | { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, |
935 | { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, |
936 | { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, |
937 | { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, |
938 | { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, |
939 | { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, |
940 | { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, |
941 | { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, |
942 | { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, |
943 | { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, |
944 | { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, |
945 | { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, |
946 | { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, |
947 | { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, |
948 | { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, |
949 | { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, |
950 | { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, |
951 | { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, |
952 | { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, |
953 | { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, |
954 | { REG_ASRMCR1C, 0x0000 }, |
955 | }; |
956 | |
957 | static const struct regmap_config fsl_asrc_regmap_config = { |
958 | .reg_bits = 32, |
959 | .reg_stride = 4, |
960 | .val_bits = 32, |
961 | |
962 | .max_register = REG_ASRMCR1C, |
963 | .reg_defaults = fsl_asrc_reg, |
964 | .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), |
965 | .readable_reg = fsl_asrc_readable_reg, |
966 | .volatile_reg = fsl_asrc_volatile_reg, |
967 | .writeable_reg = fsl_asrc_writeable_reg, |
968 | .cache_type = REGCACHE_FLAT, |
969 | }; |
970 | |
971 | /** |
972 | * fsl_asrc_init - Initialize ASRC registers with a default configuration |
973 | * @asrc: ASRC context |
974 | */ |
975 | static int fsl_asrc_init(struct fsl_asrc *asrc) |
976 | { |
977 | unsigned long ipg_rate; |
978 | |
979 | /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ |
980 | regmap_write(map: asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN); |
981 | |
982 | /* Disable interrupt by default */ |
983 | regmap_write(map: asrc->regmap, REG_ASRIER, val: 0x0); |
984 | |
985 | /* Apply recommended settings for parameters from Reference Manual */ |
986 | regmap_write(map: asrc->regmap, REG_ASRPM1, val: 0x7fffff); |
987 | regmap_write(map: asrc->regmap, REG_ASRPM2, val: 0x255555); |
988 | regmap_write(map: asrc->regmap, REG_ASRPM3, val: 0xff7280); |
989 | regmap_write(map: asrc->regmap, REG_ASRPM4, val: 0xff7280); |
990 | regmap_write(map: asrc->regmap, REG_ASRPM5, val: 0xff7280); |
991 | |
992 | /* Base address for task queue FIFO. Set to 0x7C */ |
993 | regmap_update_bits(map: asrc->regmap, REG_ASRTFR1, |
994 | ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); |
995 | |
996 | /* |
997 | * Set the period of the 76KHz and 56KHz sampling clocks based on |
998 | * the ASRC processing clock. |
999 | * On iMX6, ipg_clk = 133MHz, REG_ASR76K = 0x06D6, REG_ASR56K = 0x0947 |
1000 | */ |
1001 | ipg_rate = clk_get_rate(clk: asrc->ipg_clk); |
1002 | regmap_write(map: asrc->regmap, REG_ASR76K, val: ipg_rate / 76000); |
1003 | return regmap_write(map: asrc->regmap, REG_ASR56K, val: ipg_rate / 56000); |
1004 | } |
1005 | |
1006 | /** |
1007 | * fsl_asrc_isr- Interrupt handler for ASRC |
1008 | * @irq: irq number |
1009 | * @dev_id: ASRC context |
1010 | */ |
1011 | static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) |
1012 | { |
1013 | struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id; |
1014 | struct device *dev = &asrc->pdev->dev; |
1015 | enum asrc_pair_index index; |
1016 | u32 status; |
1017 | |
1018 | regmap_read(map: asrc->regmap, REG_ASRSTR, val: &status); |
1019 | |
1020 | /* Clean overload error */ |
1021 | regmap_write(map: asrc->regmap, REG_ASRSTR, ASRSTR_AOLE); |
1022 | |
1023 | /* |
1024 | * We here use dev_dbg() for all exceptions because ASRC itself does |
1025 | * not care if FIFO overflowed or underrun while a warning in the |
1026 | * interrupt would result a ridged conversion. |
1027 | */ |
1028 | for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { |
1029 | if (!asrc->pair[index]) |
1030 | continue; |
1031 | |
1032 | if (status & ASRSTR_ATQOL) { |
1033 | asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; |
1034 | dev_dbg(dev, "ASRC Task Queue FIFO overload\n" ); |
1035 | } |
1036 | |
1037 | if (status & ASRSTR_AOOL(index)) { |
1038 | asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; |
1039 | pair_dbg("Output Task Overload\n" ); |
1040 | } |
1041 | |
1042 | if (status & ASRSTR_AIOL(index)) { |
1043 | asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; |
1044 | pair_dbg("Input Task Overload\n" ); |
1045 | } |
1046 | |
1047 | if (status & ASRSTR_AODO(index)) { |
1048 | asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; |
1049 | pair_dbg("Output Data Buffer has overflowed\n" ); |
1050 | } |
1051 | |
1052 | if (status & ASRSTR_AIDU(index)) { |
1053 | asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; |
1054 | pair_dbg("Input Data Buffer has underflowed\n" ); |
1055 | } |
1056 | } |
1057 | |
1058 | return IRQ_HANDLED; |
1059 | } |
1060 | |
1061 | static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) |
1062 | { |
1063 | return REG_ASRDx(dir, index); |
1064 | } |
1065 | |
1066 | static int fsl_asrc_runtime_resume(struct device *dev); |
1067 | static int fsl_asrc_runtime_suspend(struct device *dev); |
1068 | |
1069 | static int fsl_asrc_probe(struct platform_device *pdev) |
1070 | { |
1071 | struct device_node *np = pdev->dev.of_node; |
1072 | struct fsl_asrc_priv *asrc_priv; |
1073 | struct fsl_asrc *asrc; |
1074 | struct resource *res; |
1075 | void __iomem *regs; |
1076 | int irq, ret, i; |
1077 | u32 asrc_fmt = 0; |
1078 | u32 map_idx; |
1079 | char tmp[16]; |
1080 | u32 width; |
1081 | |
1082 | asrc = devm_kzalloc(dev: &pdev->dev, size: sizeof(*asrc), GFP_KERNEL); |
1083 | if (!asrc) |
1084 | return -ENOMEM; |
1085 | |
1086 | asrc_priv = devm_kzalloc(dev: &pdev->dev, size: sizeof(*asrc_priv), GFP_KERNEL); |
1087 | if (!asrc_priv) |
1088 | return -ENOMEM; |
1089 | |
1090 | asrc->pdev = pdev; |
1091 | asrc->private = asrc_priv; |
1092 | |
1093 | /* Get the addresses and IRQ */ |
1094 | regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
1095 | if (IS_ERR(ptr: regs)) |
1096 | return PTR_ERR(ptr: regs); |
1097 | |
1098 | asrc->paddr = res->start; |
1099 | |
1100 | asrc->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_asrc_regmap_config); |
1101 | if (IS_ERR(ptr: asrc->regmap)) { |
1102 | dev_err(&pdev->dev, "failed to init regmap\n" ); |
1103 | return PTR_ERR(ptr: asrc->regmap); |
1104 | } |
1105 | |
1106 | irq = platform_get_irq(pdev, 0); |
1107 | if (irq < 0) |
1108 | return irq; |
1109 | |
1110 | ret = devm_request_irq(dev: &pdev->dev, irq, handler: fsl_asrc_isr, irqflags: 0, |
1111 | devname: dev_name(dev: &pdev->dev), dev_id: asrc); |
1112 | if (ret) { |
1113 | dev_err(&pdev->dev, "failed to claim irq %u: %d\n" , irq, ret); |
1114 | return ret; |
1115 | } |
1116 | |
1117 | asrc->mem_clk = devm_clk_get(dev: &pdev->dev, id: "mem" ); |
1118 | if (IS_ERR(ptr: asrc->mem_clk)) { |
1119 | dev_err(&pdev->dev, "failed to get mem clock\n" ); |
1120 | return PTR_ERR(ptr: asrc->mem_clk); |
1121 | } |
1122 | |
1123 | asrc->ipg_clk = devm_clk_get(dev: &pdev->dev, id: "ipg" ); |
1124 | if (IS_ERR(ptr: asrc->ipg_clk)) { |
1125 | dev_err(&pdev->dev, "failed to get ipg clock\n" ); |
1126 | return PTR_ERR(ptr: asrc->ipg_clk); |
1127 | } |
1128 | |
1129 | asrc->spba_clk = devm_clk_get(dev: &pdev->dev, id: "spba" ); |
1130 | if (IS_ERR(ptr: asrc->spba_clk)) |
1131 | dev_warn(&pdev->dev, "failed to get spba clock\n" ); |
1132 | |
1133 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { |
1134 | sprintf(buf: tmp, fmt: "asrck_%x" , i); |
1135 | asrc_priv->asrck_clk[i] = devm_clk_get(dev: &pdev->dev, id: tmp); |
1136 | if (IS_ERR(ptr: asrc_priv->asrck_clk[i])) { |
1137 | dev_err(&pdev->dev, "failed to get %s clock\n" , tmp); |
1138 | return PTR_ERR(ptr: asrc_priv->asrck_clk[i]); |
1139 | } |
1140 | } |
1141 | |
1142 | asrc_priv->soc = of_device_get_match_data(dev: &pdev->dev); |
1143 | asrc->use_edma = asrc_priv->soc->use_edma; |
1144 | asrc->get_dma_channel = fsl_asrc_get_dma_channel; |
1145 | asrc->request_pair = fsl_asrc_request_pair; |
1146 | asrc->release_pair = fsl_asrc_release_pair; |
1147 | asrc->get_fifo_addr = fsl_asrc_get_fifo_addr; |
1148 | asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv); |
1149 | |
1150 | if (of_device_is_compatible(device: np, "fsl,imx35-asrc" )) { |
1151 | asrc_priv->clk_map[IN] = input_clk_map_imx35; |
1152 | asrc_priv->clk_map[OUT] = output_clk_map_imx35; |
1153 | } else if (of_device_is_compatible(device: np, "fsl,imx53-asrc" )) { |
1154 | asrc_priv->clk_map[IN] = input_clk_map_imx53; |
1155 | asrc_priv->clk_map[OUT] = output_clk_map_imx53; |
1156 | } else if (of_device_is_compatible(device: np, "fsl,imx8qm-asrc" ) || |
1157 | of_device_is_compatible(device: np, "fsl,imx8qxp-asrc" )) { |
1158 | ret = of_property_read_u32(np, propname: "fsl,asrc-clk-map" , out_value: &map_idx); |
1159 | if (ret) { |
1160 | dev_err(&pdev->dev, "failed to get clk map index\n" ); |
1161 | return ret; |
1162 | } |
1163 | |
1164 | if (map_idx > 1) { |
1165 | dev_err(&pdev->dev, "unsupported clk map index\n" ); |
1166 | return -EINVAL; |
1167 | } |
1168 | if (of_device_is_compatible(device: np, "fsl,imx8qm-asrc" )) { |
1169 | asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; |
1170 | asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; |
1171 | } else { |
1172 | asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; |
1173 | asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; |
1174 | } |
1175 | } |
1176 | |
1177 | asrc->channel_avail = 10; |
1178 | |
1179 | ret = of_property_read_u32(np, propname: "fsl,asrc-rate" , |
1180 | out_value: &asrc->asrc_rate); |
1181 | if (ret) { |
1182 | dev_err(&pdev->dev, "failed to get output rate\n" ); |
1183 | return ret; |
1184 | } |
1185 | |
1186 | ret = of_property_read_u32(np, propname: "fsl,asrc-format" , out_value: &asrc_fmt); |
1187 | asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; |
1188 | if (ret) { |
1189 | ret = of_property_read_u32(np, propname: "fsl,asrc-width" , out_value: &width); |
1190 | if (ret) { |
1191 | dev_err(&pdev->dev, "failed to decide output format\n" ); |
1192 | return ret; |
1193 | } |
1194 | |
1195 | switch (width) { |
1196 | case 16: |
1197 | asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE; |
1198 | break; |
1199 | case 24: |
1200 | asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; |
1201 | break; |
1202 | default: |
1203 | dev_warn(&pdev->dev, |
1204 | "unsupported width, use default S24_LE\n" ); |
1205 | asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; |
1206 | break; |
1207 | } |
1208 | } |
1209 | |
1210 | if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(pcm_format: asrc->asrc_format))) { |
1211 | dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n" ); |
1212 | asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; |
1213 | } |
1214 | |
1215 | platform_set_drvdata(pdev, data: asrc); |
1216 | spin_lock_init(&asrc->lock); |
1217 | pm_runtime_enable(dev: &pdev->dev); |
1218 | if (!pm_runtime_enabled(dev: &pdev->dev)) { |
1219 | ret = fsl_asrc_runtime_resume(dev: &pdev->dev); |
1220 | if (ret) |
1221 | goto err_pm_disable; |
1222 | } |
1223 | |
1224 | ret = pm_runtime_resume_and_get(dev: &pdev->dev); |
1225 | if (ret < 0) |
1226 | goto err_pm_get_sync; |
1227 | |
1228 | ret = fsl_asrc_init(asrc); |
1229 | if (ret) { |
1230 | dev_err(&pdev->dev, "failed to init asrc %d\n" , ret); |
1231 | goto err_pm_get_sync; |
1232 | } |
1233 | |
1234 | ret = pm_runtime_put_sync(dev: &pdev->dev); |
1235 | if (ret < 0 && ret != -ENOSYS) |
1236 | goto err_pm_get_sync; |
1237 | |
1238 | ret = devm_snd_soc_register_component(dev: &pdev->dev, component_driver: &fsl_asrc_component, |
1239 | dai_drv: &fsl_asrc_dai, num_dai: 1); |
1240 | if (ret) { |
1241 | dev_err(&pdev->dev, "failed to register ASoC DAI\n" ); |
1242 | goto err_pm_get_sync; |
1243 | } |
1244 | |
1245 | return 0; |
1246 | |
1247 | err_pm_get_sync: |
1248 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
1249 | fsl_asrc_runtime_suspend(dev: &pdev->dev); |
1250 | err_pm_disable: |
1251 | pm_runtime_disable(dev: &pdev->dev); |
1252 | return ret; |
1253 | } |
1254 | |
1255 | static void fsl_asrc_remove(struct platform_device *pdev) |
1256 | { |
1257 | pm_runtime_disable(dev: &pdev->dev); |
1258 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
1259 | fsl_asrc_runtime_suspend(dev: &pdev->dev); |
1260 | } |
1261 | |
1262 | static int fsl_asrc_runtime_resume(struct device *dev) |
1263 | { |
1264 | struct fsl_asrc *asrc = dev_get_drvdata(dev); |
1265 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
1266 | int reg, retry = INIT_RETRY_NUM; |
1267 | int i, ret; |
1268 | u32 asrctr; |
1269 | |
1270 | ret = clk_prepare_enable(clk: asrc->mem_clk); |
1271 | if (ret) |
1272 | return ret; |
1273 | ret = clk_prepare_enable(clk: asrc->ipg_clk); |
1274 | if (ret) |
1275 | goto disable_mem_clk; |
1276 | if (!IS_ERR(ptr: asrc->spba_clk)) { |
1277 | ret = clk_prepare_enable(clk: asrc->spba_clk); |
1278 | if (ret) |
1279 | goto disable_ipg_clk; |
1280 | } |
1281 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { |
1282 | ret = clk_prepare_enable(clk: asrc_priv->asrck_clk[i]); |
1283 | if (ret) |
1284 | goto disable_asrck_clk; |
1285 | } |
1286 | |
1287 | /* Stop all pairs provisionally */ |
1288 | regmap_read(map: asrc->regmap, REG_ASRCTR, val: &asrctr); |
1289 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
1290 | ASRCTR_ASRCEi_ALL_MASK, val: 0); |
1291 | |
1292 | /* Restore all registers */ |
1293 | regcache_cache_only(map: asrc->regmap, enable: false); |
1294 | regcache_mark_dirty(map: asrc->regmap); |
1295 | regcache_sync(map: asrc->regmap); |
1296 | |
1297 | regmap_update_bits(map: asrc->regmap, REG_ASRCFG, |
1298 | ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | |
1299 | ASRCFG_PREMODi_ALL_MASK, val: asrc_priv->regcache_cfg); |
1300 | |
1301 | /* Restart enabled pairs */ |
1302 | regmap_update_bits(map: asrc->regmap, REG_ASRCTR, |
1303 | ASRCTR_ASRCEi_ALL_MASK, val: asrctr); |
1304 | |
1305 | /* Wait for status of initialization for all enabled pairs */ |
1306 | do { |
1307 | udelay(5); |
1308 | regmap_read(map: asrc->regmap, REG_ASRCFG, val: ®); |
1309 | reg = (reg >> ASRCFG_INIRQi_SHIFT(0)) & 0x7; |
1310 | } while ((reg != ((asrctr >> ASRCTR_ASRCEi_SHIFT(0)) & 0x7)) && --retry); |
1311 | |
1312 | /* |
1313 | * NOTE: Doesn't treat initialization timeout as an error |
1314 | * Some of the pairs may success, then still can continue. |
1315 | */ |
1316 | if (!retry) { |
1317 | for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { |
1318 | if ((asrctr & ASRCTR_ASRCEi_MASK(i)) && !(reg & (1 << i))) |
1319 | dev_warn(dev, "Pair %c initialization isn't finished\n" , 'A' + i); |
1320 | } |
1321 | } |
1322 | |
1323 | return 0; |
1324 | |
1325 | disable_asrck_clk: |
1326 | for (i--; i >= 0; i--) |
1327 | clk_disable_unprepare(clk: asrc_priv->asrck_clk[i]); |
1328 | if (!IS_ERR(ptr: asrc->spba_clk)) |
1329 | clk_disable_unprepare(clk: asrc->spba_clk); |
1330 | disable_ipg_clk: |
1331 | clk_disable_unprepare(clk: asrc->ipg_clk); |
1332 | disable_mem_clk: |
1333 | clk_disable_unprepare(clk: asrc->mem_clk); |
1334 | return ret; |
1335 | } |
1336 | |
1337 | static int fsl_asrc_runtime_suspend(struct device *dev) |
1338 | { |
1339 | struct fsl_asrc *asrc = dev_get_drvdata(dev); |
1340 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
1341 | int i; |
1342 | |
1343 | regmap_read(map: asrc->regmap, REG_ASRCFG, |
1344 | val: &asrc_priv->regcache_cfg); |
1345 | |
1346 | regcache_cache_only(map: asrc->regmap, enable: true); |
1347 | |
1348 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) |
1349 | clk_disable_unprepare(clk: asrc_priv->asrck_clk[i]); |
1350 | if (!IS_ERR(ptr: asrc->spba_clk)) |
1351 | clk_disable_unprepare(clk: asrc->spba_clk); |
1352 | clk_disable_unprepare(clk: asrc->ipg_clk); |
1353 | clk_disable_unprepare(clk: asrc->mem_clk); |
1354 | |
1355 | return 0; |
1356 | } |
1357 | |
1358 | static const struct dev_pm_ops fsl_asrc_pm = { |
1359 | SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) |
1360 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
1361 | pm_runtime_force_resume) |
1362 | }; |
1363 | |
1364 | static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { |
1365 | .use_edma = false, |
1366 | .channel_bits = 3, |
1367 | }; |
1368 | |
1369 | static const struct fsl_asrc_soc_data fsl_asrc_imx53_data = { |
1370 | .use_edma = false, |
1371 | .channel_bits = 4, |
1372 | }; |
1373 | |
1374 | static const struct fsl_asrc_soc_data fsl_asrc_imx8qm_data = { |
1375 | .use_edma = true, |
1376 | .channel_bits = 4, |
1377 | }; |
1378 | |
1379 | static const struct fsl_asrc_soc_data fsl_asrc_imx8qxp_data = { |
1380 | .use_edma = true, |
1381 | .channel_bits = 4, |
1382 | }; |
1383 | |
1384 | static const struct of_device_id fsl_asrc_ids[] = { |
1385 | { .compatible = "fsl,imx35-asrc" , .data = &fsl_asrc_imx35_data }, |
1386 | { .compatible = "fsl,imx53-asrc" , .data = &fsl_asrc_imx53_data }, |
1387 | { .compatible = "fsl,imx8qm-asrc" , .data = &fsl_asrc_imx8qm_data }, |
1388 | { .compatible = "fsl,imx8qxp-asrc" , .data = &fsl_asrc_imx8qxp_data }, |
1389 | {} |
1390 | }; |
1391 | MODULE_DEVICE_TABLE(of, fsl_asrc_ids); |
1392 | |
1393 | static struct platform_driver fsl_asrc_driver = { |
1394 | .probe = fsl_asrc_probe, |
1395 | .remove_new = fsl_asrc_remove, |
1396 | .driver = { |
1397 | .name = "fsl-asrc" , |
1398 | .of_match_table = fsl_asrc_ids, |
1399 | .pm = &fsl_asrc_pm, |
1400 | }, |
1401 | }; |
1402 | module_platform_driver(fsl_asrc_driver); |
1403 | |
1404 | MODULE_DESCRIPTION("Freescale ASRC ASoC driver" ); |
1405 | MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>" ); |
1406 | MODULE_ALIAS("platform:fsl-asrc" ); |
1407 | MODULE_LICENSE("GPL v2" ); |
1408 | |