Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: hisilicon: add hi3620_mmc_clks

Suggest by Arnd: abstract mmc tuning as clock behavior,
also because different soc have different tuning method and registers.
hi3620_mmc_clks is added to handle mmc clock specifically on hi3620.

Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Zhangfei Gao and committed by
Mike Turquette
62ac983b b89cd950

+294
+14
Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
··· 30 30 resume-offset = <0x308>; 31 31 reboot-offset = <0x4>; 32 32 }; 33 + 34 + PCTRL: Peripheral misc control register 35 + 36 + Required Properties: 37 + - compatible: "hisilicon,pctrl" 38 + - reg: Address and size of pctrl. 39 + 40 + Example: 41 + 42 + /* for Hi3620 */ 43 + pctrl: pctrl@fca09000 { 44 + compatible = "hisilicon,pctrl"; 45 + reg = <0xfca09000 0x1000>; 46 + };
+1
Documentation/devicetree/bindings/clock/hi3620-clock.txt
··· 7 7 8 8 - compatible: should be one of the following. 9 9 - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC. 10 + - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc. 10 11 11 12 - reg: physical base address of the controller and length of memory mapped 12 13 region.
+274
drivers/clk/hisilicon/clk-hi3620.c
··· 240 240 base); 241 241 } 242 242 CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init); 243 + 244 + struct hisi_mmc_clock { 245 + unsigned int id; 246 + const char *name; 247 + const char *parent_name; 248 + unsigned long flags; 249 + u32 clken_reg; 250 + u32 clken_bit; 251 + u32 div_reg; 252 + u32 div_off; 253 + u32 div_bits; 254 + u32 drv_reg; 255 + u32 drv_off; 256 + u32 drv_bits; 257 + u32 sam_reg; 258 + u32 sam_off; 259 + u32 sam_bits; 260 + }; 261 + 262 + struct clk_mmc { 263 + struct clk_hw hw; 264 + u32 id; 265 + void __iomem *clken_reg; 266 + u32 clken_bit; 267 + void __iomem *div_reg; 268 + u32 div_off; 269 + u32 div_bits; 270 + void __iomem *drv_reg; 271 + u32 drv_off; 272 + u32 drv_bits; 273 + void __iomem *sam_reg; 274 + u32 sam_off; 275 + u32 sam_bits; 276 + }; 277 + 278 + #define to_mmc(_hw) container_of(_hw, struct clk_mmc, hw) 279 + 280 + static struct hisi_mmc_clock hi3620_mmc_clks[] __initdata = { 281 + { HI3620_SD_CIUCLK, "sd_bclk1", "sd_clk", CLK_SET_RATE_PARENT, 0x1f8, 0, 0x1f8, 1, 3, 0x1f8, 4, 4, 0x1f8, 8, 4}, 282 + { HI3620_MMC_CIUCLK1, "mmc_bclk1", "mmc_clk1", CLK_SET_RATE_PARENT, 0x1f8, 12, 0x1f8, 13, 3, 0x1f8, 16, 4, 0x1f8, 20, 4}, 283 + { HI3620_MMC_CIUCLK2, "mmc_bclk2", "mmc_clk2", CLK_SET_RATE_PARENT, 0x1f8, 24, 0x1f8, 25, 3, 0x1f8, 28, 4, 0x1fc, 0, 4}, 284 + { HI3620_MMC_CIUCLK3, "mmc_bclk3", "mmc_clk3", CLK_SET_RATE_PARENT, 0x1fc, 4, 0x1fc, 5, 3, 0x1fc, 8, 4, 0x1fc, 12, 4}, 285 + }; 286 + 287 + static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, 288 + unsigned long parent_rate) 289 + { 290 + switch (parent_rate) { 291 + case 26000000: 292 + return 13000000; 293 + case 180000000: 294 + return 25000000; 295 + case 360000000: 296 + return 50000000; 297 + case 720000000: 298 + return 100000000; 299 + case 1440000000: 300 + return 180000000; 301 + default: 302 + return parent_rate; 303 + } 304 + } 305 + 306 + static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, 307 + unsigned long *best_parent_rate, 308 + struct clk **best_parent_p) 309 + { 310 + struct clk_mmc *mclk = to_mmc(hw); 311 + unsigned long best = 0; 312 + 313 + if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { 314 + rate = 13000000; 315 + best = 26000000; 316 + } else if (rate <= 26000000) { 317 + rate = 25000000; 318 + best = 180000000; 319 + } else if (rate <= 52000000) { 320 + rate = 50000000; 321 + best = 360000000; 322 + } else if (rate <= 100000000) { 323 + rate = 100000000; 324 + best = 720000000; 325 + } else { 326 + /* max is 180M */ 327 + rate = 180000000; 328 + best = 1440000000; 329 + } 330 + *best_parent_rate = best; 331 + return rate; 332 + } 333 + 334 + static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len) 335 + { 336 + u32 i; 337 + 338 + if (para >= 0) { 339 + for (i = 0; i < len; i++) { 340 + if (para % 2) 341 + val |= 1 << (off + i); 342 + else 343 + val &= ~(1 << (off + i)); 344 + para = para >> 1; 345 + } 346 + } 347 + return val; 348 + } 349 + 350 + static int mmc_clk_set_timing(struct clk_hw *hw, unsigned long rate) 351 + { 352 + struct clk_mmc *mclk = to_mmc(hw); 353 + unsigned long flags; 354 + u32 sam, drv, div, val; 355 + static DEFINE_SPINLOCK(mmc_clk_lock); 356 + 357 + switch (rate) { 358 + case 13000000: 359 + sam = 3; 360 + drv = 1; 361 + div = 1; 362 + break; 363 + case 25000000: 364 + sam = 13; 365 + drv = 6; 366 + div = 6; 367 + break; 368 + case 50000000: 369 + sam = 3; 370 + drv = 6; 371 + div = 6; 372 + break; 373 + case 100000000: 374 + sam = 6; 375 + drv = 4; 376 + div = 6; 377 + break; 378 + case 180000000: 379 + sam = 6; 380 + drv = 4; 381 + div = 7; 382 + break; 383 + default: 384 + return -EINVAL; 385 + } 386 + 387 + spin_lock_irqsave(&mmc_clk_lock, flags); 388 + 389 + val = readl_relaxed(mclk->clken_reg); 390 + val &= ~(1 << mclk->clken_bit); 391 + writel_relaxed(val, mclk->clken_reg); 392 + 393 + val = readl_relaxed(mclk->sam_reg); 394 + val = mmc_clk_delay(val, sam, mclk->sam_off, mclk->sam_bits); 395 + writel_relaxed(val, mclk->sam_reg); 396 + 397 + val = readl_relaxed(mclk->drv_reg); 398 + val = mmc_clk_delay(val, drv, mclk->drv_off, mclk->drv_bits); 399 + writel_relaxed(val, mclk->drv_reg); 400 + 401 + val = readl_relaxed(mclk->div_reg); 402 + val = mmc_clk_delay(val, div, mclk->div_off, mclk->div_bits); 403 + writel_relaxed(val, mclk->div_reg); 404 + 405 + val = readl_relaxed(mclk->clken_reg); 406 + val |= 1 << mclk->clken_bit; 407 + writel_relaxed(val, mclk->clken_reg); 408 + 409 + spin_unlock_irqrestore(&mmc_clk_lock, flags); 410 + 411 + return 0; 412 + } 413 + 414 + static int mmc_clk_prepare(struct clk_hw *hw) 415 + { 416 + struct clk_mmc *mclk = to_mmc(hw); 417 + unsigned long rate; 418 + 419 + if (mclk->id == HI3620_MMC_CIUCLK1) 420 + rate = 13000000; 421 + else 422 + rate = 25000000; 423 + 424 + return mmc_clk_set_timing(hw, rate); 425 + } 426 + 427 + static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate, 428 + unsigned long parent_rate) 429 + { 430 + return mmc_clk_set_timing(hw, rate); 431 + } 432 + 433 + static struct clk_ops clk_mmc_ops = { 434 + .prepare = mmc_clk_prepare, 435 + .determine_rate = mmc_clk_determine_rate, 436 + .set_rate = mmc_clk_set_rate, 437 + .recalc_rate = mmc_clk_recalc_rate, 438 + }; 439 + 440 + static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk, 441 + void __iomem *base, struct device_node *np) 442 + { 443 + struct clk_mmc *mclk; 444 + struct clk *clk; 445 + struct clk_init_data init; 446 + 447 + mclk = kzalloc(sizeof(*mclk), GFP_KERNEL); 448 + if (!mclk) { 449 + pr_err("%s: fail to allocate mmc clk\n", __func__); 450 + return ERR_PTR(-ENOMEM); 451 + } 452 + 453 + init.name = mmc_clk->name; 454 + init.ops = &clk_mmc_ops; 455 + init.flags = mmc_clk->flags | CLK_IS_BASIC; 456 + init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL); 457 + init.num_parents = (mmc_clk->parent_name ? 1 : 0); 458 + mclk->hw.init = &init; 459 + 460 + mclk->id = mmc_clk->id; 461 + mclk->clken_reg = base + mmc_clk->clken_reg; 462 + mclk->clken_bit = mmc_clk->clken_bit; 463 + mclk->div_reg = base + mmc_clk->div_reg; 464 + mclk->div_off = mmc_clk->div_off; 465 + mclk->div_bits = mmc_clk->div_bits; 466 + mclk->drv_reg = base + mmc_clk->drv_reg; 467 + mclk->drv_off = mmc_clk->drv_off; 468 + mclk->drv_bits = mmc_clk->drv_bits; 469 + mclk->sam_reg = base + mmc_clk->sam_reg; 470 + mclk->sam_off = mmc_clk->sam_off; 471 + mclk->sam_bits = mmc_clk->sam_bits; 472 + 473 + clk = clk_register(NULL, &mclk->hw); 474 + if (WARN_ON(IS_ERR(clk))) 475 + kfree(mclk); 476 + return clk; 477 + } 478 + 479 + static void __init hi3620_mmc_clk_init(struct device_node *node) 480 + { 481 + void __iomem *base; 482 + int i, num = ARRAY_SIZE(hi3620_mmc_clks); 483 + struct clk_onecell_data *clk_data; 484 + 485 + if (!node) { 486 + pr_err("failed to find pctrl node in DTS\n"); 487 + return; 488 + } 489 + 490 + base = of_iomap(node, 0); 491 + if (!base) { 492 + pr_err("failed to map pctrl\n"); 493 + return; 494 + } 495 + 496 + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 497 + if (WARN_ON(!clk_data)) 498 + return; 499 + 500 + clk_data->clks = kzalloc(sizeof(struct clk *) * num, GFP_KERNEL); 501 + if (!clk_data->clks) { 502 + pr_err("%s: fail to allocate mmc clk\n", __func__); 503 + return; 504 + } 505 + 506 + for (i = 0; i < num; i++) { 507 + struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i]; 508 + clk_data->clks[mmc_clk->id] = 509 + hisi_register_clk_mmc(mmc_clk, base, node); 510 + } 511 + 512 + clk_data->clk_num = num; 513 + of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 514 + } 515 + 516 + CLK_OF_DECLARE(hi3620_mmc_clk, "hisilicon,hi3620-mmc-clock", hi3620_mmc_clk_init);
+5
include/dt-bindings/clock/hi3620-clock.h
··· 147 147 #define HI3620_MMC_CLK3 217 148 148 #define HI3620_MCU_CLK 218 149 149 150 + #define HI3620_SD_CIUCLK 0 151 + #define HI3620_MMC_CIUCLK1 1 152 + #define HI3620_MMC_CIUCLK2 2 153 + #define HI3620_MMC_CIUCLK3 3 154 + 150 155 #define HI3620_NR_CLKS 219 151 156 152 157 #endif /* __DTS_HI3620_CLOCK_H */