1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * PRCMU clock implementation for ux500 platform. 4 * 5 * Copyright (C) 2012 ST-Ericsson SA 6 * Author: Ulf Hansson <ulf.hansson@linaro.org> 7 */ 8 9 #include <linux/clk-provider.h> 10 #include <linux/mfd/dbx500-prcmu.h> 11 #include <linux/slab.h> 12 #include <linux/io.h> 13 #include <linux/err.h> 14 #include "clk.h" 15 16 #define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw) 17 #define to_clk_prcmu_clkout(_hw) container_of(_hw, struct clk_prcmu_clkout, hw) 18 19 struct clk_prcmu { 20 struct clk_hw hw; 21 u8 cg_sel; 22 int opp_requested; 23 }; 24 25 struct clk_prcmu_clkout { 26 struct clk_hw hw; 27 u8 clkout_id; 28 u8 source; 29 u8 divider; 30 }; 31 32 /* PRCMU clock operations. */ 33 34 static int clk_prcmu_prepare(struct clk_hw *hw) 35 { 36 struct clk_prcmu *clk = to_clk_prcmu(hw); 37 38 return prcmu_request_clock(clk->cg_sel, true); 39 } 40 41 static void clk_prcmu_unprepare(struct clk_hw *hw) 42 { 43 struct clk_prcmu *clk = to_clk_prcmu(hw); 44 if (prcmu_request_clock(clk->cg_sel, false)) 45 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 46 clk_hw_get_name(hw)); 47 } 48 49 static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw, 50 unsigned long parent_rate) 51 { 52 struct clk_prcmu *clk = to_clk_prcmu(hw); 53 return prcmu_clock_rate(clk->cg_sel); 54 } 55 56 static int clk_prcmu_determine_rate(struct clk_hw *hw, 57 struct clk_rate_request *req) 58 { 59 struct clk_prcmu *clk = to_clk_prcmu(hw); 60 req->rate = prcmu_round_clock_rate(clk->cg_sel, req->rate); 61 62 return 0; 63 } 64 65 static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate, 66 unsigned long parent_rate) 67 { 68 struct clk_prcmu *clk = to_clk_prcmu(hw); 69 return prcmu_set_clock_rate(clk->cg_sel, rate); 70 } 71 72 static int clk_prcmu_opp_prepare(struct clk_hw *hw) 73 { 74 int err; 75 struct clk_prcmu *clk = to_clk_prcmu(hw); 76 77 if (!clk->opp_requested) { 78 err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, 79 (char *)clk_hw_get_name(hw), 80 100); 81 if (err) { 82 pr_err("clk_prcmu: %s fail req APE OPP for %s.\n", 83 __func__, clk_hw_get_name(hw)); 84 return err; 85 } 86 clk->opp_requested = 1; 87 } 88 89 err = prcmu_request_clock(clk->cg_sel, true); 90 if (err) { 91 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, 92 (char *)clk_hw_get_name(hw)); 93 clk->opp_requested = 0; 94 return err; 95 } 96 97 return 0; 98 } 99 100 static void clk_prcmu_opp_unprepare(struct clk_hw *hw) 101 { 102 struct clk_prcmu *clk = to_clk_prcmu(hw); 103 104 if (prcmu_request_clock(clk->cg_sel, false)) { 105 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 106 clk_hw_get_name(hw)); 107 return; 108 } 109 110 if (clk->opp_requested) { 111 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, 112 (char *)clk_hw_get_name(hw)); 113 clk->opp_requested = 0; 114 } 115 } 116 117 static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) 118 { 119 int err; 120 struct clk_prcmu *clk = to_clk_prcmu(hw); 121 122 if (!clk->opp_requested) { 123 err = prcmu_request_ape_opp_100_voltage(true); 124 if (err) { 125 pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n", 126 __func__, clk_hw_get_name(hw)); 127 return err; 128 } 129 clk->opp_requested = 1; 130 } 131 132 err = prcmu_request_clock(clk->cg_sel, true); 133 if (err) { 134 prcmu_request_ape_opp_100_voltage(false); 135 clk->opp_requested = 0; 136 return err; 137 } 138 139 return 0; 140 } 141 142 static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) 143 { 144 struct clk_prcmu *clk = to_clk_prcmu(hw); 145 146 if (prcmu_request_clock(clk->cg_sel, false)) { 147 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 148 clk_hw_get_name(hw)); 149 return; 150 } 151 152 if (clk->opp_requested) { 153 prcmu_request_ape_opp_100_voltage(false); 154 clk->opp_requested = 0; 155 } 156 } 157 158 static const struct clk_ops clk_prcmu_scalable_ops = { 159 .prepare = clk_prcmu_prepare, 160 .unprepare = clk_prcmu_unprepare, 161 .recalc_rate = clk_prcmu_recalc_rate, 162 .determine_rate = clk_prcmu_determine_rate, 163 .set_rate = clk_prcmu_set_rate, 164 }; 165 166 static const struct clk_ops clk_prcmu_gate_ops = { 167 .prepare = clk_prcmu_prepare, 168 .unprepare = clk_prcmu_unprepare, 169 .recalc_rate = clk_prcmu_recalc_rate, 170 }; 171 172 static const struct clk_ops clk_prcmu_scalable_rate_ops = { 173 .recalc_rate = clk_prcmu_recalc_rate, 174 .determine_rate = clk_prcmu_determine_rate, 175 .set_rate = clk_prcmu_set_rate, 176 }; 177 178 static const struct clk_ops clk_prcmu_rate_ops = { 179 .recalc_rate = clk_prcmu_recalc_rate, 180 }; 181 182 static const struct clk_ops clk_prcmu_opp_gate_ops = { 183 .prepare = clk_prcmu_opp_prepare, 184 .unprepare = clk_prcmu_opp_unprepare, 185 .recalc_rate = clk_prcmu_recalc_rate, 186 }; 187 188 static const struct clk_ops clk_prcmu_opp_volt_scalable_ops = { 189 .prepare = clk_prcmu_opp_volt_prepare, 190 .unprepare = clk_prcmu_opp_volt_unprepare, 191 .recalc_rate = clk_prcmu_recalc_rate, 192 .determine_rate = clk_prcmu_determine_rate, 193 .set_rate = clk_prcmu_set_rate, 194 }; 195 196 static struct clk_hw *clk_reg_prcmu(const char *name, 197 const char *parent_name, 198 u8 cg_sel, 199 unsigned long rate, 200 unsigned long flags, 201 const struct clk_ops *clk_prcmu_ops) 202 { 203 struct clk_prcmu *clk; 204 struct clk_init_data clk_prcmu_init; 205 int ret; 206 207 if (!name) { 208 pr_err("clk_prcmu: %s invalid arguments passed\n", __func__); 209 return ERR_PTR(-EINVAL); 210 } 211 212 clk = kzalloc(sizeof(*clk), GFP_KERNEL); 213 if (!clk) 214 return ERR_PTR(-ENOMEM); 215 216 clk->cg_sel = cg_sel; 217 clk->opp_requested = 0; 218 /* "rate" can be used for changing the initial frequency */ 219 if (rate) 220 prcmu_set_clock_rate(cg_sel, rate); 221 222 clk_prcmu_init.name = name; 223 clk_prcmu_init.ops = clk_prcmu_ops; 224 clk_prcmu_init.flags = flags; 225 clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL); 226 clk_prcmu_init.num_parents = (parent_name ? 1 : 0); 227 clk->hw.init = &clk_prcmu_init; 228 229 ret = clk_hw_register(NULL, &clk->hw); 230 if (ret) 231 goto free_clk; 232 233 return &clk->hw; 234 235 free_clk: 236 kfree(clk); 237 pr_err("clk_prcmu: %s failed to register clk\n", __func__); 238 return ERR_PTR(-ENOMEM); 239 } 240 241 struct clk_hw *clk_reg_prcmu_scalable(const char *name, 242 const char *parent_name, 243 u8 cg_sel, 244 unsigned long rate, 245 unsigned long flags) 246 { 247 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, 248 &clk_prcmu_scalable_ops); 249 } 250 251 struct clk_hw *clk_reg_prcmu_gate(const char *name, 252 const char *parent_name, 253 u8 cg_sel, 254 unsigned long flags) 255 { 256 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, 257 &clk_prcmu_gate_ops); 258 } 259 260 struct clk_hw *clk_reg_prcmu_scalable_rate(const char *name, 261 const char *parent_name, 262 u8 cg_sel, 263 unsigned long rate, 264 unsigned long flags) 265 { 266 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, 267 &clk_prcmu_scalable_rate_ops); 268 } 269 270 struct clk_hw *clk_reg_prcmu_rate(const char *name, 271 const char *parent_name, 272 u8 cg_sel, 273 unsigned long flags) 274 { 275 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, 276 &clk_prcmu_rate_ops); 277 } 278 279 struct clk_hw *clk_reg_prcmu_opp_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_opp_gate_ops); 286 } 287 288 struct clk_hw *clk_reg_prcmu_opp_volt_scalable(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_opp_volt_scalable_ops); 296 } 297 298 /* The clkout (external) clock is special and need special ops */ 299 300 static int clk_prcmu_clkout_prepare(struct clk_hw *hw) 301 { 302 struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw); 303 304 return prcmu_config_clkout(clk->clkout_id, clk->source, clk->divider); 305 } 306 307 static void clk_prcmu_clkout_unprepare(struct clk_hw *hw) 308 { 309 struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw); 310 int ret; 311 312 /* The clkout clock is disabled by dividing by 0 */ 313 ret = prcmu_config_clkout(clk->clkout_id, clk->source, 0); 314 if (ret) 315 pr_err("clk_prcmu: %s failed to disable %s\n", __func__, 316 clk_hw_get_name(hw)); 317 } 318 319 static unsigned long clk_prcmu_clkout_recalc_rate(struct clk_hw *hw, 320 unsigned long parent_rate) 321 { 322 struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw); 323 324 return (parent_rate / clk->divider); 325 } 326 327 static u8 clk_prcmu_clkout_get_parent(struct clk_hw *hw) 328 { 329 struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw); 330 331 return clk->source; 332 } 333 334 static int clk_prcmu_clkout_set_parent(struct clk_hw *hw, u8 index) 335 { 336 struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw); 337 338 clk->source = index; 339 /* Make sure the change reaches the hardware immediately */ 340 if (clk_hw_is_prepared(hw)) 341 return clk_prcmu_clkout_prepare(hw); 342 return 0; 343 } 344 345 static const struct clk_ops clk_prcmu_clkout_ops = { 346 .prepare = clk_prcmu_clkout_prepare, 347 .unprepare = clk_prcmu_clkout_unprepare, 348 .recalc_rate = clk_prcmu_clkout_recalc_rate, 349 .determine_rate = clk_hw_determine_rate_no_reparent, 350 .get_parent = clk_prcmu_clkout_get_parent, 351 .set_parent = clk_prcmu_clkout_set_parent, 352 }; 353 354 struct clk_hw *clk_reg_prcmu_clkout(const char *name, 355 const char * const *parent_names, 356 int num_parents, 357 u8 source, u8 divider) 358 359 { 360 struct clk_prcmu_clkout *clk; 361 struct clk_init_data clk_prcmu_clkout_init; 362 u8 clkout_id; 363 int ret; 364 365 if (!name) { 366 pr_err("clk_prcmu_clkout: %s invalid arguments passed\n", __func__); 367 return ERR_PTR(-EINVAL); 368 } 369 370 if (!strcmp(name, "clkout1")) 371 clkout_id = 0; 372 else if (!strcmp(name, "clkout2")) 373 clkout_id = 1; 374 else { 375 pr_err("clk_prcmu_clkout: %s bad clock name\n", __func__); 376 return ERR_PTR(-EINVAL); 377 } 378 379 clk = kzalloc(sizeof(*clk), GFP_KERNEL); 380 if (!clk) 381 return ERR_PTR(-ENOMEM); 382 383 clk->clkout_id = clkout_id; 384 clk->source = source; 385 clk->divider = divider; 386 387 clk_prcmu_clkout_init.name = name; 388 clk_prcmu_clkout_init.ops = &clk_prcmu_clkout_ops; 389 clk_prcmu_clkout_init.flags = CLK_GET_RATE_NOCACHE; 390 clk_prcmu_clkout_init.parent_names = parent_names; 391 clk_prcmu_clkout_init.num_parents = num_parents; 392 clk->hw.init = &clk_prcmu_clkout_init; 393 394 ret = clk_hw_register(NULL, &clk->hw); 395 if (ret) 396 goto free_clkout; 397 398 return &clk->hw; 399 free_clkout: 400 kfree(clk); 401 pr_err("clk_prcmu_clkout: %s failed to register clk\n", __func__); 402 return ERR_PTR(-ENOMEM); 403 } 404