diff options
Diffstat (limited to 'sound/mips/au1x00.c')
| -rw-r--r-- | sound/mips/au1x00.c | 263 |
1 files changed, 154 insertions, 109 deletions
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index 6d8f8b3eabd..fbcaa5434fd 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c @@ -36,13 +36,14 @@ #include <linux/ioport.h> #include <linux/interrupt.h> -#include <sound/driver.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/version.h> +#include <linux/module.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <sound/ac97_codec.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1000_dma.h> @@ -98,6 +99,7 @@ struct snd_au1000 { struct snd_pcm *pcm; struct audio_stream *stream[2]; /* playback & capture */ + int dmaid[2]; /* tx(0)/rx(1) DMA ids */ }; /*--------------------------- Local Functions --------------------------------*/ @@ -153,6 +155,7 @@ au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes, { struct snd_pcm_substream *substream = stream->substream; struct snd_pcm_runtime *runtime = substream->runtime; + struct au1000_period *pointer; unsigned long dma_start; int i; @@ -190,14 +193,16 @@ au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes, static void au1000_dma_stop(struct audio_stream *stream) { - snd_assert(stream->buffer, return); + if (snd_BUG_ON(!stream->buffer)) + return; disable_dma(stream->dma); } static void au1000_dma_start(struct audio_stream *stream) { - snd_assert(stream->buffer, return); + if (snd_BUG_ON(!stream->buffer)) + return; init_dma(stream->dma); if (get_dma_active_buffer(stream->dma) == 0) { @@ -218,7 +223,7 @@ au1000_dma_start(struct audio_stream *stream) } static irqreturn_t -au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +au1000_dma_interrupt(int irq, void *dev_id) { struct audio_stream *stream = (struct audio_stream *) dev_id; struct snd_pcm_substream *substream = stream->substream; @@ -256,7 +261,7 @@ au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) static unsigned int rates[] = {8000, 11025, 16000, 22050}; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = sizeof(rates) / sizeof(rates[0]), + .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; @@ -436,7 +441,7 @@ static struct snd_pcm_ops snd_card_au1000_capture_ops = { .pointer = snd_au1000_pointer, }; -static int __devinit +static int snd_au1000_pcm_new(struct snd_au1000 *au1000) { struct snd_pcm *pcm; @@ -462,15 +467,17 @@ snd_au1000_pcm_new(struct snd_au1000 *au1000) spin_lock_init(&au1000->stream[CAPTURE]->dma_lock); flags = claim_dma_lock(); - if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX, - "AC97 TX", au1000_dma_interrupt, SA_INTERRUPT, - au1000->stream[PLAYBACK])) < 0) { + au1000->stream[PLAYBACK]->dma = request_au1000_dma(au1000->dmaid[0], + "AC97 TX", au1000_dma_interrupt, 0, + au1000->stream[PLAYBACK]); + if (au1000->stream[PLAYBACK]->dma < 0) { release_dma_lock(flags); return -EBUSY; } - if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX, - "AC97 RX", au1000_dma_interrupt, SA_INTERRUPT, - au1000->stream[CAPTURE])) < 0){ + au1000->stream[CAPTURE]->dma = request_au1000_dma(au1000->dmaid[1], + "AC97 RX", au1000_dma_interrupt, 0, + au1000->stream[CAPTURE]); + if (au1000->stream[CAPTURE]->dma < 0){ release_dma_lock(flags); return -EBUSY; } @@ -496,8 +503,8 @@ snd_au1000_ac97_read(struct snd_ac97 *ac97, unsigned short reg) int i; spin_lock(&au1000->ac97_lock); -/* would rather use the interupt than this polling but it works and I can't -get the interupt driven case to work efficiently */ +/* would rather use the interrupt than this polling but it works and I can't +get the interrupt driven case to work efficiently */ for (i = 0; i < 0x5000; i++) if (!(au1000->ac97_ioport->status & AC97C_CP)) break; @@ -514,6 +521,7 @@ get the interupt driven case to work efficiently */ break; if (i == 0x5000) { printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n"); + spin_unlock(&au1000->ac97_lock); return 0; } @@ -533,8 +541,8 @@ snd_au1000_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short int i; spin_lock(&au1000->ac97_lock); -/* would rather use the interupt than this polling but it works and I can't -get the interupt driven case to work efficiently */ +/* would rather use the interrupt than this polling but it works and I can't +get the interrupt driven case to work efficiently */ for (i = 0; i < 0x5000; i++) if (!(au1000->ac97_ioport->status & AC97C_CP)) break; @@ -548,26 +556,111 @@ get the interupt driven case to work efficiently */ spin_unlock(&au1000->ac97_lock); } -static int __devinit -snd_au1000_ac97_new(struct snd_au1000 *au1000) +/*------------------------------ Setup / Destroy ----------------------------*/ + +static void snd_au1000_free(struct snd_card *card) +{ + struct snd_au1000 *au1000 = card->private_data; + + if (au1000->stream[PLAYBACK]) { + if (au1000->stream[PLAYBACK]->dma >= 0) + free_au1000_dma(au1000->stream[PLAYBACK]->dma); + kfree(au1000->stream[PLAYBACK]); + } + + if (au1000->stream[CAPTURE]) { + if (au1000->stream[CAPTURE]->dma >= 0) + free_au1000_dma(au1000->stream[CAPTURE]->dma); + kfree(au1000->stream[CAPTURE]); + } + + if (au1000->ac97_res_port) { + /* put internal AC97 block into reset */ + if (au1000->ac97_ioport) { + au1000->ac97_ioport->cntrl = AC97C_RS; + iounmap(au1000->ac97_ioport); + au1000->ac97_ioport = NULL; + } + release_and_free_resource(au1000->ac97_res_port); + au1000->ac97_res_port = NULL; + } +} + +static struct snd_ac97_bus_ops ops = { + .write = snd_au1000_ac97_write, + .read = snd_au1000_ac97_read, +}; + +static int au1000_ac97_probe(struct platform_device *pdev) { int err; + void __iomem *io; + struct resource *r; + struct snd_card *card; + struct snd_au1000 *au1000; struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; - static struct snd_ac97_bus_ops ops = { - .write = snd_au1000_ac97_write, - .read = snd_au1000_ac97_read, - }; - - if ((au1000->ac97_res_port = request_region(AC97C_CONFIG, - sizeof(struct au1000_ac97_reg), "Au1x00 AC97")) == NULL) { - snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n"); - return -EBUSY; - } - au1000->ac97_ioport = (struct au1000_ac97_reg *) au1000->ac97_res_port->start; + err = snd_card_new(&pdev->dev, -1, "AC97", THIS_MODULE, + sizeof(struct snd_au1000), &card); + if (err < 0) + return err; + + au1000 = card->private_data; + au1000->card = card; spin_lock_init(&au1000->ac97_lock); + /* from here on let ALSA call the special freeing function */ + card->private_free = snd_au1000_free; + + /* TX DMA ID */ + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) { + err = -ENODEV; + snd_printk(KERN_INFO "no TX DMA platform resource!\n"); + goto out; + } + au1000->dmaid[0] = r->start; + + /* RX DMA ID */ + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!r) { + err = -ENODEV; + snd_printk(KERN_INFO "no RX DMA platform resource!\n"); + goto out; + } + au1000->dmaid[1] = r->start; + + au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), + GFP_KERNEL); + if (!au1000->stream[PLAYBACK]) + goto out; + au1000->stream[PLAYBACK]->dma = -1; + + au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream), + GFP_KERNEL); + if (!au1000->stream[CAPTURE]) + goto out; + au1000->stream[CAPTURE]->dma = -1; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + goto out; + + err = -EBUSY; + au1000->ac97_res_port = request_mem_region(r->start, resource_size(r), + pdev->name); + if (!au1000->ac97_res_port) { + snd_printk(KERN_ERR "ALSA AC97: can't grab AC97 port\n"); + goto out; + } + + io = ioremap(r->start, resource_size(r)); + if (!io) + goto out; + + au1000->ac97_ioport = (struct au1000_ac97_reg *)io; + /* configure pins for AC'97 TODO: move to board_setup.c */ au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); @@ -585,99 +678,51 @@ snd_au1000_ac97_new(struct snd_au1000 *au1000) mdelay(5); /* Initialise AC97 middle-layer */ - if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0) - return err; + err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus); + if (err < 0) + goto out; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = au1000; - if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0) - return err; - - return 0; -} - -/*------------------------------ Setup / Destroy ----------------------------*/ - -void -snd_au1000_free(struct snd_card *card) -{ - struct snd_au1000 *au1000 = card->private_data; - - if (au1000->ac97_res_port) { - /* put internal AC97 block into reset */ - au1000->ac97_ioport->cntrl = AC97C_RS; - au1000->ac97_ioport = NULL; - release_and_free_resource(au1000->ac97_res_port); - } - - if (au1000->stream[PLAYBACK]->dma >= 0) - free_au1000_dma(au1000->stream[PLAYBACK]->dma); - - if (au1000->stream[CAPTURE]->dma >= 0) - free_au1000_dma(au1000->stream[CAPTURE]->dma); - - kfree(au1000->stream[PLAYBACK]); - kfree(au1000->stream[CAPTURE]); -} - - -static struct snd_card *au1000_card; - -static int __init -au1000_init(void) -{ - int err; - struct snd_card *card; - struct snd_au1000 *au1000; - - card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(struct snd_au1000)); - if (card == NULL) - return -ENOMEM; - - card->private_free = snd_au1000_free; - au1000 = card->private_data; - /* so that snd_au1000_free will work as intended */ - au1000->card = card; - au1000->stream[PLAYBACK]->dma = -1; - au1000->stream[CAPTURE]->dma = -1; - au1000->ac97_res_port = NULL; - au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL); - au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL); - if (au1000->stream[PLAYBACK] == NULL || - au1000->stream[CAPTURE] == NULL) { - snd_card_free(card); - return -ENOMEM; - } - - if ((err = snd_au1000_ac97_new(au1000)) < 0 ) { - snd_card_free(card); - return err; - } + err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97); + if (err < 0) + goto out; - if ((err = snd_au1000_pcm_new(au1000)) < 0) { - snd_card_free(card); - return err; - } + err = snd_au1000_pcm_new(au1000); + if (err < 0) + goto out; strcpy(card->driver, "Au1000-AC97"); strcpy(card->shortname, "AMD Au1000-AC97"); sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver"); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + err = snd_card_register(card); + if (err < 0) + goto out; + + printk(KERN_INFO "ALSA AC97: Driver Initialized\n"); + + platform_set_drvdata(pdev, card); - printk( KERN_INFO "ALSA AC97: Driver Initialized\n" ); - au1000_card = card; return 0; + + out: + snd_card_free(card); + return err; } -static void __exit au1000_exit(void) +static int au1000_ac97_remove(struct platform_device *pdev) { - snd_card_free(au1000_card); + return snd_card_free(platform_get_drvdata(pdev)); } -module_init(au1000_init); -module_exit(au1000_exit); +struct platform_driver au1000_ac97c_driver = { + .driver = { + .name = "au1000-ac97c", + .owner = THIS_MODULE, + }, + .probe = au1000_ac97_probe, + .remove = au1000_ac97_remove, +}; +module_platform_driver(au1000_ac97c_driver); |
