clk: renesas: cpg-mssr: Add early clock support
authorChris Brandt <chris.brandt@renesas.com>
Mon, 24 Sep 2018 16:49:35 +0000 (11:49 -0500)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Wed, 26 Sep 2018 12:22:00 +0000 (14:22 +0200)
Add support for SoCs that need to register core and module clocks early in
order to use OF drivers that exclusively use macros such as
TIMER_OF_DECLARE.

Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/renesas/renesas-cpg-mssr.h

index e0c11a5b176152c64cee55ad7d4dd53a30179533..394a7d10392a2ef0fed3d1b7f9fafc1e4214c402 100644 (file)
@@ -130,6 +130,7 @@ struct cpg_mssr_priv {
        struct device *dev;
        void __iomem *base;
        spinlock_t rmw_lock;
+       struct device_node *np;
 
        struct clk **clks;
        unsigned int num_core_clks;
@@ -144,6 +145,7 @@ struct cpg_mssr_priv {
        } smstpcr_saved[ARRAY_SIZE(smstpcr)];
 };
 
+static struct cpg_mssr_priv *cpg_mssr_priv;
 
 /**
  * struct mstp_clock - MSTP gating clock
@@ -319,7 +321,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
 
        switch (core->type) {
        case CLK_TYPE_IN:
-               clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+               clk = of_clk_get_by_name(priv->np, core->name);
                break;
 
        case CLK_TYPE_FF:
@@ -891,42 +893,43 @@ static const struct dev_pm_ops cpg_mssr_pm = {
 #define DEV_PM_OPS     NULL
 #endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */
 
-static int __init cpg_mssr_probe(struct platform_device *pdev)
+static int __init cpg_mssr_common_init(struct device *dev,
+                                      struct device_node *np,
+                                      const struct cpg_mssr_info *info)
 {
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       const struct cpg_mssr_info *info;
        struct cpg_mssr_priv *priv;
+       struct clk **clks = NULL;
        unsigned int nclks, i;
-       struct resource *res;
-       struct clk **clks;
        int error;
 
-       info = of_device_get_match_data(dev);
        if (info->init) {
                error = info->init(dev);
                if (error)
                        return error;
        }
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
+       priv->np = np;
        priv->dev = dev;
        spin_lock_init(&priv->rmw_lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(priv->base))
-               return PTR_ERR(priv->base);
+       priv->base = of_iomap(np, 0);
+       if (!priv->base) {
+               error = -ENOMEM;
+               goto out_err;
+       }
 
        nclks = info->num_total_core_clks + info->num_hw_mod_clks;
-       clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
-       if (!clks)
-               return -ENOMEM;
+       clks = kmalloc_array(nclks, sizeof(*clks), GFP_KERNEL);
+       if (!clks) {
+               error = -ENOMEM;
+               goto out_err;
+       }
 
-       dev_set_drvdata(dev, priv);
+       cpg_mssr_priv = priv;
        priv->clks = clks;
        priv->num_core_clks = info->num_total_core_clks;
        priv->num_mod_clks = info->num_hw_mod_clks;
@@ -937,16 +940,68 @@ static int __init cpg_mssr_probe(struct platform_device *pdev)
        for (i = 0; i < nclks; i++)
                clks[i] = ERR_PTR(-ENOENT);
 
+       error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
+       if (error)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       kfree(clks);
+       if (priv->base)
+               iounmap(priv->base);
+       kfree(priv);
+
+       return error;
+}
+
+void __init cpg_mssr_early_init(struct device_node *np,
+                               const struct cpg_mssr_info *info)
+{
+       int error;
+       int i;
+
+       error = cpg_mssr_common_init(NULL, np, info);
+       if (error)
+               return;
+
+       for (i = 0; i < info->num_early_core_clks; i++)
+               cpg_mssr_register_core_clk(&info->early_core_clks[i], info,
+                                          cpg_mssr_priv);
+
+       for (i = 0; i < info->num_early_mod_clks; i++)
+               cpg_mssr_register_mod_clk(&info->early_mod_clks[i], info,
+                                         cpg_mssr_priv);
+
+}
+
+static int __init cpg_mssr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       const struct cpg_mssr_info *info;
+       struct cpg_mssr_priv *priv;
+       unsigned int i;
+       int error;
+
+       info = of_device_get_match_data(dev);
+
+       if (!cpg_mssr_priv) {
+               error = cpg_mssr_common_init(dev, dev->of_node, info);
+               if (error)
+                       return error;
+       }
+
+       priv = cpg_mssr_priv;
+       priv->dev = dev;
+       dev_set_drvdata(dev, priv);
+
        for (i = 0; i < info->num_core_clks; i++)
                cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
 
        for (i = 0; i < info->num_mod_clks; i++)
                cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
 
-       error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
-       if (error)
-               return error;
-
        error = devm_add_action_or_reset(dev,
                                         cpg_mssr_del_clk_provider,
                                         np);
index d43d00351638545719638d86e54bbf46fe9ab274..4e639fb8da9a25c62391b6f1dc9d38f457c4612c 100644 (file)
@@ -91,6 +91,11 @@ struct device_node;
     /**
      * SoC-specific CPG/MSSR Description
      *
+     * @early_core_clks: Array of Early Core Clock definitions
+     * @num_early_core_clks: Number of entries in early_core_clks[]
+     * @early_mod_clks: Array of Early Module Clock definitions
+     * @num_early_mod_clks: Number of entries in early_mod_clks[]
+     *
      * @core_clks: Array of Core Clock definitions
      * @num_core_clks: Number of entries in core_clks[]
      * @last_dt_core_clk: ID of the last Core Clock exported to DT
@@ -117,6 +122,12 @@ struct device_node;
      */
 
 struct cpg_mssr_info {
+       /* Early Clocks */
+       const struct cpg_core_clk *early_core_clks;
+       unsigned int num_early_core_clks;
+       const struct mssr_mod_clk *early_mod_clks;
+       unsigned int num_early_mod_clks;
+
        /* Core Clocks */
        const struct cpg_core_clk *core_clks;
        unsigned int num_core_clks;
@@ -164,6 +175,8 @@ extern const struct cpg_mssr_info r8a77980_cpg_mssr_info;
 extern const struct cpg_mssr_info r8a77990_cpg_mssr_info;
 extern const struct cpg_mssr_info r8a77995_cpg_mssr_info;
 
+void __init cpg_mssr_early_init(struct device_node *np,
+                               const struct cpg_mssr_info *info);
 
     /*
      * Helpers for fixing up clock tables depending on SoC revision