diff options
author | Emilio López <emilio@elopez.com.ar> | 2013-12-22 22:32:37 -0500 |
---|---|---|
committer | Emilio López <emilio@elopez.com.ar> | 2013-12-28 15:08:17 -0500 |
commit | d584c1331d6421e2387eab10b11fa6f08b4a4b5f (patch) | |
tree | 7c1d6a78ae45ac0aed61a96ae856f9cd295f70a3 | |
parent | 5f4e0be3a72325fbc4d349a847cc9b2edd85b6d2 (diff) |
clk: sunxi: add PLL5 and PLL6 support
This commit implements PLL5 and PLL6 support on the sunxi clock driver.
These PLLs use a similar factor clock, but differ on their outputs.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Acked-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | Documentation/devicetree/bindings/clock/sunxi.txt | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 230 |
2 files changed, 232 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index b8c6cc449a3e..80b2a39b17a2 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt | |||
@@ -9,6 +9,8 @@ Required properties: | |||
9 | "allwinner,sun4i-osc-clk" - for a gatable oscillator | 9 | "allwinner,sun4i-osc-clk" - for a gatable oscillator |
10 | "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4 | 10 | "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4 |
11 | "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 | 11 | "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 |
12 | "allwinner,sun4i-pll5-clk" - for the PLL5 clock | ||
13 | "allwinner,sun4i-pll6-clk" - for the PLL6 clock | ||
12 | "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock | 14 | "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock |
13 | "allwinner,sun4i-axi-clk" - for the AXI clock | 15 | "allwinner,sun4i-axi-clk" - for the AXI clock |
14 | "allwinner,sun4i-axi-gates-clk" - for the AXI gates | 16 | "allwinner,sun4i-axi-gates-clk" - for the AXI gates |
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 31e1fe1d2aea..e90df083a36d 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -218,6 +218,40 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate, | |||
218 | } | 218 | } |
219 | 219 | ||
220 | /** | 220 | /** |
221 | * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 | ||
222 | * PLL5 rate is calculated as follows | ||
223 | * rate = parent_rate * n * (k + 1) | ||
224 | * parent_rate is always 24Mhz | ||
225 | */ | ||
226 | |||
227 | static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, | ||
228 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
229 | { | ||
230 | u8 div; | ||
231 | |||
232 | /* Normalize value to a parent_rate multiple (24M) */ | ||
233 | div = *freq / parent_rate; | ||
234 | *freq = parent_rate * div; | ||
235 | |||
236 | /* we were called to round the frequency, we can now return */ | ||
237 | if (n == NULL) | ||
238 | return; | ||
239 | |||
240 | if (div < 31) | ||
241 | *k = 0; | ||
242 | else if (div / 2 < 31) | ||
243 | *k = 1; | ||
244 | else if (div / 3 < 31) | ||
245 | *k = 2; | ||
246 | else | ||
247 | *k = 3; | ||
248 | |||
249 | *n = DIV_ROUND_UP(div, (*k+1)); | ||
250 | } | ||
251 | |||
252 | |||
253 | |||
254 | /** | ||
221 | * sun4i_get_apb1_factors() - calculates m, p factors for APB1 | 255 | * sun4i_get_apb1_factors() - calculates m, p factors for APB1 |
222 | * APB1 rate is calculated as follows | 256 | * APB1 rate is calculated as follows |
223 | * rate = (parent_rate >> p) / (m + 1); | 257 | * rate = (parent_rate >> p) / (m + 1); |
@@ -293,6 +327,13 @@ static struct clk_factors_config sun6i_a31_pll1_config = { | |||
293 | .mwidth = 2, | 327 | .mwidth = 2, |
294 | }; | 328 | }; |
295 | 329 | ||
330 | static struct clk_factors_config sun4i_pll5_config = { | ||
331 | .nshift = 8, | ||
332 | .nwidth = 5, | ||
333 | .kshift = 4, | ||
334 | .kwidth = 2, | ||
335 | }; | ||
336 | |||
296 | static struct clk_factors_config sun4i_apb1_config = { | 337 | static struct clk_factors_config sun4i_apb1_config = { |
297 | .mshift = 0, | 338 | .mshift = 0, |
298 | .mwidth = 5, | 339 | .mwidth = 5, |
@@ -312,6 +353,12 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = { | |||
312 | .getter = sun6i_a31_get_pll1_factors, | 353 | .getter = sun6i_a31_get_pll1_factors, |
313 | }; | 354 | }; |
314 | 355 | ||
356 | static const struct factors_data sun4i_pll5_data __initconst = { | ||
357 | .enable = 31, | ||
358 | .table = &sun4i_pll5_config, | ||
359 | .getter = sun4i_get_pll5_factors, | ||
360 | }; | ||
361 | |||
315 | static const struct factors_data sun4i_apb1_data __initconst = { | 362 | static const struct factors_data sun4i_apb1_data __initconst = { |
316 | .table = &sun4i_apb1_config, | 363 | .table = &sun4i_apb1_config, |
317 | .getter = sun4i_get_apb1_factors, | 364 | .getter = sun4i_get_apb1_factors, |
@@ -627,6 +674,179 @@ static void __init sunxi_gates_clk_setup(struct device_node *node, | |||
627 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | 674 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); |
628 | } | 675 | } |
629 | 676 | ||
677 | |||
678 | |||
679 | /** | ||
680 | * sunxi_divs_clk_setup() helper data | ||
681 | */ | ||
682 | |||
683 | #define SUNXI_DIVS_MAX_QTY 2 | ||
684 | #define SUNXI_DIVISOR_WIDTH 2 | ||
685 | |||
686 | struct divs_data { | ||
687 | const struct factors_data *factors; /* data for the factor clock */ | ||
688 | struct { | ||
689 | u8 fixed; /* is it a fixed divisor? if not... */ | ||
690 | struct clk_div_table *table; /* is it a table based divisor? */ | ||
691 | u8 shift; /* otherwise it's a normal divisor with this shift */ | ||
692 | u8 pow; /* is it power-of-two based? */ | ||
693 | u8 gate; /* is it independently gateable? */ | ||
694 | } div[SUNXI_DIVS_MAX_QTY]; | ||
695 | }; | ||
696 | |||
697 | static struct clk_div_table pll6_sata_tbl[] = { | ||
698 | { .val = 0, .div = 6, }, | ||
699 | { .val = 1, .div = 12, }, | ||
700 | { .val = 2, .div = 18, }, | ||
701 | { .val = 3, .div = 24, }, | ||
702 | { } /* sentinel */ | ||
703 | }; | ||
704 | |||
705 | static const struct divs_data pll5_divs_data __initconst = { | ||
706 | .factors = &sun4i_pll5_data, | ||
707 | .div = { | ||
708 | { .shift = 0, .pow = 0, }, /* M, DDR */ | ||
709 | { .shift = 16, .pow = 1, }, /* P, other */ | ||
710 | } | ||
711 | }; | ||
712 | |||
713 | static const struct divs_data pll6_divs_data __initconst = { | ||
714 | .factors = &sun4i_pll5_data, | ||
715 | .div = { | ||
716 | { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ | ||
717 | { .fixed = 2 }, /* P, other */ | ||
718 | } | ||
719 | }; | ||
720 | |||
721 | /** | ||
722 | * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks | ||
723 | * | ||
724 | * These clocks look something like this | ||
725 | * ________________________ | ||
726 | * | ___divisor 1---|----> to consumer | ||
727 | * parent >--| pll___/___divisor 2---|----> to consumer | ||
728 | * | \_______________|____> to consumer | ||
729 | * |________________________| | ||
730 | */ | ||
731 | |||
732 | static void __init sunxi_divs_clk_setup(struct device_node *node, | ||
733 | struct divs_data *data) | ||
734 | { | ||
735 | struct clk_onecell_data *clk_data; | ||
736 | const char *parent = node->name; | ||
737 | const char *clk_name; | ||
738 | struct clk **clks, *pclk; | ||
739 | struct clk_hw *gate_hw, *rate_hw; | ||
740 | const struct clk_ops *rate_ops; | ||
741 | struct clk_gate *gate = NULL; | ||
742 | struct clk_fixed_factor *fix_factor; | ||
743 | struct clk_divider *divider; | ||
744 | void *reg; | ||
745 | int i = 0; | ||
746 | int flags, clkflags; | ||
747 | |||
748 | /* Set up factor clock that we will be dividing */ | ||
749 | pclk = sunxi_factors_clk_setup(node, data->factors); | ||
750 | |||
751 | reg = of_iomap(node, 0); | ||
752 | |||
753 | clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); | ||
754 | if (!clk_data) | ||
755 | return; | ||
756 | |||
757 | clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL); | ||
758 | if (!clks) | ||
759 | goto free_clkdata; | ||
760 | |||
761 | clk_data->clks = clks; | ||
762 | |||
763 | /* It's not a good idea to have automatic reparenting changing | ||
764 | * our RAM clock! */ | ||
765 | clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT; | ||
766 | |||
767 | for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) { | ||
768 | if (of_property_read_string_index(node, "clock-output-names", | ||
769 | i, &clk_name) != 0) | ||
770 | break; | ||
771 | |||
772 | gate_hw = NULL; | ||
773 | rate_hw = NULL; | ||
774 | rate_ops = NULL; | ||
775 | |||
776 | /* If this leaf clock can be gated, create a gate */ | ||
777 | if (data->div[i].gate) { | ||
778 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | ||
779 | if (!gate) | ||
780 | goto free_clks; | ||
781 | |||
782 | gate->reg = reg; | ||
783 | gate->bit_idx = data->div[i].gate; | ||
784 | gate->lock = &clk_lock; | ||
785 | |||
786 | gate_hw = &gate->hw; | ||
787 | } | ||
788 | |||
789 | /* Leaves can be fixed or configurable divisors */ | ||
790 | if (data->div[i].fixed) { | ||
791 | fix_factor = kzalloc(sizeof(*fix_factor), GFP_KERNEL); | ||
792 | if (!fix_factor) | ||
793 | goto free_gate; | ||
794 | |||
795 | fix_factor->mult = 1; | ||
796 | fix_factor->div = data->div[i].fixed; | ||
797 | |||
798 | rate_hw = &fix_factor->hw; | ||
799 | rate_ops = &clk_fixed_factor_ops; | ||
800 | } else { | ||
801 | divider = kzalloc(sizeof(*divider), GFP_KERNEL); | ||
802 | if (!divider) | ||
803 | goto free_gate; | ||
804 | |||
805 | flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0; | ||
806 | |||
807 | divider->reg = reg; | ||
808 | divider->shift = data->div[i].shift; | ||
809 | divider->width = SUNXI_DIVISOR_WIDTH; | ||
810 | divider->flags = flags; | ||
811 | divider->lock = &clk_lock; | ||
812 | divider->table = data->div[i].table; | ||
813 | |||
814 | rate_hw = ÷r->hw; | ||
815 | rate_ops = &clk_divider_ops; | ||
816 | } | ||
817 | |||
818 | /* Wrap the (potential) gate and the divisor on a composite | ||
819 | * clock to unify them */ | ||
820 | clks[i] = clk_register_composite(NULL, clk_name, &parent, 1, | ||
821 | NULL, NULL, | ||
822 | rate_hw, rate_ops, | ||
823 | gate_hw, &clk_gate_ops, | ||
824 | clkflags); | ||
825 | |||
826 | WARN_ON(IS_ERR(clk_data->clks[i])); | ||
827 | clk_register_clkdev(clks[i], clk_name, NULL); | ||
828 | } | ||
829 | |||
830 | /* The last clock available on the getter is the parent */ | ||
831 | clks[i++] = pclk; | ||
832 | |||
833 | /* Adjust to the real max */ | ||
834 | clk_data->clk_num = i; | ||
835 | |||
836 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | ||
837 | |||
838 | return; | ||
839 | |||
840 | free_gate: | ||
841 | kfree(gate); | ||
842 | free_clks: | ||
843 | kfree(clks); | ||
844 | free_clkdata: | ||
845 | kfree(clk_data); | ||
846 | } | ||
847 | |||
848 | |||
849 | |||
630 | /* Matches for factors clocks */ | 850 | /* Matches for factors clocks */ |
631 | static const struct of_device_id clk_factors_match[] __initconst = { | 851 | static const struct of_device_id clk_factors_match[] __initconst = { |
632 | {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, | 852 | {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, |
@@ -644,6 +864,13 @@ static const struct of_device_id clk_div_match[] __initconst = { | |||
644 | {} | 864 | {} |
645 | }; | 865 | }; |
646 | 866 | ||
867 | /* Matches for divided outputs */ | ||
868 | static const struct of_device_id clk_divs_match[] __initconst = { | ||
869 | {.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,}, | ||
870 | {.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,}, | ||
871 | {} | ||
872 | }; | ||
873 | |||
647 | /* Matches for mux clocks */ | 874 | /* Matches for mux clocks */ |
648 | static const struct of_device_id clk_mux_match[] __initconst = { | 875 | static const struct of_device_id clk_mux_match[] __initconst = { |
649 | {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,}, | 876 | {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,}, |
@@ -721,6 +948,9 @@ static void __init sunxi_init_clocks(void) | |||
721 | /* Register divider clocks */ | 948 | /* Register divider clocks */ |
722 | of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); | 949 | of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); |
723 | 950 | ||
951 | /* Register divided output clocks */ | ||
952 | of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup); | ||
953 | |||
724 | /* Register mux clocks */ | 954 | /* Register mux clocks */ |
725 | of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); | 955 | of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); |
726 | 956 | ||