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 con_id = 30; 401 break; 402 case HCLK_EMMC: 403 con_id = 32; 404 break; 405 default: 406 return -EINVAL; 407 } 408 con = readl(&cru->clksel_con[con_id]); 409 div = (con & CLK_EMMC_DIV_CON_MASK) >> CLK_EMMC_DIV_CON_SHIFT; 410 411 if ((con & CLK_EMMC_PLL_MASK) >> CLK_EMMC_PLL_SHIFT 412 == CLK_EMMC_PLL_SEL_24M) 413 return DIV_TO_RATE(OSC_HZ, div); 414 else 415 return DIV_TO_RATE(GPLL_HZ, div); 416 } 417 418 static ulong rk3328_mmc_set_clk(struct rk3328_cru *cru, 419 ulong clk_id, ulong set_rate) 420 { 421 int src_clk_div; 422 u32 con_id; 423 424 switch (clk_id) { 425 case HCLK_SDMMC: 426 con_id = 30; 427 break; 428 case HCLK_EMMC: 429 con_id = 32; 430 break; 431 default: 432 return -EINVAL; 433 } 434 /* Select clk_sdmmc/emmc source from GPLL by default */ 435 src_clk_div = GPLL_HZ / set_rate; 436 437 if (src_clk_div > 127) { 438 /* use 24MHz source for 400KHz clock */ 439 src_clk_div = OSC_HZ / set_rate; 440 rk_clrsetreg(&cru->clksel_con[con_id], 441 CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK, 442 CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT | 443 (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT); 444 } else { 445 rk_clrsetreg(&cru->clksel_con[con_id], 446 CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK, 447 CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT | 448 (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT); 449 } 450 451 return rk3328_mmc_get_clk(cru, clk_id); 452 } 453 454 static ulong rk3328_pwm_get_clk(struct rk3328_cru *cru) 455 { 456 u32 div, con; 457 458 con = readl(&cru->clksel_con[24]); 459 div = (con & CLK_PWM_DIV_CON_MASK) >> CLK_PWM_DIV_CON_SHIFT; 460 461 return DIV_TO_RATE(GPLL_HZ, div); 462 } 463 464 static ulong rk3328_pwm_set_clk(struct rk3328_cru *cru, uint hz) 465 { 466 u32 div = GPLL_HZ / hz; 467 468 rk_clrsetreg(&cru->clksel_con[24], 469 CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK, 470 CLK_PWM_PLL_SEL_GPLL << CLK_PWM_PLL_SEL_SHIFT | 471 (div - 1) << CLK_PWM_DIV_CON_SHIFT); 472 473 return DIV_TO_RATE(GPLL_HZ, div); 474 } 475 476 static ulong rk3328_clk_get_rate(struct clk *clk) 477 { 478 struct rk3328_clk_priv *priv = dev_get_priv(clk->dev); 479 ulong rate = 0; 480 481 switch (clk->id) { 482 case 0 ... 29: 483 return 0; 484 case HCLK_SDMMC: 485 case HCLK_EMMC: 486 rate = rk3328_mmc_get_clk(priv->cru, clk->id); 487 break; 488 case SCLK_I2C0: 489 case SCLK_I2C1: 490 case SCLK_I2C2: 491 case SCLK_I2C3: 492 rate = rk3328_i2c_get_clk(priv->cru, clk->id); 493 break; 494 case SCLK_PWM: 495 rate = rk3328_pwm_get_clk(priv->cru); 496 break; 497 default: 498 return -ENOENT; 499 } 500 501 return rate; 502 } 503 504 static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) 505 { 506 struct rk3328_clk_priv *priv = dev_get_priv(clk->dev); 507 ulong ret = 0; 508 509 switch (clk->id) { 510 case 0 ... 29: 511 return 0; 512 case HCLK_SDMMC: 513 case HCLK_EMMC: 514 ret = rk3328_mmc_set_clk(priv->cru, clk->id, rate); 515 break; 516 case SCLK_I2C0: 517 case SCLK_I2C1: 518 case SCLK_I2C2: 519 case SCLK_I2C3: 520 ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate); 521 break; 522 case SCLK_PWM: 523 ret = rk3328_pwm_set_clk(priv->cru, rate); 524 break; 525 default: 526 return -ENOENT; 527 } 528 529 return ret; 530 } 531 532 static struct clk_ops rk3328_clk_ops = { 533 .get_rate = rk3328_clk_get_rate, 534 .set_rate = rk3328_clk_set_rate, 535 }; 536 537 static int rk3328_clk_probe(struct udevice *dev) 538 { 539 struct rk3328_clk_priv *priv = dev_get_priv(dev); 540 541 rkclk_init(priv->cru); 542 543 return 0; 544 } 545 546 static int rk3328_clk_ofdata_to_platdata(struct udevice *dev) 547 { 548 struct rk3328_clk_priv *priv = dev_get_priv(dev); 549 550 priv->cru = (struct rk3328_cru *)dev_get_addr(dev); 551 552 return 0; 553 } 554 555 static int rk3328_clk_bind(struct udevice *dev) 556 { 557 int ret; 558 559 /* The reset driver does not have a device node, so bind it here */ 560 ret = device_bind_driver(gd->dm_root, "rk3328_sysreset", "reset", &dev); 561 if (ret) 562 printf("Warning: No RK3328 reset driver: ret=%d\n", ret); 563 564 return ret; 565 } 566 567 static const struct udevice_id rk3328_clk_ids[] = { 568 { .compatible = "rockchip,rk3328-cru" }, 569 { } 570 }; 571 572 U_BOOT_DRIVER(rockchip_rk3328_cru) = { 573 .name = "rockchip_rk3328_cru", 574 .id = UCLASS_CLK, 575 .of_match = rk3328_clk_ids, 576 .priv_auto_alloc_size = sizeof(struct rk3328_clk_priv), 577 .ofdata_to_platdata = rk3328_clk_ofdata_to_platdata, 578 .ops = &rk3328_clk_ops, 579 .bind = rk3328_clk_bind, 580 .probe = rk3328_clk_probe, 581 }; 582