1 /* 2 * Copyright (c) 2014 MundoReader S.L. 3 * Author: Heiko Stuebner <heiko@sntech.de> 4 * 5 * based on 6 * 7 * samsung/clk.c 8 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 9 * Copyright (c) 2013 Linaro Ltd. 10 * Author: Thomas Abraham <thomas.ab@samsung.com> 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 */ 22 23 #include <linux/slab.h> 24 #include <linux/clk.h> 25 #include <linux/clk-provider.h> 26 #include <linux/mfd/syscon.h> 27 #include <linux/regmap.h> 28 #include "clk.h" 29 30 /** 31 * Register a clock branch. 32 * Most clock branches have a form like 33 * 34 * src1 --|--\ 35 * |M |--[GATE]-[DIV]- 36 * src2 --|--/ 37 * 38 * sometimes without one of those components. 39 */ 40 struct clk *rockchip_clk_register_branch(const char *name, 41 const char **parent_names, u8 num_parents, void __iomem *base, 42 int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, 43 u8 div_shift, u8 div_width, u8 div_flags, 44 struct clk_div_table *div_table, int gate_offset, 45 u8 gate_shift, u8 gate_flags, unsigned long flags, 46 spinlock_t *lock) 47 { 48 struct clk *clk; 49 struct clk_mux *mux = NULL; 50 struct clk_gate *gate = NULL; 51 struct clk_divider *div = NULL; 52 const struct clk_ops *mux_ops = NULL, *div_ops = NULL, 53 *gate_ops = NULL; 54 55 if (num_parents > 1) { 56 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 57 if (!mux) 58 return ERR_PTR(-ENOMEM); 59 60 mux->reg = base + muxdiv_offset; 61 mux->shift = mux_shift; 62 mux->mask = BIT(mux_width) - 1; 63 mux->flags = mux_flags; 64 mux->lock = lock; 65 mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops 66 : &clk_mux_ops; 67 } 68 69 if (gate_offset >= 0) { 70 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 71 if (!gate) 72 return ERR_PTR(-ENOMEM); 73 74 gate->flags = gate_flags; 75 gate->reg = base + gate_offset; 76 gate->bit_idx = gate_shift; 77 gate->lock = lock; 78 gate_ops = &clk_gate_ops; 79 } 80 81 if (div_width > 0) { 82 div = kzalloc(sizeof(*div), GFP_KERNEL); 83 if (!div) 84 return ERR_PTR(-ENOMEM); 85 86 div->flags = div_flags; 87 div->reg = base + muxdiv_offset; 88 div->shift = div_shift; 89 div->width = div_width; 90 div->lock = lock; 91 div->table = div_table; 92 div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) 93 ? &clk_divider_ro_ops 94 : &clk_divider_ops; 95 } 96 97 clk = clk_register_composite(NULL, name, parent_names, num_parents, 98 mux ? &mux->hw : NULL, mux_ops, 99 div ? &div->hw : NULL, div_ops, 100 gate ? &gate->hw : NULL, gate_ops, 101 flags); 102 103 return clk; 104 } 105 106 static DEFINE_SPINLOCK(clk_lock); 107 static struct clk **clk_table; 108 static void __iomem *reg_base; 109 static struct clk_onecell_data clk_data; 110 static struct device_node *cru_node; 111 static struct regmap *grf; 112 113 void __init rockchip_clk_init(struct device_node *np, void __iomem *base, 114 unsigned long nr_clks) 115 { 116 reg_base = base; 117 cru_node = np; 118 grf = ERR_PTR(-EPROBE_DEFER); 119 120 clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); 121 if (!clk_table) 122 pr_err("%s: could not allocate clock lookup table\n", __func__); 123 124 clk_data.clks = clk_table; 125 clk_data.clk_num = nr_clks; 126 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 127 } 128 129 struct regmap *rockchip_clk_get_grf(void) 130 { 131 if (IS_ERR(grf)) 132 grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf"); 133 return grf; 134 } 135 136 void rockchip_clk_add_lookup(struct clk *clk, unsigned int id) 137 { 138 if (clk_table && id) 139 clk_table[id] = clk; 140 } 141 142 void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list, 143 unsigned int nr_pll, int grf_lock_offset) 144 { 145 struct clk *clk; 146 int idx; 147 148 for (idx = 0; idx < nr_pll; idx++, list++) { 149 clk = rockchip_clk_register_pll(list->type, list->name, 150 list->parent_names, list->num_parents, 151 reg_base, list->con_offset, grf_lock_offset, 152 list->lock_shift, list->mode_offset, 153 list->mode_shift, list->rate_table, &clk_lock); 154 if (IS_ERR(clk)) { 155 pr_err("%s: failed to register clock %s\n", __func__, 156 list->name); 157 continue; 158 } 159 160 rockchip_clk_add_lookup(clk, list->id); 161 } 162 } 163 164 void __init rockchip_clk_register_branches( 165 struct rockchip_clk_branch *list, 166 unsigned int nr_clk) 167 { 168 struct clk *clk = NULL; 169 unsigned int idx; 170 unsigned long flags; 171 172 for (idx = 0; idx < nr_clk; idx++, list++) { 173 flags = list->flags; 174 175 /* catch simple muxes */ 176 switch (list->branch_type) { 177 case branch_mux: 178 clk = clk_register_mux(NULL, list->name, 179 list->parent_names, list->num_parents, 180 flags, reg_base + list->muxdiv_offset, 181 list->mux_shift, list->mux_width, 182 list->mux_flags, &clk_lock); 183 break; 184 case branch_divider: 185 if (list->div_table) 186 clk = clk_register_divider_table(NULL, 187 list->name, list->parent_names[0], 188 flags, reg_base + list->muxdiv_offset, 189 list->div_shift, list->div_width, 190 list->div_flags, list->div_table, 191 &clk_lock); 192 else 193 clk = clk_register_divider(NULL, list->name, 194 list->parent_names[0], flags, 195 reg_base + list->muxdiv_offset, 196 list->div_shift, list->div_width, 197 list->div_flags, &clk_lock); 198 break; 199 case branch_fraction_divider: 200 /* unimplemented */ 201 continue; 202 break; 203 case branch_gate: 204 flags |= CLK_SET_RATE_PARENT; 205 206 /* keep all gates untouched for now */ 207 flags |= CLK_IGNORE_UNUSED; 208 209 clk = clk_register_gate(NULL, list->name, 210 list->parent_names[0], flags, 211 reg_base + list->gate_offset, 212 list->gate_shift, list->gate_flags, &clk_lock); 213 break; 214 case branch_composite: 215 /* keep all gates untouched for now */ 216 flags |= CLK_IGNORE_UNUSED; 217 218 clk = rockchip_clk_register_branch(list->name, 219 list->parent_names, list->num_parents, 220 reg_base, list->muxdiv_offset, list->mux_shift, 221 list->mux_width, list->mux_flags, 222 list->div_shift, list->div_width, 223 list->div_flags, list->div_table, 224 list->gate_offset, list->gate_shift, 225 list->gate_flags, flags, &clk_lock); 226 break; 227 } 228 229 /* none of the cases above matched */ 230 if (!clk) { 231 pr_err("%s: unknown clock type %d\n", 232 __func__, list->branch_type); 233 continue; 234 } 235 236 if (IS_ERR(clk)) { 237 pr_err("%s: failed to register clock %s: %ld\n", 238 __func__, list->name, PTR_ERR(clk)); 239 continue; 240 } 241 242 rockchip_clk_add_lookup(clk, list->id); 243 } 244 } 245