Commit | Line | Data |
---|---|---|
2ba28053 FE |
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> | |
3117bb31 NC |
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> | |
c6547c2e | 14 | #include <linux/dma/imx-dma.h> |
3117bb31 NC |
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 | |
32038634 | 22 | #define DIVIDER_NUM 64 |
d2de3f5e | 23 | #define INIT_RETRY_NUM 50 |
3117bb31 NC |
24 | |
25 | #define pair_err(fmt, ...) \ | |
7470704d | 26 | dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) |
3117bb31 NC |
27 | |
28 | #define pair_dbg(fmt, ...) \ | |
7470704d | 29 | dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) |
3117bb31 | 30 | |
d2de3f5e SW |
31 | #define pair_warn(fmt, ...) \ |
32 | dev_warn(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) | |
33 | ||
3117bb31 | 34 | /* Corresponding to process_option */ |
d281bf5d W |
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, | |
3117bb31 NC |
38 | }; |
39 | ||
d281bf5d W |
40 | static struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { |
41 | .count = ARRAY_SIZE(supported_asrc_rate), | |
42 | .list = supported_asrc_rate, | |
3117bb31 NC |
43 | }; |
44 | ||
45e039d9 | 45 | /* |
3117bb31 NC |
46 | * The following tables map the relationship between asrc_inclk/asrc_outclk in |
47 | * fsl_asrc.h and the registers of ASRCSR | |
48 | */ | |
c05f10f2 | 49 | static unsigned char input_clk_map_imx35[ASRC_CLK_MAP_LEN] = { |
3117bb31 | 50 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, |
c05f10f2 SW |
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, | |
3117bb31 NC |
53 | }; |
54 | ||
c05f10f2 | 55 | static unsigned char output_clk_map_imx35[ASRC_CLK_MAP_LEN] = { |
3117bb31 | 56 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, |
c05f10f2 SW |
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, | |
3117bb31 NC |
59 | }; |
60 | ||
61 | /* i.MX53 uses the same map for input and output */ | |
c05f10f2 | 62 | static unsigned char input_clk_map_imx53[ASRC_CLK_MAP_LEN] = { |
3117bb31 NC |
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, | |
c05f10f2 SW |
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, | |
3117bb31 NC |
67 | }; |
68 | ||
c05f10f2 | 69 | static unsigned char output_clk_map_imx53[ASRC_CLK_MAP_LEN] = { |
3117bb31 NC |
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, | |
c05f10f2 SW |
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, | |
3117bb31 NC |
74 | }; |
75 | ||
45e039d9 | 76 | /* |
c05f10f2 SW |
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 | }; | |
3117bb31 | 108 | |
32038634 SW |
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 | ||
4aecaa0a | 158 | /** |
45e039d9 PLB |
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 | * | |
4aecaa0a W |
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 | * | |
4aecaa0a W |
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 | ||
3117bb31 | 205 | /** |
45e039d9 PLB |
206 | * fsl_asrc_request_pair - Request ASRC pair |
207 | * @channels: number of channels | |
208 | * @pair: pointer to pair | |
3117bb31 NC |
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 | */ | |
c16e923d | 214 | static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) |
3117bb31 NC |
215 | { |
216 | enum asrc_pair_index index = ASRC_INVALID_PAIR; | |
7470704d SW |
217 | struct fsl_asrc *asrc = pair->asrc; |
218 | struct device *dev = &asrc->pdev->dev; | |
3117bb31 NC |
219 | unsigned long lock_flags; |
220 | int i, ret = 0; | |
221 | ||
7470704d | 222 | spin_lock_irqsave(&asrc->lock, lock_flags); |
3117bb31 NC |
223 | |
224 | for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { | |
7470704d | 225 | if (asrc->pair[i] != NULL) |
3117bb31 NC |
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; | |
7470704d | 237 | } else if (asrc->channel_avail < channels) { |
3117bb31 NC |
238 | dev_err(dev, "can't afford required channels: %d\n", channels); |
239 | ret = -EINVAL; | |
240 | } else { | |
7470704d SW |
241 | asrc->channel_avail -= channels; |
242 | asrc->pair[index] = pair; | |
3117bb31 NC |
243 | pair->channels = channels; |
244 | pair->index = index; | |
245 | } | |
246 | ||
7470704d | 247 | spin_unlock_irqrestore(&asrc->lock, lock_flags); |
3117bb31 NC |
248 | |
249 | return ret; | |
250 | } | |
251 | ||
252 | /** | |
45e039d9 PLB |
253 | * fsl_asrc_release_pair - Release ASRC pair |
254 | * @pair: pair to release | |
3117bb31 | 255 | * |
7470704d | 256 | * It clears the resource from asrc and releases the occupied channels. |
3117bb31 | 257 | */ |
c16e923d | 258 | static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) |
3117bb31 | 259 | { |
7470704d | 260 | struct fsl_asrc *asrc = pair->asrc; |
3117bb31 NC |
261 | enum asrc_pair_index index = pair->index; |
262 | unsigned long lock_flags; | |
263 | ||
264 | /* Make sure the pair is disabled */ | |
7470704d | 265 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 NC |
266 | ASRCTR_ASRCEi_MASK(index), 0); |
267 | ||
7470704d | 268 | spin_lock_irqsave(&asrc->lock, lock_flags); |
3117bb31 | 269 | |
7470704d SW |
270 | asrc->channel_avail += pair->channels; |
271 | asrc->pair[index] = NULL; | |
3117bb31 NC |
272 | pair->error = 0; |
273 | ||
7470704d | 274 | spin_unlock_irqrestore(&asrc->lock, lock_flags); |
3117bb31 NC |
275 | } |
276 | ||
277 | /** | |
45e039d9 PLB |
278 | * fsl_asrc_set_watermarks- configure input and output thresholds |
279 | * @pair: pointer to pair | |
280 | * @in: input threshold | |
281 | * @out: output threshold | |
3117bb31 NC |
282 | */ |
283 | static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) | |
284 | { | |
7470704d | 285 | struct fsl_asrc *asrc = pair->asrc; |
3117bb31 NC |
286 | enum asrc_pair_index index = pair->index; |
287 | ||
7470704d | 288 | regmap_update_bits(asrc->regmap, REG_ASRMCR(index), |
3117bb31 NC |
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 | /** | |
45e039d9 PLB |
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 | |
3117bb31 NC |
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 | /** | |
45e039d9 PLB |
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 | |
3117bb31 NC |
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 | { | |
7470704d | 326 | struct fsl_asrc *asrc = pair->asrc; |
3117bb31 NC |
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 | ||
7470704d SW |
355 | regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio); |
356 | regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24); | |
3117bb31 NC |
357 | |
358 | return 0; | |
359 | } | |
360 | ||
361 | /** | |
45e039d9 PLB |
362 | * fsl_asrc_config_pair - Configure the assigned ASRC pair |
363 | * @pair: pointer to pair | |
364 | * @use_ideal_rate: boolean configuration | |
3117bb31 NC |
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. | |
b39eb1e2 SW |
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. | |
3117bb31 | 376 | */ |
b39eb1e2 | 377 | static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) |
3117bb31 | 378 | { |
be7bd03f SW |
379 | struct fsl_asrc_pair_priv *pair_priv = pair->private; |
380 | struct asrc_config *config = pair_priv->config; | |
7470704d | 381 | struct fsl_asrc *asrc = pair->asrc; |
be7bd03f | 382 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
3117bb31 | 383 | enum asrc_pair_index index = pair->index; |
4bf62571 SW |
384 | enum asrc_word_width input_word_width; |
385 | enum asrc_word_width output_word_width; | |
4e13eb72 | 386 | u32 inrate, outrate, indiv, outdiv; |
32038634 | 387 | u32 clk_index[2], div[2]; |
b39eb1e2 | 388 | u64 clk_rate; |
3117bb31 | 389 | int in, out, channels; |
4aecaa0a | 390 | int pre_proc, post_proc; |
3117bb31 | 391 | struct clk *clk; |
32038634 | 392 | bool ideal, div_avail; |
3117bb31 NC |
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 | ||
4bf62571 SW |
405 | switch (snd_pcm_format_width(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(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); | |
3117bb31 NC |
431 | return -EINVAL; |
432 | } | |
433 | ||
4e13eb72 NC |
434 | inrate = config->input_sample_rate; |
435 | outrate = config->output_sample_rate; | |
436 | ideal = config->inclk == INCLK_NONE; | |
437 | ||
3117bb31 | 438 | /* Validate input and output sample rates */ |
d281bf5d W |
439 | for (in = 0; in < ARRAY_SIZE(supported_asrc_rate); in++) |
440 | if (inrate == supported_asrc_rate[in]) | |
3117bb31 NC |
441 | break; |
442 | ||
d281bf5d | 443 | if (in == ARRAY_SIZE(supported_asrc_rate)) { |
3117bb31 NC |
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 | ||
d281bf5d | 457 | if ((outrate >= 5512 && outrate <= 30000) && |
b06c58c2 | 458 | (outrate > 24 * inrate || inrate > 8 * outrate)) { |
fff6e03c ZW |
459 | pair_err("exceed supported ratio range [1/24, 8] for \ |
460 | inrate/outrate: %d/%d\n", inrate, outrate); | |
461 | return -EINVAL; | |
462 | } | |
463 | ||
3117bb31 | 464 | /* Validate input and output clock sources */ |
be7bd03f SW |
465 | clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; |
466 | clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk]; | |
3117bb31 NC |
467 | |
468 | /* We only have output clock for ideal ratio mode */ | |
be7bd03f | 469 | clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; |
3117bb31 | 470 | |
b39eb1e2 | 471 | clk_rate = clk_get_rate(clk); |
32038634 | 472 | div_avail = fsl_asrc_divider_avail(clk_rate, inrate, &div[IN]); |
b39eb1e2 SW |
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 | */ | |
32038634 | 481 | if (div[IN] == 0 || (!ideal && !div_avail)) { |
3117bb31 NC |
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 | ||
b39eb1e2 | 487 | div[IN] = min_t(u32, 1024, div[IN]); |
3117bb31 | 488 | |
be7bd03f | 489 | clk = asrc_priv->asrck_clk[clk_index[OUT]]; |
b39eb1e2 SW |
490 | clk_rate = clk_get_rate(clk); |
491 | if (ideal && use_ideal_rate) | |
32038634 | 492 | div_avail = fsl_asrc_divider_avail(clk_rate, IDEAL_RATIO_RATE, &div[OUT]); |
3117bb31 | 493 | else |
32038634 | 494 | div_avail = fsl_asrc_divider_avail(clk_rate, outrate, &div[OUT]); |
3117bb31 | 495 | |
b39eb1e2 | 496 | /* Output divider has the same limitation as the input one */ |
32038634 | 497 | if (div[OUT] == 0 || (!ideal && !div_avail)) { |
3117bb31 NC |
498 | pair_err("failed to support output sample rate %dHz by asrck_%x\n", |
499 | outrate, clk_index[OUT]); | |
500 | return -EINVAL; | |
501 | } | |
502 | ||
b39eb1e2 SW |
503 | div[OUT] = min_t(u32, 1024, div[OUT]); |
504 | ||
3117bb31 NC |
505 | /* Set the channel number */ |
506 | channels = config->channel_num; | |
507 | ||
be7bd03f | 508 | if (asrc_priv->soc->channel_bits < 4) |
3117bb31 NC |
509 | channels /= 2; |
510 | ||
511 | /* Update channels for current pair */ | |
7470704d | 512 | regmap_update_bits(asrc->regmap, REG_ASRCNCR, |
be7bd03f SW |
513 | ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), |
514 | ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits)); | |
3117bb31 NC |
515 | |
516 | /* Default setting: Automatic selection for processing mode */ | |
7470704d | 517 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 | 518 | ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); |
7470704d | 519 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 NC |
520 | ASRCTR_USRi_MASK(index), 0); |
521 | ||
522 | /* Set the input and output clock sources */ | |
7470704d | 523 | regmap_update_bits(asrc->regmap, REG_ASRCSR, |
3117bb31 NC |
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[IN]); | |
530 | outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); | |
531 | ||
532 | /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ | |
7470704d | 533 | regmap_update_bits(asrc->regmap, REG_ASRCDR(index), |
3117bb31 NC |
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 */ | |
7470704d | 539 | regmap_update_bits(asrc->regmap, REG_ASRMCR1(index), |
3117bb31 | 540 | ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, |
4bf62571 SW |
541 | ASRMCR1i_OW16(output_word_width) | |
542 | ASRMCR1i_IWD(input_word_width)); | |
3117bb31 NC |
543 | |
544 | /* Enable BUFFER STALL */ | |
7470704d | 545 | regmap_update_bits(asrc->regmap, REG_ASRMCR(index), |
3117bb31 NC |
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 | ||
4091fb95 | 552 | /* Configure the following only for Ideal Ratio mode */ |
3117bb31 NC |
553 | if (!ideal) |
554 | return 0; | |
555 | ||
556 | /* Clear ASTSx bit to use Ideal Ratio mode */ | |
7470704d | 557 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 NC |
558 | ASRCTR_ATSi_MASK(index), 0); |
559 | ||
560 | /* Enable Ideal Ratio mode */ | |
7470704d | 561 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 NC |
562 | ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), |
563 | ASRCTR_IDR(index) | ASRCTR_USR(index)); | |
564 | ||
4aecaa0a W |
565 | fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc); |
566 | ||
3117bb31 | 567 | /* Apply configurations for pre- and post-processing */ |
7470704d | 568 | regmap_update_bits(asrc->regmap, REG_ASRCFG, |
3117bb31 | 569 | ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), |
4aecaa0a W |
570 | ASRCFG_PREMOD(index, pre_proc) | |
571 | ASRCFG_POSTMOD(index, post_proc)); | |
3117bb31 NC |
572 | |
573 | return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); | |
574 | } | |
575 | ||
576 | /** | |
45e039d9 PLB |
577 | * fsl_asrc_start_pair - Start the assigned ASRC pair |
578 | * @pair: pointer to pair | |
3117bb31 NC |
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 | { | |
7470704d | 584 | struct fsl_asrc *asrc = pair->asrc; |
3117bb31 | 585 | enum asrc_pair_index index = pair->index; |
d2de3f5e | 586 | int reg, retry = INIT_RETRY_NUM, i; |
3117bb31 NC |
587 | |
588 | /* Enable the current pair */ | |
7470704d | 589 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 NC |
590 | ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); |
591 | ||
592 | /* Wait for status of initialization */ | |
593 | do { | |
594 | udelay(5); | |
7470704d | 595 | regmap_read(asrc->regmap, REG_ASRCFG, ®); |
3117bb31 NC |
596 | reg &= ASRCFG_INIRQi_MASK(index); |
597 | } while (!reg && --retry); | |
598 | ||
d2de3f5e SW |
599 | /* NOTE: Doesn't treat initialization timeout as an error */ |
600 | if (!retry) | |
601 | pair_warn("initialization isn't finished\n"); | |
602 | ||
3117bb31 | 603 | /* Make the input fifo to ASRC STALL level */ |
7470704d | 604 | regmap_read(asrc->regmap, REG_ASRCNCR, ®); |
3117bb31 | 605 | for (i = 0; i < pair->channels * 4; i++) |
7470704d | 606 | regmap_write(asrc->regmap, REG_ASRDI(index), 0); |
3117bb31 NC |
607 | |
608 | /* Enable overload interrupt */ | |
7470704d | 609 | regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE); |
3117bb31 NC |
610 | } |
611 | ||
612 | /** | |
45e039d9 PLB |
613 | * fsl_asrc_stop_pair - Stop the assigned ASRC pair |
614 | * @pair: pointer to pair | |
3117bb31 NC |
615 | */ |
616 | static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) | |
617 | { | |
7470704d | 618 | struct fsl_asrc *asrc = pair->asrc; |
3117bb31 NC |
619 | enum asrc_pair_index index = pair->index; |
620 | ||
621 | /* Stop the current pair */ | |
7470704d | 622 | regmap_update_bits(asrc->regmap, REG_ASRCTR, |
3117bb31 NC |
623 | ASRCTR_ASRCEi_MASK(index), 0); |
624 | } | |
625 | ||
626 | /** | |
45e039d9 PLB |
627 | * fsl_asrc_get_dma_channel- Get DMA channel according to the pair and direction. |
628 | * @pair: pointer to pair | |
629 | * @dir: DMA direction | |
3117bb31 | 630 | */ |
cff1f8b4 | 631 | static struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, |
632 | bool dir) | |
3117bb31 | 633 | { |
7470704d | 634 | struct fsl_asrc *asrc = pair->asrc; |
3117bb31 NC |
635 | enum asrc_pair_index index = pair->index; |
636 | char name[4]; | |
637 | ||
638 | sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); | |
639 | ||
7470704d | 640 | return dma_request_slave_channel(&asrc->pdev->dev, name); |
3117bb31 | 641 | } |
3117bb31 | 642 | |
53f67a78 W |
643 | static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, |
644 | struct snd_soc_dai *dai) | |
645 | { | |
7470704d | 646 | struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
be7bd03f | 647 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
53f67a78 W |
648 | |
649 | /* Odd channel number is not valid for older ASRC (channel_bits==3) */ | |
be7bd03f | 650 | if (asrc_priv->soc->channel_bits == 3) |
53f67a78 W |
651 | snd_pcm_hw_constraint_step(substream->runtime, 0, |
652 | SNDRV_PCM_HW_PARAM_CHANNELS, 2); | |
653 | ||
d281bf5d W |
654 | |
655 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | |
656 | SNDRV_PCM_HW_PARAM_RATE, &fsl_asrc_rate_constraints); | |
53f67a78 W |
657 | } |
658 | ||
d0250cf4 SW |
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; | |
b2967435 | 669 | int i, j; |
d0250cf4 SW |
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(asrc_priv->asrck_clk[clk_index]); | |
679 | /* Only match a perfect clock source with no remainder */ | |
32038634 | 680 | if (fsl_asrc_divider_avail(clk_rate, rate[j], NULL)) |
d0250cf4 SW |
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 | ||
3117bb31 NC |
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 | { | |
7470704d | 701 | struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
d0250cf4 | 702 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
3117bb31 NC |
703 | struct snd_pcm_runtime *runtime = substream->runtime; |
704 | struct fsl_asrc_pair *pair = runtime->private_data; | |
be7bd03f | 705 | struct fsl_asrc_pair_priv *pair_priv = pair->private; |
3117bb31 NC |
706 | unsigned int channels = params_channels(params); |
707 | unsigned int rate = params_rate(params); | |
708 | struct asrc_config config; | |
4bf62571 | 709 | int ret; |
3117bb31 NC |
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 | ||
be7bd03f | 717 | pair_priv->config = &config; |
3117bb31 | 718 | |
3117bb31 NC |
719 | config.pair = pair->index; |
720 | config.channel_num = channels; | |
3117bb31 NC |
721 | |
722 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
4bf62571 | 723 | config.input_format = params_format(params); |
4520af41 | 724 | config.output_format = asrc->asrc_format; |
3117bb31 | 725 | config.input_sample_rate = rate; |
7470704d | 726 | config.output_sample_rate = asrc->asrc_rate; |
3117bb31 | 727 | } else { |
4520af41 | 728 | config.input_format = asrc->asrc_format; |
4bf62571 | 729 | config.output_format = params_format(params); |
7470704d | 730 | config.input_sample_rate = asrc->asrc_rate; |
3117bb31 NC |
731 | config.output_sample_rate = rate; |
732 | } | |
733 | ||
d0250cf4 SW |
734 | fsl_asrc_select_clk(asrc_priv, pair, |
735 | config.input_sample_rate, | |
736 | config.output_sample_rate); | |
737 | ||
b39eb1e2 | 738 | ret = fsl_asrc_config_pair(pair, false); |
3117bb31 NC |
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 | ||
29a22ebf | 783 | static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { |
53f67a78 | 784 | .startup = fsl_asrc_dai_startup, |
3117bb31 NC |
785 | .hw_params = fsl_asrc_dai_hw_params, |
786 | .hw_free = fsl_asrc_dai_hw_free, | |
787 | .trigger = fsl_asrc_dai_trigger, | |
788 | }; | |
789 | ||
790 | static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) | |
791 | { | |
7470704d | 792 | struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
3117bb31 | 793 | |
7470704d SW |
794 | snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx, |
795 | &asrc->dma_params_rx); | |
3117bb31 NC |
796 | |
797 | return 0; | |
798 | } | |
799 | ||
3117bb31 NC |
800 | #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ |
801 | SNDRV_PCM_FMTBIT_S16_LE | \ | |
109539c9 | 802 | SNDRV_PCM_FMTBIT_S24_3LE) |
3117bb31 NC |
803 | |
804 | static struct snd_soc_dai_driver fsl_asrc_dai = { | |
805 | .probe = fsl_asrc_dai_probe, | |
806 | .playback = { | |
807 | .stream_name = "ASRC-Playback", | |
808 | .channels_min = 1, | |
809 | .channels_max = 10, | |
d281bf5d W |
810 | .rate_min = 5512, |
811 | .rate_max = 192000, | |
812 | .rates = SNDRV_PCM_RATE_KNOT, | |
109539c9 SW |
813 | .formats = FSL_ASRC_FORMATS | |
814 | SNDRV_PCM_FMTBIT_S8, | |
3117bb31 NC |
815 | }, |
816 | .capture = { | |
817 | .stream_name = "ASRC-Capture", | |
818 | .channels_min = 1, | |
819 | .channels_max = 10, | |
d281bf5d W |
820 | .rate_min = 5512, |
821 | .rate_max = 192000, | |
822 | .rates = SNDRV_PCM_RATE_KNOT, | |
3117bb31 NC |
823 | .formats = FSL_ASRC_FORMATS, |
824 | }, | |
825 | .ops = &fsl_asrc_dai_ops, | |
826 | }; | |
827 | ||
3117bb31 NC |
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 | ||
86a570c5 NC |
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 | ||
bf16d883 | 957 | static const struct regmap_config fsl_asrc_regmap_config = { |
3117bb31 NC |
958 | .reg_bits = 32, |
959 | .reg_stride = 4, | |
960 | .val_bits = 32, | |
961 | ||
962 | .max_register = REG_ASRMCR1C, | |
86a570c5 NC |
963 | .reg_defaults = fsl_asrc_reg, |
964 | .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), | |
3117bb31 NC |
965 | .readable_reg = fsl_asrc_readable_reg, |
966 | .volatile_reg = fsl_asrc_volatile_reg, | |
967 | .writeable_reg = fsl_asrc_writeable_reg, | |
b4138868 | 968 | .cache_type = REGCACHE_FLAT, |
3117bb31 NC |
969 | }; |
970 | ||
971 | /** | |
45e039d9 PLB |
972 | * fsl_asrc_init - Initialize ASRC registers with a default configuration |
973 | * @asrc: ASRC context | |
3117bb31 | 974 | */ |
7470704d | 975 | static int fsl_asrc_init(struct fsl_asrc *asrc) |
3117bb31 | 976 | { |
f8953043 SW |
977 | unsigned long ipg_rate; |
978 | ||
3117bb31 | 979 | /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ |
7470704d | 980 | regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN); |
3117bb31 NC |
981 | |
982 | /* Disable interrupt by default */ | |
7470704d | 983 | regmap_write(asrc->regmap, REG_ASRIER, 0x0); |
3117bb31 NC |
984 | |
985 | /* Apply recommended settings for parameters from Reference Manual */ | |
7470704d SW |
986 | regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff); |
987 | regmap_write(asrc->regmap, REG_ASRPM2, 0x255555); | |
988 | regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280); | |
989 | regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280); | |
990 | regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280); | |
3117bb31 NC |
991 | |
992 | /* Base address for task queue FIFO. Set to 0x7C */ | |
7470704d | 993 | regmap_update_bits(asrc->regmap, REG_ASRTFR1, |
3117bb31 NC |
994 | ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); |
995 | ||
f8953043 SW |
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(asrc->ipg_clk); | |
1002 | regmap_write(asrc->regmap, REG_ASR76K, ipg_rate / 76000); | |
1003 | return regmap_write(asrc->regmap, REG_ASR56K, ipg_rate / 56000); | |
3117bb31 NC |
1004 | } |
1005 | ||
1006 | /** | |
45e039d9 PLB |
1007 | * fsl_asrc_isr- Interrupt handler for ASRC |
1008 | * @irq: irq number | |
1009 | * @dev_id: ASRC context | |
3117bb31 NC |
1010 | */ |
1011 | static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) | |
1012 | { | |
7470704d SW |
1013 | struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id; |
1014 | struct device *dev = &asrc->pdev->dev; | |
3117bb31 NC |
1015 | enum asrc_pair_index index; |
1016 | u32 status; | |
1017 | ||
7470704d | 1018 | regmap_read(asrc->regmap, REG_ASRSTR, &status); |
3117bb31 NC |
1019 | |
1020 | /* Clean overload error */ | |
7470704d | 1021 | regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE); |
3117bb31 NC |
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++) { | |
7470704d | 1029 | if (!asrc->pair[index]) |
3117bb31 NC |
1030 | continue; |
1031 | ||
1032 | if (status & ASRSTR_ATQOL) { | |
7470704d | 1033 | asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; |
3117bb31 NC |
1034 | dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); |
1035 | } | |
1036 | ||
1037 | if (status & ASRSTR_AOOL(index)) { | |
7470704d | 1038 | asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; |
3117bb31 NC |
1039 | pair_dbg("Output Task Overload\n"); |
1040 | } | |
1041 | ||
1042 | if (status & ASRSTR_AIOL(index)) { | |
7470704d | 1043 | asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; |
3117bb31 NC |
1044 | pair_dbg("Input Task Overload\n"); |
1045 | } | |
1046 | ||
1047 | if (status & ASRSTR_AODO(index)) { | |
7470704d | 1048 | asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; |
3117bb31 NC |
1049 | pair_dbg("Output Data Buffer has overflowed\n"); |
1050 | } | |
1051 | ||
1052 | if (status & ASRSTR_AIDU(index)) { | |
7470704d | 1053 | asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; |
3117bb31 NC |
1054 | pair_dbg("Input Data Buffer has underflowed\n"); |
1055 | } | |
1056 | } | |
1057 | ||
1058 | return IRQ_HANDLED; | |
1059 | } | |
1060 | ||
be7bd03f SW |
1061 | static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) |
1062 | { | |
1063 | return REG_ASRDx(dir, index); | |
1064 | } | |
1065 | ||
cab04ab5 SW |
1066 | static int fsl_asrc_runtime_resume(struct device *dev); |
1067 | static int fsl_asrc_runtime_suspend(struct device *dev); | |
1068 | ||
3117bb31 NC |
1069 | static int fsl_asrc_probe(struct platform_device *pdev) |
1070 | { | |
1071 | struct device_node *np = pdev->dev.of_node; | |
be7bd03f | 1072 | struct fsl_asrc_priv *asrc_priv; |
7470704d | 1073 | struct fsl_asrc *asrc; |
3117bb31 NC |
1074 | struct resource *res; |
1075 | void __iomem *regs; | |
1076 | int irq, ret, i; | |
c4993272 | 1077 | u32 asrc_fmt = 0; |
c05f10f2 | 1078 | u32 map_idx; |
3117bb31 | 1079 | char tmp[16]; |
4520af41 | 1080 | u32 width; |
3117bb31 | 1081 | |
7470704d SW |
1082 | asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL); |
1083 | if (!asrc) | |
3117bb31 NC |
1084 | return -ENOMEM; |
1085 | ||
be7bd03f SW |
1086 | asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); |
1087 | if (!asrc_priv) | |
1088 | return -ENOMEM; | |
1089 | ||
7470704d | 1090 | asrc->pdev = pdev; |
be7bd03f | 1091 | asrc->private = asrc_priv; |
3117bb31 NC |
1092 | |
1093 | /* Get the addresses and IRQ */ | |
c66d7621 | 1094 | regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
3117bb31 NC |
1095 | if (IS_ERR(regs)) |
1096 | return PTR_ERR(regs); | |
1097 | ||
7470704d | 1098 | asrc->paddr = res->start; |
3117bb31 | 1099 | |
cab04ab5 | 1100 | asrc->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_asrc_regmap_config); |
7470704d | 1101 | if (IS_ERR(asrc->regmap)) { |
3117bb31 | 1102 | dev_err(&pdev->dev, "failed to init regmap\n"); |
7470704d | 1103 | return PTR_ERR(asrc->regmap); |
3117bb31 NC |
1104 | } |
1105 | ||
1106 | irq = platform_get_irq(pdev, 0); | |
cf9441ad | 1107 | if (irq < 0) |
3117bb31 | 1108 | return irq; |
3117bb31 NC |
1109 | |
1110 | ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, | |
7470704d | 1111 | dev_name(&pdev->dev), asrc); |
3117bb31 NC |
1112 | if (ret) { |
1113 | dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); | |
1114 | return ret; | |
1115 | } | |
1116 | ||
7470704d SW |
1117 | asrc->mem_clk = devm_clk_get(&pdev->dev, "mem"); |
1118 | if (IS_ERR(asrc->mem_clk)) { | |
3117bb31 | 1119 | dev_err(&pdev->dev, "failed to get mem clock\n"); |
7470704d | 1120 | return PTR_ERR(asrc->mem_clk); |
3117bb31 NC |
1121 | } |
1122 | ||
7470704d SW |
1123 | asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); |
1124 | if (IS_ERR(asrc->ipg_clk)) { | |
3117bb31 | 1125 | dev_err(&pdev->dev, "failed to get ipg clock\n"); |
7470704d | 1126 | return PTR_ERR(asrc->ipg_clk); |
3117bb31 NC |
1127 | } |
1128 | ||
7470704d SW |
1129 | asrc->spba_clk = devm_clk_get(&pdev->dev, "spba"); |
1130 | if (IS_ERR(asrc->spba_clk)) | |
13b8a97a SW |
1131 | dev_warn(&pdev->dev, "failed to get spba clock\n"); |
1132 | ||
3117bb31 NC |
1133 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { |
1134 | sprintf(tmp, "asrck_%x", i); | |
be7bd03f SW |
1135 | asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); |
1136 | if (IS_ERR(asrc_priv->asrck_clk[i])) { | |
3117bb31 | 1137 | dev_err(&pdev->dev, "failed to get %s clock\n", tmp); |
be7bd03f | 1138 | return PTR_ERR(asrc_priv->asrck_clk[i]); |
3117bb31 NC |
1139 | } |
1140 | } | |
1141 | ||
be7bd03f | 1142 | asrc_priv->soc = of_device_get_match_data(&pdev->dev); |
be7bd03f SW |
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 | ||
f3d8ac8c | 1150 | if (of_device_is_compatible(np, "fsl,imx35-asrc")) { |
be7bd03f SW |
1151 | asrc_priv->clk_map[IN] = input_clk_map_imx35; |
1152 | asrc_priv->clk_map[OUT] = output_clk_map_imx35; | |
c05f10f2 | 1153 | } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { |
be7bd03f SW |
1154 | asrc_priv->clk_map[IN] = input_clk_map_imx53; |
1155 | asrc_priv->clk_map[OUT] = output_clk_map_imx53; | |
c05f10f2 SW |
1156 | } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || |
1157 | of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { | |
1158 | ret = of_property_read_u32(np, "fsl,asrc-clk-map", &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(np, "fsl,imx8qm-asrc")) { | |
be7bd03f SW |
1169 | asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; |
1170 | asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; | |
c05f10f2 | 1171 | } else { |
be7bd03f SW |
1172 | asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; |
1173 | asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; | |
c05f10f2 | 1174 | } |
3117bb31 NC |
1175 | } |
1176 | ||
7470704d | 1177 | asrc->channel_avail = 10; |
3117bb31 NC |
1178 | |
1179 | ret = of_property_read_u32(np, "fsl,asrc-rate", | |
7470704d | 1180 | &asrc->asrc_rate); |
3117bb31 NC |
1181 | if (ret) { |
1182 | dev_err(&pdev->dev, "failed to get output rate\n"); | |
c0296950 | 1183 | return ret; |
3117bb31 NC |
1184 | } |
1185 | ||
c4993272 SW |
1186 | ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); |
1187 | asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; | |
3117bb31 | 1188 | if (ret) { |
4520af41 SW |
1189 | ret = of_property_read_u32(np, "fsl,asrc-width", &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 | } | |
3117bb31 NC |
1208 | } |
1209 | ||
c4993272 | 1210 | if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) { |
4520af41 SW |
1211 | dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n"); |
1212 | asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; | |
3117bb31 NC |
1213 | } |
1214 | ||
7470704d | 1215 | platform_set_drvdata(pdev, asrc); |
7470704d | 1216 | spin_lock_init(&asrc->lock); |
cab04ab5 SW |
1217 | pm_runtime_enable(&pdev->dev); |
1218 | if (!pm_runtime_enabled(&pdev->dev)) { | |
1219 | ret = fsl_asrc_runtime_resume(&pdev->dev); | |
1220 | if (ret) | |
1221 | goto err_pm_disable; | |
1222 | } | |
1223 | ||
d0504074 MC |
1224 | ret = pm_runtime_resume_and_get(&pdev->dev); |
1225 | if (ret < 0) | |
cab04ab5 | 1226 | goto err_pm_get_sync; |
cab04ab5 SW |
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(&pdev->dev); | |
6a564338 | 1235 | if (ret < 0 && ret != -ENOSYS) |
cab04ab5 | 1236 | goto err_pm_get_sync; |
3117bb31 NC |
1237 | |
1238 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, | |
1239 | &fsl_asrc_dai, 1); | |
1240 | if (ret) { | |
1241 | dev_err(&pdev->dev, "failed to register ASoC DAI\n"); | |
cab04ab5 | 1242 | goto err_pm_get_sync; |
3117bb31 NC |
1243 | } |
1244 | ||
3117bb31 | 1245 | return 0; |
cab04ab5 SW |
1246 | |
1247 | err_pm_get_sync: | |
1248 | if (!pm_runtime_status_suspended(&pdev->dev)) | |
1249 | fsl_asrc_runtime_suspend(&pdev->dev); | |
1250 | err_pm_disable: | |
1251 | pm_runtime_disable(&pdev->dev); | |
1252 | return ret; | |
1253 | } | |
1254 | ||
7a2d15b9 | 1255 | static void fsl_asrc_remove(struct platform_device *pdev) |
cab04ab5 SW |
1256 | { |
1257 | pm_runtime_disable(&pdev->dev); | |
1258 | if (!pm_runtime_status_suspended(&pdev->dev)) | |
1259 | fsl_asrc_runtime_suspend(&pdev->dev); | |
3117bb31 NC |
1260 | } |
1261 | ||
3117bb31 NC |
1262 | static int fsl_asrc_runtime_resume(struct device *dev) |
1263 | { | |
7470704d | 1264 | struct fsl_asrc *asrc = dev_get_drvdata(dev); |
be7bd03f | 1265 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
d2de3f5e | 1266 | int reg, retry = INIT_RETRY_NUM; |
b1ade0f2 | 1267 | int i, ret; |
393dc21d | 1268 | u32 asrctr; |
3117bb31 | 1269 | |
7470704d | 1270 | ret = clk_prepare_enable(asrc->mem_clk); |
b1ade0f2 FE |
1271 | if (ret) |
1272 | return ret; | |
7470704d | 1273 | ret = clk_prepare_enable(asrc->ipg_clk); |
b1ade0f2 FE |
1274 | if (ret) |
1275 | goto disable_mem_clk; | |
7470704d SW |
1276 | if (!IS_ERR(asrc->spba_clk)) { |
1277 | ret = clk_prepare_enable(asrc->spba_clk); | |
13b8a97a SW |
1278 | if (ret) |
1279 | goto disable_ipg_clk; | |
1280 | } | |
b1ade0f2 | 1281 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { |
be7bd03f | 1282 | ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); |
b1ade0f2 FE |
1283 | if (ret) |
1284 | goto disable_asrck_clk; | |
1285 | } | |
3117bb31 | 1286 | |
393dc21d SW |
1287 | /* Stop all pairs provisionally */ |
1288 | regmap_read(asrc->regmap, REG_ASRCTR, &asrctr); | |
1289 | regmap_update_bits(asrc->regmap, REG_ASRCTR, | |
1290 | ASRCTR_ASRCEi_ALL_MASK, 0); | |
1291 | ||
1292 | /* Restore all registers */ | |
1293 | regcache_cache_only(asrc->regmap, false); | |
1294 | regcache_mark_dirty(asrc->regmap); | |
1295 | regcache_sync(asrc->regmap); | |
1296 | ||
1297 | regmap_update_bits(asrc->regmap, REG_ASRCFG, | |
1298 | ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | | |
1299 | ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); | |
1300 | ||
1301 | /* Restart enabled pairs */ | |
1302 | regmap_update_bits(asrc->regmap, REG_ASRCTR, | |
1303 | ASRCTR_ASRCEi_ALL_MASK, asrctr); | |
1304 | ||
d2de3f5e SW |
1305 | /* Wait for status of initialization for all enabled pairs */ |
1306 | do { | |
1307 | udelay(5); | |
1308 | regmap_read(asrc->regmap, REG_ASRCFG, ®); | |
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 | ||
3117bb31 | 1323 | return 0; |
b1ade0f2 FE |
1324 | |
1325 | disable_asrck_clk: | |
1326 | for (i--; i >= 0; i--) | |
be7bd03f | 1327 | clk_disable_unprepare(asrc_priv->asrck_clk[i]); |
7470704d SW |
1328 | if (!IS_ERR(asrc->spba_clk)) |
1329 | clk_disable_unprepare(asrc->spba_clk); | |
13b8a97a | 1330 | disable_ipg_clk: |
7470704d | 1331 | clk_disable_unprepare(asrc->ipg_clk); |
b1ade0f2 | 1332 | disable_mem_clk: |
7470704d | 1333 | clk_disable_unprepare(asrc->mem_clk); |
b1ade0f2 | 1334 | return ret; |
3117bb31 NC |
1335 | } |
1336 | ||
1337 | static int fsl_asrc_runtime_suspend(struct device *dev) | |
1338 | { | |
7470704d | 1339 | struct fsl_asrc *asrc = dev_get_drvdata(dev); |
be7bd03f | 1340 | struct fsl_asrc_priv *asrc_priv = asrc->private; |
3117bb31 NC |
1341 | int i; |
1342 | ||
393dc21d SW |
1343 | regmap_read(asrc->regmap, REG_ASRCFG, |
1344 | &asrc_priv->regcache_cfg); | |
1345 | ||
1346 | regcache_cache_only(asrc->regmap, true); | |
1347 | ||
3117bb31 | 1348 | for (i = 0; i < ASRC_CLK_MAX_NUM; i++) |
be7bd03f | 1349 | clk_disable_unprepare(asrc_priv->asrck_clk[i]); |
7470704d SW |
1350 | if (!IS_ERR(asrc->spba_clk)) |
1351 | clk_disable_unprepare(asrc->spba_clk); | |
1352 | clk_disable_unprepare(asrc->ipg_clk); | |
1353 | clk_disable_unprepare(asrc->mem_clk); | |
3117bb31 NC |
1354 | |
1355 | return 0; | |
1356 | } | |
3117bb31 | 1357 | |
3117bb31 NC |
1358 | static const struct dev_pm_ops fsl_asrc_pm = { |
1359 | SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) | |
393dc21d SW |
1360 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
1361 | pm_runtime_force_resume) | |
3117bb31 NC |
1362 | }; |
1363 | ||
c05f10f2 SW |
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 | ||
3117bb31 | 1384 | static const struct of_device_id fsl_asrc_ids[] = { |
c05f10f2 SW |
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 }, | |
3117bb31 NC |
1389 | {} |
1390 | }; | |
1391 | MODULE_DEVICE_TABLE(of, fsl_asrc_ids); | |
1392 | ||
1393 | static struct platform_driver fsl_asrc_driver = { | |
1394 | .probe = fsl_asrc_probe, | |
7a2d15b9 | 1395 | .remove_new = fsl_asrc_remove, |
3117bb31 NC |
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"); |