clk: renesas: cpg-mssr: Add support to restore core clocks during resume
authorGeert Uytterhoeven <geert+renesas@glider.be>
Wed, 21 Jun 2017 20:24:15 +0000 (22:24 +0200)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Fri, 20 Oct 2017 09:15:33 +0000 (11:15 +0200)
On R-Car Gen3 systems, PSCI system suspend powers down the SoC, possibly
losing clock configuration.  Hence add a notifier chain that can be used
by core clocks to save/restore clock state during system suspend/resume.

The implementation of the actual clock state save/restore operations is
clock-specific, and to be registered with the notifier chain in the SoC
or family-specific cpg_mssr_info.cpg_clk_register() callback.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Tested-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
drivers/clk/renesas/rcar-gen2-cpg.c
drivers/clk/renesas/rcar-gen2-cpg.h
drivers/clk/renesas/rcar-gen3-cpg.c
drivers/clk/renesas/rcar-gen3-cpg.h
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/renesas/renesas-cpg-mssr.h

index 123b1e6..feb1457 100644 (file)
@@ -262,10 +262,9 @@ static unsigned int cpg_pll0_div __initdata;
 static u32 cpg_mode __initdata;
 
 struct clk * __init rcar_gen2_cpg_clk_register(struct device *dev,
-                                              const struct cpg_core_clk *core,
-                                              const struct cpg_mssr_info *info,
-                                              struct clk **clks,
-                                              void __iomem *base)
+       const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
+       struct clk **clks, void __iomem *base,
+       struct raw_notifier_head *notifiers)
 {
        const struct clk_div_table *table = NULL;
        const struct clk *parent;
index 9eba07f..020a3ba 100644 (file)
@@ -34,9 +34,9 @@ struct rcar_gen2_cpg_pll_config {
 };
 
 struct clk *rcar_gen2_cpg_clk_register(struct device *dev,
-                                      const struct cpg_core_clk *core,
-                                      const struct cpg_mssr_info *info,
-                                      struct clk **clks, void __iomem *base);
+       const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
+       struct clk **clks, void __iomem *base,
+       struct raw_notifier_head *notifiers);
 int rcar_gen2_cpg_init(const struct rcar_gen2_cpg_pll_config *config,
                       unsigned int pll0_div, u32 mode);
 
index 9511058..1399852 100644 (file)
@@ -265,7 +265,8 @@ static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
 
 struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
        const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
-       struct clk **clks, void __iomem *base)
+       struct clk **clks, void __iomem *base,
+       struct raw_notifier_head *notifiers)
 {
        const struct clk *parent;
        unsigned int mult = 1;
index d756ef8..2e42843 100644 (file)
@@ -44,7 +44,8 @@ struct rcar_gen3_cpg_pll_config {
 
 struct clk *rcar_gen3_cpg_clk_register(struct device *dev,
        const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
-       struct clk **clks, void __iomem *base);
+       struct clk **clks, void __iomem *base,
+       struct raw_notifier_head *notifiers);
 int rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config,
                       unsigned int clk_extalr, u32 mode);
 
index 15fc867..485dce0 100644 (file)
@@ -107,6 +107,7 @@ static const u16 srcr[] = {
  * @num_core_clks: Number of Core Clocks in clks[]
  * @num_mod_clks: Number of Module Clocks in clks[]
  * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @notifiers: Notifier chain to save/restore clock state for system resume
  * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
  * @smstpcr_saved[].val: Saved values of SMSTPCR[]
  */
@@ -123,6 +124,7 @@ struct cpg_mssr_priv {
        unsigned int num_mod_clks;
        unsigned int last_dt_core_clk;
 
+       struct raw_notifier_head notifiers;
        struct {
                u32 mask;
                u32 val;
@@ -312,7 +314,8 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
        default:
                if (info->cpg_clk_register)
                        clk = info->cpg_clk_register(dev, core, info,
-                                                    priv->clks, priv->base);
+                                                    priv->clks, priv->base,
+                                                    &priv->notifiers);
                else
                        dev_err(dev, "%s has unsupported core clock type %u\n",
                                core->name, core->type);
@@ -726,6 +729,9 @@ static int cpg_mssr_suspend_noirq(struct device *dev)
                                readl(priv->base + SMSTPCR(reg));
        }
 
+       /* Save core clocks */
+       raw_notifier_call_chain(&priv->notifiers, PM_EVENT_SUSPEND, NULL);
+
        return 0;
 }
 
@@ -739,6 +745,9 @@ static int cpg_mssr_resume_noirq(struct device *dev)
        if (!psci_ops.cpu_suspend)
                return 0;
 
+       /* Restore core clocks */
+       raw_notifier_call_chain(&priv->notifiers, PM_EVENT_RESUME, NULL);
+
        /* Restore module clocks */
        for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
                mask = priv->smstpcr_saved[reg].mask;
@@ -822,6 +831,7 @@ static int __init cpg_mssr_probe(struct platform_device *pdev)
        priv->num_core_clks = info->num_total_core_clks;
        priv->num_mod_clks = info->num_hw_mod_clks;
        priv->last_dt_core_clk = info->last_dt_core_clk;
+       RAW_INIT_NOTIFIER_HEAD(&priv->notifiers);
 
        for (i = 0; i < nclks; i++)
                clks[i] = ERR_PTR(-ENOENT);
index 66528ce..0745b09 100644 (file)
@@ -127,7 +127,8 @@ struct cpg_mssr_info {
        struct clk *(*cpg_clk_register)(struct device *dev,
                                        const struct cpg_core_clk *core,
                                        const struct cpg_mssr_info *info,
-                                       struct clk **clks, void __iomem *base);
+                                       struct clk **clks, void __iomem *base,
+                                       struct raw_notifier_head *notifiers);
 };
 
 extern const struct cpg_mssr_info r8a7743_cpg_mssr_info;