[alsa-devel] [PATCH 1/4] Separate common pxa2xx-ac97 code
ASoC and non-ASoC drivers for ACLINK on PXA share lot's of common code. Move all common code into separate module snd-pxa2xx-lib.
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com --- include/sound/pxa2xx-lib.h | 20 +++ sound/arm/Kconfig | 6 +- sound/arm/Makefile | 3 + sound/arm/pxa2xx-ac97-lib.c | 323 +++++++++++++++++++++++++++++++++++++++++++ sound/arm/pxa2xx-ac97.c | 247 +++------------------------------ sound/soc/pxa/Kconfig | 2 + sound/soc/pxa/pxa2xx-ac97.c | 272 ++----------------------------------- 7 files changed, 380 insertions(+), 493 deletions(-) create mode 100644 include/sound/pxa2xx-lib.h create mode 100644 sound/arm/pxa2xx-ac97-lib.c
diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h new file mode 100644 index 0000000..d18dd2d --- /dev/null +++ b/include/sound/pxa2xx-lib.h @@ -0,0 +1,20 @@ +#ifndef PXA2XX_LIB_H +#define PXA2XX_LIB_H + +#include <linux/platform_device.h> +#include <sound/ac97_codec.h> + +extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg); +extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val); + +extern bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97); +extern bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97); +extern void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97); + +extern int pxa2xx_ac97_hw_suspend(void); +extern int pxa2xx_ac97_hw_resume(void); + +extern int pxa2xx_ac97_hw_probe(struct platform_device *dev); +extern void pxa2xx_ac97_hw_remove(struct platform_device *dev); + +#endif diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 351e19e..3fd2642 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -32,11 +32,15 @@ config SND_PXA2XX_PCM tristate select SND_PCM
+config SND_PXA2XX_LIB + tristate + select SND_AC97_CODEC + 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 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 4ef6dd0..bb2ed88 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -11,5 +11,8 @@ 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-objs := 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/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c new file mode 100644 index 0000000..61cf41f --- /dev/null +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -0,0 +1,323 @@ +/* + * 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; +#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). + */ + +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 defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) + reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; +#else + if (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; +#endif + 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 defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) + reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; +#else + if (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; +#endif + 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); + +bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) +{ +#ifdef CONFIG_PXA3xx + int timeout = 100; +#endif + 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) + /* 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); + + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); + +bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) +{ +#ifdef CONFIG_PXA3xx + int timeout = 1000; + + /* 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) + /* 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); + + 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); + +#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; + } + + 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) +{ + 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); +#endif + 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; + + 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_irq; + } +#endif + + 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; +#ifdef CONFIG_PXA27x + if (ac97conf_clk) { + clk_put(ac97conf_clk); + ac97conf_clk = NULL; + } +#endif + 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); +#ifdef CONFIG_PXA27x + clk_put(ac97conf_clk); + ac97conf_clk = NULL; +#endif + 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 199cca3..cba71d8 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 = { @@ -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/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 9212c37..d1ccbdc 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -13,6 +13,8 @@ config SND_PXA2XX_AC97 config SND_PXA2XX_SOC_AC97 tristate select AC97_BUS + select SND_ARM + select SND_PXA2XX_LIB select SND_SOC_AC97_BUS
config SND_PXA2XX_SOC_I2S diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index d94a495..a80ae07 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -13,225 +13,30 @@ #include <linux/init.h> #include <linux/module.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/soc.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" #include "pxa2xx-ac97.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/modem space */ -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) - reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; -#else - if (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; -#endif - reg_addr += (reg >> 1); - -#ifndef CONFIG_PXA27x - if (reg == AC97_GPIO_STATUS) { - /* read from controller cache */ - val = *reg_addr; - goto out; - } -#endif - - /* start read access across the ac97 link */ - GSR = GSR_CDONE | GSR_SDONE; - gsr_bits = 0; - val = *reg_addr; - - wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); - if (!((GSR | gsr_bits) & GSR_SDONE)) { - printk(KERN_ERR "%s: read error (ac97_reg=%x 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/modem space */ -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) - reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; -#else - if (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; -#endif - reg_addr += (reg >> 1); - - GSR = GSR_CDONE | GSR_SDONE; - gsr_bits = 0; - *reg_addr = val; - wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1); - if (!((GSR | gsr_bits) & GSR_CDONE)) - printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n", - __func__, reg, GSR | gsr_bits); - - mutex_unlock(&car_mutex); -} - static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) { -#ifdef CONFIG_PXA3xx - int timeout = 100; -#endif - 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) - /* 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); + pxa2xx_ac97_try_warm_reset(ac97);
- GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); - GCR |= GCR_SDONE_IE|GCR_CDONE_IE; + pxa2xx_ac97_finish_reset(ac97); }
static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) { -#ifdef CONFIG_PXA3xx - int timeout = 1000; - - /* Hold CLKBPB for 100us */ - GCR = 0; - GCR = GCR_CLKBPB; - udelay(100); - GCR = 0; -#endif + pxa2xx_ac97_try_cold_reset(ac97);
- 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) - /* 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); - - 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; - } - - return IRQ_NONE; + pxa2xx_ac97_finish_reset(ac97); }
struct snd_ac97_bus_ops soc_ac97_ops = { @@ -285,24 +90,13 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { static int pxa2xx_ac97_suspend(struct platform_device *pdev, struct snd_soc_dai *dai) { - GCR |= GCR_ACLINK_OFF; - clk_disable(ac97_clk); - return 0; + return pxa2xx_ac97_hw_suspend(); }
static int pxa2xx_ac97_resume(struct platform_device *pdev, struct snd_soc_dai *dai) { - 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); -#endif - clk_enable(ac97_clk); - return 0; + return pxa2xx_ac97_hw_resume(); }
#else @@ -313,61 +107,13 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev, static int pxa2xx_ac97_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - int ret; - - ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "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(&pdev->dev, "AC97CONFCLK"); - if (IS_ERR(ac97conf_clk)) { - ret = PTR_ERR(ac97conf_clk); - ac97conf_clk = NULL; - goto err_irq; - } -#endif - ac97_clk = clk_get(&pdev->dev, "AC97CLK"); - if (IS_ERR(ac97_clk)) { - ret = PTR_ERR(ac97_clk); - ac97_clk = NULL; - goto err_irq; - } - clk_enable(ac97_clk); - return 0; - - err_irq: - GCR |= GCR_ACLINK_OFF; -#ifdef CONFIG_PXA27x - if (ac97conf_clk) { - clk_put(ac97conf_clk); - ac97conf_clk = NULL; - } -#endif - free_irq(IRQ_AC97, NULL); - err: - return ret; + return pxa2xx_ac97_hw_probe(pdev); }
static void pxa2xx_ac97_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { - GCR |= GCR_ACLINK_OFF; - free_irq(IRQ_AC97, NULL); -#ifdef CONFIG_PXA27x - clk_put(ac97conf_clk); - ac97conf_clk = NULL; -#endif - clk_disable(ac97_clk); - clk_put(ac97_clk); - ac97_clk = NULL; + pxa2xx_ac97_hw_remove(pdev); }
static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
Support building of pxa2xx-ac97-lib for several CPUs by making code run-time selected, not only compile-time.
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com --- sound/arm/pxa2xx-ac97-lib.c | 215 +++++++++++++++++++++++++++---------------- 1 files changed, 137 insertions(+), 78 deletions(-)
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 61cf41f..61aee0b 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -29,9 +29,7 @@ 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: @@ -51,14 +49,10 @@ unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) mutex_lock(&car_mutex);
/* set up primary or secondary codec space */ -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) - reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; -#else - if (reg == AC97_GPIO_STATUS) + 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; -#endif reg_addr += (reg >> 1);
/* start read access across the ac97 link */ @@ -94,14 +88,10 @@ void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short mutex_lock(&car_mutex);
/* set up primary or secondary codec space */ -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) - reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; -#else - if (reg == AC97_GPIO_STATUS) + 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; -#endif reg_addr += (reg >> 1);
GSR = GSR_CDONE | GSR_SDONE; @@ -116,14 +106,33 @@ void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short } EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
-bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) +#ifdef CONFIG_PXA25x +static inline void pxa_ac97_warm_pxa25x(void) { -#ifdef CONFIG_PXA3xx - int timeout = 100; -#endif 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); @@ -131,30 +140,39 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) GCR |= GCR_WARM_RST; pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); udelay(500); -#elif defined(CONFIG_PXA3xx) - /* 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); +} + +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
- if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { - printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", - __func__, gsr_bits); +#ifdef CONFIG_PXA3xx +static inline void pxa_ac97_warm_pxa3xx(void) +{ + int timeout = 100;
- return false; - } + gsr_bits = 0;
- return true; + /* Can't use interrupts */ + GCR |= GCR_WARM_RST; + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); } -EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
-bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) +static inline void pxa_ac97_cold_pxa3xx(void) { -#ifdef CONFIG_PXA3xx int timeout = 1000;
/* Hold CLKBPB for 100us */ @@ -162,31 +180,69 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) 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) + /* 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 + +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", @@ -217,14 +273,14 @@ static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) 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 + if (cpu_is_pxa27x()) { + MISR = MISR_EOC; + PISR = PISR_EOC; + MCSR = MCSR_EOC; + }
return IRQ_HANDLED; } @@ -243,14 +299,16 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);
int pxa2xx_ac97_hw_resume(void) { - 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); -#endif + 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; } @@ -265,20 +323,23 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) 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_irq; + 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; + } } -#endif
ac97_clk = clk_get(&dev->dev, "AC97CLK"); if (IS_ERR(ac97_clk)) { @@ -291,12 +352,10 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
err_irq: GCR |= GCR_ACLINK_OFF; -#ifdef CONFIG_PXA27x if (ac97conf_clk) { clk_put(ac97conf_clk); ac97conf_clk = NULL; } -#endif free_irq(IRQ_AC97, NULL); err: return ret; @@ -307,10 +366,10 @@ void pxa2xx_ac97_hw_remove(struct platform_device *dev) { GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); -#ifdef CONFIG_PXA27x - clk_put(ac97conf_clk); - ac97conf_clk = NULL; -#endif + if (ac97conf_clk) { + clk_put(ac97conf_clk); + ac97conf_clk = NULL; + } clk_disable(ac97_clk); clk_put(ac97_clk); ac97_clk = NULL;
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com --- sound/soc/pxa/pxa2xx-i2s.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index c796b18..21ca3fe 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -65,11 +65,6 @@ static struct pxa2xx_gpio gpio_bus[] = { .frm = GPIO31_SYNC_I2S_MD, }, { /* I2S SoC Master */ -#ifdef CONFIG_PXA27x - .sys = GPIO113_I2S_SYSCLK_MD, -#else - .sys = GPIO32_SYSCLK_I2S_MD, -#endif .rx = GPIO29_SDATA_IN_I2S_MD, .tx = GPIO30_SDATA_OUT_I2S_MD, .clk = GPIO28_BITCLK_OUT_I2S_MD, @@ -343,6 +338,11 @@ static struct platform_driver pxa2xx_i2s_driver = {
static int __init pxa2xx_i2s_init(void) { + if (cpu_is_pxa27x()) + gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD; + else + gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD; + clk_i2s = ERR_PTR(-ENOENT); return platform_driver_register(&pxa2xx_i2s_driver); }
ASoC and non-ASoC drivers for PCM DMA on PXA share lot's of common code. Move it to pxa2xx-lib.
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com --- include/sound/pxa2xx-lib.h | 25 ++ sound/arm/Kconfig | 7 +- sound/arm/Makefile | 3 +- .../{soc/pxa/pxa2xx-pcm.c => arm/pxa2xx-pcm-lib.c} | 247 ++++++------------- sound/arm/pxa2xx-pcm.c | 252 +------------------ sound/arm/pxa2xx-pcm.h | 13 +- sound/soc/pxa/Kconfig | 3 +- sound/soc/pxa/pxa2xx-i2s.c | 10 + sound/soc/pxa/pxa2xx-pcm.c | 261 +------------------- sound/soc/pxa/pxa2xx-pcm.h | 15 -- 10 files changed, 143 insertions(+), 693 deletions(-) copy sound/{soc/pxa/pxa2xx-pcm.c => arm/pxa2xx-pcm-lib.c} (52%)
diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h index d18dd2d..2fd3d25 100644 --- a/include/sound/pxa2xx-lib.h +++ b/include/sound/pxa2xx-lib.h @@ -4,6 +4,31 @@ #include <linux/platform_device.h> #include <sound/ac97_codec.h>
+/* PCM */ + +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 */ +}; + +extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream); +extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd); +extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream); +extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream); +extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id); +extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream); +extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream); +extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); +extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream); +extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm); + +/* AC97 */ + extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg); extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 3fd2642..234708e 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -34,13 +34,16 @@ config SND_PXA2XX_PCM
config SND_PXA2XX_LIB tristate - select SND_AC97_CODEC + 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_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 bb2ed88..2054de1 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -12,7 +12,8 @@ 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-objs := pxa2xx-ac97-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/soc/pxa/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm-lib.c similarity index 52% copy from sound/soc/pxa/pxa2xx-pcm.c copy to sound/arm/pxa2xx-pcm-lib.c index 771c592..fe20453 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -1,30 +1,19 @@ /* - * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 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/module.h> -#include <linux/init.h> -#include <linux/platform_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 <sound/soc.h> +#include <sound/pxa2xx-lib.h>
#include <asm/dma.h> -#include <mach/hardware.h> #include <mach/pxa-regs.h> -#include <mach/audio.h>
#include "pxa2xx-pcm.h"
@@ -45,123 +34,57 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { .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 void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) -{ - struct snd_pcm_substream *substream = dev_id; - struct pxa2xx_runtime_data *prtd = 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", - prtd->params->name, dma_ch, dcsr); - } -} - -static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +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 *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; + 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; - int ret; - - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!dma) - return 0; - - /* this may get called several times by oss emulation - * with different params */ - if (prtd->params == NULL) { - prtd->params = dma; - ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, - pxa2xx_pcm_dma_irq, substream); - if (ret < 0) - return ret; - prtd->dma_ch = ret; - } else if (prtd->params != dma) { - pxa_free_dma(prtd->dma_ch); - prtd->params = dma; - ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, - pxa2xx_pcm_dma_irq, substream); - if (ret < 0) - return ret; - prtd->dma_ch = ret; - }
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totsize;
- dma_desc = prtd->dma_desc_array; - next_desc_phys = prtd->dma_desc_array_phys; + 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 = prtd->params->dev_addr; + dma_desc->dtadr = rtd->params->dev_addr; } else { - dma_desc->dsadr = prtd->params->dev_addr; + dma_desc->dsadr = rtd->params->dev_addr; dma_desc->dtadr = dma_buff_phys; } if (period > totsize) period = totsize; - dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; + dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN; dma_desc++; dma_buff_phys += period; } while (totsize -= period); - dma_desc[-1].ddadr = prtd->dma_desc_array_phys; + dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
return 0; } +EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
-static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) +int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) { - struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; - - if (prtd && prtd->params) - *prtd->params->drcmr = 0; - - if (prtd->dma_ch) { - snd_pcm_set_runtime_buffer(substream, NULL); - pxa_free_dma(prtd->dma_ch); - prtd->dma_ch = 0; - } - - return 0; -} - -static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + struct pxa2xx_runtime_data *rtd = 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; + if (rtd && rtd->params) + *rtd->params->drcmr = 0;
+ snd_pcm_set_runtime_buffer(substream, NULL); return 0; } +EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
-static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; @@ -192,8 +115,9 @@ static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret; } +EXPORT_SYMBOL(pxa2xx_pcm_trigger);
-static snd_pcm_uframes_t +snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -207,14 +131,47 @@ pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) 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);
-static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) +int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *prtd; + struct pxa2xx_runtime_data *rtd; int ret;
- snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware); + runtime->hw = pxa2xx_pcm_hardware;
/* * For mysterious reasons (and despite what the manual says) @@ -235,41 +192,39 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) goto out;
- prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; + ret = -ENOMEM; + rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); + if (!rtd) goto out; - } - - prtd->dma_desc_array = + rtd->dma_desc_array = dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, - &prtd->dma_desc_array_phys, GFP_KERNEL); - if (!prtd->dma_desc_array) { - ret = -ENOMEM; + &rtd->dma_desc_array_phys, GFP_KERNEL); + if (!rtd->dma_desc_array) goto err1; - }
- runtime->private_data = prtd; + runtime->private_data = rtd; return 0;
err1: - kfree(prtd); + kfree(rtd); out: return ret; } +EXPORT_SYMBOL(__pxa2xx_pcm_open);
-static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) +int __pxa2xx_pcm_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *prtd = runtime->private_data; + struct pxa2xx_runtime_data *rtd = runtime->private_data;
dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, - prtd->dma_desc_array, prtd->dma_desc_array_phys); - kfree(prtd); + rtd->dma_desc_array, rtd->dma_desc_array_phys); + kfree(rtd); return 0; } +EXPORT_SYMBOL(__pxa2xx_pcm_close);
-static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, +int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -278,20 +233,9 @@ static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, runtime->dma_addr, runtime->dma_bytes); } +EXPORT_SYMBOL(pxa2xx_pcm_mmap);
-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, - .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) +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; @@ -306,8 +250,9 @@ static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->bytes = size; return 0; } +EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
-static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) +void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -317,54 +262,16 @@ static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) 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 = DMA_32BIT_MASK; - -static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &pxa2xx_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_32BIT_MASK; - - if (dai->playback.channels_min) { - ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -struct snd_soc_platform pxa2xx_soc_platform = { - .name = "pxa2xx-audio", - .pcm_ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, -}; -EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); +EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
MODULE_AUTHOR("Nicolas Pitre"); -MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); +MODULE_DESCRIPTION("Intel PXA2xx sound library"); MODULE_LICENSE("GPL"); diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c index 381094a..535704f 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 b79f1e8..5c4a4d3 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/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index d1ccbdc..f8c1cdd 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -1,6 +1,7 @@ config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" depends on ARCH_PXA + select SND_PXA2XX_LIB help Say Y or M if you want to add support for codecs attached to the PXA2xx AC97, I2S or SSP interface. You will also need @@ -14,7 +15,7 @@ config SND_PXA2XX_SOC_AC97 tristate select AC97_BUS select SND_ARM - select SND_PXA2XX_LIB + select SND_PXA2XX_LIB_AC97 select SND_SOC_AC97_BUS
config SND_PXA2XX_SOC_I2S diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 21ca3fe..39d1921 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -21,6 +21,7 @@ #include <sound/pcm.h> #include <sound/initval.h> #include <sound/soc.h> +#include <sound/pxa2xx-lib.h>
#include <mach/hardware.h> #include <mach/pxa-regs.h> @@ -30,6 +31,15 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-i2s.h"
+struct pxa2xx_gpio { + u32 sys; + u32 rx; + u32 tx; + u32 clk; + u32 frm; +}; + + struct pxa_i2s_port { u32 sadiv; u32 sacr0; diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 771c592..afcd892 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -10,64 +10,14 @@ * published by the Free Software Foundation. */
-#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_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 <sound/soc.h> - -#include <asm/dma.h> -#include <mach/hardware.h> -#include <mach/pxa-regs.h> -#include <mach/audio.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 | - 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, -}; - -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 void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) -{ - struct snd_pcm_substream *substream = dev_id; - struct pxa2xx_runtime_data *prtd = 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", - prtd->params->name, dma_ch, dcsr); - } -} +#include "../../arm/pxa2xx-pcm.h"
static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -76,10 +26,6 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, struct pxa2xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_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; int ret;
/* return if this is a bufferless transfer e.g. @@ -106,42 +52,16 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, prtd->dma_ch = ret; }
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = totsize; - - dma_desc = prtd->dma_desc_array; - next_desc_phys = prtd->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 = prtd->params->dev_addr; - } else { - dma_desc->dsadr = prtd->params->dev_addr; - dma_desc->dtadr = dma_buff_phys; - } - if (period > totsize) - period = totsize; - dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; - dma_desc++; - dma_buff_phys += period; - } while (totsize -= period); - dma_desc[-1].ddadr = prtd->dma_desc_array_phys; - - return 0; + return __pxa2xx_pcm_hw_params(substream, params); }
static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) { struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
- if (prtd && prtd->params) - *prtd->params->drcmr = 0; + __pxa2xx_pcm_hw_free(substream);
if (prtd->dma_ch) { - snd_pcm_set_runtime_buffer(substream, NULL); pxa_free_dma(prtd->dma_ch); prtd->dma_ch = 0; } @@ -149,185 +69,18 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; }
-static 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; -} - -static 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; -} - -static 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; -} - -static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *prtd; - int ret; - - snd_soc_set_runtime_hwparams(substream, &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; - - prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - - prtd->dma_desc_array = - dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, - &prtd->dma_desc_array_phys, GFP_KERNEL); - if (!prtd->dma_desc_array) { - ret = -ENOMEM; - goto err1; - } - - runtime->private_data = prtd; - return 0; - - err1: - kfree(prtd); - out: - return ret; -} - -static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct pxa2xx_runtime_data *prtd = runtime->private_data; - - dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, - prtd->dma_desc_array, prtd->dma_desc_array_phys); - kfree(prtd); - 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); -} - struct snd_pcm_ops pxa2xx_pcm_ops = { - .open = pxa2xx_pcm_open, - .close = pxa2xx_pcm_close, + .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, - .prepare = pxa2xx_pcm_prepare, + .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 = DMA_32BIT_MASK;
static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h index 54c9c75..60c3b20 100644 --- a/sound/soc/pxa/pxa2xx-pcm.h +++ b/sound/soc/pxa/pxa2xx-pcm.h @@ -13,21 +13,6 @@ #ifndef _PXA2XX_PCM_H #define _PXA2XX_PCM_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_gpio { - u32 sys; - u32 rx; - u32 tx; - u32 clk; - u32 frm; -}; - /* platform data */ extern struct snd_soc_platform pxa2xx_soc_platform;
On Wed, Sep 10, 2008 at 05:01:20AM +0400, Dmitry Baryshkov wrote:
config SND_PXA2XX_LIB tristate
- select SND_AC97_CODEC
- 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_PXA2XX_LIB
- select SND_PXA2XX_LIB_AC97
The select on SND_PXA2XX_LIB needs to stay since SND_PXA2XX_LIB_AC97 only does anything if SND_PXA2XX_LIB is selected. Again, I'll fix this up locally.
On Wed, Sep 10, 2008 at 05:01:18AM +0400, Dmitry Baryshkov wrote:
+#endif +#ifdef CONFIG_PXA3XX
- if (cpu_is_pxa3xx())
pxa_ac97_warm_pxa3xx();
- else
+#endif
Typo, should be CONFIG_PXA3xx (and also in cold reset). Again, I've fixed that up locally. However, PXA3xx support seems broken in some other way, it fails during init - I'll debug this and post updated patches.
On Thu, Sep 11, 2008 at 04:04:13PM +0100, Mark Brown wrote:
fixed that up locally. However, PXA3xx support seems broken in some other way, it fails during init - I'll debug this and post updated patches.
This was a false alarm, sorry - the machine I was using for testing required some unmerged MFP configuration for AC97 to work.
On Wed, Sep 10, 2008 at 05:01:17AM +0400, Dmitry Baryshkov wrote:
ASoC and non-ASoC drivers for ACLINK on PXA share lot's of common code. Move all common code into separate module snd-pxa2xx-lib.
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com
These look good from code review but I'd like to do some testing on the systems I have here before acking. Could you confirm which platforms you're able to test on?
On Wed, Sep 10, 2008 at 12:57:20PM +0100, Mark Brown wrote:
On Wed, Sep 10, 2008 at 05:01:17AM +0400, Dmitry Baryshkov wrote:
ASoC and non-ASoC drivers for ACLINK on PXA share lot's of common code. Move all common code into separate module snd-pxa2xx-lib.
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com
These look good from code review but I'd like to do some testing on the systems I have here before acking. Could you confirm which platforms you're able to test on?
Slightly tested on pxa255 (tosa, kernel compiled with support for all pxa models) and pxa27x (spitz under qemu, same kernel).
On Wed, 2008-09-10 at 16:34 +0400, Dmitry Baryshkov wrote:
On Wed, Sep 10, 2008 at 12:57:20PM +0100, Mark Brown wrote:
On Wed, Sep 10, 2008 at 05:01:17AM +0400, Dmitry Baryshkov wrote:
ASoC and non-ASoC drivers for ACLINK on PXA share lot's of common code. Move all common code into separate module snd-pxa2xx-lib.
Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com
These look good from code review but I'd like to do some testing on the systems I have here before acking. Could you confirm which platforms you're able to test on?
Slightly tested on pxa255 (tosa, kernel compiled with support for all pxa models) and pxa27x (spitz under qemu, same kernel).
I'd prefer some real hardware for pxa27x since it has some different AC97 silicon errata. However, since there are no pxa27x volunteers we should upstream and wait for any unlikely pxa27x issues in the 2.6.28-rc series.
Acked-by Liam Girdwood lrg@kernel.org
Liam
On Wed, Sep 10, 2008 at 01:52:41PM +0100, Liam Girdwood wrote:
I'd prefer some real hardware for pxa27x since it has some different AC97 silicon errata. However, since there are no pxa27x volunteers we should upstream and wait for any unlikely pxa27x issues in the 2.6.28-rc series.
I've got a PXA27x sitting here, I'll test then push to Takashi assuming I don't run into any problems.
On Wed, Sep 10, 2008 at 05:01:17AM +0400, Dmitry Baryshkov wrote:
+config SND_PXA2XX_LIB
- tristate
- select SND_AC97_CODEC
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 help
Since select ignores dependency information in the selected thing the select for SND_AC97_CODEC needs to stay in SND_PXA2XX_AC97. I'll fix this up locally.
2008/9/11 Mark Brown broonie@sirena.org.uk:
On Wed, Sep 10, 2008 at 05:01:17AM +0400, Dmitry Baryshkov wrote:
+config SND_PXA2XX_LIB
tristate
select SND_AC97_CODEC
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 help
Since select ignores dependency information in the selected thing the select for SND_AC97_CODEC needs to stay in SND_PXA2XX_AC97. I'll fix this up locally.
Fine with me, thanks!
participants (4)
-
Dmitry
-
Dmitry Baryshkov
-
Liam Girdwood
-
Mark Brown