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