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