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