linux/drivers/clk/at91/sckc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * drivers/clk/at91/sckc.c
   4 *
   5 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
   6 */
   7
   8#include <linux/clk-provider.h>
   9#include <linux/clkdev.h>
  10#include <linux/delay.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <linux/io.h>
  14
  15#define SLOW_CLOCK_FREQ         32768
  16#define SLOWCK_SW_CYCLES        5
  17#define SLOWCK_SW_TIME_USEC     ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
  18                                 SLOW_CLOCK_FREQ)
  19
  20#define AT91_SCKC_CR                    0x00
  21
  22struct clk_slow_bits {
  23        u32 cr_rcen;
  24        u32 cr_osc32en;
  25        u32 cr_osc32byp;
  26        u32 cr_oscsel;
  27};
  28
  29struct clk_slow_osc {
  30        struct clk_hw hw;
  31        void __iomem *sckcr;
  32        const struct clk_slow_bits *bits;
  33        unsigned long startup_usec;
  34};
  35
  36#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
  37
  38struct clk_sama5d4_slow_osc {
  39        struct clk_hw hw;
  40        void __iomem *sckcr;
  41        const struct clk_slow_bits *bits;
  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
  48struct clk_slow_rc_osc {
  49        struct clk_hw hw;
  50        void __iomem *sckcr;
  51        const struct clk_slow_bits *bits;
  52        unsigned long frequency;
  53        unsigned long accuracy;
  54        unsigned long startup_usec;
  55};
  56
  57#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
  58
  59struct clk_sam9x5_slow {
  60        struct clk_hw hw;
  61        void __iomem *sckcr;
  62        const struct clk_slow_bits *bits;
  63        u8 parent;
  64};
  65
  66#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
  67
  68static int clk_slow_osc_prepare(struct clk_hw *hw)
  69{
  70        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  71        void __iomem *sckcr = osc->sckcr;
  72        u32 tmp = readl(sckcr);
  73
  74        if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
  75                return 0;
  76
  77        writel(tmp | osc->bits->cr_osc32en, sckcr);
  78
  79        if (system_state < SYSTEM_RUNNING)
  80                udelay(osc->startup_usec);
  81        else
  82                usleep_range(osc->startup_usec, osc->startup_usec + 1);
  83
  84        return 0;
  85}
  86
  87static void clk_slow_osc_unprepare(struct clk_hw *hw)
  88{
  89        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  90        void __iomem *sckcr = osc->sckcr;
  91        u32 tmp = readl(sckcr);
  92
  93        if (tmp & osc->bits->cr_osc32byp)
  94                return;
  95
  96        writel(tmp & ~osc->bits->cr_osc32en, sckcr);
  97}
  98
  99static int clk_slow_osc_is_prepared(struct clk_hw *hw)
 100{
 101        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
 102        void __iomem *sckcr = osc->sckcr;
 103        u32 tmp = readl(sckcr);
 104
 105        if (tmp & osc->bits->cr_osc32byp)
 106                return 1;
 107
 108        return !!(tmp & osc->bits->cr_osc32en);
 109}
 110
 111static const struct clk_ops slow_osc_ops = {
 112        .prepare = clk_slow_osc_prepare,
 113        .unprepare = clk_slow_osc_unprepare,
 114        .is_prepared = clk_slow_osc_is_prepared,
 115};
 116
 117static struct clk_hw * __init
 118at91_clk_register_slow_osc(void __iomem *sckcr,
 119                           const char *name,
 120                           const char *parent_name,
 121                           unsigned long startup,
 122                           bool bypass,
 123                           const struct clk_slow_bits *bits)
 124{
 125        struct clk_slow_osc *osc;
 126        struct clk_hw *hw;
 127        struct clk_init_data init;
 128        int ret;
 129
 130        if (!sckcr || !name || !parent_name)
 131                return ERR_PTR(-EINVAL);
 132
 133        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 134        if (!osc)
 135                return ERR_PTR(-ENOMEM);
 136
 137        init.name = name;
 138        init.ops = &slow_osc_ops;
 139        init.parent_names = &parent_name;
 140        init.num_parents = 1;
 141        init.flags = CLK_IGNORE_UNUSED;
 142
 143        osc->hw.init = &init;
 144        osc->sckcr = sckcr;
 145        osc->startup_usec = startup;
 146        osc->bits = bits;
 147
 148        if (bypass)
 149                writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
 150                                        osc->bits->cr_osc32byp, sckcr);
 151
 152        hw = &osc->hw;
 153        ret = clk_hw_register(NULL, &osc->hw);
 154        if (ret) {
 155                kfree(osc);
 156                hw = ERR_PTR(ret);
 157        }
 158
 159        return hw;
 160}
 161
 162static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
 163{
 164        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
 165
 166        clk_hw_unregister(hw);
 167        kfree(osc);
 168}
 169
 170static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
 171                                                 unsigned long parent_rate)
 172{
 173        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 174
 175        return osc->frequency;
 176}
 177
 178static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
 179                                                     unsigned long parent_acc)
 180{
 181        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 182
 183        return osc->accuracy;
 184}
 185
 186static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
 187{
 188        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 189        void __iomem *sckcr = osc->sckcr;
 190
 191        writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
 192
 193        if (system_state < SYSTEM_RUNNING)
 194                udelay(osc->startup_usec);
 195        else
 196                usleep_range(osc->startup_usec, osc->startup_usec + 1);
 197
 198        return 0;
 199}
 200
 201static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
 202{
 203        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 204        void __iomem *sckcr = osc->sckcr;
 205
 206        writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
 207}
 208
 209static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
 210{
 211        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 212
 213        return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
 214}
 215
 216static const struct clk_ops slow_rc_osc_ops = {
 217        .prepare = clk_slow_rc_osc_prepare,
 218        .unprepare = clk_slow_rc_osc_unprepare,
 219        .is_prepared = clk_slow_rc_osc_is_prepared,
 220        .recalc_rate = clk_slow_rc_osc_recalc_rate,
 221        .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
 222};
 223
 224static struct clk_hw * __init
 225at91_clk_register_slow_rc_osc(void __iomem *sckcr,
 226                              const char *name,
 227                              unsigned long frequency,
 228                              unsigned long accuracy,
 229                              unsigned long startup,
 230                              const struct clk_slow_bits *bits)
 231{
 232        struct clk_slow_rc_osc *osc;
 233        struct clk_hw *hw;
 234        struct clk_init_data init;
 235        int ret;
 236
 237        if (!sckcr || !name)
 238                return ERR_PTR(-EINVAL);
 239
 240        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 241        if (!osc)
 242                return ERR_PTR(-ENOMEM);
 243
 244        init.name = name;
 245        init.ops = &slow_rc_osc_ops;
 246        init.parent_names = NULL;
 247        init.num_parents = 0;
 248        init.flags = CLK_IGNORE_UNUSED;
 249
 250        osc->hw.init = &init;
 251        osc->sckcr = sckcr;
 252        osc->bits = bits;
 253        osc->frequency = frequency;
 254        osc->accuracy = accuracy;
 255        osc->startup_usec = startup;
 256
 257        hw = &osc->hw;
 258        ret = clk_hw_register(NULL, &osc->hw);
 259        if (ret) {
 260                kfree(osc);
 261                hw = ERR_PTR(ret);
 262        }
 263
 264        return hw;
 265}
 266
 267static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
 268{
 269        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 270
 271        clk_hw_unregister(hw);
 272        kfree(osc);
 273}
 274
 275static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 276{
 277        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 278        void __iomem *sckcr = slowck->sckcr;
 279        u32 tmp;
 280
 281        if (index > 1)
 282                return -EINVAL;
 283
 284        tmp = readl(sckcr);
 285
 286        if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
 287            (index && (tmp & slowck->bits->cr_oscsel)))
 288                return 0;
 289
 290        if (index)
 291                tmp |= slowck->bits->cr_oscsel;
 292        else
 293                tmp &= ~slowck->bits->cr_oscsel;
 294
 295        writel(tmp, sckcr);
 296
 297        if (system_state < SYSTEM_RUNNING)
 298                udelay(SLOWCK_SW_TIME_USEC);
 299        else
 300                usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
 301
 302        return 0;
 303}
 304
 305static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
 306{
 307        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 308
 309        return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
 310}
 311
 312static const struct clk_ops sam9x5_slow_ops = {
 313        .set_parent = clk_sam9x5_slow_set_parent,
 314        .get_parent = clk_sam9x5_slow_get_parent,
 315};
 316
 317static struct clk_hw * __init
 318at91_clk_register_sam9x5_slow(void __iomem *sckcr,
 319                              const char *name,
 320                              const char **parent_names,
 321                              int num_parents,
 322                              const struct clk_slow_bits *bits)
 323{
 324        struct clk_sam9x5_slow *slowck;
 325        struct clk_hw *hw;
 326        struct clk_init_data init;
 327        int ret;
 328
 329        if (!sckcr || !name || !parent_names || !num_parents)
 330                return ERR_PTR(-EINVAL);
 331
 332        slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
 333        if (!slowck)
 334                return ERR_PTR(-ENOMEM);
 335
 336        init.name = name;
 337        init.ops = &sam9x5_slow_ops;
 338        init.parent_names = parent_names;
 339        init.num_parents = num_parents;
 340        init.flags = 0;
 341
 342        slowck->hw.init = &init;
 343        slowck->sckcr = sckcr;
 344        slowck->bits = bits;
 345        slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
 346
 347        hw = &slowck->hw;
 348        ret = clk_hw_register(NULL, &slowck->hw);
 349        if (ret) {
 350                kfree(slowck);
 351                hw = ERR_PTR(ret);
 352        }
 353
 354        return hw;
 355}
 356
 357static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
 358{
 359        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 360
 361        clk_hw_unregister(hw);
 362        kfree(slowck);
 363}
 364
 365static void __init at91sam9x5_sckc_register(struct device_node *np,
 366                                            unsigned int rc_osc_startup_us,
 367                                            const struct clk_slow_bits *bits)
 368{
 369        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
 370        void __iomem *regbase = of_iomap(np, 0);
 371        struct device_node *child = NULL;
 372        const char *xtal_name;
 373        struct clk_hw *slow_rc, *slow_osc, *slowck;
 374        bool bypass;
 375        int ret;
 376
 377        if (!regbase)
 378                return;
 379
 380        slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
 381                                                32768, 50000000,
 382                                                rc_osc_startup_us, bits);
 383        if (IS_ERR(slow_rc))
 384                return;
 385
 386        xtal_name = of_clk_get_parent_name(np, 0);
 387        if (!xtal_name) {
 388                /* DT backward compatibility */
 389                child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
 390                if (!child)
 391                        goto unregister_slow_rc;
 392
 393                xtal_name = of_clk_get_parent_name(child, 0);
 394                bypass = of_property_read_bool(child, "atmel,osc-bypass");
 395
 396                child =  of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
 397        } else {
 398                bypass = of_property_read_bool(np, "atmel,osc-bypass");
 399        }
 400
 401        if (!xtal_name)
 402                goto unregister_slow_rc;
 403
 404        slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
 405                                              xtal_name, 1200000, bypass, bits);
 406        if (IS_ERR(slow_osc))
 407                goto unregister_slow_rc;
 408
 409        slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
 410                                               2, bits);
 411        if (IS_ERR(slowck))
 412                goto unregister_slow_osc;
 413
 414        /* DT backward compatibility */
 415        if (child)
 416                ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
 417                                             slowck);
 418        else
 419                ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
 420
 421        if (WARN_ON(ret))
 422                goto unregister_slowck;
 423
 424        return;
 425
 426unregister_slowck:
 427        at91_clk_unregister_sam9x5_slow(slowck);
 428unregister_slow_osc:
 429        at91_clk_unregister_slow_osc(slow_osc);
 430unregister_slow_rc:
 431        at91_clk_unregister_slow_rc_osc(slow_rc);
 432}
 433
 434static const struct clk_slow_bits at91sam9x5_bits = {
 435        .cr_rcen = BIT(0),
 436        .cr_osc32en = BIT(1),
 437        .cr_osc32byp = BIT(2),
 438        .cr_oscsel = BIT(3),
 439};
 440
 441static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
 442{
 443        at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
 444}
 445CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
 446               of_at91sam9x5_sckc_setup);
 447
 448static void __init of_sama5d3_sckc_setup(struct device_node *np)
 449{
 450        at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
 451}
 452CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
 453               of_sama5d3_sckc_setup);
 454
 455static const struct clk_slow_bits at91sam9x60_bits = {
 456        .cr_osc32en = BIT(1),
 457        .cr_osc32byp = BIT(2),
 458        .cr_oscsel = BIT(24),
 459};
 460
 461static void __init of_sam9x60_sckc_setup(struct device_node *np)
 462{
 463        void __iomem *regbase = of_iomap(np, 0);
 464        struct clk_hw_onecell_data *clk_data;
 465        struct clk_hw *slow_rc, *slow_osc;
 466        const char *xtal_name;
 467        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
 468        bool bypass;
 469        int ret;
 470
 471        if (!regbase)
 472                return;
 473
 474        slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
 475                                                           NULL, 0, 32768,
 476                                                           93750000);
 477        if (IS_ERR(slow_rc))
 478                return;
 479
 480        xtal_name = of_clk_get_parent_name(np, 0);
 481        if (!xtal_name)
 482                goto unregister_slow_rc;
 483
 484        bypass = of_property_read_bool(np, "atmel,osc-bypass");
 485        slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
 486                                              xtal_name, 5000000, bypass,
 487                                              &at91sam9x60_bits);
 488        if (IS_ERR(slow_osc))
 489                goto unregister_slow_rc;
 490
 491        clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL);
 492        if (!clk_data)
 493                goto unregister_slow_osc;
 494
 495        /* MD_SLCK and TD_SLCK. */
 496        clk_data->num = 2;
 497        clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
 498                                                      parent_names[0],
 499                                                      0, 32768);
 500        if (IS_ERR(clk_data->hws[0]))
 501                goto clk_data_free;
 502
 503        clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
 504                                                         parent_names, 2,
 505                                                         &at91sam9x60_bits);
 506        if (IS_ERR(clk_data->hws[1]))
 507                goto unregister_md_slck;
 508
 509        ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 510        if (WARN_ON(ret))
 511                goto unregister_td_slck;
 512
 513        return;
 514
 515unregister_td_slck:
 516        at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
 517unregister_md_slck:
 518        clk_hw_unregister(clk_data->hws[0]);
 519clk_data_free:
 520        kfree(clk_data);
 521unregister_slow_osc:
 522        at91_clk_unregister_slow_osc(slow_osc);
 523unregister_slow_rc:
 524        clk_hw_unregister(slow_rc);
 525}
 526CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
 527               of_sam9x60_sckc_setup);
 528
 529static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
 530{
 531        struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
 532
 533        if (osc->prepared)
 534                return 0;
 535
 536        /*
 537         * Assume that if it has already been selected (for example by the
 538         * bootloader), enough time has aready passed.
 539         */
 540        if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
 541                osc->prepared = true;
 542                return 0;
 543        }
 544
 545        if (system_state < SYSTEM_RUNNING)
 546                udelay(osc->startup_usec);
 547        else
 548                usleep_range(osc->startup_usec, osc->startup_usec + 1);
 549        osc->prepared = true;
 550
 551        return 0;
 552}
 553
 554static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
 555{
 556        struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
 557
 558        return osc->prepared;
 559}
 560
 561static const struct clk_ops sama5d4_slow_osc_ops = {
 562        .prepare = clk_sama5d4_slow_osc_prepare,
 563        .is_prepared = clk_sama5d4_slow_osc_is_prepared,
 564};
 565
 566static const struct clk_slow_bits at91sama5d4_bits = {
 567        .cr_oscsel = BIT(3),
 568};
 569
 570static void __init of_sama5d4_sckc_setup(struct device_node *np)
 571{
 572        void __iomem *regbase = of_iomap(np, 0);
 573        struct clk_hw *slow_rc, *slowck;
 574        struct clk_sama5d4_slow_osc *osc;
 575        struct clk_init_data init;
 576        const char *xtal_name;
 577        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
 578        int ret;
 579
 580        if (!regbase)
 581                return;
 582
 583        slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
 584                                                           parent_names[0],
 585                                                           NULL, 0, 32768,
 586                                                           250000000);
 587        if (IS_ERR(slow_rc))
 588                return;
 589
 590        xtal_name = of_clk_get_parent_name(np, 0);
 591
 592        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 593        if (!osc)
 594                goto unregister_slow_rc;
 595
 596        init.name = parent_names[1];
 597        init.ops = &sama5d4_slow_osc_ops;
 598        init.parent_names = &xtal_name;
 599        init.num_parents = 1;
 600        init.flags = CLK_IGNORE_UNUSED;
 601
 602        osc->hw.init = &init;
 603        osc->sckcr = regbase;
 604        osc->startup_usec = 1200000;
 605        osc->bits = &at91sama5d4_bits;
 606
 607        ret = clk_hw_register(NULL, &osc->hw);
 608        if (ret)
 609                goto free_slow_osc_data;
 610
 611        slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
 612                                               parent_names, 2,
 613                                               &at91sama5d4_bits);
 614        if (IS_ERR(slowck))
 615                goto unregister_slow_osc;
 616
 617        ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
 618        if (WARN_ON(ret))
 619                goto unregister_slowck;
 620
 621        return;
 622
 623unregister_slowck:
 624        at91_clk_unregister_sam9x5_slow(slowck);
 625unregister_slow_osc:
 626        clk_hw_unregister(&osc->hw);
 627free_slow_osc_data:
 628        kfree(osc);
 629unregister_slow_rc:
 630        clk_hw_unregister(slow_rc);
 631}
 632CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
 633               of_sama5d4_sckc_setup);
 634