]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/rockchip/clk/rk_clk_pll.c
MFHead@r345275
[FreeBSD/FreeBSD.git] / sys / arm64 / rockchip / clk / rk_clk_pll.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37
38 #include <dev/extres/clk/clk.h>
39
40 #include <arm64/rockchip/clk/rk_clk_pll.h>
41
42 #include "clkdev_if.h"
43
44 struct rk_clk_pll_sc {
45         uint32_t        base_offset;
46
47         uint32_t        gate_offset;
48         uint32_t        gate_shift;
49
50         uint32_t        mode_reg;
51         uint32_t        mode_shift;
52
53         uint32_t        flags;
54
55         struct rk_clk_pll_rate  *rates;
56         struct rk_clk_pll_rate  *frac_rates;
57 };
58
59 #define WRITE4(_clk, off, val)                                  \
60         CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
61 #define READ4(_clk, off, val)                                   \
62         CLKDEV_READ_4(clknode_get_device(_clk), off, val)
63 #define DEVICE_LOCK(_clk)                                       \
64         CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
65 #define DEVICE_UNLOCK(_clk)                                     \
66         CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
67
68 #define RK_CLK_PLL_MASK_SHIFT   16
69
70 /* #define      dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */
71 #define dprintf(format, arg...)
72
73 static int
74 rk_clk_pll_set_gate(struct clknode *clk, bool enable)
75 {
76         struct rk_clk_pll_sc *sc;
77         uint32_t val = 0;
78
79         sc = clknode_get_softc(clk);
80
81         if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
82                 return (0);
83
84         dprintf("%sabling gate\n", enable ? "En" : "Dis");
85         if (!enable)
86                 val |= 1 << sc->gate_shift;
87         dprintf("sc->gate_shift: %x\n", sc->gate_shift);
88         val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT;
89         dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val);
90         DEVICE_LOCK(clk);
91         WRITE4(clk, sc->gate_offset, val);
92         DEVICE_UNLOCK(clk);
93
94         return (0);
95 }
96
97 #define RK3328_CLK_PLL_FBDIV_OFFSET     0
98 #define RK3328_CLK_PLL_FBDIV_SHIFT      0
99 #define RK3328_CLK_PLL_FBDIV_MASK       0xFFF
100
101 #define RK3328_CLK_PLL_POSTDIV1_OFFSET  0
102 #define RK3328_CLK_PLL_POSTDIV1_SHIFT   12
103 #define RK3328_CLK_PLL_POSTDIV1_MASK    0x7000
104
105 #define RK3328_CLK_PLL_DSMPD_OFFSET     4
106 #define RK3328_CLK_PLL_DSMPD_SHIFT      12
107 #define RK3328_CLK_PLL_DSMPD_MASK       0x1000
108
109 #define RK3328_CLK_PLL_REFDIV_OFFSET    4
110 #define RK3328_CLK_PLL_REFDIV_SHIFT     0
111 #define RK3328_CLK_PLL_REFDIV_MASK      0x3F
112
113 #define RK3328_CLK_PLL_POSTDIV2_OFFSET  4
114 #define RK3328_CLK_PLL_POSTDIV2_SHIFT   6
115 #define RK3328_CLK_PLL_POSTDIV2_MASK    0x1C0
116
117 #define RK3328_CLK_PLL_FRAC_OFFSET      8
118 #define RK3328_CLK_PLL_FRAC_SHIFT       0
119 #define RK3328_CLK_PLL_FRAC_MASK        0xFFFFFF
120
121 #define RK3328_CLK_PLL_LOCK_MASK        0x400
122
123 #define RK3328_CLK_PLL_MODE_SLOW        0
124 #define RK3328_CLK_PLL_MODE_NORMAL      1
125 #define RK3328_CLK_PLL_MODE_MASK        0x1
126
127 static int
128 rk3328_clk_pll_init(struct clknode *clk, device_t dev)
129 {
130         struct rk_clk_pll_sc *sc;
131
132         sc = clknode_get_softc(clk);
133
134         clknode_init_parent_idx(clk, 0);
135
136         return (0);
137 }
138
139 static int
140 rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
141 {
142         struct rk_clk_pll_sc *sc;
143         uint64_t rate;
144         uint32_t dsmpd, refdiv, fbdiv;
145         uint32_t postdiv1, postdiv2, frac;
146         uint32_t raw1, raw2, raw3;
147
148         sc = clknode_get_softc(clk);
149
150         DEVICE_LOCK(clk);
151
152         READ4(clk, sc->base_offset, &raw1);
153         READ4(clk, sc->base_offset + 4, &raw2);
154         READ4(clk, sc->base_offset + 8, &raw3);
155
156         fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;
157         postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;
158
159         dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;
160         refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;
161         postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;
162
163         frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
164
165         DEVICE_UNLOCK(clk);
166
167         rate = *freq * fbdiv / refdiv;
168         if (dsmpd == 0) {
169                 /* Fractional mode */
170                 uint64_t frac_rate;
171
172                 frac_rate = *freq * frac / refdiv;
173                 rate += frac_rate >> 24;
174         }
175
176         *freq = rate / postdiv1 / postdiv2;
177
178         if (*freq % 2)
179                 *freq = *freq + 1;
180
181         return (0);
182 }
183
184 static int
185 rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
186     int flags, int *stop)
187 {
188         struct rk_clk_pll_rate *rates;
189         struct rk_clk_pll_sc *sc;
190         uint32_t reg;
191         int timeout;
192
193         sc = clknode_get_softc(clk);
194
195         if (sc->rates)
196                 rates = sc->rates;
197         else if (sc->frac_rates)
198                 rates = sc->frac_rates;
199         else
200                 return (EINVAL);
201
202         for (; rates->freq; rates++) {
203                 if (rates->freq == *fout)
204                         break;
205         }
206         if (rates->freq == 0) {
207                 *stop = 1;
208                 return (EINVAL);
209         }
210
211         DEVICE_LOCK(clk);
212
213         /* Setting to slow mode during frequency change */
214         reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
215                 RK_CLK_PLL_MASK_SHIFT;
216         dprintf("Set PLL_MODEREG to %x\n", reg);
217         WRITE4(clk, sc->mode_reg, reg);
218
219         /* Setting postdiv1 and fbdiv */
220         reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |
221                 (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);
222         reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;
223         dprintf("Set PLL_CON0 to %x\n", reg);
224         WRITE4(clk, sc->base_offset, reg);
225
226         /* Setting dsmpd, postdiv2 and refdiv */
227         reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |
228                 (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |
229                 (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);
230         reg |= (RK3328_CLK_PLL_DSMPD_MASK |
231             RK3328_CLK_PLL_POSTDIV2_MASK |
232             RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
233         dprintf("Set PLL_CON1 to %x\n", reg);
234         WRITE4(clk, sc->base_offset + 0x4, reg);
235
236         /* Setting frac */
237         READ4(clk, sc->base_offset + 0x8, &reg);
238         reg &= ~RK3328_CLK_PLL_FRAC_MASK;
239         reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;
240         dprintf("Set PLL_CON2 to %x\n", reg);
241         WRITE4(clk, sc->base_offset + 0x8, reg);
242
243         /* Reading lock */
244         for (timeout = 1000; timeout; timeout--) {
245                 READ4(clk, sc->base_offset + 0x4, &reg);
246                 if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
247                         break;
248                 DELAY(1);
249         }
250
251         /* Set back to normal mode */
252         reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);
253         reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
254                 RK_CLK_PLL_MASK_SHIFT;
255         dprintf("Set PLL_MODEREG to %x\n", reg);
256         WRITE4(clk, sc->mode_reg, reg);
257
258         DEVICE_UNLOCK(clk);
259
260         *stop = 1;
261         return (0);
262 }
263
264 static clknode_method_t rk3328_clk_pll_clknode_methods[] = {
265         /* Device interface */
266         CLKNODEMETHOD(clknode_init,             rk3328_clk_pll_init),
267         CLKNODEMETHOD(clknode_set_gate,         rk_clk_pll_set_gate),
268         CLKNODEMETHOD(clknode_recalc_freq,      rk3328_clk_pll_recalc),
269         CLKNODEMETHOD(clknode_set_freq,         rk3328_clk_pll_set_freq),
270         CLKNODEMETHOD_END
271 };
272
273 DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,
274     rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
275
276 int
277 rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
278 {
279         struct clknode *clk;
280         struct rk_clk_pll_sc *sc;
281
282         clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
283             &clkdef->clkdef);
284         if (clk == NULL)
285                 return (1);
286
287         sc = clknode_get_softc(clk);
288
289         sc->base_offset = clkdef->base_offset;
290         sc->gate_offset = clkdef->gate_offset;
291         sc->gate_shift = clkdef->gate_shift;
292         sc->mode_reg = clkdef->mode_reg;
293         sc->mode_shift = clkdef->mode_shift;
294         sc->flags = clkdef->flags;
295         sc->rates = clkdef->rates;
296         sc->frac_rates = clkdef->frac_rates;
297
298         clknode_register(clkdom, clk);
299
300         return (0);
301 }
302
303 #define RK3399_CLK_PLL_FBDIV_OFFSET             0
304 #define RK3399_CLK_PLL_FBDIV_SHIFT              0
305 #define RK3399_CLK_PLL_FBDIV_MASK               0xFFF
306
307 #define RK3399_CLK_PLL_POSTDIV2_OFFSET  4
308 #define RK3399_CLK_PLL_POSTDIV2_SHIFT   12
309 #define RK3399_CLK_PLL_POSTDIV2_MASK    0x7000
310
311 #define RK3399_CLK_PLL_POSTDIV1_OFFSET  4
312 #define RK3399_CLK_PLL_POSTDIV1_SHIFT   8
313 #define RK3399_CLK_PLL_POSTDIV1_MASK    0x700
314
315 #define RK3399_CLK_PLL_REFDIV_OFFSET    4
316 #define RK3399_CLK_PLL_REFDIV_SHIFT     0
317 #define RK3399_CLK_PLL_REFDIV_MASK      0x3F
318
319 #define RK3399_CLK_PLL_FRAC_OFFSET      8
320 #define RK3399_CLK_PLL_FRAC_SHIFT       0
321 #define RK3399_CLK_PLL_FRAC_MASK        0xFFFFFF
322
323 #define RK3399_CLK_PLL_DSMPD_OFFSET     0xC
324 #define RK3399_CLK_PLL_DSMPD_SHIFT      3
325 #define RK3399_CLK_PLL_DSMPD_MASK       0x8
326
327 #define RK3399_CLK_PLL_LOCK_OFFSET      8
328 #define RK3399_CLK_PLL_LOCK_MASK        0x400
329
330 #define RK3399_CLK_PLL_MODE_OFFSET      0xC
331 #define RK3399_CLK_PLL_MODE_MASK        0x300
332 #define RK3399_CLK_PLL_MODE_SLOW        0
333 #define RK3399_CLK_PLL_MODE_NORMAL      1
334 #define RK3399_CLK_PLL_MODE_DEEPSLOW    2
335 #define RK3399_CLK_PLL_MODE_SHIFT       8
336
337 #define RK3399_CLK_PLL_WRITE_MASK       0xFFFF0000
338
339 static int
340 rk3399_clk_pll_init(struct clknode *clk, device_t dev)
341 {
342         struct rk_clk_pll_sc *sc;
343         uint32_t reg;
344
345         sc = clknode_get_softc(clk);
346
347         /* Setting to normal mode */
348         reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
349         reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
350         WRITE4(clk, sc->base_offset + RK3399_CLK_PLL_MODE_OFFSET,
351             reg | RK3399_CLK_PLL_WRITE_MASK);
352
353         clknode_init_parent_idx(clk, 0);
354
355         return (0);
356 }
357
358 static int
359 rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
360 {
361         struct rk_clk_pll_sc *sc;
362         uint32_t dsmpd, refdiv, fbdiv;
363         uint32_t postdiv1, postdiv2, fracdiv;
364         uint32_t con1, con2, con3, con4;
365         uint64_t foutvco;
366
367         sc = clknode_get_softc(clk);
368
369         DEVICE_LOCK(clk);
370         READ4(clk, sc->base_offset, &con1);
371         READ4(clk, sc->base_offset + 4, &con2);
372         READ4(clk, sc->base_offset + 8, &con3);
373         READ4(clk, sc->base_offset + 0xC, &con4);
374         DEVICE_UNLOCK(clk);
375
376         dprintf("con0: %x\n", con1);
377         dprintf("con1: %x\n", con2);
378         dprintf("con2: %x\n", con3);
379         dprintf("con3: %x\n", con4);
380
381         fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK) >> RK3399_CLK_PLL_FBDIV_SHIFT;
382
383         postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK) >> RK3399_CLK_PLL_POSTDIV1_SHIFT;
384         postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK) >> RK3399_CLK_PLL_POSTDIV2_SHIFT;
385         refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK) >> RK3399_CLK_PLL_REFDIV_SHIFT;
386
387         fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK) >> RK3399_CLK_PLL_FRAC_SHIFT;
388         fracdiv >>= 24;
389
390         dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
391
392         dprintf("fbdiv: %d\n", fbdiv);
393         dprintf("postdiv1: %d\n", postdiv1);
394         dprintf("postdiv2: %d\n", postdiv2);
395         dprintf("refdiv: %d\n", refdiv);
396         dprintf("fracdiv: %d\n", fracdiv);
397         dprintf("dsmpd: %d\n", dsmpd);
398
399         dprintf("parent freq=%lu\n", *freq);
400
401         if (dsmpd == 0) {
402                 /* Fractional mode */
403                 foutvco = *freq / refdiv * (fbdiv + fracdiv);
404         } else {
405                 /* Integer mode */
406                 foutvco = *freq / refdiv * fbdiv;
407         }
408         dprintf("foutvco: %lu\n", foutvco);
409
410         *freq = foutvco / postdiv1 / postdiv2;
411         dprintf("freq: %lu\n", *freq);
412
413         return (0);
414 }
415
416 static int
417 rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
418     int flags, int *stop)
419 {
420         struct rk_clk_pll_rate *rates;
421         struct rk_clk_pll_sc *sc;
422         uint32_t reg;
423         int timeout;
424
425         sc = clknode_get_softc(clk);
426
427         if (sc->rates)
428                 rates = sc->rates;
429         else if (sc->frac_rates)
430                 rates = sc->frac_rates;
431         else
432                 return (EINVAL);
433
434         for (; rates->freq; rates++) {
435                 if (rates->freq == *fout)
436                         break;
437         }
438         if (rates->freq == 0) {
439                 *stop = 1;
440                 return (EINVAL);
441         }
442
443         DEVICE_LOCK(clk);
444
445         /* Set to slow mode during frequency change */
446         reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;
447         reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
448         WRITE4(clk, sc->base_offset + 0xC, reg);
449
450         /* Setting fbdiv */
451         reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;
452         reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;
453         WRITE4(clk, sc->base_offset, reg);
454
455         /* Setting postdiv1, postdiv2 and refdiv */
456         reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;
457         reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;
458         reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;
459         reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |
460             RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
461         WRITE4(clk, sc->base_offset + 0x4, reg);
462
463         /* Setting frac */
464         READ4(clk, sc->base_offset + 0x8, &reg);
465         reg &= ~RK3399_CLK_PLL_FRAC_MASK;
466         reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;
467         WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);
468
469         /* Set dsmpd */
470         reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;
471         reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;
472         WRITE4(clk, sc->base_offset + 0xC, reg);
473
474         /* Reading lock */
475         for (timeout = 1000; timeout; timeout--) {
476                 READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, &reg);
477                 if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
478                         break;
479                 DELAY(1);
480         }
481
482         /* Set back to normal mode */
483         reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
484         reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
485         WRITE4(clk, sc->base_offset + 0xC, reg);
486
487         DEVICE_UNLOCK(clk);
488
489         *stop = 1;
490         return (0);
491 }
492
493 static clknode_method_t rk3399_clk_pll_clknode_methods[] = {
494         /* Device interface */
495         CLKNODEMETHOD(clknode_init,             rk3399_clk_pll_init),
496         CLKNODEMETHOD(clknode_set_gate,         rk_clk_pll_set_gate),
497         CLKNODEMETHOD(clknode_recalc_freq,      rk3399_clk_pll_recalc),
498         CLKNODEMETHOD(clknode_set_freq,         rk3399_clk_pll_set_freq),
499         CLKNODEMETHOD_END
500 };
501
502 DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,
503     rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
504
505 int
506 rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
507 {
508         struct clknode *clk;
509         struct rk_clk_pll_sc *sc;
510
511         clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
512             &clkdef->clkdef);
513         if (clk == NULL)
514                 return (1);
515
516         sc = clknode_get_softc(clk);
517
518         sc->base_offset = clkdef->base_offset;
519         sc->gate_offset = clkdef->gate_offset;
520         sc->gate_shift = clkdef->gate_shift;
521         sc->flags = clkdef->flags;
522         sc->rates = clkdef->rates;
523         sc->frac_rates = clkdef->frac_rates;
524
525         clknode_register(clkdom, clk);
526
527         return (0);
528 }