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