diff options
-rw-r--r-- | Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt | 76 | ||||
-rw-r--r-- | drivers/clk/mvebu/Kconfig | 2 | ||||
-rw-r--r-- | drivers/clk/mvebu/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/mvebu/clk-gating-ctrl.c | 177 | ||||
-rw-r--r-- | drivers/clk/mvebu/clk-gating-ctrl.h | 22 | ||||
-rw-r--r-- | drivers/clk/mvebu/clk.c | 2 |
6 files changed, 280 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt new file mode 100644 index 00000000000..4ad8ccd15e6 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt | |||
@@ -0,0 +1,76 @@ | |||
1 | * Gated Clock bindings for Marvell Orion SoCs | ||
2 | |||
3 | Marvell Dove and Kirkwood allow some peripheral clocks to be gated to save | ||
4 | some power. The clock consumer should specify the desired clock by having | ||
5 | the clock ID in its "clocks" phandle cell. The clock ID is directly mapped to | ||
6 | the corresponding clock gating control bit in HW to ease manual clock lookup | ||
7 | in datasheet. | ||
8 | |||
9 | The following is a list of provided IDs for Dove: | ||
10 | ID Clock Peripheral | ||
11 | ----------------------------------- | ||
12 | 0 usb0 USB Host 0 | ||
13 | 1 usb1 USB Host 1 | ||
14 | 2 ge Gigabit Ethernet | ||
15 | 3 sata SATA Host | ||
16 | 4 pex0 PCIe Cntrl 0 | ||
17 | 5 pex1 PCIe Cntrl 1 | ||
18 | 8 sdio0 SDHCI Host 0 | ||
19 | 9 sdio1 SDHCI Host 1 | ||
20 | 10 nand NAND Cntrl | ||
21 | 11 camera Camera Cntrl | ||
22 | 12 i2s0 I2S Cntrl 0 | ||
23 | 13 i2s1 I2S Cntrl 1 | ||
24 | 15 crypto CESA engine | ||
25 | 21 ac97 AC97 Cntrl | ||
26 | 22 pdma Peripheral DMA | ||
27 | 23 xor0 XOR DMA 0 | ||
28 | 24 xor1 XOR DMA 1 | ||
29 | 30 gephy Gigabit Ethernel PHY | ||
30 | Note: gephy(30) is implemented as a parent clock of ge(2) | ||
31 | |||
32 | The following is a list of provided IDs for Kirkwood: | ||
33 | ID Clock Peripheral | ||
34 | ----------------------------------- | ||
35 | 0 ge0 Gigabit Ethernet 0 | ||
36 | 2 pex0 PCIe Cntrl 0 | ||
37 | 3 usb0 USB Host 0 | ||
38 | 4 sdio SDIO Cntrl | ||
39 | 5 tsu Transp. Stream Unit | ||
40 | 6 dunit SDRAM Cntrl | ||
41 | 7 runit Runit | ||
42 | 8 xor0 XOR DMA 0 | ||
43 | 9 audio I2S Cntrl 0 | ||
44 | 14 sata0 SATA Host 0 | ||
45 | 15 sata1 SATA Host 1 | ||
46 | 16 xor1 XOR DMA 1 | ||
47 | 17 crypto CESA engine | ||
48 | 18 pex1 PCIe Cntrl 1 | ||
49 | 19 ge1 Gigabit Ethernet 0 | ||
50 | 20 tdm Time Division Mplx | ||
51 | |||
52 | Required properties: | ||
53 | - compatible : shall be one of the following: | ||
54 | "marvell,dove-gating-clock" - for Dove SoC clock gating | ||
55 | "marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating | ||
56 | - reg : shall be the register address of the Clock Gating Control register | ||
57 | - #clock-cells : from common clock binding; shall be set to 1 | ||
58 | |||
59 | Optional properties: | ||
60 | - clocks : default parent clock phandle (e.g. tclk) | ||
61 | |||
62 | Example: | ||
63 | |||
64 | gate_clk: clock-gating-control@d0038 { | ||
65 | compatible = "marvell,dove-gating-clock"; | ||
66 | reg = <0xd0038 0x4>; | ||
67 | /* default parent clock is tclk */ | ||
68 | clocks = <&core_clk 0>; | ||
69 | #clock-cells = <1>; | ||
70 | }; | ||
71 | |||
72 | sdio0: sdio@92000 { | ||
73 | compatible = "marvell,dove-sdhci"; | ||
74 | /* get clk gate bit 8 (sdio0) */ | ||
75 | clocks = <&gate_clk 8>; | ||
76 | }; | ||
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 1dd93ada9cb..57323fd15ec 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig | |||
@@ -4,3 +4,5 @@ config MVEBU_CLK_CORE | |||
4 | config MVEBU_CLK_CPU | 4 | config MVEBU_CLK_CPU |
5 | bool | 5 | bool |
6 | 6 | ||
7 | config MVEBU_CLK_GATING | ||
8 | bool | ||
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 93da083b77e..58df3dc4936 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | obj-$(CONFIG_MVEBU_CLK_CORE) += clk.o clk-core.o | 1 | obj-$(CONFIG_MVEBU_CLK_CORE) += clk.o clk-core.o |
2 | obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o | 2 | obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o |
3 | obj-$(CONFIG_MVEBU_CLK_GATING) += clk-gating-ctrl.o | ||
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c new file mode 100644 index 00000000000..fa69f87c579 --- /dev/null +++ b/drivers/clk/mvebu/clk-gating-ctrl.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Marvell MVEBU clock gating control. | ||
3 | * | ||
4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
5 | * Andrew Lunn <andrew@lunn.ch> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/bitops.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/clkdev.h> | ||
16 | #include <linux/clk-provider.h> | ||
17 | #include <linux/clk/mvebu.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_address.h> | ||
20 | |||
21 | struct mvebu_gating_ctrl { | ||
22 | spinlock_t lock; | ||
23 | struct clk **gates; | ||
24 | int num_gates; | ||
25 | }; | ||
26 | |||
27 | struct mvebu_soc_descr { | ||
28 | const char *name; | ||
29 | const char *parent; | ||
30 | int bit_idx; | ||
31 | }; | ||
32 | |||
33 | #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) | ||
34 | |||
35 | static struct clk __init *mvebu_clk_gating_get_src( | ||
36 | struct of_phandle_args *clkspec, void *data) | ||
37 | { | ||
38 | struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data; | ||
39 | int n; | ||
40 | |||
41 | if (clkspec->args_count < 1) | ||
42 | return ERR_PTR(-EINVAL); | ||
43 | |||
44 | for (n = 0; n < ctrl->num_gates; n++) { | ||
45 | struct clk_gate *gate = | ||
46 | to_clk_gate(__clk_get_hw(ctrl->gates[n])); | ||
47 | if (clkspec->args[0] == gate->bit_idx) | ||
48 | return ctrl->gates[n]; | ||
49 | } | ||
50 | return ERR_PTR(-ENODEV); | ||
51 | } | ||
52 | |||
53 | static void __init mvebu_clk_gating_setup( | ||
54 | struct device_node *np, const struct mvebu_soc_descr *descr) | ||
55 | { | ||
56 | struct mvebu_gating_ctrl *ctrl; | ||
57 | struct clk *clk; | ||
58 | void __iomem *base; | ||
59 | const char *default_parent = NULL; | ||
60 | int n; | ||
61 | |||
62 | base = of_iomap(np, 0); | ||
63 | |||
64 | clk = of_clk_get(np, 0); | ||
65 | if (!IS_ERR(clk)) { | ||
66 | default_parent = __clk_get_name(clk); | ||
67 | clk_put(clk); | ||
68 | } | ||
69 | |||
70 | ctrl = kzalloc(sizeof(struct mvebu_gating_ctrl), GFP_KERNEL); | ||
71 | if (WARN_ON(!ctrl)) | ||
72 | return; | ||
73 | |||
74 | spin_lock_init(&ctrl->lock); | ||
75 | |||
76 | /* | ||
77 | * Count, allocate, and register clock gates | ||
78 | */ | ||
79 | for (n = 0; descr[n].name;) | ||
80 | n++; | ||
81 | |||
82 | ctrl->num_gates = n; | ||
83 | ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *), | ||
84 | GFP_KERNEL); | ||
85 | if (WARN_ON(!ctrl->gates)) { | ||
86 | kfree(ctrl); | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | for (n = 0; n < ctrl->num_gates; n++) { | ||
91 | const char *parent = | ||
92 | (descr[n].parent) ? descr[n].parent : default_parent; | ||
93 | ctrl->gates[n] = clk_register_gate(NULL, descr[n].name, parent, | ||
94 | 0, base, descr[n].bit_idx, 0, &ctrl->lock); | ||
95 | WARN_ON(IS_ERR(ctrl->gates[n])); | ||
96 | } | ||
97 | of_clk_add_provider(np, mvebu_clk_gating_get_src, ctrl); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * SoC specific clock gating control | ||
102 | */ | ||
103 | |||
104 | #ifdef CONFIG_ARCH_DOVE | ||
105 | static const struct mvebu_soc_descr __initconst dove_gating_descr[] = { | ||
106 | { "usb0", NULL, 0 }, | ||
107 | { "usb1", NULL, 1 }, | ||
108 | { "ge", "gephy", 2 }, | ||
109 | { "sata", NULL, 3 }, | ||
110 | { "pex0", NULL, 4 }, | ||
111 | { "pex1", NULL, 5 }, | ||
112 | { "sdio0", NULL, 8 }, | ||
113 | { "sdio1", NULL, 9 }, | ||
114 | { "nand", NULL, 10 }, | ||
115 | { "camera", NULL, 11 }, | ||
116 | { "i2s0", NULL, 12 }, | ||
117 | { "i2s1", NULL, 13 }, | ||
118 | { "crypto", NULL, 15 }, | ||
119 | { "ac97", NULL, 21 }, | ||
120 | { "pdma", NULL, 22 }, | ||
121 | { "xor0", NULL, 23 }, | ||
122 | { "xor1", NULL, 24 }, | ||
123 | { "gephy", NULL, 30 }, | ||
124 | { } | ||
125 | }; | ||
126 | #endif | ||
127 | |||
128 | #ifdef CONFIG_ARCH_KIRKWOOD | ||
129 | static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = { | ||
130 | { "ge0", NULL, 0 }, | ||
131 | { "pex0", NULL, 2 }, | ||
132 | { "usb0", NULL, 3 }, | ||
133 | { "sdio", NULL, 4 }, | ||
134 | { "tsu", NULL, 5 }, | ||
135 | { "runit", NULL, 7 }, | ||
136 | { "xor0", NULL, 8 }, | ||
137 | { "audio", NULL, 9 }, | ||
138 | { "sata0", NULL, 14 }, | ||
139 | { "sata1", NULL, 15 }, | ||
140 | { "xor1", NULL, 16 }, | ||
141 | { "crypto", NULL, 17 }, | ||
142 | { "pex1", NULL, 18 }, | ||
143 | { "ge1", NULL, 19 }, | ||
144 | { "tdm", NULL, 20 }, | ||
145 | { } | ||
146 | }; | ||
147 | #endif | ||
148 | |||
149 | static const __initdata struct of_device_id clk_gating_match[] = { | ||
150 | #ifdef CONFIG_ARCH_DOVE | ||
151 | { | ||
152 | .compatible = "marvell,dove-gating-clock", | ||
153 | .data = dove_gating_descr, | ||
154 | }, | ||
155 | #endif | ||
156 | |||
157 | #ifdef CONFIG_ARCH_KIRKWOOD | ||
158 | { | ||
159 | .compatible = "marvell,kirkwood-gating-clock", | ||
160 | .data = kirkwood_gating_descr, | ||
161 | }, | ||
162 | #endif | ||
163 | |||
164 | { } | ||
165 | }; | ||
166 | |||
167 | void __init mvebu_gating_clk_init(void) | ||
168 | { | ||
169 | struct device_node *np; | ||
170 | |||
171 | for_each_matching_node(np, clk_gating_match) { | ||
172 | const struct of_device_id *match = | ||
173 | of_match_node(clk_gating_match, np); | ||
174 | mvebu_clk_gating_setup(np, | ||
175 | (const struct mvebu_soc_descr *)match->data); | ||
176 | } | ||
177 | } | ||
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.h b/drivers/clk/mvebu/clk-gating-ctrl.h new file mode 100644 index 00000000000..9275d1e51f1 --- /dev/null +++ b/drivers/clk/mvebu/clk-gating-ctrl.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Marvell EBU gating clock handling | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell | ||
5 | * | ||
6 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #ifndef __MVEBU_CLK_GATING_H | ||
14 | #define __MVEBU_CLK_GATING_H | ||
15 | |||
16 | #ifdef CONFIG_MVEBU_CLK_GATING | ||
17 | void __init mvebu_gating_clk_init(void); | ||
18 | #else | ||
19 | void mvebu_gating_clk_init(void) {} | ||
20 | #endif | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/clk/mvebu/clk.c b/drivers/clk/mvebu/clk.c index e3d4d7a9de6..855681b8a9d 100644 --- a/drivers/clk/mvebu/clk.c +++ b/drivers/clk/mvebu/clk.c | |||
@@ -17,9 +17,11 @@ | |||
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include "clk-core.h" | 18 | #include "clk-core.h" |
19 | #include "clk-cpu.h" | 19 | #include "clk-cpu.h" |
20 | #include "clk-gating-ctrl.h" | ||
20 | 21 | ||
21 | void __init mvebu_clocks_init(void) | 22 | void __init mvebu_clocks_init(void) |
22 | { | 23 | { |
23 | mvebu_core_clk_init(); | 24 | mvebu_core_clk_init(); |
25 | mvebu_gating_clk_init(); | ||
24 | mvebu_cpu_clk_init(); | 26 | mvebu_cpu_clk_init(); |
25 | } | 27 | } |