xref: /linux/drivers/clk/at91/clk-utmi.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4  */
5 
6 #include <linux/clk-provider.h>
7 #include <linux/clkdev.h>
8 #include <linux/clk/at91_pmc.h>
9 #include <linux/of.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/regmap.h>
12 #include <soc/at91/atmel-sfr.h>
13 
14 #include "pmc.h"
15 
16 /*
17  * The purpose of this clock is to generate a 480 MHz signal. A different
18  * rate can't be configured.
19  */
20 #define UTMI_RATE	480000000
21 
22 struct clk_utmi {
23 	struct clk_hw hw;
24 	struct regmap *regmap_pmc;
25 	struct regmap *regmap_sfr;
26 	struct at91_clk_pms pms;
27 };
28 
29 #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
30 
clk_utmi_ready(struct regmap * regmap)31 static inline bool clk_utmi_ready(struct regmap *regmap)
32 {
33 	unsigned int status;
34 
35 	regmap_read(regmap, AT91_PMC_SR, &status);
36 
37 	return status & AT91_PMC_LOCKU;
38 }
39 
clk_utmi_prepare(struct clk_hw * hw)40 static int clk_utmi_prepare(struct clk_hw *hw)
41 {
42 	struct clk_hw *hw_parent;
43 	struct clk_utmi *utmi = to_clk_utmi(hw);
44 	unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
45 			    AT91_PMC_BIASEN;
46 	unsigned int utmi_ref_clk_freq;
47 	unsigned long parent_rate;
48 
49 	/*
50 	 * If mainck rate is different from 12 MHz, we have to configure the
51 	 * FREQ field of the SFR_UTMICKTRIM register to generate properly
52 	 * the utmi clock.
53 	 */
54 	hw_parent = clk_hw_get_parent(hw);
55 	parent_rate = clk_hw_get_rate(hw_parent);
56 
57 	switch (parent_rate) {
58 	case 12000000:
59 		utmi_ref_clk_freq = 0;
60 		break;
61 	case 16000000:
62 		utmi_ref_clk_freq = 1;
63 		break;
64 	case 24000000:
65 		utmi_ref_clk_freq = 2;
66 		break;
67 	/*
68 	 * Not supported on SAMA5D2 but it's not an issue since MAINCK
69 	 * maximum value is 24 MHz.
70 	 */
71 	case 48000000:
72 		utmi_ref_clk_freq = 3;
73 		break;
74 	default:
75 		pr_err("UTMICK: unsupported mainck rate\n");
76 		return -EINVAL;
77 	}
78 
79 	if (utmi->regmap_sfr) {
80 		regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
81 				   AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
82 	} else if (utmi_ref_clk_freq) {
83 		pr_err("UTMICK: sfr node required\n");
84 		return -EINVAL;
85 	}
86 
87 	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, uckr, uckr);
88 
89 	while (!clk_utmi_ready(utmi->regmap_pmc))
90 		cpu_relax();
91 
92 	return 0;
93 }
94 
clk_utmi_is_prepared(struct clk_hw * hw)95 static int clk_utmi_is_prepared(struct clk_hw *hw)
96 {
97 	struct clk_utmi *utmi = to_clk_utmi(hw);
98 
99 	return clk_utmi_ready(utmi->regmap_pmc);
100 }
101 
clk_utmi_unprepare(struct clk_hw * hw)102 static void clk_utmi_unprepare(struct clk_hw *hw)
103 {
104 	struct clk_utmi *utmi = to_clk_utmi(hw);
105 
106 	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR,
107 			   AT91_PMC_UPLLEN, 0);
108 }
109 
clk_utmi_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)110 static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
111 					  unsigned long parent_rate)
112 {
113 	/* UTMI clk rate is fixed. */
114 	return UTMI_RATE;
115 }
116 
clk_utmi_save_context(struct clk_hw * hw)117 static int clk_utmi_save_context(struct clk_hw *hw)
118 {
119 	struct clk_utmi *utmi = to_clk_utmi(hw);
120 
121 	utmi->pms.status = clk_utmi_is_prepared(hw);
122 
123 	return 0;
124 }
125 
clk_utmi_restore_context(struct clk_hw * hw)126 static void clk_utmi_restore_context(struct clk_hw *hw)
127 {
128 	struct clk_utmi *utmi = to_clk_utmi(hw);
129 
130 	if (utmi->pms.status)
131 		clk_utmi_prepare(hw);
132 }
133 
134 static const struct clk_ops utmi_ops = {
135 	.prepare = clk_utmi_prepare,
136 	.unprepare = clk_utmi_unprepare,
137 	.is_prepared = clk_utmi_is_prepared,
138 	.recalc_rate = clk_utmi_recalc_rate,
139 	.save_context = clk_utmi_save_context,
140 	.restore_context = clk_utmi_restore_context,
141 };
142 
143 static struct clk_hw * __init
at91_clk_register_utmi_internal(struct regmap * regmap_pmc,struct regmap * regmap_sfr,const char * name,const char * parent_name,struct clk_hw * parent_hw,const struct clk_ops * ops,unsigned long flags)144 at91_clk_register_utmi_internal(struct regmap *regmap_pmc,
145 				struct regmap *regmap_sfr,
146 				const char *name, const char *parent_name,
147 				struct clk_hw *parent_hw,
148 				const struct clk_ops *ops, unsigned long flags)
149 {
150 	struct clk_utmi *utmi;
151 	struct clk_hw *hw;
152 	struct clk_init_data init = {};
153 	int ret;
154 
155 	if (!(parent_name || parent_hw))
156 		return ERR_PTR(-EINVAL);
157 
158 	utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
159 	if (!utmi)
160 		return ERR_PTR(-ENOMEM);
161 
162 	init.name = name;
163 	init.ops = ops;
164 	if (parent_hw)
165 		init.parent_hws = (const struct clk_hw **)&parent_hw;
166 	else
167 		init.parent_names = &parent_name;
168 	init.num_parents = 1;
169 	init.flags = flags;
170 
171 	utmi->hw.init = &init;
172 	utmi->regmap_pmc = regmap_pmc;
173 	utmi->regmap_sfr = regmap_sfr;
174 
175 	hw = &utmi->hw;
176 	ret = clk_hw_register(NULL, &utmi->hw);
177 	if (ret) {
178 		kfree(utmi);
179 		hw = ERR_PTR(ret);
180 	}
181 
182 	return hw;
183 }
184 
185 struct clk_hw * __init
at91_clk_register_utmi(struct regmap * regmap_pmc,struct regmap * regmap_sfr,const char * name,const char * parent_name,struct clk_hw * parent_hw)186 at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
187 		       const char *name, const char *parent_name,
188 		       struct clk_hw *parent_hw)
189 {
190 	return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name,
191 			parent_name, parent_hw, &utmi_ops, CLK_SET_RATE_GATE);
192 }
193 
clk_utmi_sama7g5_prepare(struct clk_hw * hw)194 static int clk_utmi_sama7g5_prepare(struct clk_hw *hw)
195 {
196 	struct clk_utmi *utmi = to_clk_utmi(hw);
197 	struct clk_hw *hw_parent;
198 	unsigned long parent_rate;
199 	unsigned int val;
200 
201 	hw_parent = clk_hw_get_parent(hw);
202 	parent_rate = clk_hw_get_rate(hw_parent);
203 
204 	switch (parent_rate) {
205 	case 16000000:
206 		val = 0;
207 		break;
208 	case 20000000:
209 		val = 2;
210 		break;
211 	case 24000000:
212 		val = 3;
213 		break;
214 	case 32000000:
215 		val = 5;
216 		break;
217 	default:
218 		pr_err("UTMICK: unsupported main_xtal rate\n");
219 		return -EINVAL;
220 	}
221 
222 	regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val);
223 
224 	return 0;
225 
226 }
227 
clk_utmi_sama7g5_is_prepared(struct clk_hw * hw)228 static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw)
229 {
230 	struct clk_utmi *utmi = to_clk_utmi(hw);
231 	struct clk_hw *hw_parent;
232 	unsigned long parent_rate;
233 	unsigned int val;
234 
235 	hw_parent = clk_hw_get_parent(hw);
236 	parent_rate = clk_hw_get_rate(hw_parent);
237 
238 	regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val);
239 	switch (val & 0x7) {
240 	case 0:
241 		if (parent_rate == 16000000)
242 			return 1;
243 		break;
244 	case 2:
245 		if (parent_rate == 20000000)
246 			return 1;
247 		break;
248 	case 3:
249 		if (parent_rate == 24000000)
250 			return 1;
251 		break;
252 	case 5:
253 		if (parent_rate == 32000000)
254 			return 1;
255 		break;
256 	default:
257 		break;
258 	}
259 
260 	return 0;
261 }
262 
clk_utmi_sama7g5_save_context(struct clk_hw * hw)263 static int clk_utmi_sama7g5_save_context(struct clk_hw *hw)
264 {
265 	struct clk_utmi *utmi = to_clk_utmi(hw);
266 
267 	utmi->pms.status = clk_utmi_sama7g5_is_prepared(hw);
268 
269 	return 0;
270 }
271 
clk_utmi_sama7g5_restore_context(struct clk_hw * hw)272 static void clk_utmi_sama7g5_restore_context(struct clk_hw *hw)
273 {
274 	struct clk_utmi *utmi = to_clk_utmi(hw);
275 
276 	if (utmi->pms.status)
277 		clk_utmi_sama7g5_prepare(hw);
278 }
279 
280 static const struct clk_ops sama7g5_utmi_ops = {
281 	.prepare = clk_utmi_sama7g5_prepare,
282 	.is_prepared = clk_utmi_sama7g5_is_prepared,
283 	.recalc_rate = clk_utmi_recalc_rate,
284 	.save_context = clk_utmi_sama7g5_save_context,
285 	.restore_context = clk_utmi_sama7g5_restore_context,
286 };
287 
288 struct clk_hw * __init
at91_clk_sama7g5_register_utmi(struct regmap * regmap_pmc,const char * name,const char * parent_name,struct clk_hw * parent_hw)289 at91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name,
290 			       const char *parent_name, struct clk_hw *parent_hw)
291 {
292 	return at91_clk_register_utmi_internal(regmap_pmc, NULL, name,
293 			parent_name, parent_hw, &sama7g5_utmi_ops, 0);
294 }
295