c3a6650de0328d563bf869582b596c043d75d862
[oweals/u-boot.git] / drivers / clk / rockchip / clk_rk3328.c
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0
5  */
6
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <syscon.h>
12 #include <asm/arch/clock.h>
13 #include <asm/arch/cru_rk3328.h>
14 #include <asm/arch/hardware.h>
15 #include <asm/io.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rk3328-cru.h>
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 struct pll_div {
22         u32 refdiv;
23         u32 fbdiv;
24         u32 postdiv1;
25         u32 postdiv2;
26         u32 frac;
27 };
28
29 #define RATE_TO_DIV(input_rate, output_rate) \
30         ((input_rate) / (output_rate) - 1);
31 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
32
33 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
34         .refdiv = _refdiv,\
35         .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
36         .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};
37
38 static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 4, 1);
39 static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 2, 1);
40
41 static const struct pll_div apll_816_cfg = PLL_DIVISORS(816 * MHz, 1, 2, 1);
42 static const struct pll_div apll_600_cfg = PLL_DIVISORS(600 * MHz, 1, 3, 1);
43
44 static const struct pll_div *apll_cfgs[] = {
45         [APLL_816_MHZ] = &apll_816_cfg,
46         [APLL_600_MHZ] = &apll_600_cfg,
47 };
48
49 enum {
50         /* PLL_CON0 */
51         PLL_POSTDIV1_SHIFT              = 12,
52         PLL_POSTDIV1_MASK               = 0x7 << PLL_POSTDIV1_SHIFT,
53         PLL_FBDIV_SHIFT                 = 0,
54         PLL_FBDIV_MASK                  = 0xfff,
55
56         /* PLL_CON1 */
57         PLL_DSMPD_SHIFT                 = 12,
58         PLL_DSMPD_MASK                  = 1 << PLL_DSMPD_SHIFT,
59         PLL_INTEGER_MODE                = 1,
60         PLL_LOCK_STATUS_SHIFT           = 10,
61         PLL_LOCK_STATUS_MASK            = 1 << PLL_LOCK_STATUS_SHIFT,
62         PLL_POSTDIV2_SHIFT              = 6,
63         PLL_POSTDIV2_MASK               = 0x7 << PLL_POSTDIV2_SHIFT,
64         PLL_REFDIV_SHIFT                = 0,
65         PLL_REFDIV_MASK                 = 0x3f,
66
67         /* PLL_CON2 */
68         PLL_FRACDIV_SHIFT               = 0,
69         PLL_FRACDIV_MASK                = 0xffffff,
70
71         /* MODE_CON */
72         APLL_MODE_SHIFT                 = 0,
73         NPLL_MODE_SHIFT                 = 1,
74         DPLL_MODE_SHIFT                 = 4,
75         CPLL_MODE_SHIFT                 = 8,
76         GPLL_MODE_SHIFT                 = 12,
77         PLL_MODE_SLOW                   = 0,
78         PLL_MODE_NORM,
79
80         /* CLKSEL_CON0 */
81         CLK_CORE_PLL_SEL_APLL           = 0,
82         CLK_CORE_PLL_SEL_GPLL,
83         CLK_CORE_PLL_SEL_DPLL,
84         CLK_CORE_PLL_SEL_NPLL,
85         CLK_CORE_PLL_SEL_SHIFT          = 6,
86         CLK_CORE_PLL_SEL_MASK           = 3 << CLK_CORE_PLL_SEL_SHIFT,
87         CLK_CORE_DIV_SHIFT              = 0,
88         CLK_CORE_DIV_MASK               = 0x1f,
89
90         /* CLKSEL_CON1 */
91         ACLKM_CORE_DIV_SHIFT            = 4,
92         ACLKM_CORE_DIV_MASK             = 0x7 << ACLKM_CORE_DIV_SHIFT,
93         PCLK_DBG_DIV_SHIFT              = 0,
94         PCLK_DBG_DIV_MASK               = 0xF << PCLK_DBG_DIV_SHIFT,
95
96         /* CLKSEL_CON28 */
97         ACLK_PERIHP_PLL_SEL_CPLL        = 0,
98         ACLK_PERIHP_PLL_SEL_GPLL,
99         ACLK_PERIHP_PLL_SEL_HDMIPHY,
100         ACLK_PERIHP_PLL_SEL_SHIFT       = 6,
101         ACLK_PERIHP_PLL_SEL_MASK        = 3 << ACLK_PERIHP_PLL_SEL_SHIFT,
102         ACLK_PERIHP_DIV_CON_SHIFT       = 0,
103         ACLK_PERIHP_DIV_CON_MASK        = 0x1f,
104
105         /* CLKSEL_CON29 */
106         PCLK_PERIHP_DIV_CON_SHIFT       = 4,
107         PCLK_PERIHP_DIV_CON_MASK        = 0x7 << PCLK_PERIHP_DIV_CON_SHIFT,
108         HCLK_PERIHP_DIV_CON_SHIFT       = 0,
109         HCLK_PERIHP_DIV_CON_MASK        = 3 << HCLK_PERIHP_DIV_CON_SHIFT,
110
111         /* CLKSEL_CON22 */
112         CLK_TSADC_DIV_CON_SHIFT         = 0,
113         CLK_TSADC_DIV_CON_MASK          = 0x3ff,
114
115         /* CLKSEL_CON23 */
116         CLK_SARADC_DIV_CON_SHIFT        = 0,
117         CLK_SARADC_DIV_CON_MASK         = 0x3ff << CLK_SARADC_DIV_CON_SHIFT,
118
119         /* CLKSEL_CON24 */
120         CLK_PWM_PLL_SEL_CPLL            = 0,
121         CLK_PWM_PLL_SEL_GPLL,
122         CLK_PWM_PLL_SEL_SHIFT           = 15,
123         CLK_PWM_PLL_SEL_MASK            = 1 << CLK_PWM_PLL_SEL_SHIFT,
124         CLK_PWM_DIV_CON_SHIFT           = 8,
125         CLK_PWM_DIV_CON_MASK            = 0x7f << CLK_PWM_DIV_CON_SHIFT,
126
127         CLK_SPI_PLL_SEL_CPLL            = 0,
128         CLK_SPI_PLL_SEL_GPLL,
129         CLK_SPI_PLL_SEL_SHIFT           = 7,
130         CLK_SPI_PLL_SEL_MASK            = 1 << CLK_SPI_PLL_SEL_SHIFT,
131         CLK_SPI_DIV_CON_SHIFT           = 0,
132         CLK_SPI_DIV_CON_MASK            = 0x7f << CLK_SPI_DIV_CON_SHIFT,
133
134         /* CLKSEL_CON30 */
135         CLK_SDMMC_PLL_SEL_CPLL          = 0,
136         CLK_SDMMC_PLL_SEL_GPLL,
137         CLK_SDMMC_PLL_SEL_24M,
138         CLK_SDMMC_PLL_SEL_USBPHY,
139         CLK_SDMMC_PLL_SHIFT             = 8,
140         CLK_SDMMC_PLL_MASK              = 0x3 << CLK_SDMMC_PLL_SHIFT,
141         CLK_SDMMC_DIV_CON_SHIFT          = 0,
142         CLK_SDMMC_DIV_CON_MASK           = 0xff << CLK_SDMMC_DIV_CON_SHIFT,
143
144         /* CLKSEL_CON32 */
145         CLK_EMMC_PLL_SEL_CPLL           = 0,
146         CLK_EMMC_PLL_SEL_GPLL,
147         CLK_EMMC_PLL_SEL_24M,
148         CLK_EMMC_PLL_SEL_USBPHY,
149         CLK_EMMC_PLL_SHIFT              = 8,
150         CLK_EMMC_PLL_MASK               = 0x3 << CLK_EMMC_PLL_SHIFT,
151         CLK_EMMC_DIV_CON_SHIFT          = 0,
152         CLK_EMMC_DIV_CON_MASK           = 0xff << CLK_EMMC_DIV_CON_SHIFT,
153
154         /* CLKSEL_CON34 */
155         CLK_I2C_PLL_SEL_CPLL            = 0,
156         CLK_I2C_PLL_SEL_GPLL,
157         CLK_I2C_DIV_CON_MASK            = 0x7f,
158         CLK_I2C_PLL_SEL_MASK            = 1,
159         CLK_I2C1_PLL_SEL_SHIFT          = 15,
160         CLK_I2C1_DIV_CON_SHIFT          = 8,
161         CLK_I2C0_PLL_SEL_SHIFT          = 7,
162         CLK_I2C0_DIV_CON_SHIFT          = 0,
163
164         /* CLKSEL_CON35 */
165         CLK_I2C3_PLL_SEL_SHIFT          = 15,
166         CLK_I2C3_DIV_CON_SHIFT          = 8,
167         CLK_I2C2_PLL_SEL_SHIFT          = 7,
168         CLK_I2C2_DIV_CON_SHIFT          = 0,
169 };
170
171 #define VCO_MAX_KHZ     (3200 * (MHz / KHz))
172 #define VCO_MIN_KHZ     (800 * (MHz / KHz))
173 #define OUTPUT_MAX_KHZ  (3200 * (MHz / KHz))
174 #define OUTPUT_MIN_KHZ  (16 * (MHz / KHz))
175
176 /*
177  *  the div restructions of pll in integer mode, these are defined in
178  *  * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
179  */
180 #define PLL_DIV_MIN     16
181 #define PLL_DIV_MAX     3200
182
183 /*
184  * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
185  * Formulas also embedded within the Fractional PLL Verilog model:
186  * If DSMPD = 1 (DSM is disabled, "integer mode")
187  * FOUTVCO = FREF / REFDIV * FBDIV
188  * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
189  * Where:
190  * FOUTVCO = Fractional PLL non-divided output frequency
191  * FOUTPOSTDIV = Fractional PLL divided output frequency
192  *               (output of second post divider)
193  * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
194  * REFDIV = Fractional PLL input reference clock divider
195  * FBDIV = Integer value programmed into feedback divide
196  *
197  */
198 static void rkclk_set_pll(struct rk3328_cru *cru, enum rk_clk_id clk_id,
199                         const struct pll_div *div)
200 {
201         u32 *pll_con;
202         u32 mode_shift, mode_mask;
203
204         pll_con = NULL;
205         mode_shift = 0;
206         switch (clk_id) {
207         case CLK_ARM:
208                 pll_con = cru->apll_con;
209                 mode_shift = APLL_MODE_SHIFT;
210                 break;
211         case CLK_DDR:
212                 pll_con = cru->dpll_con;
213                 mode_shift = DPLL_MODE_SHIFT;
214                 break;
215         case CLK_CODEC:
216                 pll_con = cru->cpll_con;
217                 mode_shift = CPLL_MODE_SHIFT;
218                 break;
219         case CLK_GENERAL:
220                 pll_con = cru->gpll_con;
221                 mode_shift = GPLL_MODE_SHIFT;
222                 break;
223         case CLK_NEW:
224                 pll_con = cru->npll_con;
225                 mode_shift = NPLL_MODE_SHIFT;
226                 break;
227         default:
228                 break;
229         }
230         mode_mask = 1 << mode_shift;
231
232         /* All 8 PLLs have same VCO and output frequency range restrictions. */
233         u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv;
234         u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
235
236         debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, \
237               postdiv2=%d, vco=%u khz, output=%u khz\n",
238               pll_con, div->fbdiv, div->refdiv, div->postdiv1,
239               div->postdiv2, vco_khz, output_khz);
240         assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ &&
241                output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ &&
242                div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX);
243
244         /*
245          * When power on or changing PLL setting,
246          * we must force PLL into slow mode to ensure output stable clock.
247          */
248         rk_clrsetreg(&cru->mode_con, mode_mask, PLL_MODE_SLOW << mode_shift);
249
250         /* use integer mode */
251         rk_clrsetreg(&pll_con[1], PLL_DSMPD_MASK,
252                      PLL_INTEGER_MODE << PLL_DSMPD_SHIFT);
253
254         rk_clrsetreg(&pll_con[0],
255                      PLL_FBDIV_MASK | PLL_POSTDIV1_MASK,
256                      (div->fbdiv << PLL_FBDIV_SHIFT) |
257                      (div->postdiv1 << PLL_POSTDIV1_SHIFT));
258         rk_clrsetreg(&pll_con[1],
259                      PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
260                      (div->postdiv2 << PLL_POSTDIV2_SHIFT) |
261                      (div->refdiv << PLL_REFDIV_SHIFT));
262
263         /* waiting for pll lock */
264         while (!(readl(&pll_con[1]) & (1 << PLL_LOCK_STATUS_SHIFT)))
265                 udelay(1);
266
267         /* pll enter normal mode */
268         rk_clrsetreg(&cru->mode_con, mode_mask, PLL_MODE_NORM << mode_shift);
269 }
270
271 static void rkclk_init(struct rk3328_cru *cru)
272 {
273         u32 aclk_div;
274         u32 hclk_div;
275         u32 pclk_div;
276
277         /* configure gpll cpll */
278         rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
279         rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
280
281         /* configure perihp aclk, hclk, pclk */
282         aclk_div = GPLL_HZ / PERIHP_ACLK_HZ - 1;
283         hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1;
284         pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1;
285
286         rk_clrsetreg(&cru->clksel_con[28],
287                      ACLK_PERIHP_PLL_SEL_MASK | ACLK_PERIHP_DIV_CON_MASK,
288                      ACLK_PERIHP_PLL_SEL_GPLL << ACLK_PERIHP_PLL_SEL_SHIFT |
289                      aclk_div << ACLK_PERIHP_DIV_CON_SHIFT);
290         rk_clrsetreg(&cru->clksel_con[29],
291                      PCLK_PERIHP_DIV_CON_MASK | HCLK_PERIHP_DIV_CON_MASK,
292                      pclk_div << PCLK_PERIHP_DIV_CON_SHIFT |
293                      hclk_div << HCLK_PERIHP_DIV_CON_SHIFT);
294 }
295
296 void rk3328_configure_cpu(struct rk3328_cru *cru,
297                           enum apll_frequencies apll_freq)
298 {
299         u32 clk_core_div;
300         u32 aclkm_div;
301         u32 pclk_dbg_div;
302
303         rkclk_set_pll(cru, CLK_ARM, apll_cfgs[apll_freq]);
304
305         clk_core_div = APLL_HZ / CLK_CORE_HZ - 1;
306         aclkm_div = APLL_HZ / ACLKM_CORE_HZ / (clk_core_div + 1) - 1;
307         pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ / (clk_core_div + 1) - 1;
308
309         rk_clrsetreg(&cru->clksel_con[0],
310                      CLK_CORE_PLL_SEL_MASK | CLK_CORE_DIV_MASK,
311                      CLK_CORE_PLL_SEL_APLL << CLK_CORE_PLL_SEL_SHIFT |
312                      clk_core_div << CLK_CORE_DIV_SHIFT);
313
314         rk_clrsetreg(&cru->clksel_con[1],
315                      PCLK_DBG_DIV_MASK | ACLKM_CORE_DIV_MASK,
316                      pclk_dbg_div << PCLK_DBG_DIV_SHIFT |
317                      aclkm_div << ACLKM_CORE_DIV_SHIFT);
318 }
319
320
321 static ulong rk3328_i2c_get_clk(struct rk3328_cru *cru, ulong clk_id)
322 {
323         u32 div, con;
324
325         switch (clk_id) {
326         case SCLK_I2C0:
327                 con = readl(&cru->clksel_con[34]);
328                 div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
329                 break;
330         case SCLK_I2C1:
331                 con = readl(&cru->clksel_con[34]);
332                 div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
333                 break;
334         case SCLK_I2C2:
335                 con = readl(&cru->clksel_con[35]);
336                 div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
337                 break;
338         case SCLK_I2C3:
339                 con = readl(&cru->clksel_con[35]);
340                 div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
341                 break;
342         default:
343                 printf("do not support this i2c bus\n");
344                 return -EINVAL;
345         }
346
347         return DIV_TO_RATE(GPLL_HZ, div);
348 }
349
350 static ulong rk3328_i2c_set_clk(struct rk3328_cru *cru, ulong clk_id, uint hz)
351 {
352         int src_clk_div;
353
354         src_clk_div = GPLL_HZ / hz;
355         assert(src_clk_div - 1 < 127);
356
357         switch (clk_id) {
358         case SCLK_I2C0:
359                 rk_clrsetreg(&cru->clksel_con[34],
360                              CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT |
361                              CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT,
362                              (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
363                              CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT);
364                 break;
365         case SCLK_I2C1:
366                 rk_clrsetreg(&cru->clksel_con[34],
367                              CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT |
368                              CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT,
369                              (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
370                              CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
371                 break;
372         case SCLK_I2C2:
373                 rk_clrsetreg(&cru->clksel_con[35],
374                              CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT |
375                              CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT,
376                              (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
377                              CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
378                 break;
379         case SCLK_I2C3:
380                 rk_clrsetreg(&cru->clksel_con[35],
381                              CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT |
382                              CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT,
383                              (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
384                              CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
385                 break;
386         default:
387                 printf("do not support this i2c bus\n");
388                 return -EINVAL;
389         }
390
391         return DIV_TO_RATE(GPLL_HZ, src_clk_div);
392 }
393
394 static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id)
395 {
396         u32 div, con, con_id;
397
398         switch (clk_id) {
399         case HCLK_SDMMC:
400         case SCLK_SDMMC:
401                 con_id = 30;
402                 break;
403         case HCLK_EMMC:
404         case SCLK_EMMC:
405                 con_id = 32;
406                 break;
407         default:
408                 return -EINVAL;
409         }
410         con = readl(&cru->clksel_con[con_id]);
411         div = (con & CLK_EMMC_DIV_CON_MASK) >> CLK_EMMC_DIV_CON_SHIFT;
412
413         if ((con & CLK_EMMC_PLL_MASK) >> CLK_EMMC_PLL_SHIFT
414             == CLK_EMMC_PLL_SEL_24M)
415                 return DIV_TO_RATE(OSC_HZ, div) / 2;
416         else
417                 return DIV_TO_RATE(GPLL_HZ, div) / 2;
418 }
419
420 static ulong rk3328_mmc_set_clk(struct rk3328_cru *cru,
421                                 ulong clk_id, ulong set_rate)
422 {
423         int src_clk_div;
424         u32 con_id;
425
426         switch (clk_id) {
427         case HCLK_SDMMC:
428         case SCLK_SDMMC:
429                 con_id = 30;
430                 break;
431         case HCLK_EMMC:
432         case SCLK_EMMC:
433                 con_id = 32;
434                 break;
435         default:
436                 return -EINVAL;
437         }
438         /* Select clk_sdmmc/emmc source from GPLL by default */
439         /* mmc clock defaulg div 2 internal, need provide double in cru */
440         src_clk_div = DIV_ROUND_UP(GPLL_HZ / 2, set_rate);
441
442         if (src_clk_div > 127) {
443                 /* use 24MHz source for 400KHz clock */
444                 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
445                 rk_clrsetreg(&cru->clksel_con[con_id],
446                              CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
447                              CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT |
448                              (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
449         } else {
450                 rk_clrsetreg(&cru->clksel_con[con_id],
451                              CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
452                              CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT |
453                              (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
454         }
455
456         return rk3328_mmc_get_clk(cru, clk_id);
457 }
458
459 static ulong rk3328_pwm_get_clk(struct rk3328_cru *cru)
460 {
461         u32 div, con;
462
463         con = readl(&cru->clksel_con[24]);
464         div = (con & CLK_PWM_DIV_CON_MASK) >> CLK_PWM_DIV_CON_SHIFT;
465
466         return DIV_TO_RATE(GPLL_HZ, div);
467 }
468
469 static ulong rk3328_pwm_set_clk(struct rk3328_cru *cru, uint hz)
470 {
471         u32 div = GPLL_HZ / hz;
472
473         rk_clrsetreg(&cru->clksel_con[24],
474                      CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
475                      CLK_PWM_PLL_SEL_GPLL << CLK_PWM_PLL_SEL_SHIFT |
476                      (div - 1) << CLK_PWM_DIV_CON_SHIFT);
477
478         return DIV_TO_RATE(GPLL_HZ, div);
479 }
480
481 static ulong rk3328_clk_get_rate(struct clk *clk)
482 {
483         struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
484         ulong rate = 0;
485
486         switch (clk->id) {
487         case 0 ... 29:
488                 return 0;
489         case HCLK_SDMMC:
490         case HCLK_EMMC:
491         case SCLK_SDMMC:
492         case SCLK_EMMC:
493                 rate = rk3328_mmc_get_clk(priv->cru, clk->id);
494                 break;
495         case SCLK_I2C0:
496         case SCLK_I2C1:
497         case SCLK_I2C2:
498         case SCLK_I2C3:
499                 rate = rk3328_i2c_get_clk(priv->cru, clk->id);
500                 break;
501         case SCLK_PWM:
502                 rate = rk3328_pwm_get_clk(priv->cru);
503                 break;
504         default:
505                 return -ENOENT;
506         }
507
508         return rate;
509 }
510
511 static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
512 {
513         struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
514         ulong ret = 0;
515
516         switch (clk->id) {
517         case 0 ... 29:
518                 return 0;
519         case HCLK_SDMMC:
520         case HCLK_EMMC:
521         case SCLK_SDMMC:
522         case SCLK_EMMC:
523                 ret = rk3328_mmc_set_clk(priv->cru, clk->id, rate);
524                 break;
525         case SCLK_I2C0:
526         case SCLK_I2C1:
527         case SCLK_I2C2:
528         case SCLK_I2C3:
529                 ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate);
530                 break;
531         case SCLK_PWM:
532                 ret = rk3328_pwm_set_clk(priv->cru, rate);
533                 break;
534         default:
535                 return -ENOENT;
536         }
537
538         return ret;
539 }
540
541 static struct clk_ops rk3328_clk_ops = {
542         .get_rate = rk3328_clk_get_rate,
543         .set_rate = rk3328_clk_set_rate,
544 };
545
546 static int rk3328_clk_probe(struct udevice *dev)
547 {
548         struct rk3328_clk_priv *priv = dev_get_priv(dev);
549
550         rkclk_init(priv->cru);
551
552         return 0;
553 }
554
555 static int rk3328_clk_ofdata_to_platdata(struct udevice *dev)
556 {
557         struct rk3328_clk_priv *priv = dev_get_priv(dev);
558
559         priv->cru = (struct rk3328_cru *)devfdt_get_addr(dev);
560
561         return 0;
562 }
563
564 static int rk3328_clk_bind(struct udevice *dev)
565 {
566         int ret;
567
568         /* The reset driver does not have a device node, so bind it here */
569         ret = device_bind_driver(gd->dm_root, "rk3328_sysreset", "reset", &dev);
570         if (ret)
571                 printf("Warning: No RK3328 reset driver: ret=%d\n", ret);
572
573         return ret;
574 }
575
576 static const struct udevice_id rk3328_clk_ids[] = {
577         { .compatible = "rockchip,rk3328-cru" },
578         { }
579 };
580
581 U_BOOT_DRIVER(rockchip_rk3328_cru) = {
582         .name           = "rockchip_rk3328_cru",
583         .id             = UCLASS_CLK,
584         .of_match       = rk3328_clk_ids,
585         .priv_auto_alloc_size = sizeof(struct rk3328_clk_priv),
586         .ofdata_to_platdata = rk3328_clk_ofdata_to_platdata,
587         .ops            = &rk3328_clk_ops,
588         .bind           = rk3328_clk_bind,
589         .probe          = rk3328_clk_probe,
590 };