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