pxa2xx-ac97: switch AC unit to correct state before probing
authorDmitry Baryshkov <dbaryshkov@gmail.com>
Mon, 5 Jan 2009 09:58:06 +0000 (12:58 +0300)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 5 Jan 2009 17:47:17 +0000 (17:47 +0000)
If AC97 unit is in partially enabled state, early request_irq can trigger
IRQ storm or even full hang up. Workaround this by forcibly switching ACLINK off
at the start of the probe.

Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/arm/pxa2xx-ac97-lib.c

index ef6539e..35afd0c 100644 (file)
@@ -321,10 +321,6 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
 {
        int ret;
 
-       ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
-       if (ret < 0)
-               goto err;
-
        if (cpu_is_pxa25x() || cpu_is_pxa27x()) {
                pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
                pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
@@ -339,7 +335,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
                if (IS_ERR(ac97conf_clk)) {
                        ret = PTR_ERR(ac97conf_clk);
                        ac97conf_clk = NULL;
-                       goto err_irq;
+                       goto err_conf;
                }
        }
 
@@ -347,19 +343,30 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
        if (IS_ERR(ac97_clk)) {
                ret = PTR_ERR(ac97_clk);
                ac97_clk = NULL;
-               goto err_irq;
+               goto err_clk;
        }
 
-       return clk_enable(ac97_clk);
+       ret = clk_enable(ac97_clk);
+       if (ret)
+               goto err_clk2;
+
+       ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
+       if (ret < 0)
+               goto err_irq;
+
+       return 0;
 
 err_irq:
        GCR |= GCR_ACLINK_OFF;
+err_clk2:
+       clk_put(ac97_clk);
+       ac97_clk = NULL;
+err_clk:
        if (ac97conf_clk) {
                clk_put(ac97conf_clk);
                ac97conf_clk = NULL;
        }
-       free_irq(IRQ_AC97, NULL);
-err:
+err_conf:
        return ret;
 }
 EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);