diff options
author | Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> | 2009-06-10 10:39:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-06-10 10:53:09 -0400 |
commit | cb6492e4a4e68281358510f0ffe2b0c4972ec166 (patch) | |
tree | 09cf532a7486d52e3b69698f0dc2d170dcea2e15 /sound | |
parent | 112ac808eb8a953dd356bbbc8322fdd6861e2c75 (diff) |
ALSA: sound/ps3: Restructure driver source
Sort includes, and reorder code so we can kill the forward declarations
No functional changes
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/ppc/snd_ps3.c | 621 |
1 files changed, 288 insertions, 333 deletions
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index d660b0f6bcae..cd9109aaa55e 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c | |||
@@ -18,80 +18,30 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/dmapool.h> | ||
21 | #include <linux/init.h> | 23 | #include <linux/init.h> |
22 | #include <linux/slab.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/io.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include <sound/asound.h> | ||
29 | #include <sound/control.h> | ||
25 | #include <sound/core.h> | 30 | #include <sound/core.h> |
26 | #include <sound/initval.h> | 31 | #include <sound/initval.h> |
27 | #include <sound/pcm.h> | ||
28 | #include <sound/asound.h> | ||
29 | #include <sound/memalloc.h> | 32 | #include <sound/memalloc.h> |
33 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | 34 | #include <sound/pcm_params.h> |
31 | #include <sound/control.h> | 35 | |
32 | #include <linux/dmapool.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | #include <asm/firmware.h> | ||
35 | #include <asm/dma.h> | 36 | #include <asm/dma.h> |
37 | #include <asm/firmware.h> | ||
36 | #include <asm/lv1call.h> | 38 | #include <asm/lv1call.h> |
37 | #include <asm/ps3.h> | 39 | #include <asm/ps3.h> |
38 | #include <asm/ps3av.h> | 40 | #include <asm/ps3av.h> |
39 | 41 | ||
40 | #include "snd_ps3_reg.h" | ||
41 | #include "snd_ps3.h" | 42 | #include "snd_ps3.h" |
43 | #include "snd_ps3_reg.h" | ||
42 | 44 | ||
43 | MODULE_LICENSE("GPL v2"); | ||
44 | MODULE_DESCRIPTION("PS3 sound driver"); | ||
45 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
46 | |||
47 | /* module entries */ | ||
48 | static int __init snd_ps3_init(void); | ||
49 | static void __exit snd_ps3_exit(void); | ||
50 | |||
51 | /* ALSA snd driver ops */ | ||
52 | static int snd_ps3_pcm_open(struct snd_pcm_substream *substream); | ||
53 | static int snd_ps3_pcm_close(struct snd_pcm_substream *substream); | ||
54 | static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream); | ||
55 | static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, | ||
56 | int cmd); | ||
57 | static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream | ||
58 | *substream); | ||
59 | static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, | ||
60 | struct snd_pcm_hw_params *hw_params); | ||
61 | static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream); | ||
62 | |||
63 | |||
64 | /* ps3_system_bus_driver entries */ | ||
65 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev); | ||
66 | static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev); | ||
67 | |||
68 | /* address setup */ | ||
69 | static int snd_ps3_map_mmio(void); | ||
70 | static void snd_ps3_unmap_mmio(void); | ||
71 | static int snd_ps3_allocate_irq(void); | ||
72 | static void snd_ps3_free_irq(void); | ||
73 | static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start); | ||
74 | |||
75 | /* interrupt handler */ | ||
76 | static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id); | ||
77 | |||
78 | |||
79 | /* set sampling rate/format */ | ||
80 | static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream); | ||
81 | /* take effect parameter change */ | ||
82 | static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card); | ||
83 | /* initialize avsetting and take it effect */ | ||
84 | static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card); | ||
85 | /* setup dma */ | ||
86 | static int snd_ps3_program_dma(struct snd_ps3_card_info *card, | ||
87 | enum snd_ps3_dma_filltype filltype); | ||
88 | static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card); | ||
89 | |||
90 | static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch); | ||
91 | |||
92 | |||
93 | module_init(snd_ps3_init); | ||
94 | module_exit(snd_ps3_exit); | ||
95 | 45 | ||
96 | /* | 46 | /* |
97 | * global | 47 | * global |
@@ -165,17 +115,6 @@ static const struct snd_pcm_hardware snd_ps3_pcm_hw = { | |||
165 | .fifo_size = PS3_AUDIO_FIFO_SIZE | 115 | .fifo_size = PS3_AUDIO_FIFO_SIZE |
166 | }; | 116 | }; |
167 | 117 | ||
168 | static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { | ||
169 | .open = snd_ps3_pcm_open, | ||
170 | .close = snd_ps3_pcm_close, | ||
171 | .prepare = snd_ps3_pcm_prepare, | ||
172 | .ioctl = snd_pcm_lib_ioctl, | ||
173 | .trigger = snd_ps3_pcm_trigger, | ||
174 | .pointer = snd_ps3_pcm_pointer, | ||
175 | .hw_params = snd_ps3_pcm_hw_params, | ||
176 | .hw_free = snd_ps3_pcm_hw_free | ||
177 | }; | ||
178 | |||
179 | static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card, | 118 | static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card, |
180 | int count, int force_stop) | 119 | int count, int force_stop) |
181 | { | 120 | { |
@@ -369,6 +308,71 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, | |||
369 | } | 308 | } |
370 | 309 | ||
371 | /* | 310 | /* |
311 | * Interrupt handler | ||
312 | */ | ||
313 | static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) | ||
314 | { | ||
315 | |||
316 | uint32_t port_intr; | ||
317 | int underflow_occured = 0; | ||
318 | struct snd_ps3_card_info *card = dev_id; | ||
319 | |||
320 | if (!card->running) { | ||
321 | update_reg(PS3_AUDIO_AX_IS, 0); | ||
322 | update_reg(PS3_AUDIO_INTR_0, 0); | ||
323 | return IRQ_HANDLED; | ||
324 | } | ||
325 | |||
326 | port_intr = read_reg(PS3_AUDIO_AX_IS); | ||
327 | /* | ||
328 | *serial buffer empty detected (every 4 times), | ||
329 | *program next dma and kick it | ||
330 | */ | ||
331 | if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { | ||
332 | write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); | ||
333 | if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { | ||
334 | write_reg(PS3_AUDIO_AX_IS, port_intr); | ||
335 | underflow_occured = 1; | ||
336 | } | ||
337 | if (card->silent) { | ||
338 | /* we are still in silent time */ | ||
339 | snd_ps3_program_dma(card, | ||
340 | (underflow_occured) ? | ||
341 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : | ||
342 | SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); | ||
343 | snd_ps3_kick_dma(card); | ||
344 | card->silent--; | ||
345 | } else { | ||
346 | snd_ps3_program_dma(card, | ||
347 | (underflow_occured) ? | ||
348 | SND_PS3_DMA_FILLTYPE_FIRSTFILL : | ||
349 | SND_PS3_DMA_FILLTYPE_RUNNING); | ||
350 | snd_ps3_kick_dma(card); | ||
351 | snd_pcm_period_elapsed(card->substream); | ||
352 | } | ||
353 | } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { | ||
354 | write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); | ||
355 | /* | ||
356 | * serial out underflow, but buffer empty not detected. | ||
357 | * in this case, fill fifo with 0 to recover. After | ||
358 | * filling dummy data, serial automatically start to | ||
359 | * consume them and then will generate normal buffer | ||
360 | * empty interrupts. | ||
361 | * If both buffer underflow and buffer empty are occured, | ||
362 | * it is better to do nomal data transfer than empty one | ||
363 | */ | ||
364 | snd_ps3_program_dma(card, | ||
365 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
366 | snd_ps3_kick_dma(card); | ||
367 | snd_ps3_program_dma(card, | ||
368 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
369 | snd_ps3_kick_dma(card); | ||
370 | } | ||
371 | /* clear interrupt cause */ | ||
372 | return IRQ_HANDLED; | ||
373 | }; | ||
374 | |||
375 | /* | ||
372 | * audio mute on/off | 376 | * audio mute on/off |
373 | * mute_on : 0 output enabled | 377 | * mute_on : 0 output enabled |
374 | * 1 mute | 378 | * 1 mute |
@@ -379,6 +383,142 @@ static int snd_ps3_mute(int mute_on) | |||
379 | } | 383 | } |
380 | 384 | ||
381 | /* | 385 | /* |
386 | * av setting | ||
387 | * NOTE: calling this function may generate audio interrupt. | ||
388 | */ | ||
389 | static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) | ||
390 | { | ||
391 | int ret, retries, i; | ||
392 | pr_debug("%s: start\n", __func__); | ||
393 | |||
394 | ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, | ||
395 | card->avs.avs_audio_rate, | ||
396 | card->avs.avs_audio_width, | ||
397 | card->avs.avs_audio_format, | ||
398 | card->avs.avs_audio_source); | ||
399 | /* | ||
400 | * Reset the following unwanted settings: | ||
401 | */ | ||
402 | |||
403 | /* disable all 3wire buffers */ | ||
404 | update_mask_reg(PS3_AUDIO_AO_3WMCTRL, | ||
405 | ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | | ||
406 | PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | | ||
407 | PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | | ||
408 | PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), | ||
409 | 0); | ||
410 | wmb(); /* ensure the hardware sees the change */ | ||
411 | /* wait for actually stopped */ | ||
412 | retries = 1000; | ||
413 | while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & | ||
414 | (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | | ||
415 | PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | | ||
416 | PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | | ||
417 | PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && | ||
418 | --retries) { | ||
419 | udelay(1); | ||
420 | } | ||
421 | |||
422 | /* reset buffer pointer */ | ||
423 | for (i = 0; i < 4; i++) { | ||
424 | update_reg(PS3_AUDIO_AO_3WCTRL(i), | ||
425 | PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); | ||
426 | udelay(10); | ||
427 | } | ||
428 | wmb(); /* ensure the hardware actually start resetting */ | ||
429 | |||
430 | /* enable 3wire#0 buffer */ | ||
431 | update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); | ||
432 | |||
433 | |||
434 | /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ | ||
435 | update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), | ||
436 | ~PS3_AUDIO_AO_3WCTRL_ASODF, | ||
437 | PS3_AUDIO_AO_3WCTRL_ASODF_LSB); | ||
438 | update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), | ||
439 | ~PS3_AUDIO_AO_SPDCTRL_SPODF, | ||
440 | PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); | ||
441 | /* ensure all the setting above is written back to register */ | ||
442 | wmb(); | ||
443 | /* avsetting driver altered AX_IE, caller must reset it if you want */ | ||
444 | pr_debug("%s: end\n", __func__); | ||
445 | return ret; | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * set sampling rate according to the substream | ||
450 | */ | ||
451 | static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) | ||
452 | { | ||
453 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
454 | struct snd_ps3_avsetting_info avs; | ||
455 | int ret; | ||
456 | |||
457 | avs = card->avs; | ||
458 | |||
459 | pr_debug("%s: called freq=%d width=%d\n", __func__, | ||
460 | substream->runtime->rate, | ||
461 | snd_pcm_format_width(substream->runtime->format)); | ||
462 | |||
463 | pr_debug("%s: before freq=%d width=%d\n", __func__, | ||
464 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | ||
465 | |||
466 | /* sample rate */ | ||
467 | switch (substream->runtime->rate) { | ||
468 | case 44100: | ||
469 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; | ||
470 | break; | ||
471 | case 48000: | ||
472 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; | ||
473 | break; | ||
474 | case 88200: | ||
475 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; | ||
476 | break; | ||
477 | case 96000: | ||
478 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; | ||
479 | break; | ||
480 | default: | ||
481 | pr_info("%s: invalid rate %d\n", __func__, | ||
482 | substream->runtime->rate); | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | /* width */ | ||
487 | switch (snd_pcm_format_width(substream->runtime->format)) { | ||
488 | case 16: | ||
489 | avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | ||
490 | break; | ||
491 | case 24: | ||
492 | avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; | ||
493 | break; | ||
494 | default: | ||
495 | pr_info("%s: invalid width %d\n", __func__, | ||
496 | snd_pcm_format_width(substream->runtime->format)); | ||
497 | return 1; | ||
498 | } | ||
499 | |||
500 | memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); | ||
501 | |||
502 | if (memcmp(&card->avs, &avs, sizeof(avs))) { | ||
503 | pr_debug("%s: after freq=%d width=%d\n", __func__, | ||
504 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | ||
505 | |||
506 | card->avs = avs; | ||
507 | snd_ps3_change_avsetting(card); | ||
508 | ret = 0; | ||
509 | } else | ||
510 | ret = 1; | ||
511 | |||
512 | /* check CS non-audio bit and mute accordingly */ | ||
513 | if (avs.avs_cs_info[0] & 0x02) | ||
514 | ps3av_audio_mute_analog(1); /* mute if non-audio */ | ||
515 | else | ||
516 | ps3av_audio_mute_analog(0); | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | /* | ||
382 | * PCM operators | 522 | * PCM operators |
383 | */ | 523 | */ |
384 | static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) | 524 | static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) |
@@ -403,6 +543,13 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) | |||
403 | return 0; | 543 | return 0; |
404 | }; | 544 | }; |
405 | 545 | ||
546 | static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) | ||
547 | { | ||
548 | /* mute on */ | ||
549 | snd_ps3_mute(1); | ||
550 | return 0; | ||
551 | }; | ||
552 | |||
406 | static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, | 553 | static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, |
407 | struct snd_pcm_hw_params *hw_params) | 554 | struct snd_pcm_hw_params *hw_params) |
408 | { | 555 | { |
@@ -414,6 +561,13 @@ static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, | |||
414 | return 0; | 561 | return 0; |
415 | }; | 562 | }; |
416 | 563 | ||
564 | static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) | ||
565 | { | ||
566 | int ret; | ||
567 | ret = snd_pcm_lib_free_pages(substream); | ||
568 | return ret; | ||
569 | }; | ||
570 | |||
417 | static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, | 571 | static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, |
418 | unsigned int delay_ms) | 572 | unsigned int delay_ms) |
419 | { | 573 | { |
@@ -553,202 +707,6 @@ static snd_pcm_uframes_t snd_ps3_pcm_pointer( | |||
553 | return ret; | 707 | return ret; |
554 | }; | 708 | }; |
555 | 709 | ||
556 | static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) | ||
557 | { | ||
558 | int ret; | ||
559 | ret = snd_pcm_lib_free_pages(substream); | ||
560 | return ret; | ||
561 | }; | ||
562 | |||
563 | static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) | ||
564 | { | ||
565 | /* mute on */ | ||
566 | snd_ps3_mute(1); | ||
567 | return 0; | ||
568 | }; | ||
569 | |||
570 | static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) | ||
571 | { | ||
572 | /* | ||
573 | * avsetting driver seems to never change the followings | ||
574 | * so, init them here once | ||
575 | */ | ||
576 | |||
577 | /* no dma interrupt needed */ | ||
578 | write_reg(PS3_AUDIO_INTR_EN_0, 0); | ||
579 | |||
580 | /* use every 4 buffer empty interrupt */ | ||
581 | update_mask_reg(PS3_AUDIO_AX_IC, | ||
582 | PS3_AUDIO_AX_IC_AASOIMD_MASK, | ||
583 | PS3_AUDIO_AX_IC_AASOIMD_EVERY4); | ||
584 | |||
585 | /* enable 3wire clocks */ | ||
586 | update_mask_reg(PS3_AUDIO_AO_3WMCTRL, | ||
587 | ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | | ||
588 | PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), | ||
589 | 0); | ||
590 | update_reg(PS3_AUDIO_AO_3WMCTRL, | ||
591 | PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * av setting | ||
596 | * NOTE: calling this function may generate audio interrupt. | ||
597 | */ | ||
598 | static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) | ||
599 | { | ||
600 | int ret, retries, i; | ||
601 | pr_debug("%s: start\n", __func__); | ||
602 | |||
603 | ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, | ||
604 | card->avs.avs_audio_rate, | ||
605 | card->avs.avs_audio_width, | ||
606 | card->avs.avs_audio_format, | ||
607 | card->avs.avs_audio_source); | ||
608 | /* | ||
609 | * Reset the following unwanted settings: | ||
610 | */ | ||
611 | |||
612 | /* disable all 3wire buffers */ | ||
613 | update_mask_reg(PS3_AUDIO_AO_3WMCTRL, | ||
614 | ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | | ||
615 | PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | | ||
616 | PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | | ||
617 | PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), | ||
618 | 0); | ||
619 | wmb(); /* ensure the hardware sees the change */ | ||
620 | /* wait for actually stopped */ | ||
621 | retries = 1000; | ||
622 | while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & | ||
623 | (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | | ||
624 | PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | | ||
625 | PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | | ||
626 | PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && | ||
627 | --retries) { | ||
628 | udelay(1); | ||
629 | } | ||
630 | |||
631 | /* reset buffer pointer */ | ||
632 | for (i = 0; i < 4; i++) { | ||
633 | update_reg(PS3_AUDIO_AO_3WCTRL(i), | ||
634 | PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); | ||
635 | udelay(10); | ||
636 | } | ||
637 | wmb(); /* ensure the hardware actually start resetting */ | ||
638 | |||
639 | /* enable 3wire#0 buffer */ | ||
640 | update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); | ||
641 | |||
642 | |||
643 | /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ | ||
644 | update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), | ||
645 | ~PS3_AUDIO_AO_3WCTRL_ASODF, | ||
646 | PS3_AUDIO_AO_3WCTRL_ASODF_LSB); | ||
647 | update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), | ||
648 | ~PS3_AUDIO_AO_SPDCTRL_SPODF, | ||
649 | PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); | ||
650 | /* ensure all the setting above is written back to register */ | ||
651 | wmb(); | ||
652 | /* avsetting driver altered AX_IE, caller must reset it if you want */ | ||
653 | pr_debug("%s: end\n", __func__); | ||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) | ||
658 | { | ||
659 | int ret; | ||
660 | pr_debug("%s: start\n", __func__); | ||
661 | card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; | ||
662 | card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; | ||
663 | card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | ||
664 | card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; | ||
665 | card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; | ||
666 | memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); | ||
667 | |||
668 | ret = snd_ps3_change_avsetting(card); | ||
669 | |||
670 | snd_ps3_audio_fixup(card); | ||
671 | |||
672 | /* to start to generate SPDIF signal, fill data */ | ||
673 | snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
674 | snd_ps3_kick_dma(card); | ||
675 | pr_debug("%s: end\n", __func__); | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | /* | ||
680 | * set sampling rate according to the substream | ||
681 | */ | ||
682 | static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) | ||
683 | { | ||
684 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
685 | struct snd_ps3_avsetting_info avs; | ||
686 | int ret; | ||
687 | |||
688 | avs = card->avs; | ||
689 | |||
690 | pr_debug("%s: called freq=%d width=%d\n", __func__, | ||
691 | substream->runtime->rate, | ||
692 | snd_pcm_format_width(substream->runtime->format)); | ||
693 | |||
694 | pr_debug("%s: before freq=%d width=%d\n", __func__, | ||
695 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | ||
696 | |||
697 | /* sample rate */ | ||
698 | switch (substream->runtime->rate) { | ||
699 | case 44100: | ||
700 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; | ||
701 | break; | ||
702 | case 48000: | ||
703 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; | ||
704 | break; | ||
705 | case 88200: | ||
706 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; | ||
707 | break; | ||
708 | case 96000: | ||
709 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; | ||
710 | break; | ||
711 | default: | ||
712 | pr_info("%s: invalid rate %d\n", __func__, | ||
713 | substream->runtime->rate); | ||
714 | return 1; | ||
715 | } | ||
716 | |||
717 | /* width */ | ||
718 | switch (snd_pcm_format_width(substream->runtime->format)) { | ||
719 | case 16: | ||
720 | avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | ||
721 | break; | ||
722 | case 24: | ||
723 | avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; | ||
724 | break; | ||
725 | default: | ||
726 | pr_info("%s: invalid width %d\n", __func__, | ||
727 | snd_pcm_format_width(substream->runtime->format)); | ||
728 | return 1; | ||
729 | } | ||
730 | |||
731 | memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); | ||
732 | |||
733 | if (memcmp(&card->avs, &avs, sizeof(avs))) { | ||
734 | pr_debug("%s: after freq=%d width=%d\n", __func__, | ||
735 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | ||
736 | |||
737 | card->avs = avs; | ||
738 | snd_ps3_change_avsetting(card); | ||
739 | ret = 0; | ||
740 | } else | ||
741 | ret = 1; | ||
742 | |||
743 | /* check CS non-audio bit and mute accordingly */ | ||
744 | if (avs.avs_cs_info[0] & 0x02) | ||
745 | ps3av_audio_mute_analog(1); /* mute if non-audio */ | ||
746 | else | ||
747 | ps3av_audio_mute_analog(0); | ||
748 | |||
749 | return ret; | ||
750 | } | ||
751 | |||
752 | /* | 710 | /* |
753 | * SPDIF status bits controls | 711 | * SPDIF status bits controls |
754 | */ | 712 | */ |
@@ -815,6 +773,17 @@ static struct snd_kcontrol_new spdif_ctls[] = { | |||
815 | }, | 773 | }, |
816 | }; | 774 | }; |
817 | 775 | ||
776 | static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { | ||
777 | .open = snd_ps3_pcm_open, | ||
778 | .close = snd_ps3_pcm_close, | ||
779 | .ioctl = snd_pcm_lib_ioctl, | ||
780 | .hw_params = snd_ps3_pcm_hw_params, | ||
781 | .hw_free = snd_ps3_pcm_hw_free, | ||
782 | .prepare = snd_ps3_pcm_prepare, | ||
783 | .trigger = snd_ps3_pcm_trigger, | ||
784 | .pointer = snd_ps3_pcm_pointer, | ||
785 | }; | ||
786 | |||
818 | 787 | ||
819 | static int snd_ps3_map_mmio(void) | 788 | static int snd_ps3_map_mmio(void) |
820 | { | 789 | { |
@@ -912,6 +881,52 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) | |||
912 | ret); | 881 | ret); |
913 | } | 882 | } |
914 | 883 | ||
884 | static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) | ||
885 | { | ||
886 | /* | ||
887 | * avsetting driver seems to never change the followings | ||
888 | * so, init them here once | ||
889 | */ | ||
890 | |||
891 | /* no dma interrupt needed */ | ||
892 | write_reg(PS3_AUDIO_INTR_EN_0, 0); | ||
893 | |||
894 | /* use every 4 buffer empty interrupt */ | ||
895 | update_mask_reg(PS3_AUDIO_AX_IC, | ||
896 | PS3_AUDIO_AX_IC_AASOIMD_MASK, | ||
897 | PS3_AUDIO_AX_IC_AASOIMD_EVERY4); | ||
898 | |||
899 | /* enable 3wire clocks */ | ||
900 | update_mask_reg(PS3_AUDIO_AO_3WMCTRL, | ||
901 | ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | | ||
902 | PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), | ||
903 | 0); | ||
904 | update_reg(PS3_AUDIO_AO_3WMCTRL, | ||
905 | PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); | ||
906 | } | ||
907 | |||
908 | static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) | ||
909 | { | ||
910 | int ret; | ||
911 | pr_debug("%s: start\n", __func__); | ||
912 | card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; | ||
913 | card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; | ||
914 | card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | ||
915 | card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; | ||
916 | card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; | ||
917 | memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); | ||
918 | |||
919 | ret = snd_ps3_change_avsetting(card); | ||
920 | |||
921 | snd_ps3_audio_fixup(card); | ||
922 | |||
923 | /* to start to generate SPDIF signal, fill data */ | ||
924 | snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
925 | snd_ps3_kick_dma(card); | ||
926 | pr_debug("%s: end\n", __func__); | ||
927 | return ret; | ||
928 | } | ||
929 | |||
915 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) | 930 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) |
916 | { | 931 | { |
917 | int i, ret; | 932 | int i, ret; |
@@ -1113,71 +1128,6 @@ static struct ps3_system_bus_driver snd_ps3_bus_driver_info = { | |||
1113 | 1128 | ||
1114 | 1129 | ||
1115 | /* | 1130 | /* |
1116 | * Interrupt handler | ||
1117 | */ | ||
1118 | static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) | ||
1119 | { | ||
1120 | |||
1121 | uint32_t port_intr; | ||
1122 | int underflow_occured = 0; | ||
1123 | struct snd_ps3_card_info *card = dev_id; | ||
1124 | |||
1125 | if (!card->running) { | ||
1126 | update_reg(PS3_AUDIO_AX_IS, 0); | ||
1127 | update_reg(PS3_AUDIO_INTR_0, 0); | ||
1128 | return IRQ_HANDLED; | ||
1129 | } | ||
1130 | |||
1131 | port_intr = read_reg(PS3_AUDIO_AX_IS); | ||
1132 | /* | ||
1133 | *serial buffer empty detected (every 4 times), | ||
1134 | *program next dma and kick it | ||
1135 | */ | ||
1136 | if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { | ||
1137 | write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); | ||
1138 | if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { | ||
1139 | write_reg(PS3_AUDIO_AX_IS, port_intr); | ||
1140 | underflow_occured = 1; | ||
1141 | } | ||
1142 | if (card->silent) { | ||
1143 | /* we are still in silent time */ | ||
1144 | snd_ps3_program_dma(card, | ||
1145 | (underflow_occured) ? | ||
1146 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : | ||
1147 | SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); | ||
1148 | snd_ps3_kick_dma(card); | ||
1149 | card->silent--; | ||
1150 | } else { | ||
1151 | snd_ps3_program_dma(card, | ||
1152 | (underflow_occured) ? | ||
1153 | SND_PS3_DMA_FILLTYPE_FIRSTFILL : | ||
1154 | SND_PS3_DMA_FILLTYPE_RUNNING); | ||
1155 | snd_ps3_kick_dma(card); | ||
1156 | snd_pcm_period_elapsed(card->substream); | ||
1157 | } | ||
1158 | } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { | ||
1159 | write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); | ||
1160 | /* | ||
1161 | * serial out underflow, but buffer empty not detected. | ||
1162 | * in this case, fill fifo with 0 to recover. After | ||
1163 | * filling dummy data, serial automatically start to | ||
1164 | * consume them and then will generate normal buffer | ||
1165 | * empty interrupts. | ||
1166 | * If both buffer underflow and buffer empty are occured, | ||
1167 | * it is better to do nomal data transfer than empty one | ||
1168 | */ | ||
1169 | snd_ps3_program_dma(card, | ||
1170 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
1171 | snd_ps3_kick_dma(card); | ||
1172 | snd_ps3_program_dma(card, | ||
1173 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
1174 | snd_ps3_kick_dma(card); | ||
1175 | } | ||
1176 | /* clear interrupt cause */ | ||
1177 | return IRQ_HANDLED; | ||
1178 | }; | ||
1179 | |||
1180 | /* | ||
1181 | * module/subsystem initialize/terminate | 1131 | * module/subsystem initialize/terminate |
1182 | */ | 1132 | */ |
1183 | static int __init snd_ps3_init(void) | 1133 | static int __init snd_ps3_init(void) |
@@ -1195,10 +1145,15 @@ static int __init snd_ps3_init(void) | |||
1195 | 1145 | ||
1196 | return ret; | 1146 | return ret; |
1197 | } | 1147 | } |
1148 | module_init(snd_ps3_init); | ||
1198 | 1149 | ||
1199 | static void __exit snd_ps3_exit(void) | 1150 | static void __exit snd_ps3_exit(void) |
1200 | { | 1151 | { |
1201 | ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info); | 1152 | ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info); |
1202 | } | 1153 | } |
1154 | module_exit(snd_ps3_exit); | ||
1203 | 1155 | ||
1156 | MODULE_LICENSE("GPL v2"); | ||
1157 | MODULE_DESCRIPTION("PS3 sound driver"); | ||
1158 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
1204 | MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND); | 1159 | MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND); |