From 11e7ff129807394d87c937b880bb58972dc91fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Thu, 28 Nov 2013 09:00:47 -0300 Subject: [PATCH] fixup! clk: sunxi: add PLL5 and PLL6 support --- drivers/clk/sunxi/clk-sunxi.c | 83 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index d2b8d3c..3ce33b8 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -807,10 +807,11 @@ struct divs_data { struct clk_div_table *table; /* is it a table based divisor? */ u8 shift; /* otherwise it's a normal divisor with this shift */ u8 pow; /* is it power-of-two based? */ + u8 gate; /* is it independently gateable? */ } div[SUNXI_DIVS_MAX_QTY]; }; -static struct clk_div_table pll6_sata_table[] = { +static struct clk_div_table pll6_sata_tbl[] = { { .val = 0, .div = 6, }, { .val = 1, .div = 12, }, { .val = 2, .div = 18, }, @@ -829,7 +830,7 @@ struct divs_data { static const struct divs_data pll6_divs_data __initconst = { .factors = &sun4i_pll5_data, .div = { - { .shift = 0, .table = pll6_sata_table }, /* M, SATA */ + { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ { .fixed = 2 }, /* P, other */ } }; @@ -852,6 +853,11 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, const char *parent = node->name; const char *clk_name; struct clk **clks, *pclk; + struct clk_hw *gate_hw, *rate_hw; + const struct clk_ops *rate_ops; + struct clk_gate *gate = NULL; + struct clk_fixed_factor *fix_factor; + struct clk_divider *divider; void *reg; int i = 0; int flags, clkflags; @@ -866,10 +872,9 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, return; clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL); - if (!clks) { - kfree(clk_data); - return; - } + if (!clks) + goto free_clkdata; + clk_data->clks = clks; /* It's not a good idea to have automatic reparenting changing @@ -881,19 +886,60 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, i, &clk_name) != 0) break; + gate_hw = NULL; + rate_hw = NULL; + rate_ops = NULL; + + /* If this leaf clock can be gated, create a gate */ + if (data->div[i].gate) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto free_clks; + + gate->reg = reg; + gate->bit_idx = data->div[i].gate; + gate->lock = &clk_lock; + + gate_hw = &gate->hw; + } + + /* Leaves can be fixed or configurable divisors */ if (data->div[i].fixed) { - clks[i] = clk_register_fixed_factor(NULL, clk_name, - parent, clkflags, - 1, data->div[i].fixed); + fix_factor = kzalloc(sizeof(*fix_factor), GFP_KERNEL); + if (!fix_factor) + goto free_gate; + + fix_factor->mult = 1; + fix_factor->div = data->div[i].fixed; + + rate_hw = &fix_factor->hw; + rate_ops = &clk_fixed_factor_ops; } else { + divider = kzalloc(sizeof(*divider), GFP_KERNEL); + if (!divider) + goto free_gate; + flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0; - clks[i] = clk_register_divider_table(NULL, clk_name, - parent, clkflags, reg, - data->div[i].shift, - SUNXI_DIVISOR_WIDTH, flags, - data->div[i].table, &clk_lock); + + divider->reg = reg; + divider->shift = data->div[i].shift; + divider->width = SUNXI_DIVISOR_WIDTH; + divider->flags = flags; + divider->lock = &clk_lock; + divider->table = data->div[i].table; + + rate_hw = ÷r->hw; + rate_ops = &clk_divider_ops; } + /* Wrap the (potential) gate and the divisor on a composite + * clock to unify them */ + clks[i] = clk_register_composite(NULL, clk_name, &parent, 1, + NULL, NULL, + rate_hw, rate_ops, + gate_hw, &clk_gate_ops, + clkflags); + WARN_ON(IS_ERR(clk_data->clks[i])); clk_register_clkdev(clks[i], clk_name, NULL); } @@ -905,6 +951,15 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, clk_data->clk_num = i; of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + return; + +free_gate: + kfree(gate); +free_clks: + kfree(clks); +free_clkdata: + kfree(clk_data); } -- 1.8.5.1