1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014 MediaTek Inc. 4 * Author: James Liao <jamesjj.liao@mediatek.com> 5 */ 6 7 #include <linux/of.h> 8 #include <linux/of_address.h> 9 #include <linux/err.h> 10 #include <linux/io.h> 11 #include <linux/slab.h> 12 #include <linux/delay.h> 13 #include <linux/clkdev.h> 14 #include <linux/mfd/syscon.h> 15 16 #include "clk-mtk.h" 17 #include "clk-gate.h" 18 19 struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num) 20 { 21 int i; 22 struct clk_onecell_data *clk_data; 23 24 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 25 if (!clk_data) 26 return NULL; 27 28 clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL); 29 if (!clk_data->clks) 30 goto err_out; 31 32 clk_data->clk_num = clk_num; 33 34 for (i = 0; i < clk_num; i++) 35 clk_data->clks[i] = ERR_PTR(-ENOENT); 36 37 return clk_data; 38 err_out: 39 kfree(clk_data); 40 41 return NULL; 42 } 43 44 void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, 45 int num, struct clk_onecell_data *clk_data) 46 { 47 int i; 48 struct clk *clk; 49 50 for (i = 0; i < num; i++) { 51 const struct mtk_fixed_clk *rc = &clks[i]; 52 53 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id])) 54 continue; 55 56 clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0, 57 rc->rate); 58 59 if (IS_ERR(clk)) { 60 pr_err("Failed to register clk %s: %ld\n", 61 rc->name, PTR_ERR(clk)); 62 continue; 63 } 64 65 if (clk_data) 66 clk_data->clks[rc->id] = clk; 67 } 68 } 69 70 void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, 71 int num, struct clk_onecell_data *clk_data) 72 { 73 int i; 74 struct clk *clk; 75 76 for (i = 0; i < num; i++) { 77 const struct mtk_fixed_factor *ff = &clks[i]; 78 79 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id])) 80 continue; 81 82 clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, 83 CLK_SET_RATE_PARENT, ff->mult, ff->div); 84 85 if (IS_ERR(clk)) { 86 pr_err("Failed to register clk %s: %ld\n", 87 ff->name, PTR_ERR(clk)); 88 continue; 89 } 90 91 if (clk_data) 92 clk_data->clks[ff->id] = clk; 93 } 94 } 95 96 int mtk_clk_register_gates(struct device_node *node, 97 const struct mtk_gate *clks, 98 int num, struct clk_onecell_data *clk_data) 99 { 100 int i; 101 struct clk *clk; 102 struct regmap *regmap; 103 104 if (!clk_data) 105 return -ENOMEM; 106 107 regmap = syscon_node_to_regmap(node); 108 if (IS_ERR(regmap)) { 109 pr_err("Cannot find regmap for %pOF: %ld\n", node, 110 PTR_ERR(regmap)); 111 return PTR_ERR(regmap); 112 } 113 114 for (i = 0; i < num; i++) { 115 const struct mtk_gate *gate = &clks[i]; 116 117 if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) 118 continue; 119 120 clk = mtk_clk_register_gate(gate->name, gate->parent_name, 121 regmap, 122 gate->regs->set_ofs, 123 gate->regs->clr_ofs, 124 gate->regs->sta_ofs, 125 gate->shift, gate->ops, gate->flags); 126 127 if (IS_ERR(clk)) { 128 pr_err("Failed to register clk %s: %ld\n", 129 gate->name, PTR_ERR(clk)); 130 continue; 131 } 132 133 clk_data->clks[gate->id] = clk; 134 } 135 136 return 0; 137 } 138 139 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, 140 void __iomem *base, spinlock_t *lock) 141 { 142 struct clk *clk; 143 struct clk_mux *mux = NULL; 144 struct clk_gate *gate = NULL; 145 struct clk_divider *div = NULL; 146 struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL; 147 const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL; 148 const char * const *parent_names; 149 const char *parent; 150 int num_parents; 151 int ret; 152 153 if (mc->mux_shift >= 0) { 154 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 155 if (!mux) 156 return ERR_PTR(-ENOMEM); 157 158 mux->reg = base + mc->mux_reg; 159 mux->mask = BIT(mc->mux_width) - 1; 160 mux->shift = mc->mux_shift; 161 mux->lock = lock; 162 mux->flags = mc->mux_flags; 163 mux_hw = &mux->hw; 164 mux_ops = &clk_mux_ops; 165 166 parent_names = mc->parent_names; 167 num_parents = mc->num_parents; 168 } else { 169 parent = mc->parent; 170 parent_names = &parent; 171 num_parents = 1; 172 } 173 174 if (mc->gate_shift >= 0) { 175 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 176 if (!gate) { 177 ret = -ENOMEM; 178 goto err_out; 179 } 180 181 gate->reg = base + mc->gate_reg; 182 gate->bit_idx = mc->gate_shift; 183 gate->flags = CLK_GATE_SET_TO_DISABLE; 184 gate->lock = lock; 185 186 gate_hw = &gate->hw; 187 gate_ops = &clk_gate_ops; 188 } 189 190 if (mc->divider_shift >= 0) { 191 div = kzalloc(sizeof(*div), GFP_KERNEL); 192 if (!div) { 193 ret = -ENOMEM; 194 goto err_out; 195 } 196 197 div->reg = base + mc->divider_reg; 198 div->shift = mc->divider_shift; 199 div->width = mc->divider_width; 200 div->lock = lock; 201 202 div_hw = &div->hw; 203 div_ops = &clk_divider_ops; 204 } 205 206 clk = clk_register_composite(NULL, mc->name, parent_names, num_parents, 207 mux_hw, mux_ops, 208 div_hw, div_ops, 209 gate_hw, gate_ops, 210 mc->flags); 211 212 if (IS_ERR(clk)) { 213 ret = PTR_ERR(clk); 214 goto err_out; 215 } 216 217 return clk; 218 err_out: 219 kfree(div); 220 kfree(gate); 221 kfree(mux); 222 223 return ERR_PTR(ret); 224 } 225 226 void mtk_clk_register_composites(const struct mtk_composite *mcs, 227 int num, void __iomem *base, spinlock_t *lock, 228 struct clk_onecell_data *clk_data) 229 { 230 struct clk *clk; 231 int i; 232 233 for (i = 0; i < num; i++) { 234 const struct mtk_composite *mc = &mcs[i]; 235 236 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id])) 237 continue; 238 239 clk = mtk_clk_register_composite(mc, base, lock); 240 241 if (IS_ERR(clk)) { 242 pr_err("Failed to register clk %s: %ld\n", 243 mc->name, PTR_ERR(clk)); 244 continue; 245 } 246 247 if (clk_data) 248 clk_data->clks[mc->id] = clk; 249 } 250 } 251 252 void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, 253 int num, void __iomem *base, spinlock_t *lock, 254 struct clk_onecell_data *clk_data) 255 { 256 struct clk *clk; 257 int i; 258 259 for (i = 0; i < num; i++) { 260 const struct mtk_clk_divider *mcd = &mcds[i]; 261 262 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id])) 263 continue; 264 265 clk = clk_register_divider(NULL, mcd->name, mcd->parent_name, 266 mcd->flags, base + mcd->div_reg, mcd->div_shift, 267 mcd->div_width, mcd->clk_divider_flags, lock); 268 269 if (IS_ERR(clk)) { 270 pr_err("Failed to register clk %s: %ld\n", 271 mcd->name, PTR_ERR(clk)); 272 continue; 273 } 274 275 if (clk_data) 276 clk_data->clks[mcd->id] = clk; 277 } 278 } 279