1 /* 2 * drivers/clk/at91/sckc.c 3 * 4 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 */ 12 13 #include <linux/clk-provider.h> 14 #include <linux/clkdev.h> 15 #include <linux/delay.h> 16 #include <linux/of.h> 17 #include <linux/of_address.h> 18 #include <linux/io.h> 19 20 #define SLOW_CLOCK_FREQ 32768 21 #define SLOWCK_SW_CYCLES 5 22 #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \ 23 SLOW_CLOCK_FREQ) 24 25 #define AT91_SCKC_CR 0x00 26 #define AT91_SCKC_RCEN (1 << 0) 27 #define AT91_SCKC_OSC32EN (1 << 1) 28 #define AT91_SCKC_OSC32BYP (1 << 2) 29 #define AT91_SCKC_OSCSEL (1 << 3) 30 31 struct clk_slow_osc { 32 struct clk_hw hw; 33 void __iomem *sckcr; 34 unsigned long startup_usec; 35 }; 36 37 #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) 38 39 struct clk_sama5d4_slow_osc { 40 struct clk_hw hw; 41 void __iomem *sckcr; 42 unsigned long startup_usec; 43 bool prepared; 44 }; 45 46 #define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw) 47 48 struct clk_slow_rc_osc { 49 struct clk_hw hw; 50 void __iomem *sckcr; 51 unsigned long frequency; 52 unsigned long accuracy; 53 unsigned long startup_usec; 54 }; 55 56 #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw) 57 58 struct clk_sam9x5_slow { 59 struct clk_hw hw; 60 void __iomem *sckcr; 61 u8 parent; 62 }; 63 64 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw) 65 66 static int clk_slow_osc_prepare(struct clk_hw *hw) 67 { 68 struct clk_slow_osc *osc = to_clk_slow_osc(hw); 69 void __iomem *sckcr = osc->sckcr; 70 u32 tmp = readl(sckcr); 71 72 if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN)) 73 return 0; 74 75 writel(tmp | AT91_SCKC_OSC32EN, sckcr); 76 77 usleep_range(osc->startup_usec, osc->startup_usec + 1); 78 79 return 0; 80 } 81 82 static void clk_slow_osc_unprepare(struct clk_hw *hw) 83 { 84 struct clk_slow_osc *osc = to_clk_slow_osc(hw); 85 void __iomem *sckcr = osc->sckcr; 86 u32 tmp = readl(sckcr); 87 88 if (tmp & AT91_SCKC_OSC32BYP) 89 return; 90 91 writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); 92 } 93 94 static int clk_slow_osc_is_prepared(struct clk_hw *hw) 95 { 96 struct clk_slow_osc *osc = to_clk_slow_osc(hw); 97 void __iomem *sckcr = osc->sckcr; 98 u32 tmp = readl(sckcr); 99 100 if (tmp & AT91_SCKC_OSC32BYP) 101 return 1; 102 103 return !!(tmp & AT91_SCKC_OSC32EN); 104 } 105 106 static const struct clk_ops slow_osc_ops = { 107 .prepare = clk_slow_osc_prepare, 108 .unprepare = clk_slow_osc_unprepare, 109 .is_prepared = clk_slow_osc_is_prepared, 110 }; 111 112 static struct clk_hw * __init 113 at91_clk_register_slow_osc(void __iomem *sckcr, 114 const char *name, 115 const char *parent_name, 116 unsigned long startup, 117 bool bypass) 118 { 119 struct clk_slow_osc *osc; 120 struct clk_hw *hw; 121 struct clk_init_data init; 122 int ret; 123 124 if (!sckcr || !name || !parent_name) 125 return ERR_PTR(-EINVAL); 126 127 osc = kzalloc(sizeof(*osc), GFP_KERNEL); 128 if (!osc) 129 return ERR_PTR(-ENOMEM); 130 131 init.name = name; 132 init.ops = &slow_osc_ops; 133 init.parent_names = &parent_name; 134 init.num_parents = 1; 135 init.flags = CLK_IGNORE_UNUSED; 136 137 osc->hw.init = &init; 138 osc->sckcr = sckcr; 139 osc->startup_usec = startup; 140 141 if (bypass) 142 writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, 143 sckcr); 144 145 hw = &osc->hw; 146 ret = clk_hw_register(NULL, &osc->hw); 147 if (ret) { 148 kfree(osc); 149 hw = ERR_PTR(ret); 150 } 151 152 return hw; 153 } 154 155 static void __init 156 of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) 157 { 158 struct clk_hw *hw; 159 const char *parent_name; 160 const char *name = np->name; 161 u32 startup; 162 bool bypass; 163 164 parent_name = of_clk_get_parent_name(np, 0); 165 of_property_read_string(np, "clock-output-names", &name); 166 of_property_read_u32(np, "atmel,startup-time-usec", &startup); 167 bypass = of_property_read_bool(np, "atmel,osc-bypass"); 168 169 hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, 170 bypass); 171 if (IS_ERR(hw)) 172 return; 173 174 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 175 } 176 177 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, 178 unsigned long parent_rate) 179 { 180 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 181 182 return osc->frequency; 183 } 184 185 static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw, 186 unsigned long parent_acc) 187 { 188 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 189 190 return osc->accuracy; 191 } 192 193 static int clk_slow_rc_osc_prepare(struct clk_hw *hw) 194 { 195 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 196 void __iomem *sckcr = osc->sckcr; 197 198 writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); 199 200 usleep_range(osc->startup_usec, osc->startup_usec + 1); 201 202 return 0; 203 } 204 205 static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) 206 { 207 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 208 void __iomem *sckcr = osc->sckcr; 209 210 writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); 211 } 212 213 static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) 214 { 215 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 216 217 return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); 218 } 219 220 static const struct clk_ops slow_rc_osc_ops = { 221 .prepare = clk_slow_rc_osc_prepare, 222 .unprepare = clk_slow_rc_osc_unprepare, 223 .is_prepared = clk_slow_rc_osc_is_prepared, 224 .recalc_rate = clk_slow_rc_osc_recalc_rate, 225 .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy, 226 }; 227 228 static struct clk_hw * __init 229 at91_clk_register_slow_rc_osc(void __iomem *sckcr, 230 const char *name, 231 unsigned long frequency, 232 unsigned long accuracy, 233 unsigned long startup) 234 { 235 struct clk_slow_rc_osc *osc; 236 struct clk_hw *hw; 237 struct clk_init_data init; 238 int ret; 239 240 if (!sckcr || !name) 241 return ERR_PTR(-EINVAL); 242 243 osc = kzalloc(sizeof(*osc), GFP_KERNEL); 244 if (!osc) 245 return ERR_PTR(-ENOMEM); 246 247 init.name = name; 248 init.ops = &slow_rc_osc_ops; 249 init.parent_names = NULL; 250 init.num_parents = 0; 251 init.flags = CLK_IGNORE_UNUSED; 252 253 osc->hw.init = &init; 254 osc->sckcr = sckcr; 255 osc->frequency = frequency; 256 osc->accuracy = accuracy; 257 osc->startup_usec = startup; 258 259 hw = &osc->hw; 260 ret = clk_hw_register(NULL, &osc->hw); 261 if (ret) { 262 kfree(osc); 263 hw = ERR_PTR(ret); 264 } 265 266 return hw; 267 } 268 269 static void __init 270 of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) 271 { 272 struct clk_hw *hw; 273 u32 frequency = 0; 274 u32 accuracy = 0; 275 u32 startup = 0; 276 const char *name = np->name; 277 278 of_property_read_string(np, "clock-output-names", &name); 279 of_property_read_u32(np, "clock-frequency", &frequency); 280 of_property_read_u32(np, "clock-accuracy", &accuracy); 281 of_property_read_u32(np, "atmel,startup-time-usec", &startup); 282 283 hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, 284 startup); 285 if (IS_ERR(hw)) 286 return; 287 288 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 289 } 290 291 static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) 292 { 293 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); 294 void __iomem *sckcr = slowck->sckcr; 295 u32 tmp; 296 297 if (index > 1) 298 return -EINVAL; 299 300 tmp = readl(sckcr); 301 302 if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || 303 (index && (tmp & AT91_SCKC_OSCSEL))) 304 return 0; 305 306 if (index) 307 tmp |= AT91_SCKC_OSCSEL; 308 else 309 tmp &= ~AT91_SCKC_OSCSEL; 310 311 writel(tmp, sckcr); 312 313 usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1); 314 315 return 0; 316 } 317 318 static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) 319 { 320 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); 321 322 return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); 323 } 324 325 static const struct clk_ops sam9x5_slow_ops = { 326 .set_parent = clk_sam9x5_slow_set_parent, 327 .get_parent = clk_sam9x5_slow_get_parent, 328 }; 329 330 static struct clk_hw * __init 331 at91_clk_register_sam9x5_slow(void __iomem *sckcr, 332 const char *name, 333 const char **parent_names, 334 int num_parents) 335 { 336 struct clk_sam9x5_slow *slowck; 337 struct clk_hw *hw; 338 struct clk_init_data init; 339 int ret; 340 341 if (!sckcr || !name || !parent_names || !num_parents) 342 return ERR_PTR(-EINVAL); 343 344 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); 345 if (!slowck) 346 return ERR_PTR(-ENOMEM); 347 348 init.name = name; 349 init.ops = &sam9x5_slow_ops; 350 init.parent_names = parent_names; 351 init.num_parents = num_parents; 352 init.flags = 0; 353 354 slowck->hw.init = &init; 355 slowck->sckcr = sckcr; 356 slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); 357 358 hw = &slowck->hw; 359 ret = clk_hw_register(NULL, &slowck->hw); 360 if (ret) { 361 kfree(slowck); 362 hw = ERR_PTR(ret); 363 } 364 365 return hw; 366 } 367 368 static void __init 369 of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) 370 { 371 struct clk_hw *hw; 372 const char *parent_names[2]; 373 unsigned int num_parents; 374 const char *name = np->name; 375 376 num_parents = of_clk_get_parent_count(np); 377 if (num_parents == 0 || num_parents > 2) 378 return; 379 380 of_clk_parent_fill(np, parent_names, num_parents); 381 382 of_property_read_string(np, "clock-output-names", &name); 383 384 hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, 385 num_parents); 386 if (IS_ERR(hw)) 387 return; 388 389 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 390 } 391 392 static const struct of_device_id sckc_clk_ids[] __initconst = { 393 /* Slow clock */ 394 { 395 .compatible = "atmel,at91sam9x5-clk-slow-osc", 396 .data = of_at91sam9x5_clk_slow_osc_setup, 397 }, 398 { 399 .compatible = "atmel,at91sam9x5-clk-slow-rc-osc", 400 .data = of_at91sam9x5_clk_slow_rc_osc_setup, 401 }, 402 { 403 .compatible = "atmel,at91sam9x5-clk-slow", 404 .data = of_at91sam9x5_clk_slow_setup, 405 }, 406 { /*sentinel*/ } 407 }; 408 409 static void __init of_at91sam9x5_sckc_setup(struct device_node *np) 410 { 411 struct device_node *childnp; 412 void (*clk_setup)(struct device_node *, void __iomem *); 413 const struct of_device_id *clk_id; 414 void __iomem *regbase = of_iomap(np, 0); 415 416 if (!regbase) 417 return; 418 419 for_each_child_of_node(np, childnp) { 420 clk_id = of_match_node(sckc_clk_ids, childnp); 421 if (!clk_id) 422 continue; 423 clk_setup = clk_id->data; 424 clk_setup(childnp, regbase); 425 } 426 } 427 CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", 428 of_at91sam9x5_sckc_setup); 429 430 static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) 431 { 432 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); 433 434 if (osc->prepared) 435 return 0; 436 437 /* 438 * Assume that if it has already been selected (for example by the 439 * bootloader), enough time has aready passed. 440 */ 441 if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) { 442 osc->prepared = true; 443 return 0; 444 } 445 446 usleep_range(osc->startup_usec, osc->startup_usec + 1); 447 osc->prepared = true; 448 449 return 0; 450 } 451 452 static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw) 453 { 454 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); 455 456 return osc->prepared; 457 } 458 459 static const struct clk_ops sama5d4_slow_osc_ops = { 460 .prepare = clk_sama5d4_slow_osc_prepare, 461 .is_prepared = clk_sama5d4_slow_osc_is_prepared, 462 }; 463 464 static void __init of_sama5d4_sckc_setup(struct device_node *np) 465 { 466 void __iomem *regbase = of_iomap(np, 0); 467 struct clk_hw *hw; 468 struct clk_sama5d4_slow_osc *osc; 469 struct clk_init_data init; 470 const char *xtal_name; 471 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; 472 bool bypass; 473 int ret; 474 475 if (!regbase) 476 return; 477 478 hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0], 479 NULL, 0, 32768, 480 250000000); 481 if (IS_ERR(hw)) 482 return; 483 484 xtal_name = of_clk_get_parent_name(np, 0); 485 486 bypass = of_property_read_bool(np, "atmel,osc-bypass"); 487 488 osc = kzalloc(sizeof(*osc), GFP_KERNEL); 489 if (!osc) 490 return; 491 492 init.name = parent_names[1]; 493 init.ops = &sama5d4_slow_osc_ops; 494 init.parent_names = &xtal_name; 495 init.num_parents = 1; 496 init.flags = CLK_IGNORE_UNUSED; 497 498 osc->hw.init = &init; 499 osc->sckcr = regbase; 500 osc->startup_usec = 1200000; 501 502 if (bypass) 503 writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase); 504 505 hw = &osc->hw; 506 ret = clk_hw_register(NULL, &osc->hw); 507 if (ret) { 508 kfree(osc); 509 return; 510 } 511 512 hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); 513 if (IS_ERR(hw)) 514 return; 515 516 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 517 } 518 CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc", 519 of_sama5d4_sckc_setup); 520