UPSTREAM: clk: rockchip: add a factor clock type
authorHeiko Stuebner <heiko@sntech.de>
Sat, 20 Jun 2015 11:08:57 +0000 (13:08 +0200)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 1 Mar 2016 09:11:44 +0000 (17:11 +0800)
Add a clock type for fixed factor clocks. This allows us to define fixed
factor clocks where they appear in the clock hierarchy instead of in the
init function.

The additional factor_gate type, finally allows us to model some last
parts of the clock tree correctly.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
(cherry picked from commit 29a30c269aba4223e2a8b443f443d7def1e43fea)

Change-Id: Ie4ec8b9d9199cdbe0be045c2ed4c270029e37949
Signed-off-by: Xing Zheng <zhengxing@rock-chips.com>
drivers/clk/rockchip/clk.c
drivers/clk/rockchip/clk.h

index 9b642e0357daf7a7a7c569a7b6ddcb365cf195fb..3c73703fb180edbebac82382adaf8669cc417cba 100644 (file)
@@ -262,6 +262,53 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name,
        return clk;
 }
 
+static struct clk *rockchip_clk_register_factor_branch(const char *name,
+               const char *const *parent_names, u8 num_parents,
+               void __iomem *base, unsigned int mult, unsigned int div,
+               int gate_offset, u8 gate_shift, u8 gate_flags,
+               unsigned long flags, spinlock_t *lock)
+{
+       struct clk *clk;
+       struct clk_gate *gate = NULL;
+       struct clk_fixed_factor *fix = NULL;
+
+       /* without gate, register a simple factor clock */
+       if (gate_offset == 0) {
+               return clk_register_fixed_factor(NULL, name,
+                               parent_names[0], flags, mult,
+                               div);
+       }
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate)
+               return ERR_PTR(-ENOMEM);
+
+       gate->flags = gate_flags;
+       gate->reg = base + gate_offset;
+       gate->bit_idx = gate_shift;
+       gate->lock = lock;
+
+       fix = kzalloc(sizeof(*fix), GFP_KERNEL);
+       if (!fix) {
+               kfree(gate);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       fix->mult = mult;
+       fix->div = div;
+
+       clk = clk_register_composite(NULL, name, parent_names, num_parents,
+                                    NULL, NULL,
+                                    &fix->hw, &clk_fixed_factor_ops,
+                                    &gate->hw, &clk_gate_ops, flags);
+       if (IS_ERR(clk)) {
+               kfree(fix);
+               kfree(gate);
+       }
+
+       return clk;
+}
+
 static DEFINE_SPINLOCK(clk_lock);
 static struct clk **clk_table;
 static void __iomem *reg_base;
@@ -397,6 +444,14 @@ void __init rockchip_clk_register_branches(
                                reg_base + list->muxdiv_offset,
                                list->div_shift, list->div_flags, &clk_lock);
                        break;
+               case branch_factor:
+                       clk = rockchip_clk_register_factor_branch(
+                               list->name, list->parent_names,
+                               list->num_parents, reg_base,
+                               list->div_shift, list->div_width,
+                               list->gate_offset, list->gate_shift,
+                               list->gate_flags, flags, &clk_lock);
+                       break;
                }
 
                /* none of the cases above matched */
index e97171dad82470633282873e77be8cc544e4e722..cb8f405b607d3dde50b1bf6090019d8af07a44bd 100644 (file)
@@ -246,6 +246,7 @@ enum rockchip_clk_branch_type {
        branch_gate,
        branch_mmc,
        branch_inverter,
+       branch_factor,
 };
 
 struct rockchip_clk_branch {
@@ -500,6 +501,33 @@ struct rockchip_clk_branch {
                .div_flags      = if,                           \
        }
 
+#define FACTOR(_id, cname, pname,  f, fm, fd)                  \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_factor,                \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .div_shift      = fm,                           \
+               .div_width      = fd,                           \
+       }
+
+#define FACTOR_GATE(_id, cname, pname,  f, fm, fd, go, gb, gf) \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_factor,                \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .div_shift      = fm,                           \
+               .div_width      = fd,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gb,                           \
+               .gate_flags     = gf,                           \
+       }
+
 void rockchip_clk_init(struct device_node *np, void __iomem *base,
                       unsigned long nr_clks);
 struct regmap *rockchip_clk_get_grf(void);