1 /*
2  * Copyright (c) 2015 Endless Mobile, Inc.
3  * Author: Carlo Caione <carlo@endlessm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <linux/clk-provider.h>
19 #include <linux/mfd/syscon.h>
20 #include <linux/slab.h>
21 
22 #include "clkc.h"
23 
24 static DEFINE_SPINLOCK(clk_lock);
25 
26 static struct clk **clks;
27 static struct clk_onecell_data clk_data;
28 
meson_clk_init(struct device_node * np,unsigned long nr_clks)29 struct clk ** __init meson_clk_init(struct device_node *np,
30 				   unsigned long nr_clks)
31 {
32 	clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL);
33 	if (!clks)
34 		return ERR_PTR(-ENOMEM);
35 
36 	clk_data.clks = clks;
37 	clk_data.clk_num = nr_clks;
38 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
39 
40 	return clks;
41 }
42 
meson_clk_add_lookup(struct clk * clk,unsigned int id)43 static void meson_clk_add_lookup(struct clk *clk, unsigned int id)
44 {
45 	if (clks && id)
46 		clks[id] = clk;
47 }
48 
49 static struct clk * __init
meson_clk_register_composite(const struct clk_conf * clk_conf,void __iomem * clk_base)50 meson_clk_register_composite(const struct clk_conf *clk_conf,
51 			     void __iomem *clk_base)
52 {
53 	struct clk *clk;
54 	struct clk_mux *mux = NULL;
55 	struct clk_divider *div = NULL;
56 	struct clk_gate *gate = NULL;
57 	const struct clk_ops *mux_ops = NULL;
58 	const struct composite_conf *composite_conf;
59 
60 	composite_conf = clk_conf->conf.composite;
61 
62 	if (clk_conf->num_parents > 1) {
63 		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
64 		if (!mux)
65 			return ERR_PTR(-ENOMEM);
66 
67 		mux->reg = clk_base + clk_conf->reg_off
68 				+ composite_conf->mux_parm.reg_off;
69 		mux->shift = composite_conf->mux_parm.shift;
70 		mux->mask = BIT(composite_conf->mux_parm.width) - 1;
71 		mux->flags = composite_conf->mux_flags;
72 		mux->lock = &clk_lock;
73 		mux->table = composite_conf->mux_table;
74 		mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ?
75 			  &clk_mux_ro_ops : &clk_mux_ops;
76 	}
77 
78 	if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) {
79 		div = kzalloc(sizeof(*div), GFP_KERNEL);
80 		if (!div) {
81 			clk = ERR_PTR(-ENOMEM);
82 			goto error;
83 		}
84 
85 		div->reg = clk_base + clk_conf->reg_off
86 				+ composite_conf->div_parm.reg_off;
87 		div->shift = composite_conf->div_parm.shift;
88 		div->width = composite_conf->div_parm.width;
89 		div->lock = &clk_lock;
90 		div->flags = composite_conf->div_flags;
91 		div->table = composite_conf->div_table;
92 	}
93 
94 	if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) {
95 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
96 		if (!gate) {
97 			clk = ERR_PTR(-ENOMEM);
98 			goto error;
99 		}
100 
101 		gate->reg = clk_base + clk_conf->reg_off
102 				+ composite_conf->div_parm.reg_off;
103 		gate->bit_idx = composite_conf->gate_parm.shift;
104 		gate->flags = composite_conf->gate_flags;
105 		gate->lock = &clk_lock;
106 	}
107 
108 	clk = clk_register_composite(NULL, clk_conf->clk_name,
109 				    clk_conf->clks_parent,
110 				    clk_conf->num_parents,
111 				    mux ? &mux->hw : NULL, mux_ops,
112 				    div ? &div->hw : NULL, &clk_divider_ops,
113 				    gate ? &gate->hw : NULL, &clk_gate_ops,
114 				    clk_conf->flags);
115 	if (IS_ERR(clk))
116 		goto error;
117 
118 	return clk;
119 
120 error:
121 	kfree(gate);
122 	kfree(div);
123 	kfree(mux);
124 
125 	return clk;
126 }
127 
128 static struct clk * __init
meson_clk_register_fixed_factor(const struct clk_conf * clk_conf,void __iomem * clk_base)129 meson_clk_register_fixed_factor(const struct clk_conf *clk_conf,
130 				void __iomem *clk_base)
131 {
132 	struct clk *clk;
133 	const struct fixed_fact_conf *fixed_fact_conf;
134 	const struct parm *p;
135 	unsigned int mult, div;
136 	u32 reg;
137 
138 	fixed_fact_conf = &clk_conf->conf.fixed_fact;
139 
140 	mult = clk_conf->conf.fixed_fact.mult;
141 	div = clk_conf->conf.fixed_fact.div;
142 
143 	if (!mult) {
144 		mult = 1;
145 		p = &fixed_fact_conf->mult_parm;
146 		if (MESON_PARM_APPLICABLE(p)) {
147 			reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
148 			mult = PARM_GET(p->width, p->shift, reg);
149 		}
150 	}
151 
152 	if (!div) {
153 		div = 1;
154 		p = &fixed_fact_conf->div_parm;
155 		if (MESON_PARM_APPLICABLE(p)) {
156 			reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
157 			mult = PARM_GET(p->width, p->shift, reg);
158 		}
159 	}
160 
161 	clk = clk_register_fixed_factor(NULL,
162 			clk_conf->clk_name,
163 			clk_conf->clks_parent[0],
164 			clk_conf->flags,
165 			mult, div);
166 
167 	return clk;
168 }
169 
170 static struct clk * __init
meson_clk_register_fixed_rate(const struct clk_conf * clk_conf,void __iomem * clk_base)171 meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
172 			      void __iomem *clk_base)
173 {
174 	struct clk *clk;
175 	const struct fixed_rate_conf *fixed_rate_conf;
176 	const struct parm *r;
177 	unsigned long rate;
178 	u32 reg;
179 
180 	fixed_rate_conf = &clk_conf->conf.fixed_rate;
181 	rate = fixed_rate_conf->rate;
182 
183 	if (!rate) {
184 		r = &fixed_rate_conf->rate_parm;
185 		reg = readl(clk_base + clk_conf->reg_off + r->reg_off);
186 		rate = PARM_GET(r->width, r->shift, reg);
187 	}
188 
189 	rate *= 1000000;
190 
191 	clk = clk_register_fixed_rate(NULL,
192 			clk_conf->clk_name,
193 			clk_conf->num_parents
194 				? clk_conf->clks_parent[0] : NULL,
195 			clk_conf->flags, rate);
196 
197 	return clk;
198 }
199 
meson_clk_register_clks(const struct clk_conf * clk_confs,unsigned int nr_confs,void __iomem * clk_base)200 void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
201 				    unsigned int nr_confs,
202 				    void __iomem *clk_base)
203 {
204 	unsigned int i;
205 	struct clk *clk = NULL;
206 
207 	for (i = 0; i < nr_confs; i++) {
208 		const struct clk_conf *clk_conf = &clk_confs[i];
209 
210 		switch (clk_conf->clk_type) {
211 		case CLK_FIXED_RATE:
212 			clk = meson_clk_register_fixed_rate(clk_conf,
213 							    clk_base);
214 			break;
215 		case CLK_FIXED_FACTOR:
216 			clk = meson_clk_register_fixed_factor(clk_conf,
217 							      clk_base);
218 			break;
219 		case CLK_COMPOSITE:
220 			clk = meson_clk_register_composite(clk_conf,
221 							   clk_base);
222 			break;
223 		case CLK_CPU:
224 			clk = meson_clk_register_cpu(clk_conf, clk_base,
225 						     &clk_lock);
226 			break;
227 		case CLK_PLL:
228 			clk = meson_clk_register_pll(clk_conf, clk_base,
229 						     &clk_lock);
230 			break;
231 		default:
232 			clk = NULL;
233 		}
234 
235 		if (!clk) {
236 			pr_err("%s: unknown clock type %d\n", __func__,
237 			       clk_conf->clk_type);
238 			continue;
239 		}
240 
241 		if (IS_ERR(clk)) {
242 			pr_warn("%s: Unable to create %s clock\n", __func__,
243 				clk_conf->clk_name);
244 			continue;
245 		}
246 
247 		meson_clk_add_lookup(clk, clk_conf->clk_id);
248 	}
249 }
250