]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/clk/rockchip/clk.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[karo-tx-linux.git] / drivers / clk / rockchip / clk.c
index ec06350c78c4808c7dc6a849f157428402cccf0f..7ffd134995f222bac2a088146b4dd05d9320eca0 100644 (file)
@@ -2,6 +2,9 @@
  * Copyright (c) 2014 MundoReader S.L.
  * Author: Heiko Stuebner <heiko@sntech.de>
  *
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
  * based on
  *
  * samsung/clk.c
@@ -39,7 +42,8 @@
  * sometimes without one of those components.
  */
 static struct clk *rockchip_clk_register_branch(const char *name,
-               const char *const *parent_names, u8 num_parents, void __iomem *base,
+               const char *const *parent_names, u8 num_parents,
+               void __iomem *base,
                int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags,
                u8 div_shift, u8 div_width, u8 div_flags,
                struct clk_div_table *div_table, int gate_offset,
@@ -136,9 +140,11 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
        pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n",
                 __func__, event, ndata->old_rate, ndata->new_rate);
        if (event == PRE_RATE_CHANGE) {
-               frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw);
+               frac->rate_change_idx =
+                               frac->mux_ops->get_parent(&frac_mux->hw);
                if (frac->rate_change_idx != frac->mux_frac_idx) {
-                       frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx);
+                       frac->mux_ops->set_parent(&frac_mux->hw,
+                                                 frac->mux_frac_idx);
                        frac->rate_change_remuxed = 1;
                }
        } else if (event == POST_RATE_CHANGE) {
@@ -149,7 +155,8 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
                 * reaches the mux itself.
                 */
                if (frac->rate_change_remuxed) {
-                       frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx);
+                       frac->mux_ops->set_parent(&frac_mux->hw,
+                                                 frac->rate_change_idx);
                        frac->rate_change_remuxed = 0;
                }
        }
@@ -157,7 +164,8 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
        return notifier_from_errno(ret);
 }
 
-static struct clk *rockchip_clk_register_frac_branch(const char *name,
+static struct clk *rockchip_clk_register_frac_branch(
+               struct rockchip_clk_provider *ctx, const char *name,
                const char *const *parent_names, u8 num_parents,
                void __iomem *base, int muxdiv_offset, u8 div_flags,
                int gate_offset, u8 gate_shift, u8 gate_flags,
@@ -250,7 +258,7 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name,
                if (IS_ERR(mux_clk))
                        return clk;
 
-               rockchip_clk_add_lookup(mux_clk, child->id);
+               rockchip_clk_add_lookup(ctx, mux_clk, child->id);
 
                /* notifier on the fraction divider to catch rate changes */
                if (frac->mux_frac_idx >= 0) {
@@ -314,66 +322,82 @@ static struct clk *rockchip_clk_register_factor_branch(const char *name,
        return clk;
 }
 
-static DEFINE_SPINLOCK(clk_lock);
-static struct clk **clk_table;
-static void __iomem *reg_base;
-static struct clk_onecell_data clk_data;
-static struct device_node *cru_node;
-static struct regmap *grf;
-
-void __init rockchip_clk_init(struct device_node *np, void __iomem *base,
-                             unsigned long nr_clks)
+struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np,
+                       void __iomem *base, unsigned long nr_clks)
 {
-       reg_base = base;
-       cru_node = np;
-       grf = ERR_PTR(-EPROBE_DEFER);
+       struct rockchip_clk_provider *ctx;
+       struct clk **clk_table;
+       int i;
+
+       ctx = kzalloc(sizeof(struct rockchip_clk_provider), GFP_KERNEL);
+       if (!ctx)
+               return ERR_PTR(-ENOMEM);
 
        clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
        if (!clk_table)
-               pr_err("%s: could not allocate clock lookup table\n", __func__);
+               goto err_free;
 
-       clk_data.clks = clk_table;
-       clk_data.clk_num = nr_clks;
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       for (i = 0; i < nr_clks; ++i)
+               clk_table[i] = ERR_PTR(-ENOENT);
+
+       ctx->reg_base = base;
+       ctx->clk_data.clks = clk_table;
+       ctx->clk_data.clk_num = nr_clks;
+       ctx->cru_node = np;
+       ctx->grf = ERR_PTR(-EPROBE_DEFER);
+       spin_lock_init(&ctx->lock);
+
+       ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
+                                                  "rockchip,grf");
+
+       return ctx;
+
+err_free:
+       kfree(ctx);
+       return ERR_PTR(-ENOMEM);
 }
 
-struct regmap *rockchip_clk_get_grf(void)
+void __init rockchip_clk_of_add_provider(struct device_node *np,
+                               struct rockchip_clk_provider *ctx)
 {
-       if (IS_ERR(grf))
-               grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf");
-       return grf;
+       if (of_clk_add_provider(np, of_clk_src_onecell_get,
+                               &ctx->clk_data))
+               pr_err("%s: could not register clk provider\n", __func__);
 }
 
-void rockchip_clk_add_lookup(struct clk *clk, unsigned int id)
+void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
+                            struct clk *clk, unsigned int id)
 {
-       if (clk_table && id)
-               clk_table[id] = clk;
+       if (ctx->clk_data.clks && id)
+               ctx->clk_data.clks[id] = clk;
 }
 
