aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/arizona-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/arizona-core.c')
-rw-r--r--drivers/mfd/arizona-core.c113
1 files changed, 81 insertions, 32 deletions
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index e4f97b3c824b..41767f7239bb 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -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;
}