Merge branch 'parisc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[cascardo/linux.git] / drivers / mfd / arizona-core.c
index e4f97b3..41767f7 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);
 
@@ -790,35 +803,25 @@ unsigned long arizona_of_get_type(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(arizona_of_get_type);
 
-int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
-                             bool mandatory)
-{
-       int gpio;
-
-       gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
-       if (gpio < 0) {
-               if (mandatory)
-                       dev_err(arizona->dev,
-                               "Mandatory DT gpio %s missing/malformed: %d\n",
-                               prop, gpio);
-
-               gpio = 0;
-       }
-
-       return gpio;
-}
-EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
-
 static int arizona_of_get_core_pdata(struct arizona *arizona)
 {
        struct arizona_pdata *pdata = &arizona->pdata;
        struct property *prop;
        const __be32 *cur;
        u32 val;
+       u32 pdm_val[ARIZONA_MAX_PDM_SPK];
        int ret, i;
        int count = 0;
 
-       pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
+       pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0);
+       if (pdata->reset == -EPROBE_DEFER) {
+               return pdata->reset;
+       } else if (pdata->reset < 0) {
+               dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n",
+                       pdata->reset);
+
+               pdata->reset = 0;
+       }
 
        ret = of_property_read_u32_array(arizona->dev->of_node,
                                         "wlf,gpio-defaults",
@@ -871,6 +874,35 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
                count++;
        }
 
+       count = 0;
+       of_property_for_each_u32(arizona->dev->of_node,
+                                "wlf,max-channels-clocked",
+                                prop, cur, val) {
+               if (count == ARRAY_SIZE(pdata->max_channels_clocked))
+                       break;
+
+               pdata->max_channels_clocked[count] = val;
+               count++;
+       }
+
+       ret = of_property_read_u32_array(arizona->dev->of_node,
+                                        "wlf,spk-fmt",
+                                        pdm_val,
+                                        ARRAY_SIZE(pdm_val));
+
+       if (ret >= 0)
+               for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
+                       pdata->spk_fmt[count] = pdm_val[count];
+
+       ret = of_property_read_u32_array(arizona->dev->of_node,
+                                        "wlf,spk-mute",
+                                        pdm_val,
+                                        ARRAY_SIZE(pdm_val));
+
+       if (ret >= 0)
+               for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
+                       pdata->spk_mute[count] = pdm_val[count];
+
        return 0;
 }
 
@@ -1000,6 +1032,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;
@@ -1010,11 +1043,24 @@ int arizona_dev_init(struct arizona *arizona)
        dev_set_drvdata(arizona->dev, arizona);
        mutex_init(&arizona->clk_lock);
 
-       if (dev_get_platdata(arizona->dev))
+       if (dev_get_platdata(arizona->dev)) {
                memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
                       sizeof(arizona->pdata));
-       else
-               arizona_of_get_core_pdata(arizona);
+       } else {
+               ret = arizona_of_get_core_pdata(arizona);
+               if (ret < 0)
+                       return ret;
+       }
+
+       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);
 
@@ -1035,7 +1081,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 +1167,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 +1327,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;
        }