diff options
Diffstat (limited to 'sound/soc/sh/rcar/ssi.c')
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 334 |
1 files changed, 174 insertions, 160 deletions
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7ee89da4dd5f..5f848f054745 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -64,7 +64,6 @@ | |||
64 | #define SSI_NAME "ssi" | 64 | #define SSI_NAME "ssi" |
65 | 65 | ||
66 | struct rsnd_ssi { | 66 | struct rsnd_ssi { |
67 | struct rsnd_ssi *parent; | ||
68 | struct rsnd_mod mod; | 67 | struct rsnd_mod mod; |
69 | struct rsnd_mod *dma; | 68 | struct rsnd_mod *dma; |
70 | 69 | ||
@@ -75,7 +74,6 @@ struct rsnd_ssi { | |||
75 | u32 wsr; | 74 | u32 wsr; |
76 | int chan; | 75 | int chan; |
77 | int rate; | 76 | int rate; |
78 | int err; | ||
79 | int irq; | 77 | int irq; |
80 | unsigned int usrcnt; | 78 | unsigned int usrcnt; |
81 | }; | 79 | }; |
@@ -96,7 +94,10 @@ struct rsnd_ssi { | |||
96 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 94 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
97 | #define rsnd_ssi_mode_flags(p) ((p)->flags) | 95 | #define rsnd_ssi_mode_flags(p) ((p)->flags) |
98 | #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) | 96 | #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) |
99 | #define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io)) | 97 | #define rsnd_ssi_is_multi_slave(mod, io) \ |
98 | (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) | ||
99 | #define rsnd_ssi_is_run_mods(mod, io) \ | ||
100 | (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) | ||
100 | 101 | ||
101 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) | 102 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) |
102 | { | 103 | { |
@@ -141,43 +142,13 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, | |||
141 | udelay(50); | 142 | udelay(50); |
142 | } | 143 | } |
143 | 144 | ||
144 | dev_warn(dev, "status check failed\n"); | 145 | dev_warn(dev, "%s[%d] status check failed\n", |
145 | } | 146 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
146 | |||
147 | static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod) | ||
148 | { | ||
149 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
150 | |||
151 | if (rsnd_is_gen1(priv)) | ||
152 | return 0; | ||
153 | |||
154 | /* enable SSI interrupt if Gen2 */ | ||
155 | rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, | ||
156 | rsnd_ssi_is_dma_mode(ssi_mod) ? | ||
157 | 0x0e000000 : 0x0f000000); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod) | ||
163 | { | ||
164 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
165 | |||
166 | if (rsnd_is_gen1(priv)) | ||
167 | return 0; | ||
168 | |||
169 | /* disable SSI interrupt if Gen2 */ | ||
170 | rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); | ||
171 | |||
172 | return 0; | ||
173 | } | 147 | } |
174 | 148 | ||
175 | u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) | 149 | static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) |
176 | { | 150 | { |
177 | struct rsnd_mod *mod; | 151 | struct rsnd_mod *mod; |
178 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
179 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
180 | struct device *dev = rsnd_priv_to_dev(priv); | ||
181 | enum rsnd_mod_type types[] = { | 152 | enum rsnd_mod_type types[] = { |
182 | RSND_MOD_SSIM1, | 153 | RSND_MOD_SSIM1, |
183 | RSND_MOD_SSIM2, | 154 | RSND_MOD_SSIM2, |
@@ -185,16 +156,6 @@ u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) | |||
185 | }; | 156 | }; |
186 | int i, mask; | 157 | int i, mask; |
187 | 158 | ||
188 | switch (runtime->channels) { | ||
189 | case 2: /* Multi channel is not needed for Stereo */ | ||
190 | return 0; | ||
191 | case 6: | ||
192 | break; | ||
193 | default: | ||
194 | dev_err(dev, "unsupported channel\n"); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | mask = 0; | 159 | mask = 0; |
199 | for (i = 0; i < ARRAY_SIZE(types); i++) { | 160 | for (i = 0; i < ARRAY_SIZE(types); i++) { |
200 | mod = rsnd_io_to_mod(io, types[i]); | 161 | mod = rsnd_io_to_mod(io, types[i]); |
@@ -207,22 +168,41 @@ u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) | |||
207 | return mask; | 168 | return mask; |
208 | } | 169 | } |
209 | 170 | ||
210 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | 171 | static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) |
172 | { | ||
173 | struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); | ||
174 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); | ||
175 | |||
176 | return rsnd_ssi_multi_slaves_runtime(io) | | ||
177 | 1 << rsnd_mod_id(ssi_mod) | | ||
178 | 1 << rsnd_mod_id(ssi_parent_mod); | ||
179 | } | ||
180 | |||
181 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) | ||
182 | { | ||
183 | if (rsnd_runtime_is_ssi_multi(io)) | ||
184 | return rsnd_ssi_multi_slaves(io); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | ||
211 | struct rsnd_dai_stream *io) | 190 | struct rsnd_dai_stream *io) |
212 | { | 191 | { |
213 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | 192 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
214 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
215 | struct device *dev = rsnd_priv_to_dev(priv); | 193 | struct device *dev = rsnd_priv_to_dev(priv); |
216 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 194 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
217 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 195 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
218 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); | 196 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); |
219 | int slots = rsnd_get_slot_width(io); | 197 | int chan = rsnd_runtime_channel_for_ssi(io); |
220 | int j, ret; | 198 | int j, ret; |
221 | int ssi_clk_mul_table[] = { | 199 | int ssi_clk_mul_table[] = { |
222 | 1, 2, 4, 8, 16, 6, 12, | 200 | 1, 2, 4, 8, 16, 6, 12, |
223 | }; | 201 | }; |
224 | unsigned int main_rate; | 202 | unsigned int main_rate; |
225 | unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); | 203 | unsigned int rate = rsnd_io_is_play(io) ? |
204 | rsnd_src_get_out_rate(priv, io) : | ||
205 | rsnd_src_get_in_rate(priv, io); | ||
226 | 206 | ||
227 | if (!rsnd_rdai_is_clk_master(rdai)) | 207 | if (!rsnd_rdai_is_clk_master(rdai)) |
228 | return 0; | 208 | return 0; |
@@ -249,10 +229,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
249 | 229 | ||
250 | /* | 230 | /* |
251 | * this driver is assuming that | 231 | * this driver is assuming that |
252 | * system word is 32bit x slots | 232 | * system word is 32bit x chan |
253 | * see rsnd_ssi_init() | 233 | * see rsnd_ssi_init() |
254 | */ | 234 | */ |
255 | main_rate = rate * 32 * slots * ssi_clk_mul_table[j]; | 235 | main_rate = rate * 32 * chan * ssi_clk_mul_table[j]; |
256 | 236 | ||
257 | ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); | 237 | ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); |
258 | if (0 == ret) { | 238 | if (0 == ret) { |
@@ -274,11 +254,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
274 | return -EIO; | 254 | return -EIO; |
275 | } | 255 | } |
276 | 256 | ||
277 | static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, | 257 | static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, |
278 | struct rsnd_dai_stream *io) | 258 | struct rsnd_dai_stream *io) |
279 | { | 259 | { |
280 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 260 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
281 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 261 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
282 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); | 262 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); |
283 | 263 | ||
284 | if (!rsnd_rdai_is_clk_master(rdai)) | 264 | if (!rsnd_rdai_is_clk_master(rdai)) |
@@ -296,17 +276,18 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, | |||
296 | rsnd_adg_ssi_clk_stop(mod); | 276 | rsnd_adg_ssi_clk_stop(mod); |
297 | } | 277 | } |
298 | 278 | ||
299 | static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, | 279 | static void rsnd_ssi_config_init(struct rsnd_mod *mod, |
300 | struct rsnd_dai_stream *io) | 280 | struct rsnd_dai_stream *io) |
301 | { | 281 | { |
302 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 282 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
303 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 283 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
284 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
304 | u32 cr_own; | 285 | u32 cr_own; |
305 | u32 cr_mode; | 286 | u32 cr_mode; |
306 | u32 wsr; | 287 | u32 wsr; |
307 | int is_tdm; | 288 | int is_tdm; |
308 | 289 | ||
309 | is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0; | 290 | is_tdm = rsnd_runtime_is_ssi_tdm(io); |
310 | 291 | ||
311 | /* | 292 | /* |
312 | * always use 32bit system word. | 293 | * always use 32bit system word. |
@@ -332,11 +313,9 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, | |||
332 | case 32: | 313 | case 32: |
333 | cr_own |= DWL_24; | 314 | cr_own |= DWL_24; |
334 | break; | 315 | break; |
335 | default: | ||
336 | return -EINVAL; | ||
337 | } | 316 | } |
338 | 317 | ||
339 | if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) { | 318 | if (rsnd_ssi_is_dma_mode(mod)) { |
340 | cr_mode = UIEN | OIEN | /* over/under run */ | 319 | cr_mode = UIEN | OIEN | /* over/under run */ |
341 | DMEN; /* DMA : enable DMA */ | 320 | DMEN; /* DMA : enable DMA */ |
342 | } else { | 321 | } else { |
@@ -357,8 +336,16 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, | |||
357 | ssi->cr_own = cr_own; | 336 | ssi->cr_own = cr_own; |
358 | ssi->cr_mode = cr_mode; | 337 | ssi->cr_mode = cr_mode; |
359 | ssi->wsr = wsr; | 338 | ssi->wsr = wsr; |
339 | } | ||
360 | 340 | ||
361 | return 0; | 341 | static void rsnd_ssi_register_setup(struct rsnd_mod *mod) |
342 | { | ||
343 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
344 | |||
345 | rsnd_mod_write(mod, SSIWSR, ssi->wsr); | ||
346 | rsnd_mod_write(mod, SSICR, ssi->cr_own | | ||
347 | ssi->cr_clk | | ||
348 | ssi->cr_mode); /* without EN */ | ||
362 | } | 349 | } |
363 | 350 | ||
364 | /* | 351 | /* |
@@ -371,28 +358,25 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
371 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 358 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
372 | int ret; | 359 | int ret; |
373 | 360 | ||
361 | if (!rsnd_ssi_is_run_mods(mod, io)) | ||
362 | return 0; | ||
363 | |||
374 | ssi->usrcnt++; | 364 | ssi->usrcnt++; |
375 | 365 | ||
376 | rsnd_mod_power_on(mod); | 366 | rsnd_mod_power_on(mod); |
377 | 367 | ||
378 | ret = rsnd_ssi_master_clk_start(ssi, io); | 368 | ret = rsnd_ssi_master_clk_start(mod, io); |
379 | if (ret < 0) | 369 | if (ret < 0) |
380 | return ret; | 370 | return ret; |
381 | 371 | ||
382 | if (rsnd_ssi_is_parent(mod, io)) | 372 | if (!rsnd_ssi_is_parent(mod, io)) |
383 | return 0; | 373 | rsnd_ssi_config_init(mod, io); |
384 | |||
385 | ret = rsnd_ssi_config_init(ssi, io); | ||
386 | if (ret < 0) | ||
387 | return ret; | ||
388 | 374 | ||
389 | ssi->err = -1; /* ignore 1st error */ | 375 | rsnd_ssi_register_setup(mod); |
390 | 376 | ||
391 | /* clear error status */ | 377 | /* clear error status */ |
392 | rsnd_ssi_status_clear(mod); | 378 | rsnd_ssi_status_clear(mod); |
393 | 379 | ||
394 | rsnd_ssi_irq_enable(mod); | ||
395 | |||
396 | return 0; | 380 | return 0; |
397 | } | 381 | } |
398 | 382 | ||
@@ -403,25 +387,19 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
403 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 387 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
404 | struct device *dev = rsnd_priv_to_dev(priv); | 388 | struct device *dev = rsnd_priv_to_dev(priv); |
405 | 389 | ||
390 | if (!rsnd_ssi_is_run_mods(mod, io)) | ||
391 | return 0; | ||
392 | |||
406 | if (!ssi->usrcnt) { | 393 | if (!ssi->usrcnt) { |
407 | dev_err(dev, "%s[%d] usrcnt error\n", | 394 | dev_err(dev, "%s[%d] usrcnt error\n", |
408 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | 395 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
409 | return -EIO; | 396 | return -EIO; |
410 | } | 397 | } |
411 | 398 | ||
412 | if (!rsnd_ssi_is_parent(mod, io)) { | 399 | if (!rsnd_ssi_is_parent(mod, io)) |
413 | if (ssi->err > 0) | ||
414 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", | ||
415 | rsnd_mod_name(mod), rsnd_mod_id(mod), | ||
416 | ssi->err); | ||
417 | |||
418 | ssi->cr_own = 0; | 400 | ssi->cr_own = 0; |
419 | ssi->err = 0; | ||
420 | 401 | ||
421 | rsnd_ssi_irq_disable(mod); | 402 | rsnd_ssi_master_clk_stop(mod, io); |
422 | } | ||
423 | |||
424 | rsnd_ssi_master_clk_stop(ssi, io); | ||
425 | 403 | ||
426 | rsnd_mod_power_off(mod); | 404 | rsnd_mod_power_off(mod); |
427 | 405 | ||
@@ -456,61 +434,43 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, | |||
456 | return 0; | 434 | return 0; |
457 | } | 435 | } |
458 | 436 | ||
459 | static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) | 437 | static int rsnd_ssi_start(struct rsnd_mod *mod, |
460 | { | 438 | struct rsnd_dai_stream *io, |
461 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 439 | struct rsnd_priv *priv) |
462 | u32 status = rsnd_ssi_status_get(mod); | ||
463 | |||
464 | /* under/over flow error */ | ||
465 | if (status & (UIRQ | OIRQ)) | ||
466 | ssi->err++; | ||
467 | |||
468 | return status; | ||
469 | } | ||
470 | |||
471 | static int __rsnd_ssi_start(struct rsnd_mod *mod, | ||
472 | struct rsnd_dai_stream *io, | ||
473 | struct rsnd_priv *priv) | ||
474 | { | 440 | { |
475 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 441 | if (!rsnd_ssi_is_run_mods(mod, io)) |
476 | u32 cr; | 442 | return 0; |
477 | |||
478 | cr = ssi->cr_own | | ||
479 | ssi->cr_clk | | ||
480 | ssi->cr_mode; | ||
481 | 443 | ||
482 | /* | 444 | /* |
483 | * EN will be set via SSIU :: SSI_CONTROL | 445 | * EN will be set via SSIU :: SSI_CONTROL |
484 | * if Multi channel mode | 446 | * if Multi channel mode |
485 | */ | 447 | */ |
486 | if (!rsnd_ssi_multi_slaves(io)) | 448 | if (rsnd_ssi_multi_slaves_runtime(io)) |
487 | cr |= EN; | 449 | return 0; |
488 | 450 | ||
489 | rsnd_mod_write(mod, SSICR, cr); | 451 | rsnd_mod_bset(mod, SSICR, EN, EN); |
490 | rsnd_mod_write(mod, SSIWSR, ssi->wsr); | ||
491 | 452 | ||
492 | return 0; | 453 | return 0; |
493 | } | 454 | } |
494 | 455 | ||
495 | static int rsnd_ssi_start(struct rsnd_mod *mod, | 456 | static int rsnd_ssi_stop(struct rsnd_mod *mod, |
496 | struct rsnd_dai_stream *io, | 457 | struct rsnd_dai_stream *io, |
497 | struct rsnd_priv *priv) | 458 | struct rsnd_priv *priv) |
498 | { | 459 | { |
460 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
461 | u32 cr; | ||
462 | |||
463 | if (!rsnd_ssi_is_run_mods(mod, io)) | ||
464 | return 0; | ||
465 | |||
499 | /* | 466 | /* |
500 | * no limit to start | 467 | * don't stop if not last user |
501 | * see also | 468 | * see also |
502 | * rsnd_ssi_stop | 469 | * rsnd_ssi_start |
503 | * rsnd_ssi_interrupt | 470 | * rsnd_ssi_interrupt |
504 | */ | 471 | */ |
505 | return __rsnd_ssi_start(mod, io, priv); | 472 | if (ssi->usrcnt > 1) |
506 | } | 473 | return 0; |
507 | |||
508 | static int __rsnd_ssi_stop(struct rsnd_mod *mod, | ||
509 | struct rsnd_dai_stream *io, | ||
510 | struct rsnd_priv *priv) | ||
511 | { | ||
512 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
513 | u32 cr; | ||
514 | 474 | ||
515 | /* | 475 | /* |
516 | * disable all IRQ, | 476 | * disable all IRQ, |
@@ -532,33 +492,38 @@ static int __rsnd_ssi_stop(struct rsnd_mod *mod, | |||
532 | return 0; | 492 | return 0; |
533 | } | 493 | } |
534 | 494 | ||
535 | static int rsnd_ssi_stop(struct rsnd_mod *mod, | 495 | static int rsnd_ssi_irq(struct rsnd_mod *mod, |
536 | struct rsnd_dai_stream *io, | 496 | struct rsnd_dai_stream *io, |
537 | struct rsnd_priv *priv) | 497 | struct rsnd_priv *priv, |
498 | int enable) | ||
538 | { | 499 | { |
539 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 500 | u32 val = 0; |
540 | 501 | ||
541 | /* | 502 | if (rsnd_is_gen1(priv)) |
542 | * don't stop if not last user | ||
543 | * see also | ||
544 | * rsnd_ssi_start | ||
545 | * rsnd_ssi_interrupt | ||
546 | */ | ||
547 | if (ssi->usrcnt > 1) | ||
548 | return 0; | 503 | return 0; |
549 | 504 | ||
550 | return __rsnd_ssi_stop(mod, io, priv); | 505 | if (rsnd_ssi_is_parent(mod, io)) |
506 | return 0; | ||
507 | |||
508 | if (!rsnd_ssi_is_run_mods(mod, io)) | ||
509 | return 0; | ||
510 | |||
511 | if (enable) | ||
512 | val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; | ||
513 | |||
514 | rsnd_mod_write(mod, SSI_INT_ENABLE, val); | ||
515 | |||
516 | return 0; | ||
551 | } | 517 | } |
552 | 518 | ||
553 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | 519 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, |
554 | struct rsnd_dai_stream *io) | 520 | struct rsnd_dai_stream *io) |
555 | { | 521 | { |
556 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
557 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 522 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
558 | struct device *dev = rsnd_priv_to_dev(priv); | ||
559 | int is_dma = rsnd_ssi_is_dma_mode(mod); | 523 | int is_dma = rsnd_ssi_is_dma_mode(mod); |
560 | u32 status; | 524 | u32 status; |
561 | bool elapsed = false; | 525 | bool elapsed = false; |
526 | bool stop = false; | ||
562 | 527 | ||
563 | spin_lock(&priv->lock); | 528 | spin_lock(&priv->lock); |
564 | 529 | ||
@@ -566,7 +531,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
566 | if (!rsnd_io_is_working(io)) | 531 | if (!rsnd_io_is_working(io)) |
567 | goto rsnd_ssi_interrupt_out; | 532 | goto rsnd_ssi_interrupt_out; |
568 | 533 | ||
569 | status = rsnd_ssi_record_error(ssi); | 534 | status = rsnd_ssi_status_get(mod); |
570 | 535 | ||
571 | /* PIO only */ | 536 | /* PIO only */ |
572 | if (!is_dma && (status & DIRQ)) { | 537 | if (!is_dma && (status & DIRQ)) { |
@@ -588,23 +553,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
588 | } | 553 | } |
589 | 554 | ||
590 | /* DMA only */ | 555 | /* DMA only */ |
591 | if (is_dma && (status & (UIRQ | OIRQ))) { | 556 | if (is_dma && (status & (UIRQ | OIRQ))) |
592 | /* | 557 | stop = true; |
593 | * restart SSI | ||
594 | */ | ||
595 | dev_dbg(dev, "%s[%d] restart\n", | ||
596 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
597 | |||
598 | __rsnd_ssi_stop(mod, io, priv); | ||
599 | __rsnd_ssi_start(mod, io, priv); | ||
600 | } | ||
601 | |||
602 | if (ssi->err > 1024) { | ||
603 | rsnd_ssi_irq_disable(mod); | ||
604 | |||
605 | dev_warn(dev, "no more %s[%d] restart\n", | ||
606 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
607 | } | ||
608 | 558 | ||
609 | rsnd_ssi_status_clear(mod); | 559 | rsnd_ssi_status_clear(mod); |
610 | rsnd_ssi_interrupt_out: | 560 | rsnd_ssi_interrupt_out: |
@@ -612,6 +562,10 @@ rsnd_ssi_interrupt_out: | |||
612 | 562 | ||
613 | if (elapsed) | 563 | if (elapsed) |
614 | rsnd_dai_period_elapsed(io); | 564 | rsnd_dai_period_elapsed(io); |
565 | |||
566 | if (stop) | ||
567 | snd_pcm_stop_xrun(io->substream); | ||
568 | |||
615 | } | 569 | } |
616 | 570 | ||
617 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | 571 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) |
@@ -627,12 +581,17 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | |||
627 | * SSI PIO | 581 | * SSI PIO |
628 | */ | 582 | */ |
629 | static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, | 583 | static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, |
630 | struct rsnd_dai_stream *io, | 584 | struct rsnd_dai_stream *io) |
631 | struct rsnd_priv *priv) | ||
632 | { | 585 | { |
586 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
587 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
588 | |||
633 | if (!__rsnd_ssi_is_pin_sharing(mod)) | 589 | if (!__rsnd_ssi_is_pin_sharing(mod)) |
634 | return; | 590 | return; |
635 | 591 | ||
592 | if (!rsnd_rdai_is_clk_master(rdai)) | ||
593 | return; | ||
594 | |||
636 | switch (rsnd_mod_id(mod)) { | 595 | switch (rsnd_mod_id(mod)) { |
637 | case 1: | 596 | case 1: |
638 | case 2: | 597 | case 2: |
@@ -647,6 +606,20 @@ static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, | |||
647 | } | 606 | } |
648 | } | 607 | } |
649 | 608 | ||
609 | static int rsnd_ssi_pcm_new(struct rsnd_mod *mod, | ||
610 | struct rsnd_dai_stream *io, | ||
611 | struct snd_soc_pcm_runtime *rtd) | ||
612 | { | ||
613 | /* | ||
614 | * rsnd_rdai_is_clk_master() will be enabled after set_fmt, | ||
615 | * and, pcm_new will be called after it. | ||
616 | * This function reuse pcm_new at this point. | ||
617 | */ | ||
618 | rsnd_ssi_parent_attach(mod, io); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
650 | static int rsnd_ssi_common_probe(struct rsnd_mod *mod, | 623 | static int rsnd_ssi_common_probe(struct rsnd_mod *mod, |
651 | struct rsnd_dai_stream *io, | 624 | struct rsnd_dai_stream *io, |
652 | struct rsnd_priv *priv) | 625 | struct rsnd_priv *priv) |
@@ -662,7 +635,10 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, | |||
662 | if (rsnd_ssi_is_multi_slave(mod, io)) | 635 | if (rsnd_ssi_is_multi_slave(mod, io)) |
663 | return 0; | 636 | return 0; |
664 | 637 | ||
665 | rsnd_ssi_parent_attach(mod, io, priv); | 638 | /* |
639 | * It can't judge ssi parent at this point | ||
640 | * see rsnd_ssi_pcm_new() | ||
641 | */ | ||
666 | 642 | ||
667 | ret = rsnd_ssiu_attach(io, mod); | 643 | ret = rsnd_ssiu_attach(io, mod); |
668 | if (ret < 0) | 644 | if (ret < 0) |
@@ -683,6 +659,8 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | |||
683 | .quit = rsnd_ssi_quit, | 659 | .quit = rsnd_ssi_quit, |
684 | .start = rsnd_ssi_start, | 660 | .start = rsnd_ssi_start, |
685 | .stop = rsnd_ssi_stop, | 661 | .stop = rsnd_ssi_stop, |
662 | .irq = rsnd_ssi_irq, | ||
663 | .pcm_new = rsnd_ssi_pcm_new, | ||
686 | .hw_params = rsnd_ssi_hw_params, | 664 | .hw_params = rsnd_ssi_hw_params, |
687 | }; | 665 | }; |
688 | 666 | ||
@@ -705,9 +683,8 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
705 | if (ret) | 683 | if (ret) |
706 | return ret; | 684 | return ret; |
707 | 685 | ||
708 | ssi->dma = rsnd_dma_attach(io, mod, dma_id); | 686 | /* SSI probe might be called many times in MUX multi path */ |
709 | if (IS_ERR(ssi->dma)) | 687 | ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); |
710 | return PTR_ERR(ssi->dma); | ||
711 | 688 | ||
712 | return ret; | 689 | return ret; |
713 | } | 690 | } |
@@ -772,6 +749,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
772 | .quit = rsnd_ssi_quit, | 749 | .quit = rsnd_ssi_quit, |
773 | .start = rsnd_ssi_start, | 750 | .start = rsnd_ssi_start, |
774 | .stop = rsnd_ssi_stop, | 751 | .stop = rsnd_ssi_stop, |
752 | .irq = rsnd_ssi_irq, | ||
753 | .pcm_new = rsnd_ssi_pcm_new, | ||
775 | .fallback = rsnd_ssi_fallback, | 754 | .fallback = rsnd_ssi_fallback, |
776 | .hw_params = rsnd_ssi_hw_params, | 755 | .hw_params = rsnd_ssi_hw_params, |
777 | }; | 756 | }; |
@@ -858,6 +837,41 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | |||
858 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); | 837 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); |
859 | } | 838 | } |
860 | 839 | ||
840 | static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, | ||
841 | struct rsnd_mod *mod, | ||
842 | enum rsnd_mod_type type) | ||
843 | { | ||
844 | /* | ||
845 | * SSIP (= SSI parent) needs to be special, otherwise, | ||
846 | * 2nd SSI might doesn't start. see also rsnd_mod_call() | ||
847 | * | ||
848 | * We can't include parent SSI status on SSI, because we don't know | ||
849 | * how many SSI requests parent SSI. Thus, it is localed on "io" now. | ||
850 | * ex) trouble case | ||
851 | * Playback: SSI0 | ||
852 | * Capture : SSI1 (needs SSI0) | ||
853 | * | ||
854 | * 1) start Capture -> SSI0/SSI1 are started. | ||
855 | * 2) start Playback -> SSI0 doesn't work, because it is already | ||
856 | * marked as "started" on 1) | ||
857 | * | ||
858 | * OTOH, using each mod's status is good for MUX case. | ||
859 | * It doesn't need to start in 2nd start | ||
860 | * ex) | ||
861 | * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 | ||
862 | * | | ||
863 | * IO-1: SRC1 -> CTU2 -+ | ||
864 | * | ||
865 | * 1) start IO-0 -> start SSI0 | ||
866 | * 2) start IO-1 -> SSI0 doesn't need to start, because it is | ||
867 | * already started on 1) | ||
868 | */ | ||
869 | if (type == RSND_MOD_SSIP) | ||
870 | return &io->parent_ssi_status; | ||
871 | |||
872 | return rsnd_mod_get_status(io, mod, type); | ||
873 | } | ||
874 | |||
861 | int rsnd_ssi_probe(struct rsnd_priv *priv) | 875 | int rsnd_ssi_probe(struct rsnd_priv *priv) |
862 | { | 876 | { |
863 | struct device_node *node; | 877 | struct device_node *node; |
@@ -920,7 +934,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) | |||
920 | ops = &rsnd_ssi_dma_ops; | 934 | ops = &rsnd_ssi_dma_ops; |
921 | 935 | ||
922 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, | 936 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, |
923 | RSND_MOD_SSI, i); | 937 | rsnd_ssi_get_status, RSND_MOD_SSI, i); |
924 | if (ret) | 938 | if (ret) |
925 | goto rsnd_ssi_probe_done; | 939 | goto rsnd_ssi_probe_done; |
926 | 940 | ||