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 *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 mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, 53 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_factor *ff = &clks[i]; 60 61 clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, 62 CLK_SET_RATE_PARENT, ff->mult, ff->div); 63 64 if (IS_ERR(clk)) { 65 pr_err("Failed to register clk %s: %ld\n", 66 ff->name, PTR_ERR(clk)); 67 continue; 68 } 69 70 if (clk_data) 71 clk_data->clks[ff->id] = clk; 72 } 73 } 74 75 int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, 76 int num, struct clk_onecell_data *clk_data) 77 { 78 int i; 79 struct clk *clk; 80 struct regmap *regmap; 81 82 if (!clk_data) 83 return -ENOMEM; 84 85 regmap = syscon_node_to_regmap(node); 86 if (IS_ERR(regmap)) { 87 pr_err("Cannot find regmap for %s: %ld\n", node->full_name, 88 PTR_ERR(regmap)); 89 return PTR_ERR(regmap); 90 } 91 92 for (i = 0; i < num; i++) { 93 const struct mtk_gate *gate = &clks[i]; 94 95 clk = mtk_clk_register_gate(gate->name, gate->parent_name, 96 regmap, 97 gate->regs->set_ofs, 98 gate->regs->clr_ofs, 99 gate->regs->sta_ofs, 100 gate->shift, gate->ops); 101 102 if (IS_ERR(clk)) { 103 pr_err("Failed to register clk %s: %ld\n", 104 gate->name, PTR_ERR(clk)); 105 continue; 106 } 107 108 clk_data->clks[gate->id] = clk; 109 } 110 111 return 0; 112 } 113 114 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, 115 void __iomem *base, spinlock_t *lock) 116 { 117 struct clk *clk; 118 struct clk_mux *mux = NULL; 119 struct clk_gate *gate = NULL; 120 struct clk_divider *div = NULL; 121 struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL; 122 const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL; 123 const char * const *parent_names; 124 const char *parent; 125 int num_parents; 126 int ret; 127 128 if (mc->mux_shift >= 0) { 129 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 130 if (!mux) 131 return ERR_PTR(-ENOMEM); 132 133 mux->reg = base + mc->mux_reg; 134 mux->mask = BIT(mc->mux_width) - 1; 135 mux->shift = mc->mux_shift; 136 mux->lock = lock; 137 138 mux_hw = &mux->hw; 139 mux_ops = &clk_mux_ops; 140 141 parent_names = mc->parent_names; 142 num_parents = mc->num_parents; 143 } else { 144 parent = mc->parent; 145 parent_names = &parent; 146 num_parents = 1; 147 } 148 149 if (mc->gate_shift >= 0) { 150 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 151 if (!gate) { 152 ret = -ENOMEM; 153 goto err_out; 154 } 155 156 gate->reg = base + mc->gate_reg; 157 gate->bit_idx = mc->gate_shift; 158 gate->flags = CLK_GATE_SET_TO_DISABLE; 159 gate->lock = lock; 160 161 gate_hw = &gate->hw; 162 gate_ops = &clk_gate_ops; 163 } 164 165 if (mc->divider_shift >= 0) { 166 div = kzalloc(sizeof(*div), GFP_KERNEL); 167 if (!div) { 168 ret = -ENOMEM; 169 goto err_out; 170 } 171 172 div->reg = base + mc->divider_reg; 173 div->shift = mc->divider_shift; 174 div->width = mc->divider_width; 175 div->lock = lock; 176 177 div_hw = &div->hw; 178 div_ops = &clk_divider_ops; 179 } 180 181 clk = clk_register_composite(NULL, mc->name, parent_names, num_parents, 182 mux_hw, mux_ops, 183 div_hw, div_ops, 184 gate_hw, gate_ops, 185 mc->flags); 186 187 if (IS_ERR(clk)) { 188 kfree(gate); 189 kfree(mux); 190 } 191 192 return clk; 193 err_out: 194 kfree(mux); 195 196 return ERR_PTR(ret); 197 } 198 199 void mtk_clk_register_composites(const struct mtk_composite *mcs, 200 int num, void __iomem *base, spinlock_t *lock, 201 struct clk_onecell_data *clk_data) 202 { 203 struct clk *clk; 204 int i; 205 206 for (i = 0; i < num; i++) { 207 const struct mtk_composite *mc = &mcs[i]; 208 209 clk = mtk_clk_register_composite(mc, base, lock); 210 211 if (IS_ERR(clk)) { 212 pr_err("Failed to register clk %s: %ld\n", 213 mc->name, PTR_ERR(clk)); 214 continue; 215 } 216 217 if (clk_data) 218 clk_data->clks[mc->id] = clk; 219 } 220 } 221