18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * EMMA Mobile EV2 common clock framework support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Takashi Yoshii <takashi.yoshii.ze@renesas.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 Magnus Damm 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 98c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/of_address.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* EMEV2 SMU registers */ 158c2ecf20Sopenharmony_ci#define USIAU0_RSTCTRL 0x094 168c2ecf20Sopenharmony_ci#define USIBU1_RSTCTRL 0x0ac 178c2ecf20Sopenharmony_ci#define USIBU2_RSTCTRL 0x0b0 188c2ecf20Sopenharmony_ci#define USIBU3_RSTCTRL 0x0b4 198c2ecf20Sopenharmony_ci#define IIC0_RSTCTRL 0x0dc 208c2ecf20Sopenharmony_ci#define IIC1_RSTCTRL 0x0e0 218c2ecf20Sopenharmony_ci#define STI_RSTCTRL 0x124 228c2ecf20Sopenharmony_ci#define STI_CLKSEL 0x688 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(lock); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* not pretty, but hey */ 278c2ecf20Sopenharmony_cistatic void __iomem *smu_base; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void __init emev2_smu_write(unsigned long value, int offs) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci BUG_ON(!smu_base || (offs >= PAGE_SIZE)); 328c2ecf20Sopenharmony_ci writel_relaxed(value, smu_base + offs); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const struct of_device_id smu_id[] __initconst = { 368c2ecf20Sopenharmony_ci { .compatible = "renesas,emev2-smu", }, 378c2ecf20Sopenharmony_ci {}, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void __init emev2_smu_init(void) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct device_node *np; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci np = of_find_matching_node(NULL, smu_id); 458c2ecf20Sopenharmony_ci BUG_ON(!np); 468c2ecf20Sopenharmony_ci smu_base = of_iomap(np, 0); 478c2ecf20Sopenharmony_ci BUG_ON(!smu_base); 488c2ecf20Sopenharmony_ci of_node_put(np); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* setup STI timer to run on 32.768 kHz and deassert reset */ 518c2ecf20Sopenharmony_ci emev2_smu_write(0, STI_CLKSEL); 528c2ecf20Sopenharmony_ci emev2_smu_write(1, STI_RSTCTRL); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* deassert reset for UART0->UART3 */ 558c2ecf20Sopenharmony_ci emev2_smu_write(2, USIAU0_RSTCTRL); 568c2ecf20Sopenharmony_ci emev2_smu_write(2, USIBU1_RSTCTRL); 578c2ecf20Sopenharmony_ci emev2_smu_write(2, USIBU2_RSTCTRL); 588c2ecf20Sopenharmony_ci emev2_smu_write(2, USIBU3_RSTCTRL); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* deassert reset for IIC0->IIC1 */ 618c2ecf20Sopenharmony_ci emev2_smu_write(1, IIC0_RSTCTRL); 628c2ecf20Sopenharmony_ci emev2_smu_write(1, IIC1_RSTCTRL); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void __init emev2_smu_clkdiv_init(struct device_node *np) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci u32 reg[2]; 688c2ecf20Sopenharmony_ci struct clk *clk; 698c2ecf20Sopenharmony_ci const char *parent_name = of_clk_get_parent_name(np, 0); 708c2ecf20Sopenharmony_ci if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2))) 718c2ecf20Sopenharmony_ci return; 728c2ecf20Sopenharmony_ci if (!smu_base) 738c2ecf20Sopenharmony_ci emev2_smu_init(); 748c2ecf20Sopenharmony_ci clk = clk_register_divider(NULL, np->name, parent_name, 0, 758c2ecf20Sopenharmony_ci smu_base + reg[0], reg[1], 8, 0, &lock); 768c2ecf20Sopenharmony_ci of_clk_add_provider(np, of_clk_src_simple_get, clk); 778c2ecf20Sopenharmony_ci clk_register_clkdev(clk, np->full_name, NULL); 788c2ecf20Sopenharmony_ci pr_debug("## %s %pOFn %p\n", __func__, np, clk); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ciCLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv", 818c2ecf20Sopenharmony_ci emev2_smu_clkdiv_init); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void __init emev2_smu_gclk_init(struct device_node *np) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci u32 reg[2]; 868c2ecf20Sopenharmony_ci struct clk *clk; 878c2ecf20Sopenharmony_ci const char *parent_name = of_clk_get_parent_name(np, 0); 888c2ecf20Sopenharmony_ci if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2))) 898c2ecf20Sopenharmony_ci return; 908c2ecf20Sopenharmony_ci if (!smu_base) 918c2ecf20Sopenharmony_ci emev2_smu_init(); 928c2ecf20Sopenharmony_ci clk = clk_register_gate(NULL, np->name, parent_name, 0, 938c2ecf20Sopenharmony_ci smu_base + reg[0], reg[1], 0, &lock); 948c2ecf20Sopenharmony_ci of_clk_add_provider(np, of_clk_src_simple_get, clk); 958c2ecf20Sopenharmony_ci clk_register_clkdev(clk, np->full_name, NULL); 968c2ecf20Sopenharmony_ci pr_debug("## %s %pOFn %p\n", __func__, np, clk); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ciCLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init); 99