Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: versatile/icst: support for AP baseboard clocks

This adds support for the two ICST525-based clocks on the
Integrator/AP baseboard, as documented in the board manual
"Integrator/AP ASIC Development Motherboard", ARM DUI0098 B,
pages 3-15 thru 3-18.

Cc: Russell King <linux@armlinux.org.uk>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
[sboyd@codeaurora.org: fixed uninitialized val warning]
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Linus Walleij and committed by
Stephen Boyd
fa62e10d 74002fcd

+136
+136
drivers/clk/versatile/clk-icst.c
··· 29 29 30 30 #define VERSATILE_AUX_OSC_BITS 0x7FFFF 31 31 #define INTEGRATOR_AP_CM_BITS 0xFF 32 + #define INTEGRATOR_AP_SYS_BITS 0xFF 32 33 #define INTEGRATOR_CP_CM_CORE_BITS 0x7FF 33 34 #define INTEGRATOR_CP_CM_MEM_BITS 0x7FF000 35 + 36 + #define INTEGRATOR_AP_PCI_25_33_MHZ BIT(8) 34 37 35 38 /** 36 39 * enum icst_control_type - the type of ICST control register ··· 41 38 enum icst_control_type { 42 39 ICST_VERSATILE, /* The standard type, all control bits available */ 43 40 ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ 41 + ICST_INTEGRATOR_AP_SYS, /* Only 8 bits of VDW available */ 42 + ICST_INTEGRATOR_AP_PCI, /* Odd bit pattern storage */ 44 43 ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ 45 44 ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ 46 45 }; ··· 98 93 } 99 94 100 95 /* 96 + * The Integrator/AP system clock on the base board can only 97 + * access the low eight bits of the v PLL divider. Bit 8 is tied low 98 + * and always zero, r is hardwired to 46, and the output divider is 99 + * hardwired to 3 (divide by 4) according to the document 100 + * "Integrator AP ASIC Development Motherboard" ARM DUI 0098B, 101 + * page 3-16. 102 + */ 103 + if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { 104 + vco->v = val & INTEGRATOR_AP_SYS_BITS; 105 + vco->r = 46; 106 + vco->s = 3; 107 + return 0; 108 + } 109 + 110 + /* 111 + * The Integrator/AP PCI clock is using an odd pattern to create 112 + * the child clock, basically a single bit called DIVX/Y is used 113 + * to select between two different hardwired values: setting the 114 + * bit to 0 yields v = 17, r = 22 and OD = 1, whereas setting the 115 + * bit to 1 yields v = 14, r = 14 and OD = 1 giving the frequencies 116 + * 33 or 25 MHz respectively. 117 + */ 118 + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { 119 + bool divxy = !!(val & INTEGRATOR_AP_PCI_25_33_MHZ); 120 + 121 + vco->v = divxy ? 17 : 14; 122 + vco->r = divxy ? 22 : 14; 123 + vco->s = 1; 124 + return 0; 125 + } 126 + 127 + /* 101 128 * The Integrator/CP core clock can access the low eight bits 102 129 * of the v PLL divider. Bit 8 is tied low and always zero, 103 130 * r is hardwired to 22 and the output divider s is accessible ··· 178 141 if (vco.s != 1) 179 142 pr_err("ICST error: tried to use VOD != 1\n"); 180 143 if (vco.r != 22) 144 + pr_err("ICST error: tried to use RDW != 22\n"); 145 + break; 146 + case ICST_INTEGRATOR_AP_SYS: 147 + mask = INTEGRATOR_AP_SYS_BITS; 148 + val = vco.v & 0xFF; 149 + if (vco.v & 0x100) 150 + pr_err("ICST error: tried to set bit 8 of VDW\n"); 151 + if (vco.s != 3) 152 + pr_err("ICST error: tried to use VOD != 1\n"); 153 + if (vco.r != 46) 181 154 pr_err("ICST error: tried to use RDW != 22\n"); 182 155 break; 183 156 case ICST_INTEGRATOR_CP_CM_CORE: ··· 272 225 return DIV_ROUND_CLOSEST(rate, 500000) * 500000; 273 226 } 274 227 228 + if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { 229 + /* Divides between 3 and 50 MHz in steps of 0.25 MHz */ 230 + if (rate <= 3000000) 231 + return 3000000; 232 + if (rate >= 50000000) 233 + return 5000000; 234 + /* Slam to closest 0.25 MHz */ 235 + return DIV_ROUND_CLOSEST(rate, 250000) * 250000; 236 + } 237 + 238 + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { 239 + /* 240 + * If we're below or less than halfway from 25 to 33 MHz 241 + * select 25 MHz 242 + */ 243 + if (rate <= 25000000 || rate < 29000000) 244 + return 25000000; 245 + /* Else just return the default frequency */ 246 + return 33000000; 247 + } 248 + 275 249 vco = icst_hz_to_vco(icst->params, rate); 276 250 return icst_hz(icst->params, vco); 277 251 } ··· 302 234 { 303 235 struct clk_icst *icst = to_icst(hw); 304 236 struct icst_vco vco; 237 + 238 + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { 239 + /* This clock is especially primitive */ 240 + unsigned int val; 241 + int ret; 242 + 243 + if (rate == 25000000) { 244 + val = 0; 245 + } else if (rate == 33000000) { 246 + val = INTEGRATOR_AP_PCI_25_33_MHZ; 247 + } else { 248 + pr_err("ICST: cannot set PCI frequency %lu\n", 249 + rate); 250 + return -EINVAL; 251 + } 252 + ret = regmap_write(icst->map, icst->lockreg_off, 253 + VERSATILE_LOCK_VAL); 254 + if (ret) 255 + return ret; 256 + ret = regmap_update_bits(icst->map, icst->vcoreg_off, 257 + INTEGRATOR_AP_PCI_25_33_MHZ, 258 + val); 259 + if (ret) 260 + return ret; 261 + /* This locks the VCO again */ 262 + ret = regmap_write(icst->map, icst->lockreg_off, 0); 263 + if (ret) 264 + return ret; 265 + return 0; 266 + } 305 267 306 268 if (parent_rate) 307 269 icst->params->ref = parent_rate; ··· 466 368 .idx2s = icst525_idx2s, 467 369 }; 468 370 371 + static const struct icst_params icst525_ap_sys_params = { 372 + .vco_max = ICST525_VCO_MAX_5V, 373 + .vco_min = ICST525_VCO_MIN, 374 + /* Minimum 3 MHz, VDW = 4 */ 375 + .vd_min = 3, 376 + /* Maximum 50 MHz, VDW = 192 */ 377 + .vd_max = 50, 378 + /* r is hardcoded to 46 and this is the actual divisor, +2 */ 379 + .rd_min = 48, 380 + .rd_max = 48, 381 + .s2div = icst525_s2div, 382 + .idx2s = icst525_idx2s, 383 + }; 384 + 385 + static const struct icst_params icst525_ap_pci_params = { 386 + .vco_max = ICST525_VCO_MAX_5V, 387 + .vco_min = ICST525_VCO_MIN, 388 + /* Minimum 25 MHz */ 389 + .vd_min = 25, 390 + /* Maximum 33 MHz */ 391 + .vd_max = 33, 392 + /* r is hardcoded to 14 or 22 and this is the actual divisors +2 */ 393 + .rd_min = 16, 394 + .rd_max = 24, 395 + .s2div = icst525_s2div, 396 + .idx2s = icst525_idx2s, 397 + }; 398 + 469 399 static void __init of_syscon_icst_setup(struct device_node *np) 470 400 { 471 401 struct device_node *parent; ··· 534 408 } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-cm")) { 535 409 icst_desc.params = &icst525_apcp_cm_params; 536 410 ctype = ICST_INTEGRATOR_AP_CM; 411 + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-sys")) { 412 + icst_desc.params = &icst525_ap_sys_params; 413 + ctype = ICST_INTEGRATOR_AP_SYS; 414 + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-pci")) { 415 + icst_desc.params = &icst525_ap_pci_params; 416 + ctype = ICST_INTEGRATOR_AP_PCI; 537 417 } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-core")) { 538 418 icst_desc.params = &icst525_apcp_cm_params; 539 419 ctype = ICST_INTEGRATOR_CP_CM_CORE; ··· 569 437 "arm,syscon-icst307", of_syscon_icst_setup); 570 438 CLK_OF_DECLARE(arm_syscon_integratorap_cm_clk, 571 439 "arm,syscon-icst525-integratorap-cm", of_syscon_icst_setup); 440 + CLK_OF_DECLARE(arm_syscon_integratorap_sys_clk, 441 + "arm,syscon-icst525-integratorap-sys", of_syscon_icst_setup); 442 + CLK_OF_DECLARE(arm_syscon_integratorap_pci_clk, 443 + "arm,syscon-icst525-integratorap-pci", of_syscon_icst_setup); 572 444 CLK_OF_DECLARE(arm_syscon_integratorcp_cm_core_clk, 573 445 "arm,syscon-icst525-integratorcp-cm-core", of_syscon_icst_setup); 574 446 CLK_OF_DECLARE(arm_syscon_integratorcp_cm_mem_clk,