mfd: wm5102: Ensure we always boot the device fully
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Mon, 11 May 2015 12:58:03 +0000 (13:58 +0100)
committerLee Jones <lee.jones@linaro.org>
Mon, 22 Jun 2015 11:25:10 +0000 (12:25 +0100)
The wm5102 uses a custom boot sequence and the standard boot sequence is
disabled. However, the standard boot sequence must be run at least once
after a cold boot (caused by either a hard reset or removal of AVDD).
Unfortunately the register WRITE_SEQUENCER_CTRL_3 is not affected by the
hardware reset. This means if the device has been previously booted but
the AVDD supply has never been removed, arizona_dev_init will reset the
chip but the boot sequence will not run, which can cause numerous
problems. The solution is to manually clear this register and then boot
the chip again, which is what this patch does.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/mfd/arizona-core.c

index f30d9253858475d22ac09cb5aec7a9d58ec00b95..0df12995ed1b2558240cd6ca5bf2c9d86e8899d9 100644 (file)
@@ -344,6 +344,33 @@ err_fll:
                return err;
 }
 
+static int wm5102_clear_write_sequencer(struct arizona *arizona)
+{
+       int ret;
+
+       ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3,
+                          0x0);
+       if (ret) {
+               dev_err(arizona->dev,
+                       "Failed to clear write sequencer state: %d\n", ret);
+               return ret;
+       }
+
+       arizona_enable_reset(arizona);
+       regulator_disable(arizona->dcvdd);
+
+       msleep(20);
+
+       ret = regulator_enable(arizona->dcvdd);
+       if (ret) {
+               dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret);
+               return ret;
+       }
+       arizona_disable_reset(arizona);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM
 static int arizona_runtime_resume(struct device *dev)
 {
@@ -802,21 +829,24 @@ int arizona_dev_init(struct arizona *arizona)
        case WM5102:
                ret = regmap_read(arizona->regmap,
                                  ARIZONA_WRITE_SEQUENCER_CTRL_3, &val);
-               if (ret != 0)
+               if (ret) {
                        dev_err(dev,
                                "Failed to check write sequencer state: %d\n",
                                ret);
-               else if (val & 0x01)
-                       break;
-               /* Fall through */
-       default:
-               ret = arizona_wait_for_boot(arizona);
-               if (ret != 0) {
-                       dev_err(arizona->dev,
-                               "Device failed initial boot: %d\n", ret);
-                       goto err_reset;
+               } else if (val & 0x01) {
+                       ret = wm5102_clear_write_sequencer(arizona);
+                       if (ret)
+                               return ret;
                }
                break;
+       default:
+               break;
+       }
+
+       ret = arizona_wait_for_boot(arizona);
+       if (ret) {
+               dev_err(arizona->dev, "Device failed initial boot: %d\n", ret);
+               goto err_reset;
        }
 
        /* Read the device ID information & do device specific stuff */