blob: fa69f87c579740b9f3a9bb094f13c476b2d98f15 [file] [log] [blame]
Sebastian Hesselbarthf97d0d72012-11-17 15:22:26 +01001/*
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}