1 /* 2 * PRCMU clock implementation for ux500 platform. 3 * 4 * Copyright (C) 2012 ST-Ericsson SA 5 * Author: Ulf Hansson <ulf.hansson@linaro.org> 6 * 7 * License terms: GNU General Public License (GPL) version 2 8 */ 9 10 #include <linux/clk-provider.h> 11 #include <linux/clk-private.h> 12 #include <linux/mfd/dbx500-prcmu.h> 13 #include <linux/slab.h> 14 #include <linux/io.h> 15 #include <linux/err.h> 16 #include "clk.h" 17 18 #define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw) 19 20 struct clk_prcmu { 21 struct clk_hw hw; 22 u8 cg_sel; 23 int is_enabled; 24 }; 25 26 /* PRCMU clock operations. */ 27 28 static int clk_prcmu_prepare(struct clk_hw *hw) 29 { 30 struct clk_prcmu *clk = to_clk_prcmu(hw); 31 return prcmu_request_clock(clk->cg_sel, true); 32 } 33 34 static void clk_prcmu_unprepare(struct clk_hw *hw) 35 { 36 struct clk_prcmu *clk = to_clk_prcmu(hw); 37 if (prcmu_request_clock(clk->cg_sel, false)) 38 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 39 hw->init->name); 40 } 41 42 static int clk_prcmu_enable(struct clk_hw *hw) 43 { 44 struct clk_prcmu *clk = to_clk_prcmu(hw); 45 clk->is_enabled = 1; 46 return 0; 47 } 48 49 static void clk_prcmu_disable(struct clk_hw *hw) 50 { 51 struct clk_prcmu *clk = to_clk_prcmu(hw); 52 clk->is_enabled = 0; 53 } 54 55 static int clk_prcmu_is_enabled(struct clk_hw *hw) 56 { 57 struct clk_prcmu *clk = to_clk_prcmu(hw); 58 return clk->is_enabled; 59 } 60 61 static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw, 62 unsigned long parent_rate) 63 { 64 struct clk_prcmu *clk = to_clk_prcmu(hw); 65 return prcmu_clock_rate(clk->cg_sel); 66 } 67 68 static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate, 69 unsigned long *parent_rate) 70 { 71 struct clk_prcmu *clk = to_clk_prcmu(hw); 72 return prcmu_round_clock_rate(clk->cg_sel, rate); 73 } 74 75 static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate, 76 unsigned long parent_rate) 77 { 78 struct clk_prcmu *clk = to_clk_prcmu(hw); 79 return prcmu_set_clock_rate(clk->cg_sel, rate); 80 } 81 82 static int request_ape_opp100(bool enable) 83 { 84 static int reqs; 85 int err = 0; 86 87 if (enable) { 88 if (!reqs) 89 err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, 90 "clock", 100); 91 if (!err) 92 reqs++; 93 } else { 94 reqs--; 95 if (!reqs) 96 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, 97 "clock"); 98 } 99 return err; 100 } 101 102 static int clk_prcmu_opp_prepare(struct clk_hw *hw) 103 { 104 int err; 105 struct clk_prcmu *clk = to_clk_prcmu(hw); 106 107 err = request_ape_opp100(true); 108 if (err) { 109 pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n", 110 __func__, hw->init->name); 111 return err; 112 } 113 114 err = prcmu_request_clock(clk->cg_sel, true); 115 if (err) 116 request_ape_opp100(false); 117 118 return err; 119 } 120 121 static void clk_prcmu_opp_unprepare(struct clk_hw *hw) 122 { 123 struct clk_prcmu *clk = to_clk_prcmu(hw); 124 125 if (prcmu_request_clock(clk->cg_sel, false)) 126 goto out_error; 127 if (request_ape_opp100(false)) 128 goto out_error; 129 return; 130 131 out_error: 132 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 133 hw->init->name); 134 } 135 136 static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) 137 { 138 int err; 139 struct clk_prcmu *clk = to_clk_prcmu(hw); 140 141 err = prcmu_request_ape_opp_100_voltage(true); 142 if (err) { 143 pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n", 144 __func__, hw->init->name); 145 return err; 146 } 147 148 err = prcmu_request_clock(clk->cg_sel, true); 149 if (err) 150 prcmu_request_ape_opp_100_voltage(false); 151 152 return err; 153 } 154 155 static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) 156 { 157 struct clk_prcmu *clk = to_clk_prcmu(hw); 158 159 if (prcmu_request_clock(clk->cg_sel, false)) 160 goto out_error; 161 if (prcmu_request_ape_opp_100_voltage(false)) 162 goto out_error; 163 return; 164 165 out_error: 166 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 167 hw->init->name); 168 } 169 170 static struct clk_ops clk_prcmu_scalable_ops = { 171 .prepare = clk_prcmu_prepare, 172 .unprepare = clk_prcmu_unprepare, 173 .enable = clk_prcmu_enable, 174 .disable = clk_prcmu_disable, 175 .is_enabled = clk_prcmu_is_enabled, 176 .recalc_rate = clk_prcmu_recalc_rate, 177 .round_rate = clk_prcmu_round_rate, 178 .set_rate = clk_prcmu_set_rate, 179 }; 180 181 static struct clk_ops clk_prcmu_gate_ops = { 182 .prepare = clk_prcmu_prepare, 183 .unprepare = clk_prcmu_unprepare, 184 .enable = clk_prcmu_enable, 185 .disable = clk_prcmu_disable, 186 .is_enabled = clk_prcmu_is_enabled, 187 .recalc_rate = clk_prcmu_recalc_rate, 188 }; 189 190 static struct clk_ops clk_prcmu_scalable_rate_ops = { 191 .is_enabled = clk_prcmu_is_enabled, 192 .recalc_rate = clk_prcmu_recalc_rate, 193 .round_rate = clk_prcmu_round_rate, 194 .set_rate = clk_prcmu_set_rate, 195 }; 196 197 static struct clk_ops clk_prcmu_rate_ops = { 198 .is_enabled = clk_prcmu_is_enabled, 199 .recalc_rate = clk_prcmu_recalc_rate, 200 }; 201 202 static struct clk_ops clk_prcmu_opp_gate_ops = { 203 .prepare = clk_prcmu_opp_prepare, 204 .unprepare = clk_prcmu_opp_unprepare, 205 .enable = clk_prcmu_enable, 206 .disable = clk_prcmu_disable, 207 .is_enabled = clk_prcmu_is_enabled, 208 .recalc_rate = clk_prcmu_recalc_rate, 209 }; 210 211 static struct clk_ops clk_prcmu_opp_volt_scalable_ops = { 212 .prepare = clk_prcmu_opp_volt_prepare, 213 .unprepare = clk_prcmu_opp_volt_unprepare, 214 .enable = clk_prcmu_enable, 215 .disable = clk_prcmu_disable, 216 .is_enabled = clk_prcmu_is_enabled, 217 .recalc_rate = clk_prcmu_recalc_rate, 218 .round_rate = clk_prcmu_round_rate, 219 .set_rate = clk_prcmu_set_rate, 220 }; 221 222 static struct clk *clk_reg_prcmu(const char *name, 223 const char *parent_name, 224 u8 cg_sel, 225 unsigned long rate, 226 unsigned long flags, 227 struct clk_ops *clk_prcmu_ops) 228 { 229 struct clk_prcmu *clk; 230 struct clk_init_data clk_prcmu_init; 231 struct clk *clk_reg; 232 233 if (!name) { 234 pr_err("clk_prcmu: %s invalid arguments passed\n", __func__); 235 return ERR_PTR(-EINVAL); 236 } 237 238 clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL); 239 if (!clk) { 240 pr_err("clk_prcmu: %s could not allocate clk\n", __func__); 241 return ERR_PTR(-ENOMEM); 242 } 243 244 clk->cg_sel = cg_sel; 245 clk->is_enabled = 1; 246 /* "rate" can be used for changing the initial frequency */ 247 if (rate) 248 prcmu_set_clock_rate(cg_sel, rate); 249 250 clk_prcmu_init.name = name; 251 clk_prcmu_init.ops = clk_prcmu_ops; 252 clk_prcmu_init.flags = flags; 253 clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL); 254 clk_prcmu_init.num_parents = (parent_name ? 1 : 0); 255 clk->hw.init = &clk_prcmu_init; 256 257 clk_reg = clk_register(NULL, &clk->hw); 258 if (IS_ERR_OR_NULL(clk_reg)) 259 goto free_clk; 260 261 return clk_reg; 262 263 free_clk: 264 kfree(clk); 265 pr_err("clk_prcmu: %s failed to register clk\n", __func__); 266 return ERR_PTR(-ENOMEM); 267 } 268 269 struct clk *clk_reg_prcmu_scalable(const char *name, 270 const char *parent_name, 271 u8 cg_sel, 272 unsigned long rate, 273 unsigned long flags) 274 { 275 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, 276 &clk_prcmu_scalable_ops); 277 } 278 279 struct clk *clk_reg_prcmu_gate(const char *name, 280 const char *parent_name, 281 u8 cg_sel, 282 unsigned long flags) 283 { 284 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, 285 &clk_prcmu_gate_ops); 286 } 287 288 struct clk *clk_reg_prcmu_scalable_rate(const char *name, 289 const char *parent_name, 290 u8 cg_sel, 291 unsigned long rate, 292 unsigned long flags) 293 { 294 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, 295 &clk_prcmu_scalable_rate_ops); 296 } 297 298 struct clk *clk_reg_prcmu_rate(const char *name, 299 const char *parent_name, 300 u8 cg_sel, 301 unsigned long flags) 302 { 303 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, 304 &clk_prcmu_rate_ops); 305 } 306 307 struct clk *clk_reg_prcmu_opp_gate(const char *name, 308 const char *parent_name, 309 u8 cg_sel, 310 unsigned long flags) 311 { 312 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, 313 &clk_prcmu_opp_gate_ops); 314 } 315 316 struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name, 317 const char *parent_name, 318 u8 cg_sel, 319 unsigned long rate, 320 unsigned long flags) 321 { 322 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, 323 &clk_prcmu_opp_volt_scalable_ops); 324 } 325