diff options
Diffstat (limited to 'target/linux/sunxi/patches-3.12/110-clk-sunxi-fix-pll5-6.patch')
-rw-r--r-- | target/linux/sunxi/patches-3.12/110-clk-sunxi-fix-pll5-6.patch | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-3.12/110-clk-sunxi-fix-pll5-6.patch b/target/linux/sunxi/patches-3.12/110-clk-sunxi-fix-pll5-6.patch new file mode 100644 index 0000000000..ad5935c89f --- /dev/null +++ b/target/linux/sunxi/patches-3.12/110-clk-sunxi-fix-pll5-6.patch @@ -0,0 +1,149 @@ +From 11e7ff129807394d87c937b880bb58972dc91fc0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +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 + |