diff options
author | Mike Turquette <mturquette@linaro.org> | 2013-12-01 15:42:45 -0500 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2013-12-01 15:42:45 -0500 |
commit | 1d9438f7b560862fd0832355b4ad199b30e67478 (patch) | |
tree | 483dd72ab0064cf9690d4371056c2ed801220709 | |
parent | 4d04391cfe6446fb2f184d063b56a4dcce425334 (diff) | |
parent | e71c69fc3362b88b09194d486dda6d721a8004f6 (diff) |
Merge tag 'sunxi-clk-for-3.13' of https://github.com/mripard/linux into clk-next-sunxi-rebase
Allwinner sunXi SoCs clock changes
Those are mostly random fixes, except for one patch to the composite
clock that adds support for automatic reparenting.
Conflicts:
drivers/clk/sunxi/clk-sunxi.c
-rw-r--r-- | drivers/clk/clk-composite.c | 28 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.c | 4 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 58 |
3 files changed, 76 insertions, 14 deletions
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index a33f46f20a41..753d0b784762 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c | |||
@@ -55,6 +55,30 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, | |||
55 | return rate_ops->recalc_rate(rate_hw, parent_rate); | 55 | return rate_ops->recalc_rate(rate_hw, parent_rate); |
56 | } | 56 | } |
57 | 57 | ||
58 | static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
59 | unsigned long *best_parent_rate, | ||
60 | struct clk **best_parent_p) | ||
61 | { | ||
62 | struct clk_composite *composite = to_clk_composite(hw); | ||
63 | const struct clk_ops *rate_ops = composite->rate_ops; | ||
64 | const struct clk_ops *mux_ops = composite->mux_ops; | ||
65 | struct clk_hw *rate_hw = composite->rate_hw; | ||
66 | struct clk_hw *mux_hw = composite->mux_hw; | ||
67 | |||
68 | if (rate_hw && rate_ops && rate_ops->determine_rate) { | ||
69 | rate_hw->clk = hw->clk; | ||
70 | return rate_ops->determine_rate(rate_hw, rate, best_parent_rate, | ||
71 | best_parent_p); | ||
72 | } else if (mux_hw && mux_ops && mux_ops->determine_rate) { | ||
73 | mux_hw->clk = hw->clk; | ||
74 | return mux_ops->determine_rate(rate_hw, rate, best_parent_rate, | ||
75 | best_parent_p); | ||
76 | } else { | ||
77 | pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); | ||
78 | return 0; | ||
79 | } | ||
80 | } | ||
81 | |||
58 | static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate, | 82 | static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate, |
59 | unsigned long *prate) | 83 | unsigned long *prate) |
60 | { | 84 | { |
@@ -147,6 +171,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name, | |||
147 | composite->mux_ops = mux_ops; | 171 | composite->mux_ops = mux_ops; |
148 | clk_composite_ops->get_parent = clk_composite_get_parent; | 172 | clk_composite_ops->get_parent = clk_composite_get_parent; |
149 | clk_composite_ops->set_parent = clk_composite_set_parent; | 173 | clk_composite_ops->set_parent = clk_composite_set_parent; |
174 | if (mux_ops->determine_rate) | ||
175 | clk_composite_ops->determine_rate = clk_composite_determine_rate; | ||
150 | } | 176 | } |
151 | 177 | ||
152 | if (rate_hw && rate_ops) { | 178 | if (rate_hw && rate_ops) { |
@@ -170,6 +196,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name, | |||
170 | composite->rate_hw = rate_hw; | 196 | composite->rate_hw = rate_hw; |
171 | composite->rate_ops = rate_ops; | 197 | composite->rate_ops = rate_ops; |
172 | clk_composite_ops->recalc_rate = clk_composite_recalc_rate; | 198 | clk_composite_ops->recalc_rate = clk_composite_recalc_rate; |
199 | if (rate_ops->determine_rate) | ||
200 | clk_composite_ops->determine_rate = clk_composite_determine_rate; | ||
173 | } | 201 | } |
174 | 202 | ||
175 | if (gate_hw && gate_ops) { | 203 | if (gate_hw && gate_ops) { |
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 88523f91d9b7..f05207a27e5f 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c | |||
@@ -40,7 +40,7 @@ struct clk_factors { | |||
40 | 40 | ||
41 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) | 41 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) |
42 | 42 | ||
43 | #define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos)) | 43 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) |
44 | #define CLRMASK(len, pos) (~(SETMASK(len, pos))) | 44 | #define CLRMASK(len, pos) (~(SETMASK(len, pos))) |
45 | #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) | 45 | #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) |
46 | 46 | ||
@@ -88,7 +88,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, | |||
88 | static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, | 88 | static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, |
89 | unsigned long parent_rate) | 89 | unsigned long parent_rate) |
90 | { | 90 | { |
91 | u8 n, k, m, p; | 91 | u8 n = 0, k = 0, m = 0, p = 0; |
92 | u32 reg; | 92 | u32 reg; |
93 | struct clk_factors *factors = to_clk_factors(hw); | 93 | struct clk_factors *factors = to_clk_factors(hw); |
94 | struct clk_factors_config *config = factors->config; | 94 | struct clk_factors_config *config = factors->config; |
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 9bbd03514540..98fec4e4baa7 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -37,18 +37,16 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) | |||
37 | const char *clk_name = node->name; | 37 | const char *clk_name = node->name; |
38 | u32 rate; | 38 | u32 rate; |
39 | 39 | ||
40 | if (of_property_read_u32(node, "clock-frequency", &rate)) | ||
41 | return; | ||
42 | |||
40 | /* allocate fixed-rate and gate clock structs */ | 43 | /* allocate fixed-rate and gate clock structs */ |
41 | fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); | 44 | fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); |
42 | if (!fixed) | 45 | if (!fixed) |
43 | return; | 46 | return; |
44 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | 47 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); |
45 | if (!gate) { | 48 | if (!gate) |
46 | kfree(fixed); | 49 | goto err_free_fixed; |
47 | return; | ||
48 | } | ||
49 | |||
50 | if (of_property_read_u32(node, "clock-frequency", &rate)) | ||
51 | return; | ||
52 | 50 | ||
53 | /* set up gate and fixed rate properties */ | 51 | /* set up gate and fixed rate properties */ |
54 | gate->reg = of_iomap(node, 0); | 52 | gate->reg = of_iomap(node, 0); |
@@ -63,10 +61,18 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) | |||
63 | &gate->hw, &clk_gate_ops, | 61 | &gate->hw, &clk_gate_ops, |
64 | CLK_IS_ROOT); | 62 | CLK_IS_ROOT); |
65 | 63 | ||
66 | if (!IS_ERR(clk)) { | 64 | if (IS_ERR(clk)) |
67 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 65 | goto err_free_gate; |
68 | clk_register_clkdev(clk, clk_name, NULL); | 66 | |
69 | } | 67 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
68 | clk_register_clkdev(clk, clk_name, NULL); | ||
69 | |||
70 | return; | ||
71 | |||
72 | err_free_gate: | ||
73 | kfree(gate); | ||
74 | err_free_fixed: | ||
75 | kfree(fixed); | ||
70 | } | 76 | } |
71 | CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup); | 77 | CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup); |
72 | 78 | ||
@@ -616,7 +622,32 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat | |||
616 | } | 622 | } |
617 | } | 623 | } |
618 | 624 | ||
619 | static void __init sunxi_init_clocks(struct device_node *np) | 625 | /** |
626 | * System clock protection | ||
627 | * | ||
628 | * By enabling these critical clocks, we prevent their accidental gating | ||
629 | * by the framework | ||
630 | */ | ||
631 | static void __init sunxi_clock_protect(void) | ||
632 | { | ||
633 | struct clk *clk; | ||
634 | |||
635 | /* memory bus clock - sun5i+ */ | ||
636 | clk = clk_get(NULL, "mbus"); | ||
637 | if (!IS_ERR(clk)) { | ||
638 | clk_prepare_enable(clk); | ||
639 | clk_put(clk); | ||
640 | } | ||
641 | |||
642 | /* DDR clock - sun4i+ */ | ||
643 | clk = clk_get(NULL, "pll5_ddr"); | ||
644 | if (!IS_ERR(clk)) { | ||
645 | clk_prepare_enable(clk); | ||
646 | clk_put(clk); | ||
647 | } | ||
648 | } | ||
649 | |||
650 | static void __init sunxi_init_clocks(void) | ||
620 | { | 651 | { |
621 | /* Register factor clocks */ | 652 | /* Register factor clocks */ |
622 | of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); | 653 | of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); |
@@ -629,6 +660,9 @@ static void __init sunxi_init_clocks(struct device_node *np) | |||
629 | 660 | ||
630 | /* Register gate clocks */ | 661 | /* Register gate clocks */ |
631 | of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); | 662 | of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); |
663 | |||
664 | /* Enable core system clocks */ | ||
665 | sunxi_clock_protect(); | ||
632 | } | 666 | } |
633 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sunxi_init_clocks); | 667 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sunxi_init_clocks); |
634 | CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sunxi_init_clocks); | 668 | CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sunxi_init_clocks); |