1
2
3
4
5
6
7
8
9
10
11#include <asm/processor.h>
12#include <common.h>
13#include <clk-uclass.h>
14#include <dm.h>
15#include <linux/clk-provider.h>
16#include <linux/clk/at91_pmc.h>
17#include <mach/at91_sfr.h>
18#include <regmap.h>
19#include <syscon.h>
20
21#include "pmc.h"
22
23#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk"
24#define UBOOT_DM_CLK_AT91_SAMA7G5_UTMI "at91-sama7g5-utmi-clk"
25
26
27
28
29
30#define UTMI_RATE 480000000
31
32struct clk_utmi {
33 void __iomem *base;
34 struct regmap *regmap_sfr;
35 struct clk clk;
36};
37
38#define to_clk_utmi(_clk) container_of(_clk, struct clk_utmi, clk)
39
40static inline bool clk_utmi_ready(struct regmap *regmap)
41{
42 unsigned int status;
43
44 pmc_read(regmap, AT91_PMC_SR, &status);
45
46 return !!(status & AT91_PMC_LOCKU);
47}
48
49static int clk_utmi_enable(struct clk *clk)
50{
51 struct clk_utmi *utmi = to_clk_utmi(clk);
52 unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
53 AT91_PMC_BIASEN;
54 unsigned int utmi_ref_clk_freq;
55 ulong parent_rate = clk_get_parent_rate(clk);
56
57
58
59
60
61
62 switch (parent_rate) {
63 case 12000000:
64 utmi_ref_clk_freq = 0;
65 break;
66 case 16000000:
67 utmi_ref_clk_freq = 1;
68 break;
69 case 24000000:
70 utmi_ref_clk_freq = 2;
71 break;
72
73
74
75
76 case 48000000:
77 utmi_ref_clk_freq = 3;
78 break;
79 default:
80 debug("UTMICK: unsupported mainck rate\n");
81 return -EINVAL;
82 }
83
84 if (utmi->regmap_sfr) {
85 regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
86 AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
87 } else if (utmi_ref_clk_freq) {
88 debug("UTMICK: sfr node required\n");
89 return -EINVAL;
90 }
91
92 pmc_update_bits(utmi->base, AT91_CKGR_UCKR, uckr, uckr);
93
94 while (!clk_utmi_ready(utmi->base)) {
95 debug("waiting for utmi...\n");
96 cpu_relax();
97 }
98
99 return 0;
100}
101
102static int clk_utmi_disable(struct clk *clk)
103{
104 struct clk_utmi *utmi = to_clk_utmi(clk);
105
106 pmc_update_bits(utmi->base, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
107
108 return 0;
109}
110
111static ulong clk_utmi_get_rate(struct clk *clk)
112{
113
114 return UTMI_RATE;
115}
116
117static const struct clk_ops utmi_ops = {
118 .enable = clk_utmi_enable,
119 .disable = clk_utmi_disable,
120 .get_rate = clk_utmi_get_rate,
121};
122
123struct clk *at91_clk_register_utmi(void __iomem *base, struct udevice *dev,
124 const char *name, const char *parent_name)
125{
126 struct udevice *syscon;
127 struct clk_utmi *utmi;
128 struct clk *clk;
129 int ret;
130
131 if (!base || !dev || !name || !parent_name)
132 return ERR_PTR(-EINVAL);
133
134 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
135 "regmap-sfr", &syscon);
136 if (ret)
137 return ERR_PTR(ret);
138
139 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
140 if (!utmi)
141 return ERR_PTR(-ENOMEM);
142
143 utmi->base = base;
144 utmi->regmap_sfr = syscon_get_regmap(syscon);
145 if (!utmi->regmap_sfr) {
146 kfree(utmi);
147 return ERR_PTR(-ENODEV);
148 }
149
150 clk = &utmi->clk;
151 clk->flags = CLK_GET_RATE_NOCACHE;
152 ret = clk_register(clk, UBOOT_DM_CLK_AT91_UTMI, name, parent_name);
153 if (ret) {
154 kfree(utmi);
155 clk = ERR_PTR(ret);
156 }
157
158 return clk;
159}
160
161U_BOOT_DRIVER(at91_utmi_clk) = {
162 .name = UBOOT_DM_CLK_AT91_UTMI,
163 .id = UCLASS_CLK,
164 .ops = &utmi_ops,
165 .flags = DM_FLAG_PRE_RELOC,
166};
167
168static int clk_utmi_sama7g5_enable(struct clk *clk)
169{
170 struct clk_utmi *utmi = to_clk_utmi(clk);
171 ulong parent_rate = clk_get_parent_rate(clk);
172 unsigned int val;
173
174 switch (parent_rate) {
175 case 16000000:
176 val = 0;
177 break;
178 case 20000000:
179 val = 2;
180 break;
181 case 24000000:
182 val = 3;
183 break;
184 case 32000000:
185 val = 5;
186 break;
187 default:
188 debug("UTMICK: unsupported main_xtal rate\n");
189 return -EINVAL;
190 }
191
192 pmc_write(utmi->base, AT91_PMC_XTALF, val);
193
194 return 0;
195}
196
197static const struct clk_ops sama7g5_utmi_ops = {
198 .enable = clk_utmi_sama7g5_enable,
199 .get_rate = clk_utmi_get_rate,
200};
201
202struct clk *at91_clk_sama7g5_register_utmi(void __iomem *base,
203 const char *name, const char *parent_name)
204{
205 struct clk_utmi *utmi;
206 struct clk *clk;
207 int ret;
208
209 if (!base || !name || !parent_name)
210 return ERR_PTR(-EINVAL);
211
212 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
213 if (!utmi)
214 return ERR_PTR(-ENOMEM);
215
216 utmi->base = base;
217
218 clk = &utmi->clk;
219 ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_UTMI, name,
220 parent_name);
221 if (ret) {
222 kfree(utmi);
223 clk = ERR_PTR(ret);
224 }
225
226 return clk;
227}
228
229U_BOOT_DRIVER(at91_sama7g5_utmi_clk) = {
230 .name = UBOOT_DM_CLK_AT91_SAMA7G5_UTMI,
231 .id = UCLASS_CLK,
232 .ops = &sama7g5_utmi_ops,
233 .flags = DM_FLAG_PRE_RELOC,
234};
235