aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>2012-11-17 09:22:26 -0500
committerThomas Petazzoni <thomas.petazzoni@free-electrons.com>2012-11-20 08:43:24 -0500
commitf97d0d7aa8f8cec29a24d65afa12a777c6d2a2f1 (patch)
tree96b8ae53f370882f4e399f9da657e78eb388a505
parentab8ba01b3fe5e0b81bd2da0afe66f7f6968e017b (diff)
clk: mvebu: add clock gating control provider for DT
This driver allows to provide DT clocks for clock gates found on Marvell Dove and Kirkwood SoCs. The clock gates are referenced by the phandle index of the corresponding bit in the clock gating control register to ease lookup in the datasheet. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-rw-r--r--Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt76
-rw-r--r--drivers/clk/mvebu/Kconfig2
-rw-r--r--drivers/clk/mvebu/Makefile1
-rw-r--r--drivers/clk/mvebu/clk-gating-ctrl.c177
-rw-r--r--drivers/clk/mvebu/clk-gating-ctrl.h22
-rw-r--r--drivers/clk/mvebu/clk.c2
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 000000000000..4ad8ccd15e67
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
@@ -0,0 +1,76 @@
1* Gated Clock bindings for Marvell Orion SoCs
2
3Marvell Dove and Kirkwood allow some peripheral clocks to be gated to save
4some power. The clock consumer should specify the desired clock by having
5the clock ID in its "clocks" phandle cell. The clock ID is directly mapped to
6the corresponding clock gating control bit in HW to ease manual clock lookup
7in datasheet.
8
9The following is a list of provided IDs for Dove:
10ID Clock Peripheral
11-----------------------------------
120 usb0 USB Host 0
131 usb1 USB Host 1
142 ge Gigabit Ethernet
153 sata SATA Host
164 pex0 PCIe Cntrl 0
175 pex1 PCIe Cntrl 1
188 sdio0 SDHCI Host 0
199 sdio1 SDHCI Host 1
2010 nand NAND Cntrl
2111 camera Camera Cntrl
2212 i2s0 I2S Cntrl 0
2313 i2s1 I2S Cntrl 1
2415 crypto CESA engine
2521 ac97 AC97 Cntrl
2622 pdma Peripheral DMA
2723 xor0 XOR DMA 0
2824 xor1 XOR DMA 1
2930 gephy Gigabit Ethernel PHY
30Note: gephy(30) is implemented as a parent clock of ge(2)
31
32The following is a list of provided IDs for Kirkwood:
33ID Clock Peripheral
34-----------------------------------
350 ge0 Gigabit Ethernet 0
362 pex0 PCIe Cntrl 0
373 usb0 USB Host 0
384 sdio SDIO Cntrl
395 tsu Transp. Stream Unit
406 dunit SDRAM Cntrl
417 runit Runit
428 xor0 XOR DMA 0
439 audio I2S Cntrl 0
4414 sata0 SATA Host 0
4515 sata1 SATA Host 1
4616 xor1 XOR DMA 1
4717 crypto CESA engine
4818 pex1 PCIe Cntrl 1
4919 ge1 Gigabit Ethernet 0
5020 tdm Time Division Mplx
51
52Required 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
59Optional properties:
60- clocks : default parent clock phandle (e.g. tclk)
61
62Example:
63
64gate_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
72sdio0: 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 1dd93ada9cb3..57323fd15ec9 100644
--- a/drivers/clk/mvebu/Kconfig
+++ b/drivers/clk/mvebu/Kconfig
@@ -4,3 +4,5 @@ config MVEBU_CLK_CORE
4config MVEBU_CLK_CPU 4config MVEBU_CLK_CPU
5 bool 5 bool
6 6
7config MVEBU_CLK_GATING
8 bool
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 93da083b77e3..58df3dc49363 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_MVEBU_CLK_CORE) += clk.o clk-core.o 1obj-$(CONFIG_MVEBU_CLK_CORE) += clk.o clk-core.o
2obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o 2obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o
3obj-$(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 000000000000..fa69f87c5797
--- /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
21struct mvebu_gating_ctrl {
22 spinlock_t lock;
23 struct clk **gates;
24 int num_gates;
25};
26
27struct 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
35static 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
53static 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
105static 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
129static 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
149static 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
167void __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 000000000000..9275d1e51f1b
--- /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
17void __init mvebu_gating_clk_init(void);
18#else
19void 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 e3d4d7a9de6a..855681b8a9dc 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
21void __init mvebu_clocks_init(void) 22void __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}