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