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

clk: shmobile: Add R-Car Gen2 clocks support

The R-Car Gen2 SoCs (R8A7790 and R8A7791) have several clocks that are
too custom to be supported in a generic driver. Those clocks can be
divided in two categories:

- Fixed rate clocks with multiplier and divisor set according to boot
mode configuration

- Custom divider clocks with SoC-specific divider values

This driver supports both.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Kumar Gala <galak@codeaurora.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Laurent Pinchart and committed by
Mike Turquette
10cdfe9f 6ce4eac1

+355
+32
Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
··· 1 + * Renesas R-Car Gen2 Clock Pulse Generator (CPG) 2 + 3 + The CPG generates core clocks for the R-Car Gen2 SoCs. It includes three PLLs 4 + and several fixed ratio dividers. 5 + 6 + Required Properties: 7 + 8 + - compatible: Must be one of 9 + - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG 10 + - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG 11 + - "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG 12 + 13 + - reg: Base address and length of the memory resource used by the CPG 14 + 15 + - clocks: Reference to the parent clock 16 + - #clock-cells: Must be 1 17 + - clock-output-names: The names of the clocks. Supported clocks are "main", 18 + "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z" 19 + 20 + 21 + Example 22 + ------- 23 + 24 + cpg_clocks: cpg_clocks@e6150000 { 25 + compatible = "renesas,r8a7790-cpg-clocks", 26 + "renesas,rcar-gen2-cpg-clocks"; 27 + reg = <0 0xe6150000 0 0x1000>; 28 + clocks = <&extal_clk>; 29 + #clock-cells = <1>; 30 + clock-output-names = "main", "pll0, "pll1", "pll3", 31 + "lb", "qspi", "sdh", "sd0", "sd1", "z"; 32 + };
+1
drivers/clk/Makefile
··· 35 35 obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ 36 36 obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o 37 37 obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ 38 + obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ 38 39 39 40 obj-$(CONFIG_X86) += x86/ 40 41
+5
drivers/clk/shmobile/Makefile
··· 1 + obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o 2 + obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o 3 + 4 + # for emply built-in.o 5 + obj-n := dummy
+298
drivers/clk/shmobile/clk-rcar-gen2.c
··· 1 + /* 2 + * rcar_gen2 Core CPG Clocks 3 + * 4 + * Copyright (C) 2013 Ideas On Board SPRL 5 + * 6 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; version 2 of the License. 11 + */ 12 + 13 + #include <linux/clk-provider.h> 14 + #include <linux/clkdev.h> 15 + #include <linux/clk/shmobile.h> 16 + #include <linux/init.h> 17 + #include <linux/kernel.h> 18 + #include <linux/math64.h> 19 + #include <linux/of.h> 20 + #include <linux/of_address.h> 21 + #include <linux/spinlock.h> 22 + 23 + struct rcar_gen2_cpg { 24 + struct clk_onecell_data data; 25 + spinlock_t lock; 26 + void __iomem *reg; 27 + }; 28 + 29 + #define CPG_SDCKCR 0x00000074 30 + #define CPG_PLL0CR 0x000000d8 31 + #define CPG_FRQCRC 0x000000e0 32 + #define CPG_FRQCRC_ZFC_MASK (0x1f << 8) 33 + #define CPG_FRQCRC_ZFC_SHIFT 8 34 + 35 + /* ----------------------------------------------------------------------------- 36 + * Z Clock 37 + * 38 + * Traits of this clock: 39 + * prepare - clk_prepare only ensures that parents are prepared 40 + * enable - clk_enable only ensures that parents are enabled 41 + * rate - rate is adjustable. clk->rate = parent->rate * mult / 32 42 + * parent - fixed parent. No clk_set_parent support 43 + */ 44 + 45 + struct cpg_z_clk { 46 + struct clk_hw hw; 47 + void __iomem *reg; 48 + }; 49 + 50 + #define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) 51 + 52 + static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, 53 + unsigned long parent_rate) 54 + { 55 + struct cpg_z_clk *zclk = to_z_clk(hw); 56 + unsigned int mult; 57 + unsigned int val; 58 + 59 + val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) 60 + >> CPG_FRQCRC_ZFC_SHIFT; 61 + mult = 32 - val; 62 + 63 + return div_u64((u64)parent_rate * mult, 32); 64 + } 65 + 66 + static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate, 67 + unsigned long *parent_rate) 68 + { 69 + unsigned long prate = *parent_rate; 70 + unsigned int mult; 71 + 72 + if (!prate) 73 + prate = 1; 74 + 75 + mult = div_u64((u64)rate * 32, prate); 76 + mult = clamp(mult, 1U, 32U); 77 + 78 + return *parent_rate / 32 * mult; 79 + } 80 + 81 + static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, 82 + unsigned long parent_rate) 83 + { 84 + struct cpg_z_clk *zclk = to_z_clk(hw); 85 + unsigned int mult; 86 + u32 val; 87 + 88 + mult = div_u64((u64)rate * 32, parent_rate); 89 + mult = clamp(mult, 1U, 32U); 90 + 91 + val = clk_readl(zclk->reg); 92 + val &= ~CPG_FRQCRC_ZFC_MASK; 93 + val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; 94 + clk_writel(val, zclk->reg); 95 + 96 + return 0; 97 + } 98 + 99 + static const struct clk_ops cpg_z_clk_ops = { 100 + .recalc_rate = cpg_z_clk_recalc_rate, 101 + .round_rate = cpg_z_clk_round_rate, 102 + .set_rate = cpg_z_clk_set_rate, 103 + }; 104 + 105 + static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg) 106 + { 107 + static const char *parent_name = "pll0"; 108 + struct clk_init_data init; 109 + struct cpg_z_clk *zclk; 110 + struct clk *clk; 111 + 112 + zclk = kzalloc(sizeof(*zclk), GFP_KERNEL); 113 + if (!zclk) 114 + return ERR_PTR(-ENOMEM); 115 + 116 + init.name = "z"; 117 + init.ops = &cpg_z_clk_ops; 118 + init.flags = 0; 119 + init.parent_names = &parent_name; 120 + init.num_parents = 1; 121 + 122 + zclk->reg = cpg->reg + CPG_FRQCRC; 123 + zclk->hw.init = &init; 124 + 125 + clk = clk_register(NULL, &zclk->hw); 126 + if (IS_ERR(clk)) 127 + kfree(zclk); 128 + 129 + return clk; 130 + } 131 + 132 + /* ----------------------------------------------------------------------------- 133 + * CPG Clock Data 134 + */ 135 + 136 + /* 137 + * MD EXTAL PLL0 PLL1 PLL3 138 + * 14 13 19 (MHz) *1 *1 139 + *--------------------------------------------------- 140 + * 0 0 0 15 x 1 x172/2 x208/2 x106 141 + * 0 0 1 15 x 1 x172/2 x208/2 x88 142 + * 0 1 0 20 x 1 x130/2 x156/2 x80 143 + * 0 1 1 20 x 1 x130/2 x156/2 x66 144 + * 1 0 0 26 / 2 x200/2 x240/2 x122 145 + * 1 0 1 26 / 2 x200/2 x240/2 x102 146 + * 1 1 0 30 / 2 x172/2 x208/2 x106 147 + * 1 1 1 30 / 2 x172/2 x208/2 x88 148 + * 149 + * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2) 150 + */ 151 + #define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ 152 + (((md) & BIT(13)) >> 12) | \ 153 + (((md) & BIT(19)) >> 19)) 154 + struct cpg_pll_config { 155 + unsigned int extal_div; 156 + unsigned int pll1_mult; 157 + unsigned int pll3_mult; 158 + }; 159 + 160 + static const struct cpg_pll_config cpg_pll_configs[8] __initconst = { 161 + { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 }, 162 + { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 }, 163 + }; 164 + 165 + /* SDHI divisors */ 166 + static const struct clk_div_table cpg_sdh_div_table[] = { 167 + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, 168 + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, 169 + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, 170 + }; 171 + 172 + static const struct clk_div_table cpg_sd01_div_table[] = { 173 + { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, 174 + { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, 175 + }; 176 + 177 + /* ----------------------------------------------------------------------------- 178 + * Initialization 179 + */ 180 + 181 + static u32 cpg_mode __initdata; 182 + 183 + static struct clk * __init 184 + rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, 185 + const struct cpg_pll_config *config, 186 + const char *name) 187 + { 188 + const struct clk_div_table *table = NULL; 189 + const char *parent_name = "main"; 190 + unsigned int shift; 191 + unsigned int mult = 1; 192 + unsigned int div = 1; 193 + 194 + if (!strcmp(name, "main")) { 195 + parent_name = of_clk_get_parent_name(np, 0); 196 + div = config->extal_div; 197 + } else if (!strcmp(name, "pll0")) { 198 + /* PLL0 is a configurable multiplier clock. Register it as a 199 + * fixed factor clock for now as there's no generic multiplier 200 + * clock implementation and we currently have no need to change 201 + * the multiplier value. 202 + */ 203 + u32 value = clk_readl(cpg->reg + CPG_PLL0CR); 204 + mult = ((value >> 24) & ((1 << 7) - 1)) + 1; 205 + } else if (!strcmp(name, "pll1")) { 206 + mult = config->pll1_mult / 2; 207 + } else if (!strcmp(name, "pll3")) { 208 + mult = config->pll3_mult; 209 + } else if (!strcmp(name, "lb")) { 210 + div = cpg_mode & BIT(18) ? 36 : 24; 211 + } else if (!strcmp(name, "qspi")) { 212 + div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) 213 + ? 16 : 20; 214 + } else if (!strcmp(name, "sdh")) { 215 + table = cpg_sdh_div_table; 216 + shift = 8; 217 + } else if (!strcmp(name, "sd0")) { 218 + table = cpg_sd01_div_table; 219 + shift = 4; 220 + } else if (!strcmp(name, "sd1")) { 221 + table = cpg_sd01_div_table; 222 + shift = 0; 223 + } else if (!strcmp(name, "z")) { 224 + return cpg_z_clk_register(cpg); 225 + } else { 226 + return ERR_PTR(-EINVAL); 227 + } 228 + 229 + if (!table) 230 + return clk_register_fixed_factor(NULL, name, parent_name, 0, 231 + mult, div); 232 + else 233 + return clk_register_divider_table(NULL, name, parent_name, 0, 234 + cpg->reg + CPG_SDCKCR, shift, 235 + 4, 0, table, &cpg->lock); 236 + } 237 + 238 + static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) 239 + { 240 + const struct cpg_pll_config *config; 241 + struct rcar_gen2_cpg *cpg; 242 + struct clk **clks; 243 + unsigned int i; 244 + int num_clks; 245 + 246 + num_clks = of_property_count_strings(np, "clock-output-names"); 247 + if (num_clks < 0) { 248 + pr_err("%s: failed to count clocks\n", __func__); 249 + return; 250 + } 251 + 252 + cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); 253 + clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); 254 + if (cpg == NULL || clks == NULL) { 255 + /* We're leaking memory on purpose, there's no point in cleaning 256 + * up as the system won't boot anyway. 257 + */ 258 + pr_err("%s: failed to allocate cpg\n", __func__); 259 + return; 260 + } 261 + 262 + spin_lock_init(&cpg->lock); 263 + 264 + cpg->data.clks = clks; 265 + cpg->data.clk_num = num_clks; 266 + 267 + cpg->reg = of_iomap(np, 0); 268 + if (WARN_ON(cpg->reg == NULL)) 269 + return; 270 + 271 + config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; 272 + 273 + for (i = 0; i < num_clks; ++i) { 274 + const char *name; 275 + struct clk *clk; 276 + 277 + of_property_read_string_index(np, "clock-output-names", i, 278 + &name); 279 + 280 + clk = rcar_gen2_cpg_register_clock(np, cpg, config, name); 281 + if (IS_ERR(clk)) 282 + pr_err("%s: failed to register %s %s clock (%ld)\n", 283 + __func__, np->name, name, PTR_ERR(clk)); 284 + else 285 + cpg->data.clks[i] = clk; 286 + } 287 + 288 + of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); 289 + } 290 + CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks", 291 + rcar_gen2_cpg_clocks_init); 292 + 293 + void __init rcar_gen2_clocks_init(u32 mode) 294 + { 295 + cpg_mode = mode; 296 + 297 + of_clk_init(NULL); 298 + }
+19
include/linux/clk/shmobile.h
··· 1 + /* 2 + * Copyright 2013 Ideas On Board SPRL 3 + * 4 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 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; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #ifndef __LINUX_CLK_SHMOBILE_H_ 13 + #define __LINUX_CLK_SHMOBILE_H_ 14 + 15 + #include <linux/types.h> 16 + 17 + void rcar_gen2_clocks_init(u32 mode); 18 + 19 + #endif