aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorEric Millbrandt <emillbrandt@dekaresearch.com>2010-08-06 22:49:18 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-08-06 22:49:18 -0400
commitcfa6a88c83f639f17b96a34dc0bf93faf432e73a (patch)
tree4ca244d40929bac84b30f1c684253d9b5eb06630 /arch
parent17879857821adad4e180c5d6457c3b8bbf1d0c0c (diff)
powerpc/5200: add mpc5200_psc_ac97_gpio_reset
Work around a silicon bug in the ac97 reset functionality of the mpc5200(b). The implementation of the ac97 "cold" reset is flawed. If the sync and output lines are high when reset is asserted the attached ac97 device may go into test mode. Avoid this by reconfiguring the psc to gpio mode and generating the reset manually. From MPC5200B User's Manual: "Some AC97 devices goes to a test mode, if the Sync line is high during the Res line is low (reset phase). To avoid this behavior the Sync line must be also forced to zero during the reset phase. To do that, the pin muxing should switch to GPIO mode and the GPIO control register should be used to control the output lines." Signed-off-by: Eric Millbrandt <emillbrandt@dekaresearch.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/mpc52xx.h1
-rw-r--r--arch/powerpc/include/asm/mpc52xx_psc.h1
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c106
3 files changed, 108 insertions, 0 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 {
271/* mpc52xx_common.c */ 271/* mpc52xx_common.c */
272extern void mpc5200_setup_xlb_arbiter(void); 272extern void mpc5200_setup_xlb_arbiter(void);
273extern void mpc52xx_declare_of_platform_devices(void); 273extern void mpc52xx_declare_of_platform_devices(void);
274extern int mpc5200_psc_ac97_gpio_reset(int psc_number);
274extern void mpc52xx_map_common_devices(void); 275extern void mpc52xx_map_common_devices(void);
275extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv); 276extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
276extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node); 277extern 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 @@
131#define MPC52xx_PSC_SICR_SIM_FIR (0x6 << 24) 131#define MPC52xx_PSC_SICR_SIM_FIR (0x6 << 24)
132#define MPC52xx_PSC_SICR_SIM_CODEC_24 (0x7 << 24) 132#define MPC52xx_PSC_SICR_SIM_CODEC_24 (0x7 << 24)
133#define MPC52xx_PSC_SICR_SIM_CODEC_32 (0xf << 24) 133#define MPC52xx_PSC_SICR_SIM_CODEC_32 (0xf << 24)
134#define MPC52xx_PSC_SICR_ACRB (0x8 << 24)
134#define MPC52xx_PSC_SICR_AWR (1 << 30) 135#define MPC52xx_PSC_SICR_AWR (1 << 30)
135#define MPC52xx_PSC_SICR_GENCLK (1 << 23) 136#define MPC52xx_PSC_SICR_GENCLK (1 << 23)
136#define MPC52xx_PSC_SICR_I2S (1 << 22) 137#define MPC52xx_PSC_SICR_I2S (1 << 22)
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 @@
12 12
13#undef DEBUG 13#undef DEBUG
14 14
15#include <linux/gpio.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
16#include <linux/spinlock.h> 17#include <linux/spinlock.h>
17#include <linux/of_platform.h> 18#include <linux/of_platform.h>
19#include <linux/of_gpio.h>
18#include <asm/io.h> 20#include <asm/io.h>
19#include <asm/prom.h> 21#include <asm/prom.h>
20#include <asm/mpc52xx.h> 22#include <asm/mpc52xx.h>
@@ -82,6 +84,14 @@ mpc5200_setup_xlb_arbiter(void)
82 iounmap(xlb); 84 iounmap(xlb);
83} 85}
84 86
87/*
88 * This variable is mapped in mpc52xx_map_common_devices and
89 * used in mpc5200_psc_ac97_gpio_reset().
90 */
91static DEFINE_SPINLOCK(gpio_lock);
92struct mpc52xx_gpio __iomem *simple_gpio;
93struct mpc52xx_gpio_wkup __iomem *wkup_gpio;
94
85/** 95/**
86 * mpc52xx_declare_of_platform_devices: register internal devices and children 96 * mpc52xx_declare_of_platform_devices: register internal devices and children
87 * of the localplus bus to the of_platform 97 * of the localplus bus to the of_platform
@@ -109,6 +119,15 @@ static struct of_device_id mpc52xx_cdm_ids[] __initdata = {
109 { .compatible = "mpc5200-cdm", }, /* old */ 119 { .compatible = "mpc5200-cdm", }, /* old */
110 {} 120 {}
111}; 121};
122static const struct of_device_id mpc52xx_gpio_simple[] = {
123 { .compatible = "fsl,mpc5200-gpio", },
124 {}
125};
126static const struct of_device_id mpc52xx_gpio_wkup[] = {
127 { .compatible = "fsl,mpc5200-gpio-wkup", },
128 {}
129};
130
112 131
113/** 132/**
114 * mpc52xx_map_common_devices: iomap devices required by common code 133 * mpc52xx_map_common_devices: iomap devices required by common code
@@ -135,6 +154,16 @@ mpc52xx_map_common_devices(void)
135 np = of_find_matching_node(NULL, mpc52xx_cdm_ids); 154 np = of_find_matching_node(NULL, mpc52xx_cdm_ids);
136 mpc52xx_cdm = of_iomap(np, 0); 155 mpc52xx_cdm = of_iomap(np, 0);
137 of_node_put(np); 156 of_node_put(np);
157
158 /* simple_gpio registers */
159 np = of_find_matching_node(NULL, mpc52xx_gpio_simple);
160 simple_gpio = of_iomap(np, 0);
161 of_node_put(np);
162
163 /* wkup_gpio registers */
164 np = of_find_matching_node(NULL, mpc52xx_gpio_wkup);
165 wkup_gpio = of_iomap(np, 0);
166 of_node_put(np);
138} 167}
139 168
140/** 169/**
@@ -233,3 +262,80 @@ mpc52xx_restart(char *cmd)
233 262
234 while (1); 263 while (1);
235} 264}
265
266#define PSC1_RESET 0x1
267#define PSC1_SYNC 0x4
268#define PSC1_SDATA_OUT 0x1
269#define PSC2_RESET 0x2
270#define PSC2_SYNC (0x4<<4)
271#define PSC2_SDATA_OUT (0x1<<4)
272#define MPC52xx_GPIO_PSC1_MASK 0x7
273#define MPC52xx_GPIO_PSC2_MASK (0x7<<4)
274
275/**
276 * mpc5200_psc_ac97_gpio_reset: Use gpio pins to reset the ac97 bus
277 *
278 * @psc: psc number to reset (only psc 1 and 2 support ac97)
279 */
280int mpc5200_psc_ac97_gpio_reset(int psc_number)
281{
282 unsigned long flags;
283 u32 gpio;
284 u32 mux;
285 int out;
286 int reset;
287 int sync;
288
289 if ((!simple_gpio) || (!wkup_gpio))
290 return -ENODEV;
291
292 switch (psc_number) {
293 case 0:
294 reset = PSC1_RESET; /* AC97_1_RES */
295 sync = PSC1_SYNC; /* AC97_1_SYNC */
296 out = PSC1_SDATA_OUT; /* AC97_1_SDATA_OUT */
297 gpio = MPC52xx_GPIO_PSC1_MASK;
298 break;
299 case 1:
300 reset = PSC2_RESET; /* AC97_2_RES */
301 sync = PSC2_SYNC; /* AC97_2_SYNC */
302 out = PSC2_SDATA_OUT; /* AC97_2_SDATA_OUT */
303 gpio = MPC52xx_GPIO_PSC2_MASK;
304 break;
305 default:
306 pr_err(__FILE__ ": Unable to determine PSC, no ac97 "
307 "cold-reset will be performed\n");
308 return -ENODEV;
309 }
310
311 spin_lock_irqsave(&gpio_lock, flags);
312
313 /* Reconfiure pin-muxing to gpio */
314 mux = in_be32(&simple_gpio->port_config);
315 out_be32(&simple_gpio->port_config, mux & (~gpio));
316
317 /* enable gpio pins for output */
318 setbits8(&wkup_gpio->wkup_gpioe, reset);
319 setbits32(&simple_gpio->simple_gpioe, sync | out);
320
321 setbits8(&wkup_gpio->wkup_ddr, reset);
322 setbits32(&simple_gpio->simple_ddr, sync | out);
323
324 /* Assert cold reset */
325 clrbits32(&simple_gpio->simple_dvo, sync | out);
326 clrbits8(&wkup_gpio->wkup_dvo, reset);
327
328 /* wait at lease 1 us */
329 udelay(2);
330
331 /* Deassert reset */
332 setbits8(&wkup_gpio->wkup_dvo, reset);
333
334 /* Restore pin-muxing */
335 out_be32(&simple_gpio->port_config, mux);
336
337 spin_unlock_irqrestore(&gpio_lock, flags);
338
339 return 0;
340}
341EXPORT_SYMBOL(mpc5200_psc_ac97_gpio_reset);