-void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
+void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
+                               struct rockchip_pll_clock *list,
                                unsigned int nr_pll, int grf_lock_offset)
 {
        struct clk *clk;
        int idx;
 
        for (idx = 0; idx < nr_pll; idx++, list++) {
-               clk = rockchip_clk_register_pll(list->type, list->name,
+               clk = rockchip_clk_register_pll(ctx, list->type, list->name,
                                list->parent_names, list->num_parents,
-                               reg_base, list->con_offset, grf_lock_offset,
+                               list->con_offset, grf_lock_offset,
                                list->lock_shift, list->mode_offset,
                                list->mode_shift, list->rate_table,
-                               list->pll_flags, &clk_lock);
+                               list->pll_flags);
                if (IS_ERR(clk)) {
                        pr_err("%s: failed to register clock %s\n", __func__,
                                list->name);
                        continue;
                }
 
-               rockchip_clk_add_lookup(clk, list->id);
+               rockchip_clk_add_lookup(ctx, clk, list->id);
        }
 }
 
 void __init rockchip_clk_register_branches(
+                                     struct rockchip_clk_provider *ctx,
                                      struct rockchip_clk_branch *list,
                                      unsigned int nr_clk)
 {
@@ -389,56 +413,59 @@ void __init rockchip_clk_register_branches(
                case branch_mux:
                        clk = clk_register_mux(NULL, list->name,
                                list->parent_names, list->num_parents,
-                               flags, reg_base + list->muxdiv_offset,
+                               flags, ctx->reg_base + list->muxdiv_offset,
                                list->mux_shift, list->mux_width,
-                               list->mux_flags, &clk_lock);
+                               list->mux_flags, &ctx->lock);
                        break;
                case branch_divider:
                        if (list->div_table)
                                clk = clk_register_divider_table(NULL,
                                        list->name, list->parent_names[0],
-                                       flags, reg_base + list->muxdiv_offset,
+                                       flags,
+                                       ctx->reg_base + list->muxdiv_offset,
                                        list->div_shift, list->div_width,
                                        list->div_flags, list->div_table,
-                                       &clk_lock);
+                                       &ctx->lock);
                        else
                                clk = clk_register_divider(NULL, list->name,
                                        list->parent_names[0], flags,
-                                       reg_base + list->muxdiv_offset,
+                                       ctx->reg_base + list->muxdiv_offset,
                                        list->div_shift, list->div_width,
-                                       list->div_flags, &clk_lock);
+                                       list->div_flags, &ctx->lock);
                        break;
                case branch_fraction_divider:
