summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/madera-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/madera-core.c')
-rw-r--r--drivers/mfd/madera-core.c60
1 files changed, 49 insertions, 11 deletions
diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c
index 29540cbf7593..7e0835cb062b 100644
--- a/drivers/mfd/madera-core.c
+++ b/drivers/mfd/madera-core.c
@@ -35,6 +35,9 @@
#define MADERA_32KZ_MCLK2 1
+#define MADERA_RESET_MIN_US 2000
+#define MADERA_RESET_MAX_US 3000
+
static const char * const madera_core_supplies[] = {
"AVDD",
"DBVDD1",
@@ -199,7 +202,7 @@ EXPORT_SYMBOL_GPL(madera_name_from_type);
#define MADERA_BOOT_POLL_INTERVAL_USEC 5000
#define MADERA_BOOT_POLL_TIMEOUT_USEC 25000
-static int madera_wait_for_boot(struct madera *madera)
+static int madera_wait_for_boot_noack(struct madera *madera)
{
ktime_t timeout;
unsigned int val = 0;
@@ -226,6 +229,13 @@ static int madera_wait_for_boot(struct madera *madera)
ret = -ETIMEDOUT;
}
+ return ret;
+}
+
+static int madera_wait_for_boot(struct madera *madera)
+{
+ int ret = madera_wait_for_boot_noack(madera);
+
/*
* BOOT_DONE defaults to unmasked on boot so we must ack it.
* Do this even after a timeout to avoid interrupt storms.
@@ -249,16 +259,13 @@ static int madera_soft_reset(struct madera *madera)
}
/* Allow time for internal clocks to startup after reset */
- usleep_range(1000, 2000);
+ usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
return 0;
}
static void madera_enable_hard_reset(struct madera *madera)
{
- if (!madera->pdata.reset)
- return;
-
/*
* There are many existing out-of-tree users of these codecs that we
* can't break so preserve the expected behaviour of setting the line
@@ -269,11 +276,9 @@ static void madera_enable_hard_reset(struct madera *madera)
static void madera_disable_hard_reset(struct madera *madera)
{
- if (!madera->pdata.reset)
- return;
-
gpiod_set_raw_value_cansleep(madera->pdata.reset, 1);
- usleep_range(1000, 2000);
+
+ usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
}
static int __maybe_unused madera_runtime_resume(struct device *dev)
@@ -292,6 +297,8 @@ static int __maybe_unused madera_runtime_resume(struct device *dev)
regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false);
+ usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
+
ret = madera_wait_for_boot(madera);
if (ret)
goto err;
@@ -450,6 +457,21 @@ int madera_dev_init(struct madera *madera)
sizeof(madera->pdata));
}
+ madera->mclk[MADERA_MCLK1].id = "mclk1";
+ madera->mclk[MADERA_MCLK2].id = "mclk2";
+ madera->mclk[MADERA_MCLK3].id = "mclk3";
+
+ ret = devm_clk_bulk_get_optional(madera->dev, ARRAY_SIZE(madera->mclk),
+ madera->mclk);
+ if (ret) {
+ dev_err(madera->dev, "Failed to get clocks: %d\n", ret);
+ return ret;
+ }
+
+ /* Not using devm_clk_get to prevent breakage of existing DTs */
+ if (!madera->mclk[MADERA_MCLK2].clk)
+ dev_warn(madera->dev, "Missing MCLK2, requires 32kHz clock\n");
+
ret = madera_get_reset_gpio(madera);
if (ret)
return ret;
@@ -530,6 +552,12 @@ int madera_dev_init(struct madera *madera)
regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false);
+ ret = madera_wait_for_boot_noack(madera);
+ if (ret) {
+ dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
+ goto err_reset;
+ }
+
/*
* Now we can power up and verify that this is a chip we know about
* before we start doing any writes to its registers.
@@ -635,7 +663,7 @@ int madera_dev_init(struct madera *madera)
ret = madera_wait_for_boot(madera);
if (ret) {
- dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
+ dev_err(madera->dev, "Failed to clear boot done: %d\n", ret);
goto err_reset;
}
@@ -660,13 +688,19 @@ int madera_dev_init(struct madera *madera)
}
/* Init 32k clock sourced from MCLK2 */
+ ret = clk_prepare_enable(madera->mclk[MADERA_MCLK2].clk);
+ if (ret) {
+ dev_err(madera->dev, "Failed to enable 32k clock: %d\n", ret);
+ goto err_reset;
+ }
+
ret = regmap_update_bits(madera->regmap,
MADERA_CLOCK_32K_1,
MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK,
MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2);
if (ret) {
dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret);
- goto err_reset;
+ goto err_clock;
}
pm_runtime_set_active(madera->dev);
@@ -687,6 +721,8 @@ int madera_dev_init(struct madera *madera)
err_pm_runtime:
pm_runtime_disable(madera->dev);
+err_clock:
+ clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
err_reset:
madera_enable_hard_reset(madera);
regulator_disable(madera->dcvdd);
@@ -713,6 +749,8 @@ int madera_dev_exit(struct madera *madera)
*/
pm_runtime_disable(madera->dev);
+ clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
+
regulator_disable(madera->dcvdd);
regulator_put(madera->dcvdd);
OpenPOWER on IntegriCloud