On R-Car H3, some power areas (e.g. A3VP) contain I/O devices, which are
also part of the CPG/MSSR Clock Domain.  Hook up the CPG/MSSR Clock
Domain attach/detach callbacks to enable power management using module
clocks.

This also allows to support the Clock Domain for devices in the
"always-on" power area.

Signed-off-by: Geert Uytterhoeven <[email protected]>
---
v4:
  - Remove the explicit dependency on the CPG/MSSR driver by forwarding
    the attach/detach callbacks to the parent PM Domain.
    If deemed reusable, rcar_sysc_{at,de}tach_dev() can be moved to
    common genpd code later.

v3:
  - Hook up the CPG/MSSR Clock Domain attach/detach callbacks instead of
    using our own copies,

v2:
  - New.
---
 drivers/soc/renesas/rcar-sysc.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index bdab8ac6803300e7..6fad1311133a3ac7 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -224,6 +224,36 @@ static int rcar_sysc_pd_power_on(struct generic_pm_domain 
*genpd)
        return rcar_sysc_power_up(&pd->ch);
 }
 
+#ifdef CONFIG_ARCH_R8A7795
+static int rcar_sysc_attach_dev(struct generic_pm_domain *genpd,
+                               struct device *dev)
+{
+       struct gpd_link *link;
+       int error;
+
+       /* Forward call to parent */
+       list_for_each_entry(link, &genpd->slave_links, slave_node)
+               if (link->master && link->master->attach_dev) {
+                       error = link->master->attach_dev(link->master, dev);
+                       if (error)
+                               return error;
+               }
+
+       return 0;
+}
+
+static void rcar_sysc_detach_dev(struct generic_pm_domain *genpd,
+                                struct device *dev)
+{
+       struct gpd_link *link;
+
+       /* Forward call to parent */
+       list_for_each_entry(link, &genpd->slave_links, slave_node)
+               if (link->master && link->master->detach_dev)
+                       link->master->detach_dev(link->master, dev);
+}
+#endif /* CONFIG_ARCH_R8A7795 */
+
 static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
 {
        struct generic_pm_domain *genpd = &pd->genpd;
@@ -249,6 +279,15 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd 
*pd)
                gov = &pm_domain_always_on_gov;
        }
 
+#ifdef CONFIG_ARCH_R8A7795
+       if (!(pd->flags & (PD_CPU | PD_SCU))) {
+               /* Enable Clock Domain for I/O devices */
+               genpd->flags = GENPD_FLAG_PM_CLK;
+               genpd->attach_dev = rcar_sysc_attach_dev;
+               genpd->detach_dev = rcar_sysc_detach_dev;
+       }
+#endif
+
        pm_genpd_init(genpd, gov, false);
        genpd->dev_ops.active_wakeup = rcar_sysc_active_wakeup;
        genpd->power_off = rcar_sysc_pd_power_off;
-- 
1.9.1

Reply via email to