diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2014-02-17 04:31:53 -0500 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-02-26 20:02:29 -0500 |
commit | 1887c3a64fab8300a5be3fb5fd8d6474a63b50a0 (patch) | |
tree | 8313a1c3590e3aeec2fa828ca723bf9876e483fc | |
parent | 62ac983b614149db5a98f333dbb13848cb6b7524 (diff) |
clk: axi-clkgen: Add support for v2
This patch adds support for the new v2 version of the axi-clkgen core.
Unfortunately the method of accessing the registers is quite different on v2,
while the content still stays largely the same. So the patch adds a small
abstraction layer which implements the specific read and write functions for v1
and v2 in callback functions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
-rw-r--r-- | Documentation/devicetree/bindings/clock/axi-clkgen.txt | 2 | ||||
-rw-r--r-- | drivers/clk/clk-axi-clkgen.c | 312 |
2 files changed, 270 insertions, 44 deletions
diff --git a/Documentation/devicetree/bindings/clock/axi-clkgen.txt b/Documentation/devicetree/bindings/clock/axi-clkgen.txt index 028b493e97ff..20e1704e7df2 100644 --- a/Documentation/devicetree/bindings/clock/axi-clkgen.txt +++ b/Documentation/devicetree/bindings/clock/axi-clkgen.txt | |||
@@ -5,7 +5,7 @@ This binding uses the common clock binding[1]. | |||
5 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt | 5 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt |
6 | 6 | ||
7 | Required properties: | 7 | Required properties: |
8 | - compatible : shall be "adi,axi-clkgen". | 8 | - compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a". |
9 | - #clock-cells : from common clock binding; Should always be set to 0. | 9 | - #clock-cells : from common clock binding; Should always be set to 0. |
10 | - reg : Address and length of the axi-clkgen register set. | 10 | - reg : Address and length of the axi-clkgen register set. |
11 | - clocks : Phandle and clock specifier for the parent clock. | 11 | - clocks : Phandle and clock specifier for the parent clock. |
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 8137327847c3..1127ee46b802 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c | |||
@@ -17,23 +17,75 @@ | |||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | 19 | ||
20 | #define AXI_CLKGEN_REG_UPDATE_ENABLE 0x04 | 20 | #define AXI_CLKGEN_V1_REG_UPDATE_ENABLE 0x04 |
21 | #define AXI_CLKGEN_REG_CLK_OUT1 0x08 | 21 | #define AXI_CLKGEN_V1_REG_CLK_OUT1 0x08 |
22 | #define AXI_CLKGEN_REG_CLK_OUT2 0x0c | 22 | #define AXI_CLKGEN_V1_REG_CLK_OUT2 0x0c |
23 | #define AXI_CLKGEN_REG_CLK_DIV 0x10 | 23 | #define AXI_CLKGEN_V1_REG_CLK_DIV 0x10 |
24 | #define AXI_CLKGEN_REG_CLK_FB1 0x14 | 24 | #define AXI_CLKGEN_V1_REG_CLK_FB1 0x14 |
25 | #define AXI_CLKGEN_REG_CLK_FB2 0x18 | 25 | #define AXI_CLKGEN_V1_REG_CLK_FB2 0x18 |
26 | #define AXI_CLKGEN_REG_LOCK1 0x1c | 26 | #define AXI_CLKGEN_V1_REG_LOCK1 0x1c |
27 | #define AXI_CLKGEN_REG_LOCK2 0x20 | 27 | #define AXI_CLKGEN_V1_REG_LOCK2 0x20 |
28 | #define AXI_CLKGEN_REG_LOCK3 0x24 | 28 | #define AXI_CLKGEN_V1_REG_LOCK3 0x24 |
29 | #define AXI_CLKGEN_REG_FILTER1 0x28 | 29 | #define AXI_CLKGEN_V1_REG_FILTER1 0x28 |
30 | #define AXI_CLKGEN_REG_FILTER2 0x2c | 30 | #define AXI_CLKGEN_V1_REG_FILTER2 0x2c |
31 | |||
32 | #define AXI_CLKGEN_V2_REG_RESET 0x40 | ||
33 | #define AXI_CLKGEN_V2_REG_DRP_CNTRL 0x70 | ||
34 | #define AXI_CLKGEN_V2_REG_DRP_STATUS 0x74 | ||
35 | |||
36 | #define AXI_CLKGEN_V2_RESET_MMCM_ENABLE BIT(1) | ||
37 | #define AXI_CLKGEN_V2_RESET_ENABLE BIT(0) | ||
38 | |||
39 | #define AXI_CLKGEN_V2_DRP_CNTRL_SEL BIT(29) | ||
40 | #define AXI_CLKGEN_V2_DRP_CNTRL_READ BIT(28) | ||
41 | |||
42 | #define AXI_CLKGEN_V2_DRP_STATUS_BUSY BIT(16) | ||
43 | |||
44 | #define MMCM_REG_CLKOUT0_1 0x08 | ||
45 | #define MMCM_REG_CLKOUT0_2 0x09 | ||
46 | #define MMCM_REG_CLK_FB1 0x14 | ||
47 | #define MMCM_REG_CLK_FB2 0x15 | ||
48 | #define MMCM_REG_CLK_DIV 0x16 | ||
49 | #define MMCM_REG_LOCK1 0x18 | ||
50 | #define MMCM_REG_LOCK2 0x19 | ||
51 | #define MMCM_REG_LOCK3 0x1a | ||
52 | #define MMCM_REG_FILTER1 0x4e | ||
53 | #define MMCM_REG_FILTER2 0x4f | ||
54 | |||
55 | struct axi_clkgen; | ||
56 | |||
57 | struct axi_clkgen_mmcm_ops { | ||
58 | void (*enable)(struct axi_clkgen *axi_clkgen, bool enable); | ||
59 | int (*write)(struct axi_clkgen *axi_clkgen, unsigned int reg, | ||
60 | unsigned int val, unsigned int mask); | ||
61 | int (*read)(struct axi_clkgen *axi_clkgen, unsigned int reg, | ||
62 | unsigned int *val); | ||
63 | }; | ||
31 | 64 | ||
32 | struct axi_clkgen { | 65 | struct axi_clkgen { |
33 | void __iomem *base; | 66 | void __iomem *base; |
67 | const struct axi_clkgen_mmcm_ops *mmcm_ops; | ||
34 | struct clk_hw clk_hw; | 68 | struct clk_hw clk_hw; |
35 | }; | 69 | }; |
36 | 70 | ||
71 | static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen, | ||
72 | bool enable) | ||
73 | { | ||
74 | axi_clkgen->mmcm_ops->enable(axi_clkgen, enable); | ||
75 | } | ||
76 | |||
77 | static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen, | ||
78 | unsigned int reg, unsigned int val, unsigned int mask) | ||
79 | { | ||
80 | return axi_clkgen->mmcm_ops->write(axi_clkgen, reg, val, mask); | ||
81 | } | ||
82 | |||
83 | static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen, | ||
84 | unsigned int reg, unsigned int *val) | ||
85 | { | ||
86 | return axi_clkgen->mmcm_ops->read(axi_clkgen, reg, val); | ||
87 | } | ||
88 | |||
37 | static uint32_t axi_clkgen_lookup_filter(unsigned int m) | 89 | static uint32_t axi_clkgen_lookup_filter(unsigned int m) |
38 | { | 90 | { |
39 | switch (m) { | 91 | switch (m) { |
@@ -156,6 +208,148 @@ static void axi_clkgen_read(struct axi_clkgen *axi_clkgen, | |||
156 | *val = readl(axi_clkgen->base + reg); | 208 | *val = readl(axi_clkgen->base + reg); |
157 | } | 209 | } |
158 | 210 | ||
211 | static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg) | ||
212 | { | ||
213 | switch (reg) { | ||
214 | case MMCM_REG_CLKOUT0_1: | ||
215 | return AXI_CLKGEN_V1_REG_CLK_OUT1; | ||
216 | case MMCM_REG_CLKOUT0_2: | ||
217 | return AXI_CLKGEN_V1_REG_CLK_OUT2; | ||
218 | case MMCM_REG_CLK_FB1: | ||
219 | return AXI_CLKGEN_V1_REG_CLK_FB1; | ||
220 | case MMCM_REG_CLK_FB2: | ||
221 | return AXI_CLKGEN_V1_REG_CLK_FB2; | ||
222 | case MMCM_REG_CLK_DIV: | ||
223 | return AXI_CLKGEN_V1_REG_CLK_DIV; | ||
224 | case MMCM_REG_LOCK1: | ||
225 | return AXI_CLKGEN_V1_REG_LOCK1; | ||
226 | case MMCM_REG_LOCK2: | ||
227 | return AXI_CLKGEN_V1_REG_LOCK2; | ||
228 | case MMCM_REG_LOCK3: | ||
229 | return AXI_CLKGEN_V1_REG_LOCK3; | ||
230 | case MMCM_REG_FILTER1: | ||
231 | return AXI_CLKGEN_V1_REG_FILTER1; | ||
232 | case MMCM_REG_FILTER2: | ||
233 | return AXI_CLKGEN_V1_REG_FILTER2; | ||
234 | default: | ||
235 | return 0; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static int axi_clkgen_v1_mmcm_write(struct axi_clkgen *axi_clkgen, | ||
240 | unsigned int reg, unsigned int val, unsigned int mask) | ||
241 | { | ||
242 | reg = axi_clkgen_v1_map_mmcm_reg(reg); | ||
243 | if (reg == 0) | ||
244 | return -EINVAL; | ||
245 | |||
246 | axi_clkgen_write(axi_clkgen, reg, val); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int axi_clkgen_v1_mmcm_read(struct axi_clkgen *axi_clkgen, | ||
252 | unsigned int reg, unsigned int *val) | ||
253 | { | ||
254 | reg = axi_clkgen_v1_map_mmcm_reg(reg); | ||
255 | if (reg == 0) | ||
256 | return -EINVAL; | ||
257 | |||
258 | axi_clkgen_read(axi_clkgen, reg, val); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen *axi_clkgen, | ||
264 | bool enable) | ||
265 | { | ||
266 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V1_REG_UPDATE_ENABLE, enable); | ||
267 | } | ||
268 | |||
269 | static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops = { | ||
270 | .write = axi_clkgen_v1_mmcm_write, | ||
271 | .read = axi_clkgen_v1_mmcm_read, | ||
272 | .enable = axi_clkgen_v1_mmcm_enable, | ||
273 | }; | ||
274 | |||
275 | static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen) | ||
276 | { | ||
277 | unsigned int timeout = 10000; | ||
278 | unsigned int val; | ||
279 | |||
280 | do { | ||
281 | axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val); | ||
282 | } while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout); | ||
283 | |||
284 | if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) | ||
285 | return -EIO; | ||
286 | |||
287 | return val & 0xffff; | ||
288 | } | ||
289 | |||
290 | static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen, | ||
291 | unsigned int reg, unsigned int *val) | ||
292 | { | ||
293 | unsigned int reg_val; | ||
294 | int ret; | ||
295 | |||
296 | ret = axi_clkgen_wait_non_busy(axi_clkgen); | ||
297 | if (ret < 0) | ||
298 | return ret; | ||
299 | |||
300 | reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ; | ||
301 | reg_val |= (reg << 16); | ||
302 | |||
303 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val); | ||
304 | |||
305 | ret = axi_clkgen_wait_non_busy(axi_clkgen); | ||
306 | if (ret < 0) | ||
307 | return ret; | ||
308 | |||
309 | *val = ret; | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen, | ||
315 | unsigned int reg, unsigned int val, unsigned int mask) | ||
316 | { | ||
317 | unsigned int reg_val = 0; | ||
318 | int ret; | ||
319 | |||
320 | ret = axi_clkgen_wait_non_busy(axi_clkgen); | ||
321 | if (ret < 0) | ||
322 | return ret; | ||
323 | |||
324 | if (mask != 0xffff) { | ||
325 | axi_clkgen_v2_mmcm_read(axi_clkgen, reg, ®_val); | ||
326 | reg_val &= ~mask; | ||
327 | } | ||
328 | |||
329 | reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask); | ||
330 | |||
331 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen, | ||
337 | bool enable) | ||
338 | { | ||
339 | unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE; | ||
340 | |||
341 | if (enable) | ||
342 | val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE; | ||
343 | |||
344 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val); | ||
345 | } | ||
346 | |||
347 | static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops = { | ||
348 | .write = axi_clkgen_v2_mmcm_write, | ||
349 | .read = axi_clkgen_v2_mmcm_read, | ||
350 | .enable = axi_clkgen_v2_mmcm_enable, | ||
351 | }; | ||
352 | |||
159 | static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw) | 353 | static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw) |
160 | { | 354 | { |
161 | return container_of(clk_hw, struct axi_clkgen, clk_hw); | 355 | return container_of(clk_hw, struct axi_clkgen, clk_hw); |
@@ -184,33 +378,29 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw, | |||
184 | filter = axi_clkgen_lookup_filter(m - 1); | 378 | filter = axi_clkgen_lookup_filter(m - 1); |
185 | lock = axi_clkgen_lookup_lock(m - 1); | 379 | lock = axi_clkgen_lookup_lock(m - 1); |
186 | 380 | ||
187 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0); | ||
188 | |||
189 | axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount); | 381 | axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount); |
190 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, | 382 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_1, |
191 | (high << 6) | low); | 383 | (high << 6) | low, 0xefff); |
192 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2, | 384 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_2, |
193 | (edge << 7) | (nocount << 6)); | 385 | (edge << 7) | (nocount << 6), 0x03ff); |
194 | 386 | ||
195 | axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount); | 387 | axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount); |
196 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, | 388 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV, |
197 | (edge << 13) | (nocount << 12) | (high << 6) | low); | 389 | (edge << 13) | (nocount << 12) | (high << 6) | low, 0x3fff); |
198 | 390 | ||
199 | axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount); | 391 | axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount); |
200 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, | 392 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB1, |
201 | (high << 6) | low); | 393 | (high << 6) | low, 0xefff); |
202 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2, | 394 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB2, |
203 | (edge << 7) | (nocount << 6)); | 395 | (edge << 7) | (nocount << 6), 0x03ff); |
204 | 396 | ||
205 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff); | 397 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff); |
206 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2, | 398 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2, |
207 | (((lock >> 16) & 0x1f) << 10) | 0x1); | 399 | (((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff); |
208 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3, | 400 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3, |
209 | (((lock >> 24) & 0x1f) << 10) | 0x3e9); | 401 | (((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff); |
210 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16); | 402 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900); |
211 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter); | 403 | axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900); |
212 | |||
213 | axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1); | ||
214 | 404 | ||
215 | return 0; | 405 | return 0; |
216 | } | 406 | } |
@@ -236,11 +426,11 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, | |||
236 | unsigned int reg; | 426 | unsigned int reg; |
237 | unsigned long long tmp; | 427 | unsigned long long tmp; |
238 | 428 | ||
239 | axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, ®); | 429 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); |
240 | dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); | 430 | dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); |
241 | axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, ®); | 431 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®); |
242 | d = (reg & 0x3f) + ((reg >> 6) & 0x3f); | 432 | d = (reg & 0x3f) + ((reg >> 6) & 0x3f); |
243 | axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, ®); | 433 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); |
244 | m = (reg & 0x3f) + ((reg >> 6) & 0x3f); | 434 | m = (reg & 0x3f) + ((reg >> 6) & 0x3f); |
245 | 435 | ||
246 | if (d == 0 || dout == 0) | 436 | if (d == 0 || dout == 0) |
@@ -255,14 +445,45 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, | |||
255 | return tmp; | 445 | return tmp; |
256 | } | 446 | } |
257 | 447 | ||
448 | static int axi_clkgen_enable(struct clk_hw *clk_hw) | ||
449 | { | ||
450 | struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); | ||
451 | |||
452 | axi_clkgen_mmcm_enable(axi_clkgen, true); | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static void axi_clkgen_disable(struct clk_hw *clk_hw) | ||
458 | { | ||
459 | struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); | ||
460 | |||
461 | axi_clkgen_mmcm_enable(axi_clkgen, false); | ||
462 | } | ||
463 | |||
258 | static const struct clk_ops axi_clkgen_ops = { | 464 | static const struct clk_ops axi_clkgen_ops = { |
259 | .recalc_rate = axi_clkgen_recalc_rate, | 465 | .recalc_rate = axi_clkgen_recalc_rate, |
260 | .round_rate = axi_clkgen_round_rate, | 466 | .round_rate = axi_clkgen_round_rate, |
261 | .set_rate = axi_clkgen_set_rate, | 467 | .set_rate = axi_clkgen_set_rate, |
468 | .enable = axi_clkgen_enable, | ||
469 | .disable = axi_clkgen_disable, | ||
262 | }; | 470 | }; |
263 | 471 | ||
472 | static const struct of_device_id axi_clkgen_ids[] = { | ||
473 | { | ||
474 | .compatible = "adi,axi-clkgen-1.00.a", | ||
475 | .data = &axi_clkgen_v1_mmcm_ops | ||
476 | }, { | ||
477 | .compatible = "adi,axi-clkgen-2.00.a", | ||
478 | .data = &axi_clkgen_v2_mmcm_ops, | ||
479 | }, | ||
480 | { }, | ||
481 | }; | ||
482 | MODULE_DEVICE_TABLE(of, axi_clkgen_ids); | ||
483 | |||
264 | static int axi_clkgen_probe(struct platform_device *pdev) | 484 | static int axi_clkgen_probe(struct platform_device *pdev) |
265 | { | 485 | { |
486 | const struct of_device_id *id; | ||
266 | struct axi_clkgen *axi_clkgen; | 487 | struct axi_clkgen *axi_clkgen; |
267 | struct clk_init_data init; | 488 | struct clk_init_data init; |
268 | const char *parent_name; | 489 | const char *parent_name; |
@@ -270,10 +491,19 @@ static int axi_clkgen_probe(struct platform_device *pdev) | |||
270 | struct resource *mem; | 491 | struct resource *mem; |
271 | struct clk *clk; | 492 | struct clk *clk; |
272 | 493 | ||
494 | if (!pdev->dev.of_node) | ||
495 | return -ENODEV; | ||
496 | |||
497 | id = of_match_node(axi_clkgen_ids, pdev->dev.of_node); | ||
498 | if (!id) | ||
499 | return -ENODEV; | ||
500 | |||
273 | axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL); | 501 | axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL); |
274 | if (!axi_clkgen) | 502 | if (!axi_clkgen) |
275 | return -ENOMEM; | 503 | return -ENOMEM; |
276 | 504 | ||
505 | axi_clkgen->mmcm_ops = id->data; | ||
506 | |||
277 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 507 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
278 | axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem); | 508 | axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem); |
279 | if (IS_ERR(axi_clkgen->base)) | 509 | if (IS_ERR(axi_clkgen->base)) |
@@ -289,10 +519,12 @@ static int axi_clkgen_probe(struct platform_device *pdev) | |||
289 | 519 | ||
290 | init.name = clk_name; | 520 | init.name = clk_name; |
291 | init.ops = &axi_clkgen_ops; | 521 | init.ops = &axi_clkgen_ops; |
292 | init.flags = 0; | 522 | init.flags = CLK_SET_RATE_GATE; |
293 | init.parent_names = &parent_name; | 523 | init.parent_names = &parent_name; |
294 | init.num_parents = 1; | 524 | init.num_parents = 1; |
295 | 525 | ||
526 | axi_clkgen_mmcm_enable(axi_clkgen, false); | ||
527 | |||
296 | axi_clkgen->clk_hw.init = &init; | 528 | axi_clkgen->clk_hw.init = &init; |
297 | clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw); | 529 | clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw); |
298 | if (IS_ERR(clk)) | 530 | if (IS_ERR(clk)) |
@@ -309,12 +541,6 @@ static int axi_clkgen_remove(struct platform_device *pdev) | |||
309 | return 0; | 541 | return 0; |
310 | } | 542 | } |
311 | 543 | ||
312 | static const struct of_device_id axi_clkgen_ids[] = { | ||
313 | { .compatible = "adi,axi-clkgen-1.00.a" }, | ||
314 | { }, | ||
315 | }; | ||
316 | MODULE_DEVICE_TABLE(of, axi_clkgen_ids); | ||
317 | |||
318 | static struct platform_driver axi_clkgen_driver = { | 544 | static struct platform_driver axi_clkgen_driver = { |
319 | .driver = { | 545 | .driver = { |
320 | .name = "adi-axi-clkgen", | 546 | .name = "adi-axi-clkgen", |