xref: /openbmc/linux/drivers/clk/mediatek/clk-mtk.c (revision cbdf59ad)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014 MediaTek Inc.
4  * Author: James Liao <jamesjj.liao@mediatek.com>
5  */
6 
7 #include <linux/of.h>
8 #include <linux/of_address.h>
9 #include <linux/err.h>
10 #include <linux/io.h>
11 #include <linux/slab.h>
12 #include <linux/delay.h>
13 #include <linux/clkdev.h>
14 #include <linux/mfd/syscon.h>
15 
16 #include "clk-mtk.h"
17 #include "clk-gate.h"
18 
19 struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
20 {
21 	int i;
22 	struct clk_onecell_data *clk_data;
23 
24 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
25 	if (!clk_data)
26 		return NULL;
27 
28 	clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
29 	if (!clk_data->clks)
30 		goto err_out;
31 
32 	clk_data->clk_num = clk_num;
33 
34 	for (i = 0; i < clk_num; i++)
35 		clk_data->clks[i] = ERR_PTR(-ENOENT);
36 
37 	return clk_data;
38 err_out:
39 	kfree(clk_data);
40 
41 	return NULL;
42 }
43 
44 void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
45 		int num, struct clk_onecell_data *clk_data)
46 {
47 	int i;
48 	struct clk *clk;
49 
50 	for (i = 0; i < num; i++) {
51 		const struct mtk_fixed_clk *rc = &clks[i];
52 
53 		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
54 			continue;
55 
56 		clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
57 					      rc->rate);
58 
59 		if (IS_ERR(clk)) {
60 			pr_err("Failed to register clk %s: %ld\n",
61 					rc->name, PTR_ERR(clk));
62 			continue;
63 		}
64 
65 		if (clk_data)
66 			clk_data->clks[rc->id] = clk;
67 	}
68 }
69 
70 void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
71 		int num, struct clk_onecell_data *clk_data)
72 {
73 	int i;
74 	struct clk *clk;
75 
76 	for (i = 0; i < num; i++) {
77 		const struct mtk_fixed_factor *ff = &clks[i];
78 
79 		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
80 			continue;
81 
82 		clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
83 				CLK_SET_RATE_PARENT, ff->mult, ff->div);
84 
85 		if (IS_ERR(clk)) {
86 			pr_err("Failed to register clk %s: %ld\n",
87 					ff->name, PTR_ERR(clk));
88 			continue;
89 		}
90 
91 		if (clk_data)
92 			clk_data->clks[ff->id] = clk;
93 	}
94 }
95 
96 int mtk_clk_register_gates(struct device_node *node,
97 		const struct mtk_gate *clks,
98 		int num, struct clk_onecell_data *clk_data)
99 {
100 	int i;
101 	struct clk *clk;
102 	struct regmap *regmap;
103 
104 	if (!clk_data)
105 		return -ENOMEM;
106 
107 	regmap = syscon_node_to_regmap(node);
108 	if (IS_ERR(regmap)) {
109 		pr_err("Cannot find regmap for %pOF: %ld\n", node,
110 				PTR_ERR(regmap));
111 		return PTR_ERR(regmap);
112 	}
113 
114 	for (i = 0; i < num; i++) {
115 		const struct mtk_gate *gate = &clks[i];
116 
117 		if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
118 			continue;
119 
120 		clk = mtk_clk_register_gate(gate->name, gate->parent_name,
121 				regmap,
122 				gate->regs->set_ofs,
123 				gate->regs->clr_ofs,
124 				gate->regs->sta_ofs,
125 				gate->shift, gate->ops, gate->flags);
126 
127 		if (IS_ERR(clk)) {
128 			pr_err("Failed to register clk %s: %ld\n",
129 					gate->name, PTR_ERR(clk));
130 			continue;
131 		}
132 
133 		clk_data->clks[gate->id] = clk;
134 	}
135 
136 	return 0;
137 }
138 
139 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
140 		void __iomem *base, spinlock_t *lock)
141 {
142 	struct clk *clk;
143 	struct clk_mux *mux = NULL;
144 	struct clk_gate *gate = NULL;
145 	struct clk_divider *div = NULL;
146 	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
147 	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
148 	const char * const *parent_names;
149 	const char *parent;
150 	int num_parents;
151 	int ret;
152 
153 	if (mc->mux_shift >= 0) {
154 		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
155 		if (!mux)
156 			return ERR_PTR(-ENOMEM);
157 
158 		mux->reg = base + mc->mux_reg;
159 		mux->mask = BIT(mc->mux_width) - 1;
160 		mux->shift = mc->mux_shift;
161 		mux->lock = lock;
162 		mux->flags = mc->mux_flags;
163 		mux_hw = &mux->hw;
164 		mux_ops = &clk_mux_ops;
165 
166 		parent_names = mc->parent_names;
167 		num_parents = mc->num_parents;
168 	} else {
169 		parent = mc->parent;
170 		parent_names = &parent;
171 		num_parents = 1;
172 	}
173 
174 	if (mc->gate_shift >= 0) {
175 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
176 		if (!gate) {
177 			ret = -ENOMEM;
178 			goto err_out;
179 		}
180 
181 		gate->reg = base + mc->gate_reg;
182 		gate->bit_idx = mc->gate_shift;
183 		gate->flags = CLK_GATE_SET_TO_DISABLE;
184 		gate->lock = lock;
185 
186 		gate_hw = &gate->hw;
187 		gate_ops = &clk_gate_ops;
188 	}
189 
190 	if (mc->divider_shift >= 0) {
191 		div = kzalloc(sizeof(*div), GFP_KERNEL);
192 		if (!div) {
193 			ret = -ENOMEM;
194 			goto err_out;
195 		}
196 
197 		div->reg = base + mc->divider_reg;
198 		div->shift = mc->divider_shift;
199 		div->width = mc->divider_width;
200 		div->lock = lock;
201 
202 		div_hw = &div->hw;
203 		div_ops = &clk_divider_ops;
204 	}
205 
206 	clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
207 		mux_hw, mux_ops,
208 		div_hw, div_ops,
209 		gate_hw, gate_ops,
210 		mc->flags);
211 
212 	if (IS_ERR(clk)) {
213 		ret = PTR_ERR(clk);
214 		goto err_out;
215 	}
216 
217 	return clk;
218 err_out:
219 	kfree(div);
220 	kfree(gate);
221 	kfree(mux);
222 
223 	return ERR_PTR(ret);
224 }
225 
226 void mtk_clk_register_composites(const struct mtk_composite *mcs,
227 		int num, void __iomem *base, spinlock_t *lock,
228 		struct clk_onecell_data *clk_data)
229 {
230 	struct clk *clk;
231 	int i;
232 
233 	for (i = 0; i < num; i++) {
234 		const struct mtk_composite *mc = &mcs[i];
235 
236 		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
237 			continue;
238 
239 		clk = mtk_clk_register_composite(mc, base, lock);
240 
241 		if (IS_ERR(clk)) {
242 			pr_err("Failed to register clk %s: %ld\n",
243 					mc->name, PTR_ERR(clk));
244 			continue;
245 		}
246 
247 		if (clk_data)
248 			clk_data->clks[mc->id] = clk;
249 	}
250 }
251 
252 void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
253 			int num, void __iomem *base, spinlock_t *lock,
254 				struct clk_onecell_data *clk_data)
255 {
256 	struct clk *clk;
257 	int i;
258 
259 	for (i = 0; i <  num; i++) {
260 		const struct mtk_clk_divider *mcd = &mcds[i];
261 
262 		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
263 			continue;
264 
265 		clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
266 			mcd->flags, base +  mcd->div_reg, mcd->div_shift,
267 			mcd->div_width, mcd->clk_divider_flags, lock);
268 
269 		if (IS_ERR(clk)) {
270 			pr_err("Failed to register clk %s: %ld\n",
271 				mcd->name, PTR_ERR(clk));
272 			continue;
273 		}
274 
275 		if (clk_data)
276 			clk_data->clks[mcd->id] = clk;
277 	}
278 }
279