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

clk: stm32f4: Add RTC clock

This patch introduces the support of the RTC clock.
RTC clock can have 3 sources: lsi, lse and hse_rtc.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Gabriel Fernandez and committed by
Stephen Boyd
4261a881 861adc44

+136 -1
+136 -1
drivers/clk/clk-stm32f4.c
··· 126 126 { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, 127 127 }; 128 128 129 - enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, END_PRIMARY_CLK }; 129 + enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK }; 130 130 /* 131 131 * MAX_CLKS is the maximum value in the enumeration below plus the combined 132 132 * hweight of stm32f42xx_gate_map (plus one). ··· 313 313 regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8)); 314 314 } 315 315 316 + static inline void sofware_reset_backup_domain(void) 317 + { 318 + unsigned long val; 319 + 320 + val = readl(base + STM32F4_RCC_BDCR); 321 + writel(val | BIT(16), base + STM32F4_RCC_BDCR); 322 + writel(val & ~BIT(16), base + STM32F4_RCC_BDCR); 323 + } 324 + 316 325 struct stm32_rgate { 317 326 struct clk_gate gate; 318 327 u8 bit_rdy_idx; ··· 400 391 return hw; 401 392 } 402 393 394 + static int cclk_gate_enable(struct clk_hw *hw) 395 + { 396 + int ret; 397 + 398 + disable_power_domain_write_protection(); 399 + 400 + ret = clk_gate_ops.enable(hw); 401 + 402 + enable_power_domain_write_protection(); 403 + 404 + return ret; 405 + } 406 + 407 + static void cclk_gate_disable(struct clk_hw *hw) 408 + { 409 + disable_power_domain_write_protection(); 410 + 411 + clk_gate_ops.disable(hw); 412 + 413 + enable_power_domain_write_protection(); 414 + } 415 + 416 + static int cclk_gate_is_enabled(struct clk_hw *hw) 417 + { 418 + return clk_gate_ops.is_enabled(hw); 419 + } 420 + 421 + static const struct clk_ops cclk_gate_ops = { 422 + .enable = cclk_gate_enable, 423 + .disable = cclk_gate_disable, 424 + .is_enabled = cclk_gate_is_enabled, 425 + }; 426 + 427 + static u8 cclk_mux_get_parent(struct clk_hw *hw) 428 + { 429 + return clk_mux_ops.get_parent(hw); 430 + } 431 + 432 + static int cclk_mux_set_parent(struct clk_hw *hw, u8 index) 433 + { 434 + int ret; 435 + 436 + disable_power_domain_write_protection(); 437 + 438 + sofware_reset_backup_domain(); 439 + 440 + ret = clk_mux_ops.set_parent(hw, index); 441 + 442 + enable_power_domain_write_protection(); 443 + 444 + return ret; 445 + } 446 + 447 + static const struct clk_ops cclk_mux_ops = { 448 + .get_parent = cclk_mux_get_parent, 449 + .set_parent = cclk_mux_set_parent, 450 + }; 451 + 452 + static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name, 453 + const char * const *parent_names, int num_parents, 454 + void __iomem *reg, u8 bit_idx, u8 shift, unsigned long flags, 455 + spinlock_t *lock) 456 + { 457 + struct clk_hw *hw; 458 + struct clk_gate *gate; 459 + struct clk_mux *mux; 460 + 461 + gate = kzalloc(sizeof(*gate), GFP_KERNEL); 462 + if (!gate) { 463 + hw = ERR_PTR(-EINVAL); 464 + goto fail; 465 + } 466 + 467 + mux = kzalloc(sizeof(*mux), GFP_KERNEL); 468 + if (!mux) { 469 + kfree(gate); 470 + hw = ERR_PTR(-EINVAL); 471 + goto fail; 472 + } 473 + 474 + gate->reg = reg; 475 + gate->bit_idx = bit_idx; 476 + gate->flags = 0; 477 + gate->lock = lock; 478 + 479 + mux->reg = reg; 480 + mux->shift = shift; 481 + mux->mask = 3; 482 + mux->flags = 0; 483 + 484 + hw = clk_hw_register_composite(dev, name, parent_names, num_parents, 485 + &mux->hw, &cclk_mux_ops, 486 + NULL, NULL, 487 + &gate->hw, &cclk_gate_ops, 488 + flags); 489 + 490 + if (IS_ERR(hw)) { 491 + kfree(gate); 492 + kfree(mux); 493 + } 494 + 495 + fail: 496 + return hw; 497 + } 498 + 403 499 static const char *sys_parents[] __initdata = { "hsi", NULL, "pll" }; 404 500 405 501 static const struct clk_div_table ahb_div_table[] = { ··· 519 405 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, 520 406 { 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 }, 521 407 { 0 }, 408 + }; 409 + 410 + static const char *rtc_parents[4] = { 411 + "no-clock", "lse", "lsi", "hse-rtc" 522 412 }; 523 413 524 414 static void __init stm32f4_rcc_init(struct device_node *np) ··· 607 489 608 490 if (IS_ERR(clks[CLK_LSE])) { 609 491 pr_err("Unable to register lse clock\n"); 492 + goto fail; 493 + } 494 + 495 + clks[CLK_HSE_RTC] = clk_hw_register_divider(NULL, "hse-rtc", "clk-hse", 496 + 0, base + STM32F4_RCC_CFGR, 16, 5, 0, 497 + &stm32f4_clk_lock); 498 + 499 + if (IS_ERR(clks[CLK_HSE_RTC])) { 500 + pr_err("Unable to register hse-rtc clock\n"); 501 + goto fail; 502 + } 503 + 504 + clks[CLK_RTC] = stm32_register_cclk(NULL, "rtc", rtc_parents, 4, 505 + base + STM32F4_RCC_BDCR, 15, 8, 0, &stm32f4_clk_lock); 506 + 507 + if (IS_ERR(clks[CLK_RTC])) { 508 + pr_err("Unable to register rtc clock\n"); 610 509 goto fail; 611 510 } 612 511