blob: 61d713afd3a659cfc595b21a9c4f59a43ff513b1 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001/*
2 * Copyright (c) 2014 MediaTek Inc.
3 * Author: James Liao <jamesjj.liao@mediatek.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/err.h>
17#include <linux/io.h>
18#include <linux/slab.h>
19#include <linux/delay.h>
20#include <linux/clkdev.h>
21#include <linux/mfd/syscon.h>
22#include "clk-mtk.h"
23#include "clk-gate.h"
24struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
25{
26 int i;
27 struct clk_onecell_data *clk_data;
28 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
29 if (!clk_data)
30 return NULL;
31 clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
32 if (!clk_data->clks)
33 goto err_out;
34 clk_data->clk_num = clk_num;
35 for (i = 0; i < clk_num; i++)
36 clk_data->clks[i] = ERR_PTR(-ENOENT);
37 return clk_data;
38err_out:
39 kfree(clk_data);
40 return NULL;
41}
42void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
43 int num, struct clk_onecell_data *clk_data)
44{
45 int i;
46 struct clk *clk;
47 for (i = 0; i < num; i++) {
48 const struct mtk_fixed_clk *rc = &clks[i];
49 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
50 continue;
51 clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
52 rc->rate);
53 if (IS_ERR(clk)) {
54 pr_err("Failed to register clk %s: %ld\n",
55 rc->name, PTR_ERR(clk));
56 continue;
57 }
58 if (clk_data)
59 clk_data->clks[rc->id] = clk;
60 }
61}
62void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
63 int num, struct clk_onecell_data *clk_data)
64{
65 int i;
66 struct clk *clk;
67 for (i = 0; i < num; i++) {
68 const struct mtk_fixed_factor *ff = &clks[i];
69 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
70 continue;
71 clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
72 CLK_SET_RATE_PARENT, ff->mult, ff->div);
73 if (IS_ERR(clk)) {
74 pr_err("Failed to register clk %s: %ld\n",
75 ff->name, PTR_ERR(clk));
76 continue;
77 }
78 if (clk_data)
79 clk_data->clks[ff->id] = clk;
80 }
81}
82#if defined(CONFIG_MACH_MT6739)
83void __init mtk_clk_register_factors_pdn(
84 const struct mtk_fixed_factor_pdn *clks,
85 int num, struct clk_onecell_data *clk_data, void __iomem *base)
86{
87 int i;
88 struct clk *clk;
89 for (i = 0; i < num; i++) {
90 const struct mtk_fixed_factor_pdn *ff = &clks[i];
91 clk = mtk_clk_register_fixed_factor_pdn(NULL, ff->name,
92 ff->parent_name,
93 CLK_SET_RATE_PARENT, ff->mult, ff->div,
94 ff->shift, ff->pd_reg, base);
95 if (IS_ERR(clk)) {
96 pr_debug("Failed to register clk %s: %ld\n",
97 ff->name, PTR_ERR(clk));
98 continue;
99 }
100 if (clk_data)
101 clk_data->clks[ff->id] = clk;
102 }
103}
104#endif
105int mtk_clk_register_gates(struct device_node *node,
106 const struct mtk_gate *clks,
107 int num, struct clk_onecell_data *clk_data)
108{
109 int i;
110 struct clk *clk;
111 struct regmap *regmap;
112 struct regmap *pwr_regmap;
113 if (!clk_data)
114 return -ENOMEM;
115 regmap = syscon_node_to_regmap(node);
116 if (IS_ERR(regmap)) {
117 pr_err("Cannot find regmap for %pOF: %ld\n", node,
118 PTR_ERR(regmap));
119 return PTR_ERR(regmap);
120 }
121 pwr_regmap = syscon_regmap_lookup_by_phandle(node, "pwr-regmap");
122 if (IS_ERR(pwr_regmap))
123 pwr_regmap = NULL;
124 for (i = 0; i < num; i++) {
125 const struct mtk_gate *gate = &clks[i];
126 if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
127 continue;
128 clk = mtk_clk_register_gate(gate->name, gate->parent_name,
129 regmap,
130 gate->regs->set_ofs,
131 gate->regs->clr_ofs,
132 gate->regs->sta_ofs,
133 gate->shift,
134 gate->ops,
135 gate->flags,
136 gate->pwr_stat,
137 pwr_regmap);
138 if (IS_ERR(clk)) {
139 pr_err("Failed to register clk %s: %ld\n",
140 gate->name, PTR_ERR(clk));
141 continue;
142 }
143 clk_data->clks[gate->id] = clk;
144 }
145 return 0;
146}
147struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
148 void __iomem *base, spinlock_t *lock)
149{
150 struct clk *clk;
151 struct clk_mux *mux = NULL;
152 struct clk_gate *gate = NULL;
153 struct clk_divider *div = NULL;
154 struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
155 const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
156 const char * const *parent_names;
157 const char *parent;
158 int num_parents;
159 int ret;
160 if (mc->mux_shift >= 0) {
161 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
162 if (!mux)
163 return ERR_PTR(-ENOMEM);
164 mux->reg = base + mc->mux_reg;
165 mux->mask = BIT(mc->mux_width) - 1;
166 mux->shift = mc->mux_shift;
167 mux->lock = lock;
168 mux->flags = mc->mux_flags;
169 mux_hw = &mux->hw;
170 mux_ops = &clk_mux_ops;
171 parent_names = mc->parent_names;
172 num_parents = mc->num_parents;
173 } else {
174 parent = mc->parent;
175 parent_names = &parent;
176 num_parents = 1;
177 }
178 if (mc->gate_shift >= 0) {
179 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
180 if (!gate) {
181 ret = -ENOMEM;
182 goto err_out;
183 }
184 gate->reg = base + mc->gate_reg;
185 gate->bit_idx = mc->gate_shift;
186 gate->flags = CLK_GATE_SET_TO_DISABLE;
187 gate->lock = lock;
188 gate_hw = &gate->hw;
189 gate_ops = &clk_gate_ops;
190 }
191 if (mc->divider_shift >= 0) {
192 div = kzalloc(sizeof(*div), GFP_KERNEL);
193 if (!div) {
194 ret = -ENOMEM;
195 goto err_out;
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 div_hw = &div->hw;
202 div_ops = &clk_divider_ops;
203 }
204 clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
205 mux_hw, mux_ops,
206 div_hw, div_ops,
207 gate_hw, gate_ops,
208 mc->flags);
209 if (IS_ERR(clk)) {
210 ret = PTR_ERR(clk);
211 goto err_out;
212 }
213 return clk;
214err_out:
215 kfree(div);
216 kfree(gate);
217 kfree(mux);
218 return ERR_PTR(ret);
219}
220void mtk_clk_register_composites(const struct mtk_composite *mcs,
221 int num, void __iomem *base, spinlock_t *lock,
222 struct clk_onecell_data *clk_data)
223{
224 struct clk *clk;
225 int i;
226 for (i = 0; i < num; i++) {
227 const struct mtk_composite *mc = &mcs[i];
228 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
229 continue;
230 clk = mtk_clk_register_composite(mc, base, lock);
231 if (IS_ERR(clk)) {
232 pr_err("Failed to register clk %s: %ld\n",
233 mc->name, PTR_ERR(clk));
234 continue;
235 }
236 if (clk_data)
237 clk_data->clks[mc->id] = clk;
238 }
239}
240void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
241 int num, void __iomem *base, spinlock_t *lock,
242 struct clk_onecell_data *clk_data)
243{
244 struct clk *clk;
245 int i;
246 for (i = 0; i < num; i++) {
247 const struct mtk_clk_divider *mcd = &mcds[i];
248 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
249 continue;
250 clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
251 mcd->flags, base + mcd->div_reg, mcd->div_shift,
252 mcd->div_width, mcd->clk_divider_flags, lock);
253 if (IS_ERR(clk)) {
254 pr_err("Failed to register clk %s: %ld\n",
255 mcd->name, PTR_ERR(clk));
256 continue;
257 }
258 if (clk_data)
259 clk_data->clks[mcd->id] = clk;
260 }
261}