mfd: twl6040: The chip does not support bulk access
[cascardo/linux.git] / drivers / mfd / arizona-core.c
index e4f97b3..4c18c8e 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
@@ -49,7 +50,15 @@ int arizona_clk32k_enable(struct arizona *arizona)
                case ARIZONA_32KZ_MCLK1:
                        ret = pm_runtime_get_sync(arizona->dev);
                        if (ret != 0)
-                               goto out;
+                               goto err_ref;
+                       ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
+                       if (ret != 0)
+                               goto err_pm;
+                       break;
+               case ARIZONA_32KZ_MCLK2:
+                       ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
+                       if (ret != 0)
+                               goto err_ref;
                        break;
                }
 
@@ -58,7 +67,9 @@ int arizona_clk32k_enable(struct arizona *arizona)
                                         ARIZONA_CLK_32K_ENA);
        }
 
-out:
+err_pm:
+       pm_runtime_put_sync(arizona->dev);
+err_ref:
        if (ret != 0)
                arizona->clk32k_ref--;
 
@@ -83,6 +94,10 @@ int arizona_clk32k_disable(struct arizona *arizona)
                switch (arizona->pdata.clk32k_src) {
                case ARIZONA_32KZ_MCLK1:
                        pm_runtime_put_sync(arizona->dev);
+                       clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
+                       break;
+               case ARIZONA_32KZ_MCLK2:
+                       clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]);
                        break;
                }
        }
@@ -735,7 +750,7 @@ static int arizona_suspend(struct device *dev)
        return 0;
 }
 
-static int arizona_suspend_late(struct device *dev)
+static int arizona_suspend_noirq(struct device *dev)
 {
        struct arizona *arizona = dev_get_drvdata(dev);
 
@@ -759,7 +774,7 @@ static int arizona_resume(struct device *dev)
 {
        struct arizona *arizona = dev_get_drvdata(dev);
 
-       dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
+       dev_dbg(arizona->dev, "Resume, reenabling IRQ\n");
        enable_irq(arizona->irq);
 
        return 0;
@@ -771,10 +786,8 @@ const struct dev_pm_ops arizona_pm_ops = {
                           arizona_runtime_resume,
                           NULL)
        SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
-#ifdef CONFIG_PM_SLEEP
-       .suspend_late = arizona_suspend_late,
-       .resume_noirq = arizona_resume_noirq,
-#endif
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq,
+                                     arizona_resume_noirq)
 };
 EXPORT_SYMBOL_GPL(arizona_pm_ops);
 
@@ -1000,6 +1013,7 @@ static const struct mfd_cell wm8998_devs[] = {
 
 int arizona_dev_init(struct arizona *arizona)
 {
+       const char * const mclk_name[] = { "mclk1", "mclk2" };
        struct device *dev = arizona->dev;
        const char *type_name = NULL;
        unsigned int reg, val, mask;
@@ -1016,6 +1030,16 @@ int arizona_dev_init(struct arizona *arizona)
        else
                arizona_of_get_core_pdata(arizona);
 
+       BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
+       for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
+               arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
+               if (IS_ERR(arizona->mclk[i])) {
+                       dev_info(arizona->dev, "Failed to get %s: %ld\n",
+                                mclk_name[i], PTR_ERR(arizona->mclk[i]));
+                       arizona->mclk[i] = NULL;
+               }
+       }
+
        regcache_cache_only(arizona->regmap, true);
 
        switch (arizona->type) {
@@ -1035,7 +1059,7 @@ int arizona_dev_init(struct arizona *arizona)
        default:
                dev_err(arizona->dev, "Unknown device type %d\n",
                        arizona->type);
-               return -EINVAL;
+               return -ENODEV;
        }
 
        /* Mark DCVDD as external, LDO1 driver will clear if internal */
@@ -1121,6 +1145,7 @@ int arizona_dev_init(struct arizona *arizona)
                break;
        default:
                dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
+               ret = -ENODEV;
                goto err_reset;
        }
 
@@ -1280,12 +1305,14 @@ int arizona_dev_init(struct arizona *arizona)
                break;
        default:
                dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+               ret = -ENODEV;
                goto err_reset;
        }
 
        if (!subdevs) {
                dev_err(arizona->dev,
                        "No kernel support for device ID %x\n", reg);
+               ret = -ENODEV;
                goto err_reset;
        }