diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2009-03-15 09:10:54 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-03-15 16:20:37 -0400 |
commit | 26ade896b6ba3fd017ef4a26e71e7b7569222cb6 (patch) | |
tree | 274eeb6778bf399907ec2cce8a1422244d2bae7b /sound | |
parent | 77dd7e17b86bd81b3638e01d784a72652071508b (diff) |
ASoC: Allow choice of ac97 gpio reset line
As the PXA27x series allow 2 gpios to reset the ac97 bus,
allow through platform data configuration the definition of
the correct gpio which will reset the AC97 bus.
This comes from a silicon defect on the PXA27x series, where
the gpio must be manually controlled in warm reset cases.
Signed-off-by: Robert Jarzmik <rjarzmik@free.fr>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/arm/pxa2xx-ac97-lib.c | 71 |
1 files changed, 66 insertions, 5 deletions
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 35afd0c33be5..d721ea7cae8f 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c | |||
@@ -31,6 +31,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); | |||
31 | static volatile long gsr_bits; | 31 | static volatile long gsr_bits; |
32 | static struct clk *ac97_clk; | 32 | static struct clk *ac97_clk; |
33 | static struct clk *ac97conf_clk; | 33 | static struct clk *ac97conf_clk; |
34 | static int reset_gpio; | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * Beware PXA27x bugs: | 37 | * Beware PXA27x bugs: |
@@ -42,6 +43,45 @@ static struct clk *ac97conf_clk; | |||
42 | * 1 jiffy timeout if interrupt never comes). | 43 | * 1 jiffy timeout if interrupt never comes). |
43 | */ | 44 | */ |
44 | 45 | ||
46 | enum { | ||
47 | RESETGPIO_FORCE_HIGH, | ||
48 | RESETGPIO_FORCE_LOW, | ||
49 | RESETGPIO_NORMAL_ALTFUNC | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA | ||
54 | * @mode: chosen action | ||
55 | * | ||
56 | * As the PXA27x CPUs suffer from a AC97 bug, a manual control of the reset line | ||
57 | * must be done to insure proper work of AC97 reset line. This function | ||
58 | * computes the correct gpio_mode for further use by reset functions, and | ||
59 | * applied the change through pxa_gpio_mode. | ||
60 | */ | ||
61 | static void set_resetgpio_mode(int resetgpio_action) | ||
62 | { | ||
63 | int mode = 0; | ||
64 | |||
65 | if (reset_gpio) | ||
66 | switch (resetgpio_action) { | ||
67 | case RESETGPIO_NORMAL_ALTFUNC: | ||
68 | if (reset_gpio == 113) | ||
69 | mode = 113 | GPIO_OUT | GPIO_DFLT_LOW; | ||
70 | if (reset_gpio == 95) | ||
71 | mode = 95 | GPIO_ALT_FN_1_OUT; | ||
72 | break; | ||
73 | case RESETGPIO_FORCE_LOW: | ||
74 | mode = reset_gpio | GPIO_OUT | GPIO_DFLT_LOW; | ||
75 | break; | ||
76 | case RESETGPIO_FORCE_HIGH: | ||
77 | mode = reset_gpio | GPIO_OUT | GPIO_DFLT_HIGH; | ||
78 | break; | ||
79 | }; | ||
80 | |||
81 | if (mode) | ||
82 | pxa_gpio_mode(mode); | ||
83 | } | ||
84 | |||
45 | unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 85 | unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
46 | { | 86 | { |
47 | unsigned short val = -1; | 87 | unsigned short val = -1; |
@@ -137,10 +177,10 @@ static inline void pxa_ac97_warm_pxa27x(void) | |||
137 | 177 | ||
138 | /* warm reset broken on Bulverde, | 178 | /* warm reset broken on Bulverde, |
139 | so manually keep AC97 reset high */ | 179 | so manually keep AC97 reset high */ |
140 | pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); | 180 | set_resetgpio_mode(RESETGPIO_FORCE_HIGH); |
141 | udelay(10); | 181 | udelay(10); |
142 | GCR |= GCR_WARM_RST; | 182 | GCR |= GCR_WARM_RST; |
143 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | 183 | set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); |
144 | udelay(500); | 184 | udelay(500); |
145 | } | 185 | } |
146 | 186 | ||
@@ -308,8 +348,8 @@ int pxa2xx_ac97_hw_resume(void) | |||
308 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | 348 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); |
309 | } | 349 | } |
310 | if (cpu_is_pxa27x()) { | 350 | if (cpu_is_pxa27x()) { |
311 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | 351 | /* Use GPIO 113 or 95 as AC97 Reset on Bulverde */ |
312 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | 352 | set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); |
313 | } | 353 | } |
314 | clk_enable(ac97_clk); | 354 | clk_enable(ac97_clk); |
315 | return 0; | 355 | return 0; |
@@ -320,6 +360,27 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); | |||
320 | int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | 360 | int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) |
321 | { | 361 | { |
322 | int ret; | 362 | int ret; |
363 | struct pxa2xx_ac97_platform_data *pdata = dev->dev.platform_data; | ||
364 | |||
365 | if (pdata) { | ||
366 | switch (pdata->reset_gpio) { | ||
367 | case 95: | ||
368 | case 113: | ||
369 | reset_gpio = pdata->reset_gpio; | ||
370 | break; | ||
371 | case 0: | ||
372 | reset_gpio = 113; | ||
373 | break; | ||
374 | case -1: | ||
375 | break; | ||
376 | default: | ||
377 | dev_err(dev, "Invalid reset GPIO %d\n", | ||
378 | pdata->reset_gpio); | ||
379 | } | ||
380 | } else { | ||
381 | if (cpu_is_pxa27x()) | ||
382 | reset_gpio = 113; | ||
383 | } | ||
323 | 384 | ||
324 | if (cpu_is_pxa25x() || cpu_is_pxa27x()) { | 385 | if (cpu_is_pxa25x() || cpu_is_pxa27x()) { |
325 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | 386 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); |
@@ -330,7 +391,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | |||
330 | 391 | ||
331 | if (cpu_is_pxa27x()) { | 392 | if (cpu_is_pxa27x()) { |
332 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | 393 | /* Use GPIO 113 as AC97 Reset on Bulverde */ |
333 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | 394 | set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); |
334 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); | 395 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); |
335 | if (IS_ERR(ac97conf_clk)) { | 396 | if (IS_ERR(ac97conf_clk)) { |
336 | ret = PTR_ERR(ac97conf_clk); | 397 | ret = PTR_ERR(ac97conf_clk); |