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

clk: shmobile: sh73a0 common clock framework implementation

Driver for the SH73A0's clocks that are too specific to be supported by a
generic driver.

Signed-off-by: Ulrich Hecht <ulrich.hecht+renesas@gmail.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>

authored by

Ulrich Hecht and committed by
Simon Horman
ae073881 97bf6af1

+254
+35
Documentation/devicetree/bindings/clock/renesas,sh73a0-cpg-clocks.txt
··· 1 + These bindings should be considered EXPERIMENTAL for now. 2 + 3 + * Renesas SH73A0 Clock Pulse Generator (CPG) 4 + 5 + The CPG generates core clocks for the SH73A0 SoC. It includes four PLLs 6 + and several fixed ratio dividers. 7 + 8 + Required Properties: 9 + 10 + - compatible: Must be "renesas,sh73a0-cpg-clocks" 11 + 12 + - reg: Base address and length of the memory resource used by the CPG 13 + 14 + - clocks: Reference to the parent clocks ("extal1" and "extal2") 15 + 16 + - #clock-cells: Must be 1 17 + 18 + - clock-output-names: The names of the clocks. Supported clocks are "main", 19 + "pll0", "pll1", "pll2", "pll3", "dsi0phy", "dsi1phy", "zg", "m3", "b", 20 + "m1", "m2", "z", "zx", and "hp". 21 + 22 + 23 + Example 24 + ------- 25 + 26 + cpg_clocks: cpg_clocks@e6150000 { 27 + compatible = "renesas,sh73a0-cpg-clocks"; 28 + reg = <0 0xe6150000 0 0x10000>; 29 + clocks = <&extal1_clk>, <&extal2_clk>; 30 + #clock-cells = <1>; 31 + clock-output-names = "main", "pll0", "pll1", "pll2", 32 + "pll3", "dsi0phy", "dsi1phy", 33 + "zg", "m3", "b", "m1", "m2", 34 + "z", "zx", "hp"; 35 + };
+1
drivers/clk/shmobile/Makefile
··· 5 5 obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o 6 6 obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o 7 7 obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o 8 + obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o 8 9 obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o 9 10 obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o
+218
drivers/clk/shmobile/clk-sh73a0.c
··· 1 + /* 2 + * sh73a0 Core CPG Clocks 3 + * 4 + * Copyright (C) 2014 Ulrich Hecht 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; version 2 of the License. 9 + */ 10 + 11 + #include <linux/clk-provider.h> 12 + #include <linux/clkdev.h> 13 + #include <linux/clk/shmobile.h> 14 + #include <linux/init.h> 15 + #include <linux/kernel.h> 16 + #include <linux/of.h> 17 + #include <linux/of_address.h> 18 + #include <linux/spinlock.h> 19 + 20 + struct sh73a0_cpg { 21 + struct clk_onecell_data data; 22 + spinlock_t lock; 23 + void __iomem *reg; 24 + }; 25 + 26 + #define CPG_FRQCRA 0x00 27 + #define CPG_FRQCRB 0x04 28 + #define CPG_SD0CKCR 0x74 29 + #define CPG_SD1CKCR 0x78 30 + #define CPG_SD2CKCR 0x7c 31 + #define CPG_PLLECR 0xd0 32 + #define CPG_PLL0CR 0xd8 33 + #define CPG_PLL1CR 0x28 34 + #define CPG_PLL2CR 0x2c 35 + #define CPG_PLL3CR 0xdc 36 + #define CPG_CKSCR 0xc0 37 + #define CPG_DSI0PHYCR 0x6c 38 + #define CPG_DSI1PHYCR 0x70 39 + 40 + #define CLK_ENABLE_ON_INIT BIT(0) 41 + 42 + struct div4_clk { 43 + const char *name; 44 + const char *parent; 45 + unsigned int reg; 46 + unsigned int shift; 47 + }; 48 + 49 + static struct div4_clk div4_clks[] = { 50 + { "zg", "pll0", CPG_FRQCRA, 16 }, 51 + { "m3", "pll1", CPG_FRQCRA, 12 }, 52 + { "b", "pll1", CPG_FRQCRA, 8 }, 53 + { "m1", "pll1", CPG_FRQCRA, 4 }, 54 + { "m2", "pll1", CPG_FRQCRA, 0 }, 55 + { "zx", "pll1", CPG_FRQCRB, 12 }, 56 + { "hp", "pll1", CPG_FRQCRB, 4 }, 57 + { NULL, 0, 0, 0 }, 58 + }; 59 + 60 + static const struct clk_div_table div4_div_table[] = { 61 + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 }, 62 + { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 }, 63 + { 12, 7 }, { 0, 0 } 64 + }; 65 + 66 + static const struct clk_div_table z_div_table[] = { 67 + /* ZSEL == 0 */ 68 + { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 }, 69 + { 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 }, 70 + { 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 }, 71 + /* ZSEL == 1 */ 72 + { 16, 2 }, { 17, 3 }, { 18, 4 }, { 19, 6 }, { 20, 8 }, { 21, 12 }, 73 + { 22, 16 }, { 24, 24 }, { 27, 48 }, { 0, 0 } 74 + }; 75 + 76 + static struct clk * __init 77 + sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, 78 + const char *name) 79 + { 80 + const struct clk_div_table *table = NULL; 81 + unsigned int shift, reg, width; 82 + const char *parent_name; 83 + unsigned int mult = 1; 84 + unsigned int div = 1; 85 + 86 + if (!strcmp(name, "main")) { 87 + /* extal1, extal1_div2, extal2, extal2_div2 */ 88 + u32 parent_idx = (clk_readl(cpg->reg + CPG_CKSCR) >> 28) & 3; 89 + 90 + parent_name = of_clk_get_parent_name(np, parent_idx >> 1); 91 + div = (parent_idx & 1) + 1; 92 + } else if (!strncmp(name, "pll", 3)) { 93 + void __iomem *enable_reg = cpg->reg; 94 + u32 enable_bit = name[3] - '0'; 95 + 96 + parent_name = "main"; 97 + switch (enable_bit) { 98 + case 0: 99 + enable_reg += CPG_PLL0CR; 100 + break; 101 + case 1: 102 + enable_reg += CPG_PLL1CR; 103 + break; 104 + case 2: 105 + enable_reg += CPG_PLL2CR; 106 + break; 107 + case 3: 108 + enable_reg += CPG_PLL3CR; 109 + break; 110 + default: 111 + return ERR_PTR(-EINVAL); 112 + } 113 + if (clk_readl(cpg->reg + CPG_PLLECR) & BIT(enable_bit)) { 114 + mult = ((clk_readl(enable_reg) >> 24) & 0x3f) + 1; 115 + /* handle CFG bit for PLL1 and PLL2 */ 116 + if (enable_bit == 1 || enable_bit == 2) 117 + if (clk_readl(enable_reg) & BIT(20)) 118 + mult *= 2; 119 + } 120 + } else if (!strcmp(name, "dsi0phy") || !strcmp(name, "dsi1phy")) { 121 + u32 phy_no = name[3] - '0'; 122 + void __iomem *dsi_reg = cpg->reg + 123 + (phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR); 124 + 125 + parent_name = phy_no ? "dsi1pck" : "dsi0pck"; 126 + mult = __raw_readl(dsi_reg); 127 + if (!(mult & 0x8000)) 128 + mult = 1; 129 + else 130 + mult = (mult & 0x3f) + 1; 131 + } else if (!strcmp(name, "z")) { 132 + parent_name = "pll0"; 133 + table = z_div_table; 134 + reg = CPG_FRQCRB; 135 + shift = 24; 136 + width = 5; 137 + } else { 138 + struct div4_clk *c; 139 + 140 + for (c = div4_clks; c->name; c++) { 141 + if (!strcmp(name, c->name)) { 142 + parent_name = c->parent; 143 + table = div4_div_table; 144 + reg = c->reg; 145 + shift = c->shift; 146 + width = 4; 147 + break; 148 + } 149 + } 150 + if (!c->name) 151 + return ERR_PTR(-EINVAL); 152 + } 153 + 154 + if (!table) { 155 + return clk_register_fixed_factor(NULL, name, parent_name, 0, 156 + mult, div); 157 + } else { 158 + return clk_register_divider_table(NULL, name, parent_name, 0, 159 + cpg->reg + reg, shift, width, 0, 160 + table, &cpg->lock); 161 + } 162 + } 163 + 164 + static void __init sh73a0_cpg_clocks_init(struct device_node *np) 165 + { 166 + struct sh73a0_cpg *cpg; 167 + struct clk **clks; 168 + unsigned int i; 169 + int num_clks; 170 + 171 + num_clks = of_property_count_strings(np, "clock-output-names"); 172 + if (num_clks < 0) { 173 + pr_err("%s: failed to count clocks\n", __func__); 174 + return; 175 + } 176 + 177 + cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); 178 + clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL); 179 + if (cpg == NULL || clks == NULL) { 180 + /* We're leaking memory on purpose, there's no point in cleaning 181 + * up as the system won't boot anyway. 182 + */ 183 + return; 184 + } 185 + 186 + spin_lock_init(&cpg->lock); 187 + 188 + cpg->data.clks = clks; 189 + cpg->data.clk_num = num_clks; 190 + 191 + cpg->reg = of_iomap(np, 0); 192 + if (WARN_ON(cpg->reg == NULL)) 193 + return; 194 + 195 + /* Set SDHI clocks to a known state */ 196 + clk_writel(0x108, cpg->reg + CPG_SD0CKCR); 197 + clk_writel(0x108, cpg->reg + CPG_SD1CKCR); 198 + clk_writel(0x108, cpg->reg + CPG_SD2CKCR); 199 + 200 + for (i = 0; i < num_clks; ++i) { 201 + const char *name; 202 + struct clk *clk; 203 + 204 + of_property_read_string_index(np, "clock-output-names", i, 205 + &name); 206 + 207 + clk = sh73a0_cpg_register_clock(np, cpg, name); 208 + if (IS_ERR(clk)) 209 + pr_err("%s: failed to register %s %s clock (%ld)\n", 210 + __func__, np->name, name, PTR_ERR(clk)); 211 + else 212 + cpg->data.clks[i] = clk; 213 + } 214 + 215 + of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); 216 + } 217 + CLK_OF_DECLARE(sh73a0_cpg_clks, "renesas,sh73a0-cpg-clocks", 218 + sh73a0_cpg_clocks_init);