diff options
Diffstat (limited to 'sound/soc/sh/rcar/ssi.c')
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 332 |
1 files changed, 126 insertions, 206 deletions
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4b8cf7ca9d19..633b23d209b9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -64,108 +64,29 @@ struct rsnd_ssi { | |||
64 | struct rsnd_mod mod; | 64 | struct rsnd_mod mod; |
65 | 65 | ||
66 | struct rsnd_dai *rdai; | 66 | struct rsnd_dai *rdai; |
67 | struct rsnd_dai_stream *io; | ||
68 | u32 cr_own; | 67 | u32 cr_own; |
69 | u32 cr_clk; | 68 | u32 cr_clk; |
70 | u32 cr_etc; | 69 | u32 cr_etc; |
71 | int err; | 70 | int err; |
72 | int dma_offset; | ||
73 | unsigned int usrcnt; | 71 | unsigned int usrcnt; |
74 | unsigned int rate; | 72 | unsigned int rate; |
75 | }; | 73 | }; |
76 | 74 | ||
77 | struct rsnd_ssiu { | ||
78 | u32 ssi_mode0; | ||
79 | u32 ssi_mode1; | ||
80 | |||
81 | int ssi_nr; | ||
82 | struct rsnd_ssi *ssi; | ||
83 | }; | ||
84 | |||
85 | #define for_each_rsnd_ssi(pos, priv, i) \ | 75 | #define for_each_rsnd_ssi(pos, priv, i) \ |
86 | for (i = 0; \ | 76 | for (i = 0; \ |
87 | (i < rsnd_ssi_nr(priv)) && \ | 77 | (i < rsnd_ssi_nr(priv)) && \ |
88 | ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \ | 78 | ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ |
89 | i++) | 79 | i++) |
90 | 80 | ||
91 | #define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) | 81 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) |
92 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 82 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
93 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 83 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
94 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | 84 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) |
95 | #define rsnd_ssi_dma_available(ssi) \ | 85 | #define rsnd_ssi_dma_available(ssi) \ |
96 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | 86 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) |
97 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 87 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) |
98 | #define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) | ||
99 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 88 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) |
100 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | 89 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) |
101 | #define rsnd_ssi_to_ssiu(ssi)\ | ||
102 | (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) | ||
103 | |||
104 | static void rsnd_ssi_mode_set(struct rsnd_priv *priv, | ||
105 | struct rsnd_dai *rdai, | ||
106 | struct rsnd_ssi *ssi) | ||
107 | { | ||
108 | struct device *dev = rsnd_priv_to_dev(priv); | ||
109 | struct rsnd_mod *scu; | ||
110 | struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); | ||
111 | int id = rsnd_mod_id(&ssi->mod); | ||
112 | u32 flags; | ||
113 | u32 val; | ||
114 | |||
115 | scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod)); | ||
116 | |||
117 | /* | ||
118 | * SSI_MODE0 | ||
119 | */ | ||
120 | |||
121 | /* see also BUSIF_MODE */ | ||
122 | if (rsnd_scu_hpbif_is_enable(scu)) { | ||
123 | ssiu->ssi_mode0 &= ~(1 << id); | ||
124 | dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id); | ||
125 | } else { | ||
126 | ssiu->ssi_mode0 |= (1 << id); | ||
127 | dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * SSI_MODE1 | ||
132 | */ | ||
133 | #define ssi_parent_set(p, sync, adg, ext) \ | ||
134 | do { \ | ||
135 | ssi->parent = ssiu->ssi + p; \ | ||
136 | if (rsnd_rdai_is_clk_master(rdai)) \ | ||
137 | val = adg; \ | ||
138 | else \ | ||
139 | val = ext; \ | ||
140 | if (flags & RSND_SSI_SYNC) \ | ||
141 | val |= sync; \ | ||
142 | } while (0) | ||
143 | |||
144 | flags = rsnd_ssi_mode_flags(ssi); | ||
145 | if (flags & RSND_SSI_CLK_PIN_SHARE) { | ||
146 | |||
147 | val = 0; | ||
148 | switch (id) { | ||
149 | case 1: | ||
150 | ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); | ||
151 | break; | ||
152 | case 2: | ||
153 | ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2)); | ||
154 | break; | ||
155 | case 4: | ||
156 | ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16)); | ||
157 | break; | ||
158 | case 8: | ||
159 | ssi_parent_set(7, 0, 0, 0); | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | ssiu->ssi_mode1 |= val; | ||
164 | } | ||
165 | |||
166 | rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); | ||
167 | rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); | ||
168 | } | ||
169 | 90 | ||
170 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | 91 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, |
171 | u32 bit) | 92 | u32 bit) |
@@ -200,7 +121,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
200 | 1, 2, 4, 8, 16, 6, 12, | 121 | 1, 2, 4, 8, 16, 6, 12, |
201 | }; | 122 | }; |
202 | unsigned int main_rate; | 123 | unsigned int main_rate; |
203 | unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime); | 124 | unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); |
204 | 125 | ||
205 | /* | 126 | /* |
206 | * Find best clock, and try to start ADG | 127 | * Find best clock, and try to start ADG |
@@ -252,7 +173,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
252 | if (0 == ssi->usrcnt) { | 173 | if (0 == ssi->usrcnt) { |
253 | clk_enable(ssi->clk); | 174 | clk_enable(ssi->clk); |
254 | 175 | ||
255 | if (rsnd_rdai_is_clk_master(rdai)) { | 176 | if (rsnd_dai_is_clk_master(rdai)) { |
256 | if (rsnd_ssi_clk_from_parent(ssi)) | 177 | if (rsnd_ssi_clk_from_parent(ssi)) |
257 | rsnd_ssi_hw_start(ssi->parent, rdai, io); | 178 | rsnd_ssi_hw_start(ssi->parent, rdai, io); |
258 | else | 179 | else |
@@ -302,7 +223,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | |||
302 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ | 223 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ |
303 | rsnd_ssi_status_check(&ssi->mod, IIRQ); | 224 | rsnd_ssi_status_check(&ssi->mod, IIRQ); |
304 | 225 | ||
305 | if (rsnd_rdai_is_clk_master(rdai)) { | 226 | if (rsnd_dai_is_clk_master(rdai)) { |
306 | if (rsnd_ssi_clk_from_parent(ssi)) | 227 | if (rsnd_ssi_clk_from_parent(ssi)) |
307 | rsnd_ssi_hw_stop(ssi->parent, rdai); | 228 | rsnd_ssi_hw_stop(ssi->parent, rdai); |
308 | else | 229 | else |
@@ -323,8 +244,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
323 | struct rsnd_dai_stream *io) | 244 | struct rsnd_dai_stream *io) |
324 | { | 245 | { |
325 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 246 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
326 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
327 | struct device *dev = rsnd_priv_to_dev(priv); | ||
328 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 247 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
329 | u32 cr; | 248 | u32 cr; |
330 | 249 | ||
@@ -365,13 +284,10 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
365 | * set ssi parameter | 284 | * set ssi parameter |
366 | */ | 285 | */ |
367 | ssi->rdai = rdai; | 286 | ssi->rdai = rdai; |
368 | ssi->io = io; | ||
369 | ssi->cr_own = cr; | 287 | ssi->cr_own = cr; |
370 | ssi->err = -1; /* ignore 1st error */ | 288 | ssi->err = -1; /* ignore 1st error */ |
371 | 289 | ||
372 | rsnd_ssi_mode_set(priv, rdai, ssi); | 290 | rsnd_src_ssi_mode_init(mod, rdai, io); |
373 | |||
374 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
375 | 291 | ||
376 | return 0; | 292 | return 0; |
377 | } | 293 | } |
@@ -384,13 +300,10 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
384 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 300 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
385 | struct device *dev = rsnd_priv_to_dev(priv); | 301 | struct device *dev = rsnd_priv_to_dev(priv); |
386 | 302 | ||
387 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
388 | |||
389 | if (ssi->err > 0) | 303 | if (ssi->err > 0) |
390 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); | 304 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); |
391 | 305 | ||
392 | ssi->rdai = NULL; | 306 | ssi->rdai = NULL; |
393 | ssi->io = NULL; | ||
394 | ssi->cr_own = 0; | 307 | ssi->cr_own = 0; |
395 | ssi->err = 0; | 308 | ssi->err = 0; |
396 | 309 | ||
@@ -414,8 +327,9 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | |||
414 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | 327 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) |
415 | { | 328 | { |
416 | struct rsnd_ssi *ssi = data; | 329 | struct rsnd_ssi *ssi = data; |
417 | struct rsnd_dai_stream *io = ssi->io; | 330 | struct rsnd_mod *mod = &ssi->mod; |
418 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | 331 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
332 | u32 status = rsnd_mod_read(mod, SSISR); | ||
419 | irqreturn_t ret = IRQ_NONE; | 333 | irqreturn_t ret = IRQ_NONE; |
420 | 334 | ||
421 | if (io && (status & DIRQ)) { | 335 | if (io && (status & DIRQ)) { |
@@ -432,9 +346,9 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
432 | * see rsnd_ssi_init() | 346 | * see rsnd_ssi_init() |
433 | */ | 347 | */ |
434 | if (rsnd_dai_is_play(rdai, io)) | 348 | if (rsnd_dai_is_play(rdai, io)) |
435 | rsnd_mod_write(&ssi->mod, SSITDR, *buf); | 349 | rsnd_mod_write(mod, SSITDR, *buf); |
436 | else | 350 | else |
437 | *buf = rsnd_mod_read(&ssi->mod, SSIRDR); | 351 | *buf = rsnd_mod_read(mod, SSIRDR); |
438 | 352 | ||
439 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 353 | rsnd_dai_pointer_update(io, sizeof(*buf)); |
440 | 354 | ||
@@ -444,25 +358,39 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
444 | return ret; | 358 | return ret; |
445 | } | 359 | } |
446 | 360 | ||
447 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | 361 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, |
448 | struct rsnd_dai *rdai, | 362 | struct rsnd_dai *rdai, |
449 | struct rsnd_dai_stream *io) | 363 | struct rsnd_dai_stream *io) |
450 | { | 364 | { |
451 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 365 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
452 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
453 | struct device *dev = rsnd_priv_to_dev(priv); | 366 | struct device *dev = rsnd_priv_to_dev(priv); |
367 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
368 | int irq = ssi->info->pio_irq; | ||
369 | int ret; | ||
370 | |||
371 | ret = devm_request_irq(dev, irq, | ||
372 | rsnd_ssi_pio_interrupt, | ||
373 | IRQF_SHARED, | ||
374 | dev_name(dev), ssi); | ||
375 | if (ret) | ||
376 | dev_err(dev, "SSI request interrupt failed\n"); | ||
377 | |||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | ||
382 | struct rsnd_dai *rdai, | ||
383 | struct rsnd_dai_stream *io) | ||
384 | { | ||
385 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
454 | 386 | ||
455 | /* enable PIO IRQ */ | 387 | /* enable PIO IRQ */ |
456 | ssi->cr_etc = UIEN | OIEN | DIEN; | 388 | ssi->cr_etc = UIEN | OIEN | DIEN; |
457 | 389 | ||
458 | /* enable PIO interrupt if gen2 */ | 390 | rsnd_src_enable_ssi_irq(mod, rdai, io); |
459 | if (rsnd_is_gen2(priv)) | ||
460 | rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000); | ||
461 | 391 | ||
462 | rsnd_ssi_hw_start(ssi, rdai, io); | 392 | rsnd_ssi_hw_start(ssi, rdai, io); |
463 | 393 | ||
464 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
465 | |||
466 | return 0; | 394 | return 0; |
467 | } | 395 | } |
468 | 396 | ||
@@ -470,12 +398,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
470 | struct rsnd_dai *rdai, | 398 | struct rsnd_dai *rdai, |
471 | struct rsnd_dai_stream *io) | 399 | struct rsnd_dai_stream *io) |
472 | { | 400 | { |
473 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
474 | struct device *dev = rsnd_priv_to_dev(priv); | ||
475 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 401 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
476 | 402 | ||
477 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
478 | |||
479 | ssi->cr_etc = 0; | 403 | ssi->cr_etc = 0; |
480 | 404 | ||
481 | rsnd_ssi_hw_stop(ssi, rdai); | 405 | rsnd_ssi_hw_stop(ssi, rdai); |
@@ -485,35 +409,46 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
485 | 409 | ||
486 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 410 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
487 | .name = "ssi (pio)", | 411 | .name = "ssi (pio)", |
412 | .probe = rsnd_ssi_pio_probe, | ||
488 | .init = rsnd_ssi_init, | 413 | .init = rsnd_ssi_init, |
489 | .quit = rsnd_ssi_quit, | 414 | .quit = rsnd_ssi_quit, |
490 | .start = rsnd_ssi_pio_start, | 415 | .start = rsnd_ssi_pio_start, |
491 | .stop = rsnd_ssi_pio_stop, | 416 | .stop = rsnd_ssi_pio_stop, |
492 | }; | 417 | }; |
493 | 418 | ||
494 | static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len) | 419 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
420 | struct rsnd_dai *rdai, | ||
421 | struct rsnd_dai_stream *io) | ||
495 | { | 422 | { |
496 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | 423 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
497 | struct rsnd_dai_stream *io = ssi->io; | 424 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
498 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 425 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); |
426 | struct device *dev = rsnd_priv_to_dev(priv); | ||
427 | int dma_id = ssi->info->dma_id; | ||
428 | int is_play; | ||
429 | int ret; | ||
499 | 430 | ||
500 | *len = io->byte_per_period; | 431 | if (info->dai_info) |
501 | *buf = runtime->dma_addr + | 432 | is_play = rsnd_info_is_playback(priv, ssi); |
502 | rsnd_dai_pointer_offset(io, ssi->dma_offset + *len); | 433 | else |
503 | ssi->dma_offset = *len; /* it cares A/B plane */ | 434 | is_play = rsnd_ssi_is_play(&ssi->mod); |
504 | 435 | ||
505 | return 0; | 436 | ret = rsnd_dma_init( |
506 | } | 437 | priv, rsnd_mod_to_dma(mod), |
438 | is_play, | ||
439 | dma_id); | ||
507 | 440 | ||
508 | static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) | 441 | if (ret < 0) |
509 | { | 442 | dev_err(dev, "SSI DMA failed\n"); |
510 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | ||
511 | struct rsnd_dai_stream *io = ssi->io; | ||
512 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | ||
513 | 443 | ||
514 | rsnd_ssi_record_error(ssi, status); | 444 | return ret; |
445 | } | ||
515 | 446 | ||
516 | rsnd_dai_pointer_update(ssi->io, io->byte_per_period); | 447 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, |
448 | struct rsnd_dai *rdai, | ||
449 | struct rsnd_dai_stream *io) | ||
450 | { | ||
451 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | ||
517 | 452 | ||
518 | return 0; | 453 | return 0; |
519 | } | 454 | } |
@@ -527,14 +462,13 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | |||
527 | 462 | ||
528 | /* enable DMA transfer */ | 463 | /* enable DMA transfer */ |
529 | ssi->cr_etc = DMEN; | 464 | ssi->cr_etc = DMEN; |
530 | ssi->dma_offset = 0; | ||
531 | 465 | ||
532 | rsnd_dma_start(dma); | 466 | rsnd_dma_start(dma); |
533 | 467 | ||
534 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 468 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); |
535 | 469 | ||
536 | /* enable WS continue */ | 470 | /* enable WS continue */ |
537 | if (rsnd_rdai_is_clk_master(rdai)) | 471 | if (rsnd_dai_is_clk_master(rdai)) |
538 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | 472 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); |
539 | 473 | ||
540 | return 0; | 474 | return 0; |
@@ -549,6 +483,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
549 | 483 | ||
550 | ssi->cr_etc = 0; | 484 | ssi->cr_etc = 0; |
551 | 485 | ||
486 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
487 | |||
552 | rsnd_ssi_hw_stop(ssi, rdai); | 488 | rsnd_ssi_hw_stop(ssi, rdai); |
553 | 489 | ||
554 | rsnd_dma_stop(dma); | 490 | rsnd_dma_stop(dma); |
@@ -558,6 +494,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
558 | 494 | ||
559 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | 495 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { |
560 | .name = "ssi (dma)", | 496 | .name = "ssi (dma)", |
497 | .probe = rsnd_ssi_dma_probe, | ||
498 | .remove = rsnd_ssi_dma_remove, | ||
561 | .init = rsnd_ssi_init, | 499 | .init = rsnd_ssi_init, |
562 | .quit = rsnd_ssi_quit, | 500 | .quit = rsnd_ssi_quit, |
563 | .start = rsnd_ssi_dma_start, | 501 | .start = rsnd_ssi_dma_start, |
@@ -567,24 +505,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
567 | /* | 505 | /* |
568 | * Non SSI | 506 | * Non SSI |
569 | */ | 507 | */ |
570 | static int rsnd_ssi_non(struct rsnd_mod *mod, | ||
571 | struct rsnd_dai *rdai, | ||
572 | struct rsnd_dai_stream *io) | ||
573 | { | ||
574 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
575 | struct device *dev = rsnd_priv_to_dev(priv); | ||
576 | |||
577 | dev_dbg(dev, "%s\n", __func__); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { | 508 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { |
583 | .name = "ssi (non)", | 509 | .name = "ssi (non)", |
584 | .init = rsnd_ssi_non, | ||
585 | .quit = rsnd_ssi_non, | ||
586 | .start = rsnd_ssi_non, | ||
587 | .stop = rsnd_ssi_non, | ||
588 | }; | 510 | }; |
589 | 511 | ||
590 | /* | 512 | /* |
@@ -593,16 +515,30 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = { | |||
593 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 515 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
594 | int dai_id, int is_play) | 516 | int dai_id, int is_play) |
595 | { | 517 | { |
518 | struct rsnd_dai_platform_info *dai_info = NULL; | ||
519 | struct rsnd_dai_path_info *path_info = NULL; | ||
520 | struct rsnd_ssi_platform_info *target_info = NULL; | ||
596 | struct rsnd_ssi *ssi; | 521 | struct rsnd_ssi *ssi; |
597 | int i, has_play; | 522 | int i, has_play; |
598 | 523 | ||
524 | if (priv->rdai) | ||
525 | dai_info = priv->rdai[dai_id].info; | ||
526 | if (dai_info) | ||
527 | path_info = (is_play) ? &dai_info->playback : &dai_info->capture; | ||
528 | if (path_info) | ||
529 | target_info = path_info->ssi; | ||
530 | |||
599 | is_play = !!is_play; | 531 | is_play = !!is_play; |
600 | 532 | ||
601 | for_each_rsnd_ssi(ssi, priv, i) { | 533 | for_each_rsnd_ssi(ssi, priv, i) { |
534 | if (target_info == ssi->info) | ||
535 | return &ssi->mod; | ||
536 | |||
537 | /* for compatible */ | ||
602 | if (rsnd_ssi_dai_id(ssi) != dai_id) | 538 | if (rsnd_ssi_dai_id(ssi) != dai_id) |
603 | continue; | 539 | continue; |
604 | 540 | ||
605 | has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | 541 | has_play = rsnd_ssi_is_play(&ssi->mod); |
606 | 542 | ||
607 | if (is_play == has_play) | 543 | if (is_play == has_play) |
608 | return &ssi->mod; | 544 | return &ssi->mod; |
@@ -616,36 +552,66 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | |||
616 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) | 552 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) |
617 | id = 0; | 553 | id = 0; |
618 | 554 | ||
619 | return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod; | 555 | return &((struct rsnd_ssi *)(priv->ssi) + id)->mod; |
556 | } | ||
557 | |||
558 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | ||
559 | { | ||
560 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
561 | |||
562 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); | ||
563 | } | ||
564 | |||
565 | int rsnd_ssi_is_play(struct rsnd_mod *mod) | ||
566 | { | ||
567 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
568 | |||
569 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | ||
570 | } | ||
571 | |||
572 | static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) | ||
573 | { | ||
574 | if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) | ||
575 | return; | ||
576 | |||
577 | switch (rsnd_mod_id(&ssi->mod)) { | ||
578 | case 1: | ||
579 | case 2: | ||
580 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); | ||
581 | break; | ||
582 | case 4: | ||
583 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); | ||
584 | break; | ||
585 | case 8: | ||
586 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); | ||
587 | break; | ||
588 | } | ||
620 | } | 589 | } |
621 | 590 | ||
622 | int rsnd_ssi_probe(struct platform_device *pdev, | 591 | int rsnd_ssi_probe(struct platform_device *pdev, |
623 | struct rcar_snd_info *info, | ||
624 | struct rsnd_priv *priv) | 592 | struct rsnd_priv *priv) |
625 | { | 593 | { |
594 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
626 | struct rsnd_ssi_platform_info *pinfo; | 595 | struct rsnd_ssi_platform_info *pinfo; |
627 | struct device *dev = rsnd_priv_to_dev(priv); | 596 | struct device *dev = rsnd_priv_to_dev(priv); |
628 | struct rsnd_mod_ops *ops; | 597 | struct rsnd_mod_ops *ops; |
629 | struct clk *clk; | 598 | struct clk *clk; |
630 | struct rsnd_ssiu *ssiu; | ||
631 | struct rsnd_ssi *ssi; | 599 | struct rsnd_ssi *ssi; |
632 | char name[RSND_SSI_NAME_SIZE]; | 600 | char name[RSND_SSI_NAME_SIZE]; |
633 | int i, nr, ret; | 601 | int i, nr; |
634 | 602 | ||
635 | /* | 603 | /* |
636 | * init SSI | 604 | * init SSI |
637 | */ | 605 | */ |
638 | nr = info->ssi_info_nr; | 606 | nr = info->ssi_info_nr; |
639 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr), | 607 | ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); |
640 | GFP_KERNEL); | 608 | if (!ssi) { |
641 | if (!ssiu) { | ||
642 | dev_err(dev, "SSI allocate failed\n"); | 609 | dev_err(dev, "SSI allocate failed\n"); |
643 | return -ENOMEM; | 610 | return -ENOMEM; |
644 | } | 611 | } |
645 | 612 | ||
646 | priv->ssiu = ssiu; | 613 | priv->ssi = ssi; |
647 | ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1); | 614 | priv->ssi_nr = nr; |
648 | ssiu->ssi_nr = nr; | ||
649 | 615 | ||
650 | for_each_rsnd_ssi(ssi, priv, i) { | 616 | for_each_rsnd_ssi(ssi, priv, i) { |
651 | pinfo = &info->ssi_info[i]; | 617 | pinfo = &info->ssi_info[i]; |
@@ -660,61 +626,15 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
660 | ssi->clk = clk; | 626 | ssi->clk = clk; |
661 | 627 | ||
662 | ops = &rsnd_ssi_non_ops; | 628 | ops = &rsnd_ssi_non_ops; |
629 | if (pinfo->dma_id > 0) | ||
630 | ops = &rsnd_ssi_dma_ops; | ||
631 | else if (rsnd_ssi_pio_available(ssi)) | ||
632 | ops = &rsnd_ssi_pio_ops; | ||
663 | 633 | ||
664 | /* | 634 | rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i); |
665 | * SSI DMA case | ||
666 | */ | ||
667 | if (pinfo->dma_id > 0) { | ||
668 | ret = rsnd_dma_init( | ||
669 | priv, rsnd_mod_to_dma(&ssi->mod), | ||
670 | (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY), | ||
671 | pinfo->dma_id, | ||
672 | rsnd_ssi_dma_inquiry, | ||
673 | rsnd_ssi_dma_complete); | ||
674 | if (ret < 0) | ||
675 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); | ||
676 | else | ||
677 | ops = &rsnd_ssi_dma_ops; | ||
678 | |||
679 | dev_dbg(dev, "SSI%d use DMA transfer\n", i); | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * SSI PIO case | ||
684 | */ | ||
685 | if (!rsnd_ssi_dma_available(ssi) && | ||
686 | rsnd_ssi_pio_available(ssi)) { | ||
687 | ret = devm_request_irq(dev, pinfo->pio_irq, | ||
688 | &rsnd_ssi_pio_interrupt, | ||
689 | IRQF_SHARED, | ||
690 | dev_name(dev), ssi); | ||
691 | if (ret) { | ||
692 | dev_err(dev, "SSI request interrupt failed\n"); | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | ops = &rsnd_ssi_pio_ops; | ||
697 | 635 | ||
698 | dev_dbg(dev, "SSI%d use PIO transfer\n", i); | 636 | rsnd_ssi_parent_clk_setup(priv, ssi); |
699 | } | ||
700 | |||
701 | rsnd_mod_init(priv, &ssi->mod, ops, i); | ||
702 | } | 637 | } |
703 | 638 | ||
704 | dev_dbg(dev, "ssi probed\n"); | ||
705 | |||
706 | return 0; | 639 | return 0; |
707 | } | 640 | } |
708 | |||
709 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
710 | struct rsnd_priv *priv) | ||
711 | { | ||
712 | struct rsnd_ssi *ssi; | ||
713 | int i; | ||
714 | |||
715 | for_each_rsnd_ssi(ssi, priv, i) { | ||
716 | if (rsnd_ssi_dma_available(ssi)) | ||
717 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); | ||
718 | } | ||
719 | |||
720 | } | ||