soc: ti: omap-prm: Add pm_clk for genpd
authorTony Lindgren <tony@atomide.com>
Mon, 16 Nov 2020 10:57:13 +0000 (12:57 +0200)
committerTony Lindgren <tony@atomide.com>
Mon, 16 Nov 2020 10:57:32 +0000 (12:57 +0200)
In order to probe l3 and l4 interconnects with simple-pm-bus, we want
genpd to manage the clocks for the interconnects. For interconnect target
modules, we already have ti-sysc manage the clocks so let's skipe managing
clocks for ti-sysc modules.

Cc: Santosh Shilimkar <ssantosh@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/soc/ti/omap_prm.c

index 4d41dc3..3406c82 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
@@ -14,6 +15,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_clock.h>
 #include <linux/pm_domain.h>
 #include <linux/reset-controller.h>
 #include <linux/delay.h>
@@ -41,6 +43,7 @@ struct omap_prm_domain {
        u16 pwrstst;
        const struct omap_prm_domain_map *cap;
        u32 pwrstctrl_saved;
+       unsigned int uses_pm_clk:1;
 };
 
 struct omap_rst_map {
@@ -325,6 +328,38 @@ static int omap_prm_domain_power_off(struct generic_pm_domain *domain)
        return 0;
 }
 
+/*
+ * Note that ti-sysc already manages the module clocks separately so
+ * no need to manage those. Interconnect instances need clocks managed
+ * for simple-pm-bus.
+ */
+static int omap_prm_domain_attach_clock(struct device *dev,
+                                       struct omap_prm_domain *prmd)
+{
+       struct device_node *np = dev->of_node;
+       int error;
+
+       if (!of_device_is_compatible(np, "simple-pm-bus"))
+               return 0;
+
+       if (!of_property_read_bool(np, "clocks"))
+               return 0;
+
+       error = pm_clk_create(dev);
+       if (error)
+               return error;
+
+       error = of_pm_clk_add_clks(dev);
+       if (error < 0) {
+               pm_clk_destroy(dev);
+               return error;
+       }
+
+       prmd->uses_pm_clk = 1;
+
+       return 0;
+}
+
 static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
                                      struct device *dev)
 {
@@ -349,6 +384,10 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
        genpd_data = dev_gpd_data(dev);
        genpd_data->data = NULL;
 
+       ret = omap_prm_domain_attach_clock(dev, prmd);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
@@ -356,7 +395,11 @@ static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain,
                                       struct device *dev)
 {
        struct generic_pm_domain_data *genpd_data;
+       struct omap_prm_domain *prmd;
 
+       prmd = genpd_to_prm_domain(domain);
+       if (prmd->uses_pm_clk)
+               pm_clk_destroy(dev);
        genpd_data = dev_gpd_data(dev);
        genpd_data->data = NULL;
 }
@@ -393,6 +436,7 @@ static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
        prmd->pd.power_off = omap_prm_domain_power_off;
        prmd->pd.attach_dev = omap_prm_domain_attach_dev;
        prmd->pd.detach_dev = omap_prm_domain_detach_dev;
+       prmd->pd.flags = GENPD_FLAG_PM_CLK;
 
        pm_genpd_init(&prmd->pd, NULL, true);
        error = of_genpd_add_provider_simple(np, &prmd->pd);