diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-13 17:13:56 +0100 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-13 17:13:56 +0100 |
commit | e758936e02700ff88a0b08b722a3847b95283ef2 (patch) | |
tree | 50c919bef1b459a778b85159d5929de95b6c4a01 /sound/arm | |
parent | 239cfbde1f5843c4a24199f117d5f67f637d72d5 (diff) | |
parent | 4480f15b3306f43bbb0310d461142b4e897ca45b (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
include/asm-x86/statfs.h
Diffstat (limited to 'sound/arm')
-rw-r--r-- | sound/arm/Kconfig | 9 | ||||
-rw-r--r-- | sound/arm/Makefile | 4 | ||||
-rw-r--r-- | sound/arm/aaci.c | 6 | ||||
-rw-r--r-- | sound/arm/pxa2xx-ac97-lib.c | 384 | ||||
-rw-r--r-- | sound/arm/pxa2xx-ac97.c | 251 | ||||
-rw-r--r-- | sound/arm/pxa2xx-pcm-lib.c | 278 | ||||
-rw-r--r-- | sound/arm/pxa2xx-pcm.c | 252 | ||||
-rw-r--r-- | sound/arm/pxa2xx-pcm.h | 13 | ||||
-rw-r--r-- | sound/arm/sa11xx-uda1341.c | 7 |
9 files changed, 717 insertions, 487 deletions
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 351e19ea378..f8e6de48d81 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -32,11 +32,20 @@ config SND_PXA2XX_PCM tristate select SND_PCM +config SND_PXA2XX_LIB + tristate + select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 + +config SND_PXA2XX_LIB_AC97 + bool + config SND_PXA2XX_AC97 tristate "AC97 driver for the Intel PXA2xx chip" depends on ARCH_PXA select SND_PXA2XX_PCM select SND_AC97_CODEC + select SND_PXA2XX_LIB + select SND_PXA2XX_LIB_AC97 help Say Y or M if you want to support any AC97 codec attached to the PXA2xx AC97 interface. diff --git a/sound/arm/Makefile b/sound/arm/Makefile index 4ef6dd00c6e..2054de11de8 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -11,5 +11,9 @@ snd-aaci-objs := aaci.o devdma.o obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o snd-pxa2xx-pcm-objs := pxa2xx-pcm.o +obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o +snd-pxa2xx-lib-y := pxa2xx-pcm-lib.o +snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o + obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o snd-pxa2xx-ac97-objs := pxa2xx-ac97.o diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index b0a47449496..89096e811a4 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -999,7 +999,7 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev) card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, sizeof(struct aaci)); if (card == NULL) - return ERR_PTR(-ENOMEM); + return NULL; card->private_free = aaci_free_card; @@ -1083,8 +1083,8 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) return ret; aaci = aaci_init_card(dev); - if (IS_ERR(aaci)) { - ret = PTR_ERR(aaci); + if (!aaci) { + ret = -ENOMEM; goto out; } diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c new file mode 100644 index 00000000000..99026dfb81e --- /dev/null +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -0,0 +1,384 @@ +/* + * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c + * which contain: + * + * Author: Nicolas Pitre + * Created: Dec 02, 2004 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/delay.h> + +#include <sound/ac97_codec.h> +#include <sound/pxa2xx-lib.h> + +#include <asm/irq.h> +#include <mach/hardware.h> +#include <mach/pxa-regs.h> +#include <mach/pxa2xx-gpio.h> +#include <mach/audio.h> + +static DEFINE_MUTEX(car_mutex); +static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); +static volatile long gsr_bits; +static struct clk *ac97_clk; +static struct clk *ac97conf_clk; + +/* + * Beware PXA27x bugs: + * + * o Slot 12 read from modem space will hang controller. + * o CDONE, SDONE interrupt fails after any slot 12 IO. + * + * We therefore have an hybrid approach for waiting on SDONE (interrupt or + * 1 jiffy timeout if interrupt never comes). + */ + +unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) +{ + unsigned short val = -1; + volatile u32 *reg_addr; + + mutex_lock(&car_mutex); + + /* set up primary or secondary codec space */ + if ((cpu_is_pxa21x() || cpu_is_pxa25x()) && reg == AC97_GPIO_STATUS) + reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; + else + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; + reg_addr += (reg >> 1); + + /* start read access across the ac97 link */ + GSR = GSR_CDONE | GSR_SDONE; + gsr_bits = 0; + val = *reg_addr; + if (reg == AC97_GPIO_STATUS) + goto out; + if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 && + !((GSR | gsr_bits) & GSR_SDONE)) { + printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", + __func__, reg, GSR | gsr_bits); + val = -1; + goto out; + } + + /* valid data now */ + GSR = GSR_CDONE | GSR_SDONE; + gsr_bits = 0; + val = *reg_addr; + /* but we've just started another cycle... */ + wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); + +out: mutex_unlock(&car_mutex); + return val; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); + +void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + volatile u32 *reg_addr; + + mutex_lock(&car_mutex); + + /* set up primary or secondary codec space */ + if ((cpu_is_pxa21x() || cpu_is_pxa25x()) && reg == AC97_GPIO_STATUS) + reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; + else + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; + reg_addr += (reg >> 1); + + GSR = GSR_CDONE | GSR_SDONE; + gsr_bits = 0; + *reg_addr = val; + if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 && + !((GSR | gsr_bits) & GSR_CDONE)) + printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", + __func__, reg, GSR | gsr_bits); + + mutex_unlock(&car_mutex); +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_write); + +#ifdef CONFIG_PXA25x +static inline void pxa_ac97_warm_pxa25x(void) +{ + gsr_bits = 0; + + GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; + wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); +} + +static inline void pxa_ac97_cold_pxa25x(void) +{ + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ + GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + + gsr_bits = 0; + + GCR = GCR_COLD_RST; + GCR |= GCR_CDONE_IE|GCR_SDONE_IE; + wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); +} +#endif + +#ifdef CONFIG_PXA27x +static inline void pxa_ac97_warm_pxa27x(void) +{ + gsr_bits = 0; + + /* warm reset broken on Bulverde, + so manually keep AC97 reset high */ + pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); + udelay(10); + GCR |= GCR_WARM_RST; + pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); + udelay(500); +} + +static inline void pxa_ac97_cold_pxa27x(void) +{ + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ + GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + + gsr_bits = 0; + + /* PXA27x Developers Manual section 13.5.2.2.1 */ + clk_enable(ac97conf_clk); + udelay(5); + clk_disable(ac97conf_clk); + GCR = GCR_COLD_RST; + udelay(50); +} +#endif + +#ifdef CONFIG_PXA3xx +static inline void pxa_ac97_warm_pxa3xx(void) +{ + int timeout = 100; + + gsr_bits = 0; + + /* Can't use interrupts */ + GCR |= GCR_WARM_RST; + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); +} + +static inline void pxa_ac97_cold_pxa3xx(void) +{ + int timeout = 1000; + + /* Hold CLKBPB for 100us */ + GCR = 0; + GCR = GCR_CLKBPB; + udelay(100); + GCR = 0; + + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ + GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + + gsr_bits = 0; + + /* Can't use interrupts on PXA3xx */ + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + + GCR = GCR_WARM_RST | GCR_COLD_RST; + while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(10); +} +#endif + +bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) +{ +#ifdef CONFIG_PXA25x + if (cpu_is_pxa21x() || cpu_is_pxa25x()) + pxa_ac97_warm_pxa25x(); + else +#endif +#ifdef CONFIG_PXA27x + if (cpu_is_pxa27x()) + pxa_ac97_warm_pxa27x(); + else +#endif +#ifdef CONFIG_PXA3xx + if (cpu_is_pxa3xx()) + pxa_ac97_warm_pxa3xx(); + else +#endif + BUG(); + + if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { + printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", + __func__, gsr_bits); + + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); + +bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) +{ +#ifdef CONFIG_PXA25x + if (cpu_is_pxa21x() || cpu_is_pxa25x()) + pxa_ac97_cold_pxa25x(); + else +#endif +#ifdef CONFIG_PXA27x + if (cpu_is_pxa27x()) + pxa_ac97_cold_pxa27x(); + else +#endif +#ifdef CONFIG_PXA3xx + if (cpu_is_pxa3xx()) + pxa_ac97_cold_pxa3xx(); + else +#endif + BUG(); + + if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { + printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", + __func__, gsr_bits); + + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset); + + +void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97) +{ + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + GCR |= GCR_SDONE_IE|GCR_CDONE_IE; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset); + +static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) +{ + long status; + + status = GSR; + if (status) { + GSR = status; + gsr_bits |= status; + wake_up(&gsr_wq); + + /* Although we don't use those we still need to clear them + since they tend to spuriously trigger when MMC is used + (hardware bug? go figure)... */ + if (cpu_is_pxa27x()) { + MISR = MISR_EOC; + PISR = PISR_EOC; + MCSR = MCSR_EOC; + } + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +#ifdef CONFIG_PM +int pxa2xx_ac97_hw_suspend(void) +{ + GCR |= GCR_ACLINK_OFF; + clk_disable(ac97_clk); + return 0; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); + +int pxa2xx_ac97_hw_resume(void) +{ + if (cpu_is_pxa21x() || cpu_is_pxa25x() || cpu_is_pxa27x()) { + pxa_gpio_mode(GPIO31_SYNC_AC97_MD); + pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); + pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); + pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); + } + if (cpu_is_pxa27x()) { + /* Use GPIO 113 as AC97 Reset on Bulverde */ + pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); + } + clk_enable(ac97_clk); + return 0; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); +#endif + +int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) +{ + int ret; + + ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); + if (ret < 0) + goto err; + + if (cpu_is_pxa21x() || cpu_is_pxa25x() || cpu_is_pxa27x()) { + pxa_gpio_mode(GPIO31_SYNC_AC97_MD); + pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); + pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); + pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); + } + + if (cpu_is_pxa27x()) { + /* Use GPIO 113 as AC97 Reset on Bulverde */ + pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); + ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); + if (IS_ERR(ac97conf_clk)) { + ret = PTR_ERR(ac97conf_clk); + ac97conf_clk = NULL; + goto err_irq; + } + } + + ac97_clk = clk_get(&dev->dev, "AC97CLK"); + if (IS_ERR(ac97_clk)) { + ret = PTR_ERR(ac97_clk); + ac97_clk = NULL; + goto err_irq; + } + + return clk_enable(ac97_clk); + +err_irq: + GCR |= GCR_ACLINK_OFF; + if (ac97conf_clk) { + clk_put(ac97conf_clk); + ac97conf_clk = NULL; + } + free_irq(IRQ_AC97, NULL); +err: + return ret; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); + +void pxa2xx_ac97_hw_remove(struct platform_device *dev) +{ + GCR |= GCR_ACLINK_OFF; + free_irq(IRQ_AC97, NULL); + if (ac97conf_clk) { + clk_put(ac97conf_clk); + ac97conf_clk = NULL; + } + clk_disable(ac97_clk); + clk_put(ac97_clk); + ac97_clk = NULL; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove); + +MODULE_AUTHOR("Nicolas Pitre"); +MODULE_DESCRIPTION("Intel/Marvell PXA sound library"); +MODULE_LICENSE("GPL"); + diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 199cca3366d..c2635beb4c8 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -12,198 +12,27 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/kernel.h> #include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/clk.h> -#include <linux/delay.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/ac97_codec.h> #include <sound/initval.h> +#include <sound/pxa2xx-lib.h> -#include <asm/irq.h> -#include <linux/mutex.h> #include <mach/hardware.h> #include <mach/pxa-regs.h> -#include <mach/pxa2xx-gpio.h> #include <mach/audio.h> #include "pxa2xx-pcm.h" - -static DEFINE_MUTEX(car_mutex); -static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); -static volatile long gsr_bits; -static struct clk *ac97_clk; -#ifdef CONFIG_PXA27x -static struct clk *ac97conf_clk; -#endif - -/* - * Beware PXA27x bugs: - * - * o Slot 12 read from modem space will hang controller. - * o CDONE, SDONE interrupt fails after any slot 12 IO. - * - * We therefore have an hybrid approach for waiting on SDONE (interrupt or - * 1 jiffy timeout if interrupt never comes). - */ - -static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) -{ - unsigned short val = -1; - volatile u32 *reg_addr; - - mutex_lock(&car_mutex); - - /* set up primary or secondary codec space */ - reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; - reg_addr += (reg >> 1); - - /* start read access across the ac97 link */ - GSR = GSR_CDONE | GSR_SDONE; - gsr_bits = 0; - val = *reg_addr; - if (reg == AC97_GPIO_STATUS) - goto out; - if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 && - !((GSR | gsr_bits) & GSR_SDONE)) { - printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", - __func__, reg, GSR | gsr_bits); - val = -1; - goto out; - } - - /* valid data now */ - GSR = GSR_CDONE | GSR_SDONE; - gsr_bits = 0; - val = *reg_addr; - /* but we've just started another cycle... */ - wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); - -out: mutex_unlock(&car_mutex); - return val; -} - -static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) -{ - volatile u32 *reg_addr; - - mutex_lock(&car_mutex); - - /* set up primary or secondary codec space */ - reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; - reg_addr += (reg >> 1); - - GSR = GSR_CDONE | GSR_SDONE; - gsr_bits = 0; - *reg_addr = val; - if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 && - !((GSR | gsr_bits) & GSR_CDONE)) - printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", - __func__, reg, GSR | gsr_bits); - - mutex_unlock(&car_mutex); -} - static void pxa2xx_ac97_reset(struct snd_ac97 *ac97) { - /* First, try cold reset */ -#ifdef CONFIG_PXA3xx - int timeout; - - /* Hold CLKBPB for 100us */ - GCR = 0; - GCR = GCR_CLKBPB; - udelay(100); - GCR = 0; -#endif - - GCR &= GCR_COLD_RST; /* clear everything but nCRST */ - GCR &= ~GCR_COLD_RST; /* then assert nCRST */ - - gsr_bits = 0; -#ifdef CONFIG_PXA27x - /* PXA27x Developers Manual section 13.5.2.2.1 */ - clk_enable(ac97conf_clk); - udelay(5); - clk_disable(ac97conf_clk); - GCR = GCR_COLD_RST; - udelay(50); -#elif defined(CONFIG_PXA3xx) - timeout = 1000; - /* Can't use interrupts on PXA3xx */ - GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); - - GCR = GCR_WARM_RST | GCR_COLD_RST; - while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) - mdelay(10); -#else - GCR = GCR_COLD_RST; - GCR |= GCR_CDONE_IE|GCR_SDONE_IE; - wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); -#endif - - if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { - printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", - __func__, gsr_bits); - - /* let's try warm reset */ - gsr_bits = 0; -#ifdef CONFIG_PXA27x - /* warm reset broken on Bulverde, - so manually keep AC97 reset high */ - pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); - udelay(10); - GCR |= GCR_WARM_RST; - pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); - udelay(500); -#elif defined(CONFIG_PXA3xx) - timeout = 100; - /* Can't use interrupts */ - GCR |= GCR_WARM_RST; - while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) - mdelay(1); -#else - GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN; - wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); -#endif - - if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) - printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", - __func__, gsr_bits); - } - - GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); - GCR |= GCR_SDONE_IE|GCR_CDONE_IE; -} - -static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) -{ - long status; - - status = GSR; - if (status) { - GSR = status; - gsr_bits |= status; - wake_up(&gsr_wq); - -#ifdef CONFIG_PXA27x - /* Although we don't use those we still need to clear them - since they tend to spuriously trigger when MMC is used - (hardware bug? go figure)... */ - MISR = MISR_EOC; - PISR = PISR_EOC; - MCSR = MCSR_EOC; -#endif - - return IRQ_HANDLED; + if (!pxa2xx_ac97_try_cold_reset(ac97)) { + pxa2xx_ac97_try_warm_reset(ac97); } - return IRQ_NONE; + pxa2xx_ac97_finish_reset(ac97); } static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { @@ -215,7 +44,7 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = { .name = "AC97 PCM out", .dev_addr = __PREG(PCDR), - .drcmr = &DRCMRTXPCDR, + .drcmr = &DRCMR(12), .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_BURST32 | DCMD_WIDTH4, }; @@ -223,7 +52,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = { static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_in = { .name = "AC97 PCM in", .dev_addr = __PREG(PCDR), - .drcmr = &DRCMRRXPCDR, + .drcmr = &DRCMR(11), .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_BURST32 | DCMD_WIDTH4, }; @@ -288,17 +117,19 @@ static int pxa2xx_ac97_do_suspend(struct snd_card *card, pm_message_t state) snd_ac97_suspend(pxa2xx_ac97_ac97); if (platform_ops && platform_ops->suspend) platform_ops->suspend(platform_ops->priv); - GCR |= GCR_ACLINK_OFF; - clk_disable(ac97_clk); - return 0; + return pxa2xx_ac97_hw_suspend(); } static int pxa2xx_ac97_do_resume(struct snd_card *card) { pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data; + int rc; + + rc = pxa2xx_ac97_hw_resume(); + if (rc) + return rc; - clk_enable(ac97_clk); if (platform_ops && platform_ops->resume) platform_ops->resume(platform_ops->priv); snd_ac97_resume(pxa2xx_ac97_ac97); @@ -354,40 +185,17 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) if (ret) goto err; - ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); - if (ret < 0) - goto err; - - pxa_gpio_mode(GPIO31_SYNC_AC97_MD); - pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); - pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); - pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); -#ifdef CONFIG_PXA27x - /* Use GPIO 113 as AC97 Reset on Bulverde */ - pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); - ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); - if (IS_ERR(ac97conf_clk)) { - ret = PTR_ERR(ac97conf_clk); - ac97conf_clk = NULL; - goto err; - } -#endif - - ac97_clk = clk_get(&dev->dev, "AC97CLK"); - if (IS_ERR(ac97_clk)) { - ret = PTR_ERR(ac97_clk); - ac97_clk = NULL; + ret = pxa2xx_ac97_hw_probe(dev); + if (ret) goto err; - } - clk_enable(ac97_clk); ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus); if (ret) - goto err; + goto err_remove; memset(&ac97_template, 0, sizeof(ac97_template)); ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97); if (ret) - goto err; + goto err_remove; snprintf(card->shortname, sizeof(card->shortname), "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97)); @@ -401,22 +209,11 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) return 0; } - err: +err_remove: + pxa2xx_ac97_hw_remove(dev); +err: if (card) snd_card_free(card); - if (ac97_clk) { - GCR |= GCR_ACLINK_OFF; - free_irq(IRQ_AC97, NULL); - clk_disable(ac97_clk); - clk_put(ac97_clk); - ac97_clk = NULL; - } -#ifdef CONFIG_PXA27x - if (ac97conf_clk) { - clk_put(ac97conf_clk); - ac97conf_clk = NULL; - } -#endif return ret; } @@ -427,15 +224,7 @@ static int __devexit pxa2xx_ac97_remove(struct platform_device *dev) if (card) { snd_card_free(card); platform_set_drvdata(dev, NULL); - GCR |= GCR_ACLINK_OFF; - free_irq(IRQ_AC97, NULL); - clk_disable(ac97_clk); - clk_put(ac97_clk); - ac97_clk = NULL; -#ifdef CONFIG_PXA27x - clk_put(ac97conf_clk); - ac97conf_clk = NULL; -#endif + pxa2xx_ac97_hw_remove(dev); } return 0; diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c new file mode 100644 index 00000000000..1c93eb77cb9 --- /dev/null +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -0,0 +1,278 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/dma-mapping.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/pxa2xx-lib.h> + +#include <asm/dma.h> +#include <mach/pxa-regs.h> + +#include "pxa2xx-pcm.h" + +static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192 - 32, + .periods_min = 1, + .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), + .buffer_bytes_max = 128 * 1024, + .fifo_size = 32, +}; + +int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *rtd = runtime->private_data; + size_t totsize = params_buffer_bytes(params); + size_t period = params_period_bytes(params); + pxa_dma_desc *dma_desc; + dma_addr_t dma_buff_phys, next_desc_phys; + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = totsize; + + dma_desc = rtd->dma_desc_array; + next_desc_phys = rtd->dma_desc_array_phys; + dma_buff_phys = runtime->dma_addr; + do { + next_desc_phys += sizeof(pxa_dma_desc); + dma_desc->ddadr = next_desc_phys; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dma_desc->dsadr = dma_buff_phys; + dma_desc->dtadr = rtd->params->dev_addr; + } else { + dma_desc->dsadr = rtd->params->dev_addr; + dma_desc->dtadr = dma_buff_phys; + } + if (period > totsize) + period = totsize; + dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN; + dma_desc++; + dma_buff_phys += period; + } while (totsize -= period); + dma_desc[-1].ddadr = rtd->dma_desc_array_phys; + + return 0; +} +EXPORT_SYMBOL(__pxa2xx_pcm_hw_params); + +int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; + + if (rtd && rtd->params) + *rtd->params->drcmr = 0; + + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} +EXPORT_SYMBOL(__pxa2xx_pcm_hw_free); + +int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; + DCSR(prtd->dma_ch) = DCSR_RUN; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + DCSR(prtd->dma_ch) &= ~DCSR_RUN; + break; + + case SNDRV_PCM_TRIGGER_RESUME: + DCSR(prtd->dma_ch) |= DCSR_RUN; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; + DCSR(prtd->dma_ch) |= DCSR_RUN; + break; + + default: + ret = -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL(pxa2xx_pcm_trigger); + +snd_pcm_uframes_t +pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *prtd = runtime->private_data; + + dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); + snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); + + if (x == runtime->buffer_size) + x = 0; + return x; +} +EXPORT_SYMBOL(pxa2xx_pcm_pointer); + +int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + + DCSR(prtd->dma_ch) &= ~DCSR_RUN; + DCSR(prtd->dma_ch) = 0; + DCMD(prtd->dma_ch) = 0; + *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; + + return 0; +} +EXPORT_SYMBOL(__pxa2xx_pcm_prepare); + +void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; + int dcsr; + + dcsr = DCSR(dma_ch); + DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; + + if (dcsr & DCSR_ENDINTR) { + snd_pcm_period_elapsed(substream); + } else { + printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", + rtd->params->name, dma_ch, dcsr); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } +} +EXPORT_SYMBOL(pxa2xx_pcm_dma_irq); + +int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *rtd; + int ret; + + runtime->hw = pxa2xx_pcm_hardware; + + /* + * For mysterious reasons (and despite what the manual says) + * playback samples are lost if the DMA count is not a multiple + * of the DMA burst size. Let's add a rule to enforce that. + */ + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); + if (ret) + goto out; + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); + if (ret) + goto out; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + ret = -ENOMEM; + rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); + if (!rtd) + goto out; + rtd->dma_desc_array = + dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, + &rtd->dma_desc_array_phys, GFP_KERNEL); + if (!rtd->dma_desc_array) + goto err1; + + runtime->private_data = rtd; + return 0; + + err1: + kfree(rtd); + out: + return ret; +} +EXPORT_SYMBOL(__pxa2xx_pcm_open); + +int __pxa2xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *rtd = runtime->private_data; + + dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, + rtd->dma_desc_array, rtd->dma_desc_array_phys); + kfree(rtd); + return 0; +} +EXPORT_SYMBOL(__pxa2xx_pcm_close); + +int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} +EXPORT_SYMBOL(pxa2xx_pcm_mmap); + +int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + return 0; +} +EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer); + +void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + buf = &substream->dma_buffer; + if (!buf->area) + continue; + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} +EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers); + +MODULE_AUTHOR("Nicolas Pitre"); +MODULE_DESCRIPTION("Intel PXA2xx sound library"); +MODULE_LICENSE("GPL"); diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c index 381094aab23..535704f7749 100644 --- a/sound/arm/pxa2xx-pcm.c +++ b/sound/arm/pxa2xx-pcm.c @@ -10,183 +10,20 @@ * published by the Free Software Foundation. */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> - #include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> - -#include <asm/dma.h> -#include <mach/hardware.h> -#include <mach/pxa-regs.h> +#include <sound/pxa2xx-lib.h> #include "pxa2xx-pcm.h" - -static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .period_bytes_min = 32, - .period_bytes_max = 8192 - 32, - .periods_min = 1, - .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), - .buffer_bytes_max = 128 * 1024, - .fifo_size = 32, -}; - -struct pxa2xx_runtime_data { - int dma_ch; - struct pxa2xx_pcm_dma_params *params; - pxa_dma_desc *dma_desc_array; - dma_addr_t dma_desc_array_phys; -}; - -static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *rtd = runtime->private_data; - size_t totsize = params_buffer_bytes(params); - size_t period = params_period_bytes(params); - pxa_dma_desc *dma_desc; - dma_addr_t dma_buff_phys, next_desc_phys; - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = totsize; - - dma_desc = rtd->dma_desc_array; - next_desc_phys = rtd->dma_desc_array_phys; - dma_buff_phys = runtime->dma_addr; - do { - next_desc_phys += sizeof(pxa_dma_desc); - dma_desc->ddadr = next_desc_phys; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dma_desc->dsadr = dma_buff_phys; - dma_desc->dtadr = rtd->params->dev_addr; - } else { - dma_desc->dsadr = rtd->params->dev_addr; - dma_desc->dtadr = dma_buff_phys; - } - if (period > totsize) - period = totsize; - dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN; - dma_desc++; - dma_buff_phys += period; - } while (totsize -= period); - dma_desc[-1].ddadr = rtd->dma_desc_array_phys; - - return 0; -} - -static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; - - *rtd->params->drcmr = 0; - snd_pcm_set_runtime_buffer(substream, NULL); - return 0; -} - static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) { struct pxa2xx_pcm_client *client = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *rtd = runtime->private_data; - DCSR(rtd->dma_ch) &= ~DCSR_RUN; - DCSR(rtd->dma_ch) = 0; - DCMD(rtd->dma_ch) = 0; - *rtd->params->drcmr = rtd->dma_ch | DRCMR_MAPVLD; + __pxa2xx_pcm_prepare(substream); return client->prepare(substream); } -static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - DDADR(rtd->dma_ch) = rtd->dma_desc_array_phys; - DCSR(rtd->dma_ch) = DCSR_RUN; - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - DCSR(rtd->dma_ch) &= ~DCSR_RUN; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - DCSR(rtd->dma_ch) |= DCSR_RUN; - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) -{ - struct snd_pcm_substream *substream = dev_id; - struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; - int dcsr; - - dcsr = DCSR(dma_ch); - DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; - - if (dcsr & DCSR_ENDINTR) { - snd_pcm_period_elapsed(substream); - } else { - printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", - rtd->params->name, dma_ch, dcsr ); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - } -} - -static snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *rtd = runtime->private_data; - dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch); - snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); - if (x == runtime->buffer_size) - x = 0; - return x; -} - -static int -pxa2xx_pcm_hw_rule_mult32(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) -{ - struct snd_interval *i = hw_param_interval(params, rule->var); - int changed = 0; - - if (i->min & 31) { - i->min = (i->min & ~31) + 32; - i->openmin = 0; - changed = 1; - } - - if (i->max & 31) { - i->max &= ~31; - i->openmax = 0; - changed = 1; - } - - return changed; -} - static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) { struct pxa2xx_pcm_client *client = substream->private_data; @@ -194,33 +31,11 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) struct pxa2xx_runtime_data *rtd; int ret; - runtime->hw = pxa2xx_pcm_hardware; - - /* - * For mysterious reasons (and despite what the manual says) - * playback samples are lost if the DMA count is not a multiple - * of the DMA burst size. Let's add a rule to enforce that. - */ - ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - pxa2xx_pcm_hw_rule_mult32, NULL, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1); - if (ret) - goto out; - ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - pxa2xx_pcm_hw_rule_mult32, NULL, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1); + ret = __pxa2xx_pcm_open(substream); if (ret) goto out; - ret = -ENOMEM; - rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); - if (!rtd) - goto out; - rtd->dma_desc_array = - dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, - &rtd->dma_desc_array_phys, GFP_KERNEL); - if (!rtd->dma_desc_array) - goto err1; + rtd = runtime->private_data; rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? client->playback_params : client->capture_params; @@ -230,17 +45,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) goto err2; rtd->dma_ch = ret; - runtime->private_data = rtd; ret = client->startup(substream); if (!ret) goto out; pxa_free_dma(rtd->dma_ch); err2: - dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, - rtd->dma_desc_array, rtd->dma_desc_array_phys); - err1: - kfree(rtd); + __pxa2xx_pcm_close(substream); out: return ret; } @@ -252,69 +63,22 @@ static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) pxa_free_dma(rtd->dma_ch); client->shutdown(substream); - dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, - rtd->dma_desc_array, rtd->dma_desc_array_phys); - kfree(rtd); - return 0; -} -static int -pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); + return __pxa2xx_pcm_close(substream); } static struct snd_pcm_ops pxa2xx_pcm_ops = { .open = pxa2xx_pcm_open, .close = pxa2xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = pxa2xx_pcm_hw_params, - .hw_free = pxa2xx_pcm_hw_free, + .hw_params = __pxa2xx_pcm_hw_params, + .hw_free = __pxa2xx_pcm_hw_free, .prepare = pxa2xx_pcm_prepare, .trigger = pxa2xx_pcm_trigger, .pointer = pxa2xx_pcm_pointer, .mmap = pxa2xx_pcm_mmap, }; -static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - if (!buf->area) - return -ENOMEM; - buf->bytes = size; - return 0; -} - -static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - buf = &substream->dma_buffer; - if (!buf->area) - continue; - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - static u64 pxa2xx_pcm_dmamask = 0xffffffff; int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client, diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h index b79f1e80378..5c4a4d38a08 100644 --- a/sound/arm/pxa2xx-pcm.h +++ b/sound/arm/pxa2xx-pcm.h @@ -9,14 +9,15 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <asm/dma.h> -struct pxa2xx_pcm_dma_params { - char *name; /* stream identifier */ - u32 dcmd; /* DMA descriptor dcmd field */ - volatile u32 *drcmr; /* the DMA request channel to use */ - u32 dev_addr; /* device physical address for DMA */ +struct pxa2xx_runtime_data { + int dma_ch; + struct pxa2xx_pcm_dma_params *params; + pxa_dma_desc *dma_desc_array; + dma_addr_t dma_desc_array_phys; }; - + struct pxa2xx_pcm_client { struct pxa2xx_pcm_dma_params *playback_params; struct pxa2xx_pcm_dma_params *capture_params; diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index b9c51bf8cd7..1dcd51d81d1 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c @@ -442,7 +442,8 @@ static void audio_process_dma(struct audio_stream *s) /* we are requested to process synchronization DMA transfer */ if (s->tx_spin) { - snd_assert(s->stream_id == SNDRV_PCM_STREAM_PLAYBACK, return); + if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK)) + return; /* fill the xmit dma buffers and return */ #ifdef HH_VERSION sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE); @@ -472,7 +473,7 @@ static void audio_process_dma(struct audio_stream *s) continue; /* special case */ } else { offset = dma_size * s->period; - snd_assert(dma_size <= DMA_BUF_SIZE, ); + snd_BUG_ON(dma_size > DMA_BUF_SIZE); } #ifdef HH_VERSION ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size); @@ -879,7 +880,7 @@ void snd_sa11xx_uda1341_free(struct snd_card *card) audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]); } -static int __init sa11xx_uda1341_probe(struct platform_device *devptr) +static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr) { int err; struct snd_card *card; |