diff options
-rw-r--r-- | arch/powerpc/include/asm/mpc52xx.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/mpc52xx_psc.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_common.c | 106 | ||||
-rw-r--r-- | sound/soc/fsl/mpc5200_psc_ac97.c | 22 |
5 files changed, 128 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h index b664ce79a172..1f41382eda38 100644 --- a/arch/powerpc/include/asm/mpc52xx.h +++ b/arch/powerpc/include/asm/mpc52xx.h @@ -271,6 +271,7 @@ struct mpc52xx_intr { /* mpc52xx_common.c */ extern void mpc5200_setup_xlb_arbiter(void); extern void mpc52xx_declare_of_platform_devices(void); +extern int mpc5200_psc_ac97_gpio_reset(int psc_number); extern void mpc52xx_map_common_devices(void); extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv); extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node); diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h index ecc4fc69ac13..2966df604221 100644 --- a/arch/powerpc/include/asm/mpc52xx_psc.h +++ b/arch/powerpc/include/asm/mpc52xx_psc.h @@ -131,6 +131,7 @@ #define MPC52xx_PSC_SICR_SIM_FIR (0x6 << 24) #define MPC52xx_PSC_SICR_SIM_CODEC_24 (0x7 << 24) #define MPC52xx_PSC_SICR_SIM_CODEC_32 (0xf << 24) +#define MPC52xx_PSC_SICR_ACRB (0x8 << 24) #define MPC52xx_PSC_SICR_AWR (1 << 30) #define MPC52xx_PSC_SICR_GENCLK (1 << 23) #define MPC52xx_PSC_SICR_I2S (1 << 22) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 15ade0d7bbb2..9d4882a46647 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -96,7 +96,9 @@ struct screen_info screen_info = { /* Variables required to store legacy IO irq routing */ int of_i8042_kbd_irq; +EXPORT_SYMBOL_GPL(of_i8042_kbd_irq); int of_i8042_aux_irq; +EXPORT_SYMBOL_GPL(of_i8042_aux_irq); #ifdef __DO_IRQ_CANON /* XXX should go elsewhere eventually */ diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index a46bad0c2339..6e905314ad5d 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -12,9 +12,11 @@ #undef DEBUG +#include <linux/gpio.h> #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/of_platform.h> +#include <linux/of_gpio.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/mpc52xx.h> @@ -82,6 +84,14 @@ mpc5200_setup_xlb_arbiter(void) iounmap(xlb); } +/* + * This variable is mapped in mpc52xx_map_common_devices and + * used in mpc5200_psc_ac97_gpio_reset(). + */ +static DEFINE_SPINLOCK(gpio_lock); +struct mpc52xx_gpio __iomem *simple_gpio; +struct mpc52xx_gpio_wkup __iomem *wkup_gpio; + /** * mpc52xx_declare_of_platform_devices: register internal devices and children * of the localplus bus to the of_platform @@ -109,6 +119,15 @@ static struct of_device_id mpc52xx_cdm_ids[] __initdata = { { .compatible = "mpc5200-cdm", }, /* old */ {} }; +static const struct of_device_id mpc52xx_gpio_simple[] = { + { .compatible = "fsl,mpc5200-gpio", }, + {} +}; +static const struct of_device_id mpc52xx_gpio_wkup[] = { + { .compatible = "fsl,mpc5200-gpio-wkup", }, + {} +}; + /** * mpc52xx_map_common_devices: iomap devices required by common code @@ -135,6 +154,16 @@ mpc52xx_map_common_devices(void) np = of_find_matching_node(NULL, mpc52xx_cdm_ids); mpc52xx_cdm = of_iomap(np, 0); of_node_put(np); + + /* simple_gpio registers */ + np = of_find_matching_node(NULL, mpc52xx_gpio_simple); + simple_gpio = of_iomap(np, 0); + of_node_put(np); + + /* wkup_gpio registers */ + np = of_find_matching_node(NULL, mpc52xx_gpio_wkup); + wkup_gpio = of_iomap(np, 0); + of_node_put(np); } /** @@ -233,3 +262,80 @@ mpc52xx_restart(char *cmd) while (1); } + +#define PSC1_RESET 0x1 +#define PSC1_SYNC 0x4 +#define PSC1_SDATA_OUT 0x1 +#define PSC2_RESET 0x2 +#define PSC2_SYNC (0x4<<4) +#define PSC2_SDATA_OUT (0x1<<4) +#define MPC52xx_GPIO_PSC1_MASK 0x7 +#define MPC52xx_GPIO_PSC2_MASK (0x7<<4) + +/** + * mpc5200_psc_ac97_gpio_reset: Use gpio pins to reset the ac97 bus + * + * @psc: psc number to reset (only psc 1 and 2 support ac97) + */ +int mpc5200_psc_ac97_gpio_reset(int psc_number) +{ + unsigned long flags; + u32 gpio; + u32 mux; + int out; + int reset; + int sync; + + if ((!simple_gpio) || (!wkup_gpio)) + return -ENODEV; + + switch (psc_number) { + case 0: + reset = PSC1_RESET; /* AC97_1_RES */ + sync = PSC1_SYNC; /* AC97_1_SYNC */ + out = PSC1_SDATA_OUT; /* AC97_1_SDATA_OUT */ + gpio = MPC52xx_GPIO_PSC1_MASK; + break; + case 1: + reset = PSC2_RESET; /* AC97_2_RES */ + sync = PSC2_SYNC; /* AC97_2_SYNC */ + out = PSC2_SDATA_OUT; /* AC97_2_SDATA_OUT */ + gpio = MPC52xx_GPIO_PSC2_MASK; + break; + default: + pr_err(__FILE__ ": Unable to determine PSC, no ac97 " + "cold-reset will be performed\n"); + return -ENODEV; + } + + spin_lock_irqsave(&gpio_lock, flags); + + /* Reconfiure pin-muxing to gpio */ + mux = in_be32(&simple_gpio->port_config); + out_be32(&simple_gpio->port_config, mux & (~gpio)); + + /* enable gpio pins for output */ + setbits8(&wkup_gpio->wkup_gpioe, reset); + setbits32(&simple_gpio->simple_gpioe, sync | out); + + setbits8(&wkup_gpio->wkup_ddr, reset); + setbits32(&simple_gpio->simple_ddr, sync | out); + + /* Assert cold reset */ + clrbits32(&simple_gpio->simple_dvo, sync | out); + clrbits8(&wkup_gpio->wkup_dvo, reset); + + /* wait at lease 1 us */ + udelay(2); + + /* Deassert reset */ + setbits8(&wkup_gpio->wkup_dvo, reset); + + /* Restore pin-muxing */ + out_be32(&simple_gpio->port_config, mux); + + spin_unlock_irqrestore(&gpio_lock, flags); + + return 0; +} +EXPORT_SYMBOL(mpc5200_psc_ac97_gpio_reset); diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index e2ee220bfb7e..e7f5d50ed084 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -20,6 +20,7 @@ #include <asm/time.h> #include <asm/delay.h> +#include <asm/mpc52xx.h> #include <asm/mpc52xx_psc.h> #include "mpc5200_dma.h" @@ -100,19 +101,32 @@ static void psc_ac97_warm_reset(struct snd_ac97 *ac97) { struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; + mutex_lock(&psc_dma->mutex); + out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); udelay(3); out_be32(®s->sicr, psc_dma->sicr); + + mutex_unlock(&psc_dma->mutex); } static void psc_ac97_cold_reset(struct snd_ac97 *ac97) { struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - /* Do a cold reset */ - out_8(®s->op1, MPC52xx_PSC_OP_RES); - udelay(10); - out_8(®s->op0, MPC52xx_PSC_OP_RES); + mutex_lock(&psc_dma->mutex); + dev_dbg(psc_dma->dev, "cold reset\n"); + + mpc5200_psc_ac97_gpio_reset(psc_dma->id); + + /* Notify the PSC that a reset has occurred */ + out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB); + + /* Re-enable RX and TX */ + out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + + mutex_unlock(&psc_dma->mutex); + msleep(1); psc_ac97_warm_reset(ac97); } |