]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
bus: ti-sysc: Add initial support for external resets
authorTony Lindgren <tony@atomide.com>
Mon, 16 Apr 2018 17:20:27 +0000 (10:20 -0700)
committerTony Lindgren <tony@atomide.com>
Tue, 1 May 2018 13:54:17 +0000 (06:54 -0700)
Some modules need to use external resets in the rstctrl bits. Typically
only one of the rstctrl bits is for the interconnect target module while
the others are for various child devices.

For ti-sysc driver, we just need the module rstctrl bit mapped. The rest
of the rstctrl bits can be directly mapped to the child devices.

Cc: Suman Anna <s-anna@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/bus/ti-sysc.c

index 145dcc0cf48c309cc5d5c28ea235e682838c71f2..36c4c340c342dbaac6aa9b21e42d84e6719412e6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
@@ -74,6 +75,7 @@ struct sysc {
        struct clk **clocks;
        const char **clock_roles;
        int nr_clocks;
+       struct reset_control *rsts;
        const char *legacy_mode;
        const struct sysc_capabilities *cap;
        struct sysc_config cfg;
@@ -213,6 +215,42 @@ static int sysc_get_clocks(struct sysc *ddata)
        return 0;
 }
 
+/**
+ * sysc_init_resets - reset module on init
+ * @ddata: device driver data
+ *
+ * A module can have both OCP softreset control and external rstctrl.
+ * If more complicated rstctrl resets are needed, please handle these
+ * directly from the child device driver and map only the module reset
+ * for the parent interconnect target module device.
+ *
+ * Automatic reset of the module on init can be skipped with the
+ * "ti,no-reset-on-init" device tree property.
+ */
+static int sysc_init_resets(struct sysc *ddata)
+{
+       int error;
+
+       ddata->rsts =
+               devm_reset_control_array_get_optional_exclusive(ddata->dev);
+       if (IS_ERR(ddata->rsts))
+               return PTR_ERR(ddata->rsts);
+
+       if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
+               goto deassert;
+
+       error = reset_control_assert(ddata->rsts);
+       if (error)
+               return error;
+
+deassert:
+       error = reset_control_deassert(ddata->rsts);
+       if (error)
+               return error;
+
+       return 0;
+}
+
 /**
  * sysc_parse_and_check_child_range - parses module IO region from ranges
  * @ddata: device driver data
@@ -889,6 +927,7 @@ static int sysc_init_module(struct sysc *ddata)
 
                return 0;
        }
+
        ddata->revision = sysc_read_revision(ddata);
        pm_runtime_put_sync(ddata->dev);
 
@@ -1583,8 +1622,11 @@ static int sysc_probe(struct platform_device *pdev)
        if (error)
                goto unprepare;
 
-       pm_runtime_enable(ddata->dev);
+       error = sysc_init_resets(ddata);
+       if (error)
+               return error;
 
+       pm_runtime_enable(ddata->dev);
        error = sysc_init_module(ddata);
        if (error)
                goto unprepare;
@@ -1615,6 +1657,9 @@ static int sysc_probe(struct platform_device *pdev)
                pm_runtime_put(&pdev->dev);
        }
 
+       if (!of_get_available_child_count(ddata->dev->of_node))
+               reset_control_assert(ddata->rsts);
+
        return 0;
 
 err:
@@ -1644,6 +1689,7 @@ static int sysc_remove(struct platform_device *pdev)
 
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
+       reset_control_assert(ddata->rsts);
 
 unprepare:
        sysc_unprepare(ddata);