From cb6492e4a4e68281358510f0ffe2b0c4972ec166 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jun 2009 16:39:02 +0200 Subject: 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 Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3.c | 753 ++++++++++++++++++++++++---------------------------- 1 file changed, 354 insertions(+), 399 deletions(-) (limited to 'sound/ppc/snd_ps3.c') 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,81 +18,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include #include -#include -#include #include +#include +#include + +#include +#include #include #include -#include -#include #include +#include #include -#include -#include -#include -#include + #include +#include #include #include #include -#include "snd_ps3_reg.h" #include "snd_ps3.h" - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("PS3 sound driver"); -MODULE_AUTHOR("Sony Computer Entertainment Inc."); - -/* module entries */ -static int __init snd_ps3_init(void); -static void __exit snd_ps3_exit(void); - -/* ALSA snd driver ops */ -static int snd_ps3_pcm_open(struct snd_pcm_substream *substream); -static int snd_ps3_pcm_close(struct snd_pcm_substream *substream); -static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream); -static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, - int cmd); -static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream - *substream); -static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params); -static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream); - - -/* ps3_system_bus_driver entries */ -static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev); -static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev); - -/* address setup */ -static int snd_ps3_map_mmio(void); -static void snd_ps3_unmap_mmio(void); -static int snd_ps3_allocate_irq(void); -static void snd_ps3_free_irq(void); -static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start); - -/* interrupt handler */ -static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id); - - -/* set sampling rate/format */ -static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream); -/* take effect parameter change */ -static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card); -/* initialize avsetting and take it effect */ -static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card); -/* setup dma */ -static int snd_ps3_program_dma(struct snd_ps3_card_info *card, - enum snd_ps3_dma_filltype filltype); -static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card); - -static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch); +#include "snd_ps3_reg.h" -module_init(snd_ps3_init); -module_exit(snd_ps3_exit); - /* * global */ @@ -165,17 +115,6 @@ static const struct snd_pcm_hardware snd_ps3_pcm_hw = { .fifo_size = PS3_AUDIO_FIFO_SIZE }; -static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { - .open = snd_ps3_pcm_open, - .close = snd_ps3_pcm_close, - .prepare = snd_ps3_pcm_prepare, - .ioctl = snd_pcm_lib_ioctl, - .trigger = snd_ps3_pcm_trigger, - .pointer = snd_ps3_pcm_pointer, - .hw_params = snd_ps3_pcm_hw_params, - .hw_free = snd_ps3_pcm_hw_free -}; - static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card, int count, int force_stop) { @@ -368,6 +307,71 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, return 0; } +/* + * Interrupt handler + */ +static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) +{ + + uint32_t port_intr; + int underflow_occured = 0; + struct snd_ps3_card_info *card = dev_id; + + if (!card->running) { + update_reg(PS3_AUDIO_AX_IS, 0); + update_reg(PS3_AUDIO_INTR_0, 0); + return IRQ_HANDLED; + } + + port_intr = read_reg(PS3_AUDIO_AX_IS); + /* + *serial buffer empty detected (every 4 times), + *program next dma and kick it + */ + if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { + write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); + if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { + write_reg(PS3_AUDIO_AX_IS, port_intr); + underflow_occured = 1; + } + if (card->silent) { + /* we are still in silent time */ + snd_ps3_program_dma(card, + (underflow_occured) ? + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : + SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); + snd_ps3_kick_dma(card); + card->silent--; + } else { + snd_ps3_program_dma(card, + (underflow_occured) ? + SND_PS3_DMA_FILLTYPE_FIRSTFILL : + SND_PS3_DMA_FILLTYPE_RUNNING); + snd_ps3_kick_dma(card); + snd_pcm_period_elapsed(card->substream); + } + } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { + write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); + /* + * serial out underflow, but buffer empty not detected. + * in this case, fill fifo with 0 to recover. After + * filling dummy data, serial automatically start to + * consume them and then will generate normal buffer + * empty interrupts. + * If both buffer underflow and buffer empty are occured, + * it is better to do nomal data transfer than empty one + */ + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + } + /* clear interrupt cause */ + return IRQ_HANDLED; +}; + /* * audio mute on/off * mute_on : 0 output enabled @@ -378,6 +382,142 @@ static int snd_ps3_mute(int mute_on) return ps3av_audio_mute(mute_on); } +/* + * av setting + * NOTE: calling this function may generate audio interrupt. + */ +static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) +{ + int ret, retries, i; + pr_debug("%s: start\n", __func__); + + ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, + card->avs.avs_audio_rate, + card->avs.avs_audio_width, + card->avs.avs_audio_format, + card->avs.avs_audio_source); + /* + * Reset the following unwanted settings: + */ + + /* disable all 3wire buffers */ + update_mask_reg(PS3_AUDIO_AO_3WMCTRL, + ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), + 0); + wmb(); /* ensure the hardware sees the change */ + /* wait for actually stopped */ + retries = 1000; + while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & + (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && + --retries) { + udelay(1); + } + + /* reset buffer pointer */ + for (i = 0; i < 4; i++) { + update_reg(PS3_AUDIO_AO_3WCTRL(i), + PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); + udelay(10); + } + wmb(); /* ensure the hardware actually start resetting */ + + /* enable 3wire#0 buffer */ + update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); + + + /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ + update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), + ~PS3_AUDIO_AO_3WCTRL_ASODF, + PS3_AUDIO_AO_3WCTRL_ASODF_LSB); + update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), + ~PS3_AUDIO_AO_SPDCTRL_SPODF, + PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); + /* ensure all the setting above is written back to register */ + wmb(); + /* avsetting driver altered AX_IE, caller must reset it if you want */ + pr_debug("%s: end\n", __func__); + return ret; +} + +/* + * set sampling rate according to the substream + */ +static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) +{ + struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); + struct snd_ps3_avsetting_info avs; + int ret; + + avs = card->avs; + + pr_debug("%s: called freq=%d width=%d\n", __func__, + substream->runtime->rate, + snd_pcm_format_width(substream->runtime->format)); + + pr_debug("%s: before freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); + + /* sample rate */ + switch (substream->runtime->rate) { + case 44100: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; + break; + case 48000: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; + break; + case 88200: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; + break; + case 96000: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; + break; + default: + pr_info("%s: invalid rate %d\n", __func__, + substream->runtime->rate); + return 1; + } + + /* width */ + switch (snd_pcm_format_width(substream->runtime->format)) { + case 16: + avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + break; + case 24: + avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; + break; + default: + pr_info("%s: invalid width %d\n", __func__, + snd_pcm_format_width(substream->runtime->format)); + return 1; + } + + memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); + + if (memcmp(&card->avs, &avs, sizeof(avs))) { + pr_debug("%s: after freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); + + card->avs = avs; + snd_ps3_change_avsetting(card); + ret = 0; + } else + ret = 1; + + /* check CS non-audio bit and mute accordingly */ + if (avs.avs_cs_info[0] & 0x02) + ps3av_audio_mute_analog(1); /* mute if non-audio */ + else + ps3av_audio_mute_analog(0); + + return ret; +} + /* * PCM operators */ @@ -403,6 +543,13 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) return 0; }; +static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) +{ + /* mute on */ + snd_ps3_mute(1); + return 0; +}; + static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -414,6 +561,13 @@ static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, return 0; }; +static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) +{ + int ret; + ret = snd_pcm_lib_free_pages(substream); + return ret; +}; + static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, unsigned int delay_ms) { @@ -467,287 +621,91 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) runtime->dma_area; card->dma_start_bus_addr[SND_PS3_CH_L] = runtime->dma_addr; - card->dma_last_transfer_vaddr[SND_PS3_CH_R] = - card->dma_next_transfer_vaddr[SND_PS3_CH_R] = - card->dma_start_vaddr[SND_PS3_CH_R] = - runtime->dma_area + (runtime->dma_bytes / 2); - card->dma_start_bus_addr[SND_PS3_CH_R] = - runtime->dma_addr + (runtime->dma_bytes / 2); - - pr_debug("%s: vaddr=%p bus=%#llx\n", __func__, - card->dma_start_vaddr[SND_PS3_CH_L], - card->dma_start_bus_addr[SND_PS3_CH_L]); - - } - spin_unlock_irqrestore(&card->dma_lock, irqsave); - - /* ensure the hardware sees the change */ - mb(); - - return 0; -}; - -static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* clear outstanding interrupts */ - update_reg(PS3_AUDIO_AX_IS, 0); - - spin_lock(&card->dma_lock); - { - card->running = 1; - } - spin_unlock(&card->dma_lock); - - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - while (read_reg(PS3_AUDIO_KICK(7)) & - PS3_AUDIO_KICK_STATUS_MASK) { - udelay(1); - } - snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); - snd_ps3_kick_dma(card); - break; - - case SNDRV_PCM_TRIGGER_STOP: - spin_lock(&card->dma_lock); - { - card->running = 0; - } - spin_unlock(&card->dma_lock); - snd_ps3_wait_for_dma_stop(card); - break; - default: - break; - - } - - return ret; -}; - -/* - * report current pointer - */ -static snd_pcm_uframes_t snd_ps3_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - size_t bytes; - snd_pcm_uframes_t ret; - - spin_lock(&card->dma_lock); - { - bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] - - card->dma_start_vaddr[SND_PS3_CH_L]); - } - spin_unlock(&card->dma_lock); - - ret = bytes_to_frames(substream->runtime, bytes * 2); - - return ret; -}; - -static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) -{ - int ret; - ret = snd_pcm_lib_free_pages(substream); - return ret; -}; - -static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) -{ - /* mute on */ - snd_ps3_mute(1); - return 0; -}; - -static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) -{ - /* - * avsetting driver seems to never change the followings - * so, init them here once - */ - - /* no dma interrupt needed */ - write_reg(PS3_AUDIO_INTR_EN_0, 0); - - /* use every 4 buffer empty interrupt */ - update_mask_reg(PS3_AUDIO_AX_IC, - PS3_AUDIO_AX_IC_AASOIMD_MASK, - PS3_AUDIO_AX_IC_AASOIMD_EVERY4); - - /* enable 3wire clocks */ - update_mask_reg(PS3_AUDIO_AO_3WMCTRL, - ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | - PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), - 0); - update_reg(PS3_AUDIO_AO_3WMCTRL, - PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); -} - -/* - * av setting - * NOTE: calling this function may generate audio interrupt. - */ -static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) -{ - int ret, retries, i; - pr_debug("%s: start\n", __func__); - - ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, - card->avs.avs_audio_rate, - card->avs.avs_audio_width, - card->avs.avs_audio_format, - card->avs.avs_audio_source); - /* - * Reset the following unwanted settings: - */ - - /* disable all 3wire buffers */ - update_mask_reg(PS3_AUDIO_AO_3WMCTRL, - ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), - 0); - wmb(); /* ensure the hardware sees the change */ - /* wait for actually stopped */ - retries = 1000; - while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & - (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && - --retries) { - udelay(1); - } - - /* reset buffer pointer */ - for (i = 0; i < 4; i++) { - update_reg(PS3_AUDIO_AO_3WCTRL(i), - PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); - udelay(10); - } - wmb(); /* ensure the hardware actually start resetting */ - - /* enable 3wire#0 buffer */ - update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); - - - /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ - update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), - ~PS3_AUDIO_AO_3WCTRL_ASODF, - PS3_AUDIO_AO_3WCTRL_ASODF_LSB); - update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), - ~PS3_AUDIO_AO_SPDCTRL_SPODF, - PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); - /* ensure all the setting above is written back to register */ - wmb(); - /* avsetting driver altered AX_IE, caller must reset it if you want */ - pr_debug("%s: end\n", __func__); - return ret; -} - -static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) -{ - int ret; - pr_debug("%s: start\n", __func__); - card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; - card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; - card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; - card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; - card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; - memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); - - ret = snd_ps3_change_avsetting(card); + card->dma_last_transfer_vaddr[SND_PS3_CH_R] = + card->dma_next_transfer_vaddr[SND_PS3_CH_R] = + card->dma_start_vaddr[SND_PS3_CH_R] = + runtime->dma_area + (runtime->dma_bytes / 2); + card->dma_start_bus_addr[SND_PS3_CH_R] = + runtime->dma_addr + (runtime->dma_bytes / 2); - snd_ps3_audio_fixup(card); + pr_debug("%s: vaddr=%p bus=%#llx\n", __func__, + card->dma_start_vaddr[SND_PS3_CH_L], + card->dma_start_bus_addr[SND_PS3_CH_L]); - /* to start to generate SPDIF signal, fill data */ - snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - pr_debug("%s: end\n", __func__); - return ret; -} + } + spin_unlock_irqrestore(&card->dma_lock, irqsave); -/* - * set sampling rate according to the substream - */ -static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) + /* ensure the hardware sees the change */ + mb(); + + return 0; +}; + +static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) { struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - struct snd_ps3_avsetting_info avs; - int ret; - - avs = card->avs; + int ret = 0; - pr_debug("%s: called freq=%d width=%d\n", __func__, - substream->runtime->rate, - snd_pcm_format_width(substream->runtime->format)); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* clear outstanding interrupts */ + update_reg(PS3_AUDIO_AX_IS, 0); - pr_debug("%s: before freq=%d width=%d\n", __func__, - card->avs.avs_audio_rate, card->avs.avs_audio_width); + spin_lock(&card->dma_lock); + { + card->running = 1; + } + spin_unlock(&card->dma_lock); - /* sample rate */ - switch (substream->runtime->rate) { - case 44100: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; - break; - case 48000: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; - break; - case 88200: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; - break; - case 96000: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + while (read_reg(PS3_AUDIO_KICK(7)) & + PS3_AUDIO_KICK_STATUS_MASK) { + udelay(1); + } + snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); + snd_ps3_kick_dma(card); break; - default: - pr_info("%s: invalid rate %d\n", __func__, - substream->runtime->rate); - return 1; - } - /* width */ - switch (snd_pcm_format_width(substream->runtime->format)) { - case 16: - avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; - break; - case 24: - avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; + case SNDRV_PCM_TRIGGER_STOP: + spin_lock(&card->dma_lock); + { + card->running = 0; + } + spin_unlock(&card->dma_lock); + snd_ps3_wait_for_dma_stop(card); break; default: - pr_info("%s: invalid width %d\n", __func__, - snd_pcm_format_width(substream->runtime->format)); - return 1; + break; + } - memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); + return ret; +}; - if (memcmp(&card->avs, &avs, sizeof(avs))) { - pr_debug("%s: after freq=%d width=%d\n", __func__, - card->avs.avs_audio_rate, card->avs.avs_audio_width); +/* + * report current pointer + */ +static snd_pcm_uframes_t snd_ps3_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); + size_t bytes; + snd_pcm_uframes_t ret; - card->avs = avs; - snd_ps3_change_avsetting(card); - ret = 0; - } else - ret = 1; + spin_lock(&card->dma_lock); + { + bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] - + card->dma_start_vaddr[SND_PS3_CH_L]); + } + spin_unlock(&card->dma_lock); - /* check CS non-audio bit and mute accordingly */ - if (avs.avs_cs_info[0] & 0x02) - ps3av_audio_mute_analog(1); /* mute if non-audio */ - else - ps3av_audio_mute_analog(0); + ret = bytes_to_frames(substream->runtime, bytes * 2); return ret; -} +}; /* * SPDIF status bits controls @@ -815,6 +773,17 @@ static struct snd_kcontrol_new spdif_ctls[] = { }, }; +static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { + .open = snd_ps3_pcm_open, + .close = snd_ps3_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ps3_pcm_hw_params, + .hw_free = snd_ps3_pcm_hw_free, + .prepare = snd_ps3_pcm_prepare, + .trigger = snd_ps3_pcm_trigger, + .pointer = snd_ps3_pcm_pointer, +}; + static int snd_ps3_map_mmio(void) { @@ -912,6 +881,52 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) ret); } +static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) +{ + /* + * avsetting driver seems to never change the followings + * so, init them here once + */ + + /* no dma interrupt needed */ + write_reg(PS3_AUDIO_INTR_EN_0, 0); + + /* use every 4 buffer empty interrupt */ + update_mask_reg(PS3_AUDIO_AX_IC, + PS3_AUDIO_AX_IC_AASOIMD_MASK, + PS3_AUDIO_AX_IC_AASOIMD_EVERY4); + + /* enable 3wire clocks */ + update_mask_reg(PS3_AUDIO_AO_3WMCTRL, + ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | + PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), + 0); + update_reg(PS3_AUDIO_AO_3WMCTRL, + PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); +} + +static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) +{ + int ret; + pr_debug("%s: start\n", __func__); + card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; + card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; + card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; + card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; + memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); + + ret = snd_ps3_change_avsetting(card); + + snd_ps3_audio_fixup(card); + + /* to start to generate SPDIF signal, fill data */ + snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + pr_debug("%s: end\n", __func__); + return ret; +} + static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; @@ -1112,71 +1127,6 @@ static struct ps3_system_bus_driver snd_ps3_bus_driver_info = { }; -/* - * Interrupt handler - */ -static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) -{ - - uint32_t port_intr; - int underflow_occured = 0; - struct snd_ps3_card_info *card = dev_id; - - if (!card->running) { - update_reg(PS3_AUDIO_AX_IS, 0); - update_reg(PS3_AUDIO_INTR_0, 0); - return IRQ_HANDLED; - } - - port_intr = read_reg(PS3_AUDIO_AX_IS); - /* - *serial buffer empty detected (every 4 times), - *program next dma and kick it - */ - if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { - write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); - if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { - write_reg(PS3_AUDIO_AX_IS, port_intr); - underflow_occured = 1; - } - if (card->silent) { - /* we are still in silent time */ - snd_ps3_program_dma(card, - (underflow_occured) ? - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : - SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); - snd_ps3_kick_dma(card); - card->silent--; - } else { - snd_ps3_program_dma(card, - (underflow_occured) ? - SND_PS3_DMA_FILLTYPE_FIRSTFILL : - SND_PS3_DMA_FILLTYPE_RUNNING); - snd_ps3_kick_dma(card); - snd_pcm_period_elapsed(card->substream); - } - } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { - write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); - /* - * serial out underflow, but buffer empty not detected. - * in this case, fill fifo with 0 to recover. After - * filling dummy data, serial automatically start to - * consume them and then will generate normal buffer - * empty interrupts. - * If both buffer underflow and buffer empty are occured, - * it is better to do nomal data transfer than empty one - */ - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - } - /* clear interrupt cause */ - return IRQ_HANDLED; -}; - /* * module/subsystem initialize/terminate */ @@ -1195,10 +1145,15 @@ static int __init snd_ps3_init(void) return ret; } +module_init(snd_ps3_init); static void __exit snd_ps3_exit(void) { ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info); } +module_exit(snd_ps3_exit); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PS3 sound driver"); +MODULE_AUTHOR("Sony Computer Entertainment Inc."); MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND); -- cgit