-                       clk = rockchip_clk_register_frac_branch(list->name,
+                       clk = rockchip_clk_register_frac_branch(ctx, list->name,
                                list->parent_names, list->num_parents,
-                               reg_base, list->muxdiv_offset, list->div_flags,
+                               ctx->reg_base, list->muxdiv_offset,
+                               list->div_flags,
                                list->gate_offset, list->gate_shift,
                                list->gate_flags, flags, list->child,
-                               &clk_lock);
+                               &ctx->lock);
                        break;
                case branch_gate:
                        flags |= CLK_SET_RATE_PARENT;
 
                        clk = clk_register_gate(NULL, list->name,
                                list->parent_names[0], flags,
-                               reg_base + list->gate_offset,
-                               list->gate_shift, list->gate_flags, &clk_lock);
+                               ctx->reg_base + list->gate_offset,
+                               list->gate_shift, list->gate_flags, &ctx->lock);
                        break;
                case branch_composite:
                        clk = rockchip_clk_register_branch(list->name,
                                list->parent_names, list->num_parents,
-                               reg_base, list->muxdiv_offset, list->mux_shift,
+                               ctx->reg_base, list->muxdiv_offset,
+                               list->mux_shift,
                                list->mux_width, list->mux_flags,
                                list->div_shift, list->div_width,
                                list->div_flags, list->div_table,
                                list->gate_offset, list->gate_shift,
-                               list->gate_flags, flags, &clk_lock);
+                               list->gate_flags, flags, &ctx->lock);
                        break;
                case branch_mmc:
                        clk = rockchip_clk_register_mmc(
                                list->name,
                                list->parent_names, list->num_parents,
-                               reg_base + list->muxdiv_offset,
+                               ctx->reg_base + list->muxdiv_offset,
                                list->div_shift
                        );
                        break;
@@ -446,16 +473,16 @@ void __init rockchip_clk_register_branches(
                        clk = rockchip_clk_register_inverter(
                                list->name, list->parent_names,
                                list->num_parents,
-                               reg_base + list->muxdiv_offset,
-                               list->div_shift, list->div_flags, &clk_lock);
+                               ctx->reg_base + list->muxdiv_offset,
+                               list->div_shift, list->div_flags, &ctx->lock);
                        break;
                case branch_factor:
                        clk = rockchip_clk_register_factor_branch(
                                list->name, list->parent_names,
-                               list->num_parents, reg_base,
+                               list->num_parents, ctx->reg_base,
                                list->div_shift, list->div_width,
                                list->gate_offset, list->gate_shift,
-                               list->gate_flags, flags, &clk_lock);
+                               list->gate_flags, flags, &ctx->lock);
                        break;
                }
 
@@ -472,11 +499,12 @@ void __init rockchip_clk_register_branches(
                        continue;
                }
 
-               rockchip_clk_add_lookup(clk, list->id);
+               rockchip_clk_add_lookup(ctx, clk, list->id);
        }
 }
 
-void __init rockchip_clk_register_armclk(unsigned int lookup_id,
+void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
+                       unsigned int lookup_id,
                        const char *name, const char *const *parent_names,
                        u8 num_parents,
                        const struct rockchip_cpuclk_reg_data *reg_data,
@@ -486,15 +514,15 @@ void __init rockchip_clk_register_armclk(unsigned int lookup_id,
        struct clk *clk;
 
        clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
-                                          reg_data, rates, nrates, reg_base,
-                                          &clk_lock);
+                                          reg_data, rates, nrates,
+                                          ctx->reg_base, &ctx->lock);
        if (IS_ERR(clk)) {
                pr_err("%s: failed to register clock %s: %ld\n",
                       __func__, name, PTR_ERR(clk));
                return;
        }
 
-       rockchip_clk_add_lookup(clk, lookup_id);
+       rockchip_clk_add_lookup(ctx, clk, lookup_id);
 }
 
 void __init rockchip_clk_protect_critical(const char *const clocks[],
@@ -511,6 +539,7 @@ void __init rockchip_clk_protect_critical(const char *const clocks[],
        }
 }
 
+static void __iomem *rst_base;
 static unsigned int reg_restart;
 static void (*cb_restart)(void);
 static int rockchip_restart_notify(struct notifier_block *this,
@@ -519,7 +548,7 @@ static int rockchip_restart_notify(struct notifier_block *this,
        if (cb_restart)
                cb_restart();
 
-       writel(0xfdb9, reg_base + reg_restart);
+       writel(0xfdb9, rst_base + reg_restart);
        return NOTIFY_DONE;
 }
 
@@ -528,10 +557,14 @@ static struct notifier_block rockchip_restart_handler = {
        .priority = 128,
 };
 
-void __init rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void))
+void __init
+rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
+                                              unsigned int reg,
+                                              void (*cb)(void))
 {
        int ret;
 
+       rst_base = ctx->reg_base;
        reg_restart = reg;
        cb_restart = cb;
        ret = register_restart_handler(&rockchip_restart_handler);