summaryrefslogtreecommitdiff
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.c86
1 files changed, 58 insertions, 28 deletions
diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c
index 7e0835cb062b..2f74a8c644a3 100644
--- a/drivers/mfd/madera-core.c
+++ b/drivers/mfd/madera-core.c
@@ -8,13 +8,12 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -38,13 +37,19 @@
#define MADERA_RESET_MIN_US 2000
#define MADERA_RESET_MAX_US 3000
+#define ERRATA_DCVDD_MIN_US 10000
+#define ERRATA_DCVDD_MAX_US 15000
+
static const char * const madera_core_supplies[] = {
"AVDD",
"DBVDD1",
};
static const struct mfd_cell madera_ldo1_devs[] = {
- { .name = "madera-ldo1" },
+ {
+ .name = "madera-ldo1",
+ .level = MFD_DEP_LEVEL_HIGH,
+ },
};
static const char * const cs47l15_supplies[] = {
@@ -55,8 +60,8 @@ static const char * const cs47l15_supplies[] = {
static const struct mfd_cell cs47l15_devs[] = {
{ .name = "madera-pinctrl", },
- { .name = "madera-irq" },
- { .name = "madera-gpio" },
+ { .name = "madera-irq", },
+ { .name = "madera-gpio", },
{
.name = "madera-extcon",
.parent_supplies = cs47l15_supplies,
@@ -108,7 +113,7 @@ static const char * const cs47l85_supplies[] = {
static const struct mfd_cell cs47l85_devs[] = {
{ .name = "madera-pinctrl", },
{ .name = "madera-irq", },
- { .name = "madera-micsupp" },
+ { .name = "madera-micsupp", },
{ .name = "madera-gpio", },
{
.name = "madera-extcon",
@@ -155,10 +160,10 @@ static const char * const cs47l92_supplies[] = {
};
static const struct mfd_cell cs47l92_devs[] = {
- { .name = "madera-pinctrl" },
+ { .name = "madera-pinctrl", },
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
- { .name = "madera-gpio" },
+ { .name = "madera-gpio", },
{
.name = "madera-extcon",
.parent_supplies = cs47l92_supplies,
@@ -288,6 +293,9 @@ static int __maybe_unused madera_runtime_resume(struct device *dev)
dev_dbg(dev, "Leaving sleep mode\n");
+ if (!madera->reset_errata)
+ madera_enable_hard_reset(madera);
+
ret = regulator_enable(madera->dcvdd);
if (ret) {
dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
@@ -297,7 +305,22 @@ 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);
+ if (madera->reset_errata)
+ usleep_range(ERRATA_DCVDD_MIN_US, ERRATA_DCVDD_MAX_US);
+ else
+ madera_disable_hard_reset(madera);
+
+ if (!madera->pdata.reset || madera->reset_errata) {
+ ret = madera_wait_for_boot(madera);
+ if (ret)
+ goto err;
+
+ ret = madera_soft_reset(madera);
+ if (ret) {
+ dev_err(dev, "Failed to reset: %d\n", ret);
+ goto err;
+ }
+ }
ret = madera_wait_for_boot(madera);
if (ret)
@@ -366,19 +389,14 @@ EXPORT_SYMBOL_GPL(madera_of_match);
static int madera_get_reset_gpio(struct madera *madera)
{
struct gpio_desc *reset;
- int ret;
if (madera->pdata.reset)
return 0;
reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(reset)) {
- ret = PTR_ERR(reset);
- if (ret != -EPROBE_DEFER)
- dev_err(madera->dev, "Failed to request /RESET: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(reset))
+ return dev_err_probe(madera->dev, PTR_ERR(reset),
+ "Failed to request /RESET");
/*
* A hard reset is needed for full reset of the chip. We allow running
@@ -438,7 +456,7 @@ int madera_dev_init(struct madera *madera)
struct device *dev = madera->dev;
unsigned int hwid;
int (*patch_fn)(struct madera *) = NULL;
- const struct mfd_cell *mfd_devs;
+ const struct mfd_cell *mfd_devs = NULL;
int n_devs = 0;
int i, ret;
@@ -491,6 +509,8 @@ int madera_dev_init(struct madera *madera)
*/
switch (madera->type) {
case CS47L15:
+ madera->reset_errata = true;
+ break;
case CS47L35:
case CS47L90:
case CS47L91:
@@ -541,13 +561,19 @@ int madera_dev_init(struct madera *madera)
goto err_dcvdd;
}
+ if (madera->reset_errata)
+ madera_disable_hard_reset(madera);
+
ret = regulator_enable(madera->dcvdd);
if (ret) {
dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
goto err_enable;
}
- madera_disable_hard_reset(madera);
+ if (madera->reset_errata)
+ usleep_range(ERRATA_DCVDD_MIN_US, ERRATA_DCVDD_MAX_US);
+ else
+ madera_disable_hard_reset(madera);
regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false);
@@ -644,7 +670,7 @@ int madera_dev_init(struct madera *madera)
goto err_reset;
}
- if (!n_devs) {
+ if (!n_devs || !mfd_devs) {
dev_err(madera->dev, "Device ID 0x%x not a %s\n", hwid,
madera->type_name);
ret = -ENODEV;
@@ -655,7 +681,7 @@ int madera_dev_init(struct madera *madera)
* It looks like a device we support. If we don't have a hard reset
* we can now attempt a soft reset.
*/
- if (!madera->pdata.reset) {
+ if (!madera->pdata.reset || madera->reset_errata) {
ret = madera_soft_reset(madera);
if (ret)
goto err_reset;
@@ -743,18 +769,22 @@ int madera_dev_exit(struct madera *madera)
/* Prevent any IRQs being serviced while we clean up */
disable_irq(madera->irq);
- /*
- * DCVDD could be supplied by a child node, we must disable it before
- * removing the children, and prevent PM runtime from turning it back on
- */
- pm_runtime_disable(madera->dev);
+ pm_runtime_get_sync(madera->dev);
- clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
+ mfd_remove_devices(madera->dev);
+
+ pm_runtime_disable(madera->dev);
regulator_disable(madera->dcvdd);
regulator_put(madera->dcvdd);
- mfd_remove_devices(madera->dev);
+ mfd_remove_devices_late(madera->dev);
+
+ pm_runtime_set_suspended(madera->dev);
+ pm_runtime_put_noidle(madera->dev);
+
+ clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
+
madera_enable_hard_reset(madera);
regulator_bulk_disable(madera->num_core_supplies,