diff options
author | Jens Kuske <jenskuske@gmail.com> | 2015-12-04 16:24:40 -0500 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2015-12-08 03:11:53 -0500 |
commit | ab6e23a4e388f5f2696b8e92c350f845142da118 (patch) | |
tree | 646a03ca6d4c81870066d697af1838762a5a5971 | |
parent | 6d3a47c29186aa8d26ff05a6209c94291ace0696 (diff) |
clk: sunxi: Add H3 clocks support
The H3 clock control unit is similar to the those of other sun8i family
members like the A23.
It adds a new bus gates clock similar to the simple gates, but with a
different parent clock for each single gate.
Some of the gates use the new AHB2 clock as parent, whose clock source
is muxable between AHB1 and PLL6/2. The documentation isn't totally clear
about which devices belong to AHB2 now, especially USB EHIC/OHIC, so it
is mostly based on Allwinner kernel source code.
Signed-off-by: Jens Kuske <jenskuske@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
-rw-r--r-- | Documentation/devicetree/bindings/clock/sunxi.txt | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun8i-bus-gates.c | 112 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 6 |
4 files changed, 121 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index ef0b452806b1..014eab8673f5 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt | |||
@@ -29,6 +29,7 @@ Required properties: | |||
29 | "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31 | 29 | "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31 |
30 | "allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80 | 30 | "allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80 |
31 | "allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31 | 31 | "allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31 |
32 | "allwinner,sun8i-h3-ahb2-clk" - for the AHB2 clock on H3 | ||
32 | "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 | 33 | "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 |
33 | "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23 | 34 | "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23 |
34 | "allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80 | 35 | "allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80 |
@@ -56,6 +57,7 @@ Required properties: | |||
56 | "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80 | 57 | "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80 |
57 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 | 58 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 |
58 | "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 | 59 | "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 |
60 | "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3 | ||
59 | "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 | 61 | "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 |
60 | "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 | 62 | "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 |
61 | "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 | 63 | "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 |
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 103efab05ca8..abf4916f1f97 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile | |||
@@ -10,6 +10,7 @@ obj-y += clk-a10-pll2.o | |||
10 | obj-y += clk-a20-gmac.o | 10 | obj-y += clk-a20-gmac.o |
11 | obj-y += clk-mod0.o | 11 | obj-y += clk-mod0.o |
12 | obj-y += clk-simple-gates.o | 12 | obj-y += clk-simple-gates.o |
13 | obj-y += clk-sun8i-bus-gates.o | ||
13 | obj-y += clk-sun8i-mbus.o | 14 | obj-y += clk-sun8i-mbus.o |
14 | obj-y += clk-sun9i-core.o | 15 | obj-y += clk-sun9i-core.o |
15 | obj-y += clk-sun9i-mmc.o | 16 | obj-y += clk-sun9i-mmc.o |
diff --git a/drivers/clk/sunxi/clk-sun8i-bus-gates.c b/drivers/clk/sunxi/clk-sun8i-bus-gates.c new file mode 100644 index 000000000000..7ab60c59dc8d --- /dev/null +++ b/drivers/clk/sunxi/clk-sun8i-bus-gates.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com> | ||
3 | * | ||
4 | * Based on clk-simple-gates.c, which is: | ||
5 | * Copyright 2015 Maxime Ripard | ||
6 | * | ||
7 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #include <linux/clk.h> | ||
21 | #include <linux/clk-provider.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_address.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | |||
27 | static DEFINE_SPINLOCK(gates_lock); | ||
28 | |||
29 | static void __init sun8i_h3_bus_gates_init(struct device_node *node) | ||
30 | { | ||
31 | static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" }; | ||
32 | enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent; | ||
33 | const char *parents[PARENT_MAX]; | ||
34 | struct clk_onecell_data *clk_data; | ||
35 | const char *clk_name; | ||
36 | struct property *prop; | ||
37 | struct resource res; | ||
38 | void __iomem *clk_reg; | ||
39 | void __iomem *reg; | ||
40 | const __be32 *p; | ||
41 | int number, i; | ||
42 | u8 clk_bit; | ||
43 | u32 index; | ||
44 | |||
45 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
46 | if (IS_ERR(reg)) | ||
47 | return; | ||
48 | |||
49 | for (i = 0; i < ARRAY_SIZE(names); i++) { | ||
50 | index = of_property_match_string(node, "clock-names", | ||
51 | names[i]); | ||
52 | if (index < 0) | ||
53 | return; | ||
54 | |||
55 | parents[i] = of_clk_get_parent_name(node, index); | ||
56 | } | ||
57 | |||
58 | clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); | ||
59 | if (!clk_data) | ||
60 | goto err_unmap; | ||
61 | |||
62 | number = of_property_count_u32_elems(node, "clock-indices"); | ||
63 | of_property_read_u32_index(node, "clock-indices", number - 1, &number); | ||
64 | |||
65 | clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL); | ||
66 | if (!clk_data->clks) | ||
67 | goto err_free_data; | ||
68 | |||
69 | i = 0; | ||
70 | of_property_for_each_u32(node, "clock-indices", prop, p, index) { | ||
71 | of_property_read_string_index(node, "clock-output-names", | ||
72 | i, &clk_name); | ||
73 | |||
74 | if (index == 17 || (index >= 29 && index <= 31)) | ||
75 | clk_parent = AHB2; | ||
76 | else if (index <= 63 || index >= 128) | ||
77 | clk_parent = AHB1; | ||
78 | else if (index >= 64 && index <= 95) | ||
79 | clk_parent = APB1; | ||
80 | else if (index >= 96 && index <= 127) | ||
81 | clk_parent = APB2; | ||
82 | |||
83 | clk_reg = reg + 4 * (index / 32); | ||
84 | clk_bit = index % 32; | ||
85 | |||
86 | clk_data->clks[index] = clk_register_gate(NULL, clk_name, | ||
87 | parents[clk_parent], | ||
88 | 0, clk_reg, clk_bit, | ||
89 | 0, &gates_lock); | ||
90 | i++; | ||
91 | |||
92 | if (IS_ERR(clk_data->clks[index])) { | ||
93 | WARN_ON(true); | ||
94 | continue; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | clk_data->clk_num = number + 1; | ||
99 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | ||
100 | |||
101 | return; | ||
102 | |||
103 | err_free_data: | ||
104 | kfree(clk_data); | ||
105 | err_unmap: | ||
106 | iounmap(reg); | ||
107 | of_address_to_resource(node, 0, &res); | ||
108 | release_mem_region(res.start, resource_size(&res)); | ||
109 | } | ||
110 | |||
111 | CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk", | ||
112 | sun8i_h3_bus_gates_init); | ||
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 9c79af0c03b2..5ba2188ee99c 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -778,6 +778,10 @@ static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = { | |||
778 | .shift = 12, | 778 | .shift = 12, |
779 | }; | 779 | }; |
780 | 780 | ||
781 | static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = { | ||
782 | .shift = 0, | ||
783 | }; | ||
784 | |||
781 | static void __init sunxi_mux_clk_setup(struct device_node *node, | 785 | static void __init sunxi_mux_clk_setup(struct device_node *node, |
782 | struct mux_data *data) | 786 | struct mux_data *data) |
783 | { | 787 | { |
@@ -1130,6 +1134,7 @@ static const struct of_device_id clk_divs_match[] __initconst = { | |||
1130 | static const struct of_device_id clk_mux_match[] __initconst = { | 1134 | static const struct of_device_id clk_mux_match[] __initconst = { |
1131 | {.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,}, | 1135 | {.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,}, |
1132 | {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,}, | 1136 | {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,}, |
1137 | {.compatible = "allwinner,sun8i-h3-ahb2-clk", .data = &sun8i_h3_ahb2_mux_data,}, | ||
1133 | {} | 1138 | {} |
1134 | }; | 1139 | }; |
1135 | 1140 | ||
@@ -1212,6 +1217,7 @@ CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); | |||
1212 | CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks); | 1217 | CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks); |
1213 | CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); | 1218 | CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); |
1214 | CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks); | 1219 | CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks); |
1220 | CLK_OF_DECLARE(sun8i_h3_clk_init, "allwinner,sun8i-h3", sun6i_init_clocks); | ||
1215 | 1221 | ||
1216 | static void __init sun9i_init_clocks(struct device_node *node) | 1222 | static void __init sun9i_init_clocks(struct device_node *node) |
1217 | { | 1223 | { |