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