root/drivers/clk/at91/clk-main.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clk_main_osc_ready
  2. clk_main_osc_prepare
  3. clk_main_osc_unprepare
  4. clk_main_osc_is_prepared
  5. at91_clk_register_main_osc
  6. clk_main_rc_osc_ready
  7. clk_main_rc_osc_prepare
  8. clk_main_rc_osc_unprepare
  9. clk_main_rc_osc_is_prepared
  10. clk_main_rc_osc_recalc_rate
  11. clk_main_rc_osc_recalc_accuracy
  12. at91_clk_register_main_rc_osc
  13. clk_main_probe_frequency
  14. clk_main_recalc_rate
  15. clk_rm9200_main_prepare
  16. clk_rm9200_main_is_prepared
  17. clk_rm9200_main_recalc_rate
  18. at91_clk_register_rm9200_main
  19. clk_sam9x5_main_ready
  20. clk_sam9x5_main_prepare
  21. clk_sam9x5_main_is_prepared
  22. clk_sam9x5_main_recalc_rate
  23. clk_sam9x5_main_set_parent
  24. clk_sam9x5_main_get_parent
  25. at91_clk_register_sam9x5_main

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
   4  */
   5 
   6 #include <linux/clk-provider.h>
   7 #include <linux/clkdev.h>
   8 #include <linux/clk/at91_pmc.h>
   9 #include <linux/delay.h>
  10 #include <linux/mfd/syscon.h>
  11 #include <linux/regmap.h>
  12 
  13 #include "pmc.h"
  14 
  15 #define SLOW_CLOCK_FREQ         32768
  16 #define MAINF_DIV               16
  17 #define MAINFRDY_TIMEOUT        (((MAINF_DIV + 1) * USEC_PER_SEC) / \
  18                                  SLOW_CLOCK_FREQ)
  19 #define MAINF_LOOP_MIN_WAIT     (USEC_PER_SEC / SLOW_CLOCK_FREQ)
  20 #define MAINF_LOOP_MAX_WAIT     MAINFRDY_TIMEOUT
  21 
  22 #define MOR_KEY_MASK            (0xff << 16)
  23 
  24 #define clk_main_parent_select(s)       (((s) & \
  25                                         (AT91_PMC_MOSCEN | \
  26                                         AT91_PMC_OSCBYPASS)) ? 1 : 0)
  27 
  28 struct clk_main_osc {
  29         struct clk_hw hw;
  30         struct regmap *regmap;
  31 };
  32 
  33 #define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
  34 
  35 struct clk_main_rc_osc {
  36         struct clk_hw hw;
  37         struct regmap *regmap;
  38         unsigned long frequency;
  39         unsigned long accuracy;
  40 };
  41 
  42 #define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
  43 
  44 struct clk_rm9200_main {
  45         struct clk_hw hw;
  46         struct regmap *regmap;
  47 };
  48 
  49 #define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
  50 
  51 struct clk_sam9x5_main {
  52         struct clk_hw hw;
  53         struct regmap *regmap;
  54         u8 parent;
  55 };
  56 
  57 #define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
  58 
  59 static inline bool clk_main_osc_ready(struct regmap *regmap)
  60 {
  61         unsigned int status;
  62 
  63         regmap_read(regmap, AT91_PMC_SR, &status);
  64 
  65         return status & AT91_PMC_MOSCS;
  66 }
  67 
  68 static int clk_main_osc_prepare(struct clk_hw *hw)
  69 {
  70         struct clk_main_osc *osc = to_clk_main_osc(hw);
  71         struct regmap *regmap = osc->regmap;
  72         u32 tmp;
  73 
  74         regmap_read(regmap, AT91_CKGR_MOR, &tmp);
  75         tmp &= ~MOR_KEY_MASK;
  76 
  77         if (tmp & AT91_PMC_OSCBYPASS)
  78                 return 0;
  79 
  80         if (!(tmp & AT91_PMC_MOSCEN)) {
  81                 tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
  82                 regmap_write(regmap, AT91_CKGR_MOR, tmp);
  83         }
  84 
  85         while (!clk_main_osc_ready(regmap))
  86                 cpu_relax();
  87 
  88         return 0;
  89 }
  90 
  91 static void clk_main_osc_unprepare(struct clk_hw *hw)
  92 {
  93         struct clk_main_osc *osc = to_clk_main_osc(hw);
  94         struct regmap *regmap = osc->regmap;
  95         u32 tmp;
  96 
  97         regmap_read(regmap, AT91_CKGR_MOR, &tmp);
  98         if (tmp & AT91_PMC_OSCBYPASS)
  99                 return;
 100 
 101         if (!(tmp & AT91_PMC_MOSCEN))
 102                 return;
 103 
 104         tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
 105         regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
 106 }
 107 
 108 static int clk_main_osc_is_prepared(struct clk_hw *hw)
 109 {
 110         struct clk_main_osc *osc = to_clk_main_osc(hw);
 111         struct regmap *regmap = osc->regmap;
 112         u32 tmp, status;
 113 
 114         regmap_read(regmap, AT91_CKGR_MOR, &tmp);
 115         if (tmp & AT91_PMC_OSCBYPASS)
 116                 return 1;
 117 
 118         regmap_read(regmap, AT91_PMC_SR, &status);
 119 
 120         return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
 121 }
 122 
 123 static const struct clk_ops main_osc_ops = {
 124         .prepare = clk_main_osc_prepare,
 125         .unprepare = clk_main_osc_unprepare,
 126         .is_prepared = clk_main_osc_is_prepared,
 127 };
 128 
 129 struct clk_hw * __init
 130 at91_clk_register_main_osc(struct regmap *regmap,
 131                            const char *name,
 132                            const char *parent_name,
 133                            bool bypass)
 134 {
 135         struct clk_main_osc *osc;
 136         struct clk_init_data init;
 137         struct clk_hw *hw;
 138         int ret;
 139 
 140         if (!name || !parent_name)
 141                 return ERR_PTR(-EINVAL);
 142 
 143         osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 144         if (!osc)
 145                 return ERR_PTR(-ENOMEM);
 146 
 147         init.name = name;
 148         init.ops = &main_osc_ops;
 149         init.parent_names = &parent_name;
 150         init.num_parents = 1;
 151         init.flags = CLK_IGNORE_UNUSED;
 152 
 153         osc->hw.init = &init;
 154         osc->regmap = regmap;
 155 
 156         if (bypass)
 157                 regmap_update_bits(regmap,
 158                                    AT91_CKGR_MOR, MOR_KEY_MASK |
 159                                    AT91_PMC_OSCBYPASS,
 160                                    AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
 161 
 162         hw = &osc->hw;
 163         ret = clk_hw_register(NULL, &osc->hw);
 164         if (ret) {
 165                 kfree(osc);
 166                 hw = ERR_PTR(ret);
 167         }
 168 
 169         return hw;
 170 }
 171 
 172 static bool clk_main_rc_osc_ready(struct regmap *regmap)
 173 {
 174         unsigned int status;
 175 
 176         regmap_read(regmap, AT91_PMC_SR, &status);
 177 
 178         return status & AT91_PMC_MOSCRCS;
 179 }
 180 
 181 static int clk_main_rc_osc_prepare(struct clk_hw *hw)
 182 {
 183         struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
 184         struct regmap *regmap = osc->regmap;
 185         unsigned int mor;
 186 
 187         regmap_read(regmap, AT91_CKGR_MOR, &mor);
 188 
 189         if (!(mor & AT91_PMC_MOSCRCEN))
 190                 regmap_update_bits(regmap, AT91_CKGR_MOR,
 191                                    MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
 192                                    AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
 193 
 194         while (!clk_main_rc_osc_ready(regmap))
 195                 cpu_relax();
 196 
 197         return 0;
 198 }
 199 
 200 static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
 201 {
 202         struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
 203         struct regmap *regmap = osc->regmap;
 204         unsigned int mor;
 205 
 206         regmap_read(regmap, AT91_CKGR_MOR, &mor);
 207 
 208         if (!(mor & AT91_PMC_MOSCRCEN))
 209                 return;
 210 
 211         regmap_update_bits(regmap, AT91_CKGR_MOR,
 212                            MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
 213 }
 214 
 215 static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
 216 {
 217         struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
 218         struct regmap *regmap = osc->regmap;
 219         unsigned int mor, status;
 220 
 221         regmap_read(regmap, AT91_CKGR_MOR, &mor);
 222         regmap_read(regmap, AT91_PMC_SR, &status);
 223 
 224         return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
 225 }
 226 
 227 static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
 228                                                  unsigned long parent_rate)
 229 {
 230         struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
 231 
 232         return osc->frequency;
 233 }
 234 
 235 static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
 236                                                      unsigned long parent_acc)
 237 {
 238         struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
 239 
 240         return osc->accuracy;
 241 }
 242 
 243 static const struct clk_ops main_rc_osc_ops = {
 244         .prepare = clk_main_rc_osc_prepare,
 245         .unprepare = clk_main_rc_osc_unprepare,
 246         .is_prepared = clk_main_rc_osc_is_prepared,
 247         .recalc_rate = clk_main_rc_osc_recalc_rate,
 248         .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
 249 };
 250 
 251 struct clk_hw * __init
 252 at91_clk_register_main_rc_osc(struct regmap *regmap,
 253                               const char *name,
 254                               u32 frequency, u32 accuracy)
 255 {
 256         struct clk_main_rc_osc *osc;
 257         struct clk_init_data init;
 258         struct clk_hw *hw;
 259         int ret;
 260 
 261         if (!name || !frequency)
 262                 return ERR_PTR(-EINVAL);
 263 
 264         osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 265         if (!osc)
 266                 return ERR_PTR(-ENOMEM);
 267 
 268         init.name = name;
 269         init.ops = &main_rc_osc_ops;
 270         init.parent_names = NULL;
 271         init.num_parents = 0;
 272         init.flags = CLK_IGNORE_UNUSED;
 273 
 274         osc->hw.init = &init;
 275         osc->regmap = regmap;
 276         osc->frequency = frequency;
 277         osc->accuracy = accuracy;
 278 
 279         hw = &osc->hw;
 280         ret = clk_hw_register(NULL, hw);
 281         if (ret) {
 282                 kfree(osc);
 283                 hw = ERR_PTR(ret);
 284         }
 285 
 286         return hw;
 287 }
 288 
 289 static int clk_main_probe_frequency(struct regmap *regmap)
 290 {
 291         unsigned long prep_time, timeout;
 292         unsigned int mcfr;
 293 
 294         timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
 295         do {
 296                 prep_time = jiffies;
 297                 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
 298                 if (mcfr & AT91_PMC_MAINRDY)
 299                         return 0;
 300                 if (system_state < SYSTEM_RUNNING)
 301                         udelay(MAINF_LOOP_MIN_WAIT);
 302                 else
 303                         usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
 304         } while (time_before(prep_time, timeout));
 305 
 306         return -ETIMEDOUT;
 307 }
 308 
 309 static unsigned long clk_main_recalc_rate(struct regmap *regmap,
 310                                           unsigned long parent_rate)
 311 {
 312         unsigned int mcfr;
 313 
 314         if (parent_rate)
 315                 return parent_rate;
 316 
 317         pr_warn("Main crystal frequency not set, using approximate value\n");
 318         regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
 319         if (!(mcfr & AT91_PMC_MAINRDY))
 320                 return 0;
 321 
 322         return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
 323 }
 324 
 325 static int clk_rm9200_main_prepare(struct clk_hw *hw)
 326 {
 327         struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
 328 
 329         return clk_main_probe_frequency(clkmain->regmap);
 330 }
 331 
 332 static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
 333 {
 334         struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
 335         unsigned int status;
 336 
 337         regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
 338 
 339         return status & AT91_PMC_MAINRDY ? 1 : 0;
 340 }
 341 
 342 static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
 343                                                  unsigned long parent_rate)
 344 {
 345         struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
 346 
 347         return clk_main_recalc_rate(clkmain->regmap, parent_rate);
 348 }
 349 
 350 static const struct clk_ops rm9200_main_ops = {
 351         .prepare = clk_rm9200_main_prepare,
 352         .is_prepared = clk_rm9200_main_is_prepared,
 353         .recalc_rate = clk_rm9200_main_recalc_rate,
 354 };
 355 
 356 struct clk_hw * __init
 357 at91_clk_register_rm9200_main(struct regmap *regmap,
 358                               const char *name,
 359                               const char *parent_name)
 360 {
 361         struct clk_rm9200_main *clkmain;
 362         struct clk_init_data init;
 363         struct clk_hw *hw;
 364         int ret;
 365 
 366         if (!name)
 367                 return ERR_PTR(-EINVAL);
 368 
 369         if (!parent_name)
 370                 return ERR_PTR(-EINVAL);
 371 
 372         clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
 373         if (!clkmain)
 374                 return ERR_PTR(-ENOMEM);
 375 
 376         init.name = name;
 377         init.ops = &rm9200_main_ops;
 378         init.parent_names = &parent_name;
 379         init.num_parents = 1;
 380         init.flags = 0;
 381 
 382         clkmain->hw.init = &init;
 383         clkmain->regmap = regmap;
 384 
 385         hw = &clkmain->hw;
 386         ret = clk_hw_register(NULL, &clkmain->hw);
 387         if (ret) {
 388                 kfree(clkmain);
 389                 hw = ERR_PTR(ret);
 390         }
 391 
 392         return hw;
 393 }
 394 
 395 static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
 396 {
 397         unsigned int status;
 398 
 399         regmap_read(regmap, AT91_PMC_SR, &status);
 400 
 401         return status & AT91_PMC_MOSCSELS ? 1 : 0;
 402 }
 403 
 404 static int clk_sam9x5_main_prepare(struct clk_hw *hw)
 405 {
 406         struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
 407         struct regmap *regmap = clkmain->regmap;
 408 
 409         while (!clk_sam9x5_main_ready(regmap))
 410                 cpu_relax();
 411 
 412         return clk_main_probe_frequency(regmap);
 413 }
 414 
 415 static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
 416 {
 417         struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
 418 
 419         return clk_sam9x5_main_ready(clkmain->regmap);
 420 }
 421 
 422 static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
 423                                                  unsigned long parent_rate)
 424 {
 425         struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
 426 
 427         return clk_main_recalc_rate(clkmain->regmap, parent_rate);
 428 }
 429 
 430 static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
 431 {
 432         struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
 433         struct regmap *regmap = clkmain->regmap;
 434         unsigned int tmp;
 435 
 436         if (index > 1)
 437                 return -EINVAL;
 438 
 439         regmap_read(regmap, AT91_CKGR_MOR, &tmp);
 440         tmp &= ~MOR_KEY_MASK;
 441 
 442         if (index && !(tmp & AT91_PMC_MOSCSEL))
 443                 regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
 444         else if (!index && (tmp & AT91_PMC_MOSCSEL))
 445                 regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
 446 
 447         while (!clk_sam9x5_main_ready(regmap))
 448                 cpu_relax();
 449 
 450         return 0;
 451 }
 452 
 453 static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
 454 {
 455         struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
 456         unsigned int status;
 457 
 458         regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
 459 
 460         return clk_main_parent_select(status);
 461 }
 462 
 463 static const struct clk_ops sam9x5_main_ops = {
 464         .prepare = clk_sam9x5_main_prepare,
 465         .is_prepared = clk_sam9x5_main_is_prepared,
 466         .recalc_rate = clk_sam9x5_main_recalc_rate,
 467         .set_parent = clk_sam9x5_main_set_parent,
 468         .get_parent = clk_sam9x5_main_get_parent,
 469 };
 470 
 471 struct clk_hw * __init
 472 at91_clk_register_sam9x5_main(struct regmap *regmap,
 473                               const char *name,
 474                               const char **parent_names,
 475                               int num_parents)
 476 {
 477         struct clk_sam9x5_main *clkmain;
 478         struct clk_init_data init;
 479         unsigned int status;
 480         struct clk_hw *hw;
 481         int ret;
 482 
 483         if (!name)
 484                 return ERR_PTR(-EINVAL);
 485 
 486         if (!parent_names || !num_parents)
 487                 return ERR_PTR(-EINVAL);
 488 
 489         clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
 490         if (!clkmain)
 491                 return ERR_PTR(-ENOMEM);
 492 
 493         init.name = name;
 494         init.ops = &sam9x5_main_ops;
 495         init.parent_names = parent_names;
 496         init.num_parents = num_parents;
 497         init.flags = CLK_SET_PARENT_GATE;
 498 
 499         clkmain->hw.init = &init;
 500         clkmain->regmap = regmap;
 501         regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
 502         clkmain->parent = clk_main_parent_select(status);
 503 
 504         hw = &clkmain->hw;
 505         ret = clk_hw_register(NULL, &clkmain->hw);
 506         if (ret) {
 507                 kfree(clkmain);
 508                 hw = ERR_PTR(ret);
 509         }
 510 
 511         return hw;
 512 }

/* [<][>][^][v][top][bottom][index][help] */