1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * EMMA Mobile EV2 common clock framework support |
4 | * |
5 | * Copyright (C) 2013 Takashi Yoshii <takashi.yoshii.ze@renesas.com> |
6 | * Copyright (C) 2012 Magnus Damm |
7 | */ |
8 | #include <linux/clk-provider.h> |
9 | #include <linux/io.h> |
10 | #include <linux/of.h> |
11 | #include <linux/of_address.h> |
12 | |
13 | /* EMEV2 SMU registers */ |
14 | #define USIAU0_RSTCTRL 0x094 |
15 | #define USIBU1_RSTCTRL 0x0ac |
16 | #define USIBU2_RSTCTRL 0x0b0 |
17 | #define USIBU3_RSTCTRL 0x0b4 |
18 | #define IIC0_RSTCTRL 0x0dc |
19 | #define IIC1_RSTCTRL 0x0e0 |
20 | #define STI_RSTCTRL 0x124 |
21 | #define STI_CLKSEL 0x688 |
22 | |
23 | static DEFINE_SPINLOCK(lock); |
24 | |
25 | /* not pretty, but hey */ |
26 | static void __iomem *smu_base; |
27 | |
28 | static void __init emev2_smu_write(unsigned long value, int offs) |
29 | { |
30 | BUG_ON(!smu_base || (offs >= PAGE_SIZE)); |
31 | writel_relaxed(value, smu_base + offs); |
32 | } |
33 | |
34 | static const struct of_device_id smu_id[] __initconst = { |
35 | { .compatible = "renesas,emev2-smu" , }, |
36 | {}, |
37 | }; |
38 | |
39 | static void __init emev2_smu_init(void) |
40 | { |
41 | struct device_node *np; |
42 | |
43 | np = of_find_matching_node(NULL, matches: smu_id); |
44 | BUG_ON(!np); |
45 | smu_base = of_iomap(node: np, index: 0); |
46 | BUG_ON(!smu_base); |
47 | of_node_put(node: np); |
48 | |
49 | /* setup STI timer to run on 32.768 kHz and deassert reset */ |
50 | emev2_smu_write(value: 0, STI_CLKSEL); |
51 | emev2_smu_write(value: 1, STI_RSTCTRL); |
52 | |
53 | /* deassert reset for UART0->UART3 */ |
54 | emev2_smu_write(value: 2, USIAU0_RSTCTRL); |
55 | emev2_smu_write(value: 2, USIBU1_RSTCTRL); |
56 | emev2_smu_write(value: 2, USIBU2_RSTCTRL); |
57 | emev2_smu_write(value: 2, USIBU3_RSTCTRL); |
58 | |
59 | /* deassert reset for IIC0->IIC1 */ |
60 | emev2_smu_write(value: 1, IIC0_RSTCTRL); |
61 | emev2_smu_write(value: 1, IIC1_RSTCTRL); |
62 | } |
63 | |
64 | static void __init emev2_smu_clkdiv_init(struct device_node *np) |
65 | { |
66 | u32 reg[2]; |
67 | struct clk *clk; |
68 | const char *parent_name = of_clk_get_parent_name(np, index: 0); |
69 | if (WARN_ON(of_property_read_u32_array(np, "reg" , reg, 2))) |
70 | return; |
71 | if (!smu_base) |
72 | emev2_smu_init(); |
73 | clk = clk_register_divider(NULL, np->name, parent_name, 0, |
74 | smu_base + reg[0], reg[1], 8, 0, &lock); |
75 | of_clk_add_provider(np, clk_src_get: of_clk_src_simple_get, data: clk); |
76 | pr_debug("## %s %pOFn %p\n" , __func__, np, clk); |
77 | } |
78 | CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv" , |
79 | emev2_smu_clkdiv_init); |
80 | |
81 | static void __init emev2_smu_gclk_init(struct device_node *np) |
82 | { |
83 | u32 reg[2]; |
84 | struct clk *clk; |
85 | const char *parent_name = of_clk_get_parent_name(np, index: 0); |
86 | if (WARN_ON(of_property_read_u32_array(np, "reg" , reg, 2))) |
87 | return; |
88 | if (!smu_base) |
89 | emev2_smu_init(); |
90 | clk = clk_register_gate(NULL, name: np->name, parent_name, flags: 0, |
91 | reg: smu_base + reg[0], bit_idx: reg[1], clk_gate_flags: 0, lock: &lock); |
92 | of_clk_add_provider(np, clk_src_get: of_clk_src_simple_get, data: clk); |
93 | pr_debug("## %s %pOFn %p\n" , __func__, np, clk); |
94 | } |
95 | CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk" , emev2_smu_gclk_init); |
96 | |