1b3a33077SSimon Horman /* 2b3a33077SSimon Horman * rz Core CPG Clocks 3b3a33077SSimon Horman * 4b3a33077SSimon Horman * Copyright (C) 2013 Ideas On Board SPRL 5b3a33077SSimon Horman * Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> 6b3a33077SSimon Horman * 7b3a33077SSimon Horman * This program is free software; you can redistribute it and/or modify 8b3a33077SSimon Horman * it under the terms of the GNU General Public License as published by 9b3a33077SSimon Horman * the Free Software Foundation; version 2 of the License. 10b3a33077SSimon Horman */ 11b3a33077SSimon Horman 12b3a33077SSimon Horman #include <linux/clk-provider.h> 13b3a33077SSimon Horman #include <linux/clk/shmobile.h> 14b3a33077SSimon Horman #include <linux/init.h> 15b3a33077SSimon Horman #include <linux/kernel.h> 16b3a33077SSimon Horman #include <linux/of.h> 17b3a33077SSimon Horman #include <linux/of_address.h> 18b3a33077SSimon Horman #include <linux/slab.h> 19b3a33077SSimon Horman 20b3a33077SSimon Horman struct rz_cpg { 21b3a33077SSimon Horman struct clk_onecell_data data; 22b3a33077SSimon Horman void __iomem *reg; 23b3a33077SSimon Horman }; 24b3a33077SSimon Horman 25b3a33077SSimon Horman #define CPG_FRQCR 0x10 26b3a33077SSimon Horman #define CPG_FRQCR2 0x14 27b3a33077SSimon Horman 28b3a33077SSimon Horman /* ----------------------------------------------------------------------------- 29b3a33077SSimon Horman * Initialization 30b3a33077SSimon Horman */ 31b3a33077SSimon Horman 32b3a33077SSimon Horman static struct clk * __init 33b3a33077SSimon Horman rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name) 34b3a33077SSimon Horman { 35b3a33077SSimon Horman u32 val; 36b3a33077SSimon Horman unsigned mult; 37b3a33077SSimon Horman static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 }; 38b3a33077SSimon Horman 39b3a33077SSimon Horman if (strcmp(name, "pll") == 0) { 40b3a33077SSimon Horman /* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */ 41b3a33077SSimon Horman unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */ 42b3a33077SSimon Horman const char *parent_name = of_clk_get_parent_name(np, cpg_mode); 43b3a33077SSimon Horman 44b3a33077SSimon Horman mult = cpg_mode ? (32 / 4) : 30; 45b3a33077SSimon Horman 46b3a33077SSimon Horman return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1); 47b3a33077SSimon Horman } 48b3a33077SSimon Horman 49b3a33077SSimon Horman /* If mapping regs failed, skip non-pll clocks. System will boot anyhow */ 50b3a33077SSimon Horman if (!cpg->reg) 51b3a33077SSimon Horman return ERR_PTR(-ENXIO); 52b3a33077SSimon Horman 53b3a33077SSimon Horman /* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3) 54b3a33077SSimon Horman * and the constraint that always g <= i. To get the rz platform started, 55b3a33077SSimon Horman * let them run at fixed current speed and implement the details later. 56b3a33077SSimon Horman */ 57b3a33077SSimon Horman if (strcmp(name, "i") == 0) 58b3a33077SSimon Horman val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3; 59b3a33077SSimon Horman else if (strcmp(name, "g") == 0) 60b3a33077SSimon Horman val = clk_readl(cpg->reg + CPG_FRQCR2) & 3; 61b3a33077SSimon Horman else 62b3a33077SSimon Horman return ERR_PTR(-EINVAL); 63b3a33077SSimon Horman 64b3a33077SSimon Horman mult = frqcr_tab[val]; 65b3a33077SSimon Horman return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3); 66b3a33077SSimon Horman } 67b3a33077SSimon Horman 68b3a33077SSimon Horman static void __init rz_cpg_clocks_init(struct device_node *np) 69b3a33077SSimon Horman { 70b3a33077SSimon Horman struct rz_cpg *cpg; 71b3a33077SSimon Horman struct clk **clks; 72b3a33077SSimon Horman unsigned i; 73b3a33077SSimon Horman int num_clks; 74b3a33077SSimon Horman 75b3a33077SSimon Horman num_clks = of_property_count_strings(np, "clock-output-names"); 76b3a33077SSimon Horman if (WARN(num_clks <= 0, "can't count CPG clocks\n")) 77b3a33077SSimon Horman return; 78b3a33077SSimon Horman 79b3a33077SSimon Horman cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); 80b3a33077SSimon Horman clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); 81b3a33077SSimon Horman BUG_ON(!cpg || !clks); 82b3a33077SSimon Horman 83b3a33077SSimon Horman cpg->data.clks = clks; 84b3a33077SSimon Horman cpg->data.clk_num = num_clks; 85b3a33077SSimon Horman 86b3a33077SSimon Horman cpg->reg = of_iomap(np, 0); 87b3a33077SSimon Horman 88b3a33077SSimon Horman for (i = 0; i < num_clks; ++i) { 89b3a33077SSimon Horman const char *name; 90b3a33077SSimon Horman struct clk *clk; 91b3a33077SSimon Horman 92b3a33077SSimon Horman of_property_read_string_index(np, "clock-output-names", i, &name); 93b3a33077SSimon Horman 94b3a33077SSimon Horman clk = rz_cpg_register_clock(np, cpg, name); 95b3a33077SSimon Horman if (IS_ERR(clk)) 96b3a33077SSimon Horman pr_err("%s: failed to register %s %s clock (%ld)\n", 97b3a33077SSimon Horman __func__, np->name, name, PTR_ERR(clk)); 98b3a33077SSimon Horman else 99b3a33077SSimon Horman cpg->data.clks[i] = clk; 100b3a33077SSimon Horman } 101b3a33077SSimon Horman 102b3a33077SSimon Horman of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); 103b3a33077SSimon Horman 104b3a33077SSimon Horman cpg_mstp_add_clk_domain(np); 105b3a33077SSimon Horman } 106b3a33077SSimon Horman CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init); 107