linux/drivers/clk/at91/clk-slow.c
<<
>>
Prefs
   1/*
   2 * drivers/clk/at91/clk-slow.c
   3 *
   4 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 */
  12
  13#include <linux/clk-provider.h>
  14#include <linux/clkdev.h>
  15#include <linux/clk/at91_pmc.h>
  16#include <linux/delay.h>
  17#include <linux/of.h>
  18#include <linux/of_address.h>
  19#include <linux/of_irq.h>
  20#include <linux/io.h>
  21#include <linux/interrupt.h>
  22#include <linux/irq.h>
  23#include <linux/sched.h>
  24#include <linux/wait.h>
  25
  26#include "pmc.h"
  27#include "sckc.h"
  28
  29#define SLOW_CLOCK_FREQ         32768
  30#define SLOWCK_SW_CYCLES        5
  31#define SLOWCK_SW_TIME_USEC     ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
  32                                 SLOW_CLOCK_FREQ)
  33
  34#define AT91_SCKC_CR                    0x00
  35#define         AT91_SCKC_RCEN          (1 << 0)
  36#define         AT91_SCKC_OSC32EN       (1 << 1)
  37#define         AT91_SCKC_OSC32BYP      (1 << 2)
  38#define         AT91_SCKC_OSCSEL        (1 << 3)
  39
  40struct clk_slow_osc {
  41        struct clk_hw hw;
  42        void __iomem *sckcr;
  43        unsigned long startup_usec;
  44};
  45
  46#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
  47
  48struct clk_slow_rc_osc {
  49        struct clk_hw hw;
  50        void __iomem *sckcr;
  51        unsigned long frequency;
  52        unsigned long accuracy;
  53        unsigned long startup_usec;
  54};
  55
  56#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
  57
  58struct clk_sam9260_slow {
  59        struct clk_hw hw;
  60        struct at91_pmc *pmc;
  61};
  62
  63#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
  64
  65struct clk_sam9x5_slow {
  66        struct clk_hw hw;
  67        void __iomem *sckcr;
  68        u8 parent;
  69};
  70
  71#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
  72
  73static struct clk *slow_clk;
  74
  75static int clk_slow_osc_prepare(struct clk_hw *hw)
  76{
  77        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  78        void __iomem *sckcr = osc->sckcr;
  79        u32 tmp = readl(sckcr);
  80
  81        if (tmp & AT91_SCKC_OSC32BYP)
  82                return 0;
  83
  84        writel(tmp | AT91_SCKC_OSC32EN, sckcr);
  85
  86        usleep_range(osc->startup_usec, osc->startup_usec + 1);
  87
  88        return 0;
  89}
  90
  91static void clk_slow_osc_unprepare(struct clk_hw *hw)
  92{
  93        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  94        void __iomem *sckcr = osc->sckcr;
  95        u32 tmp = readl(sckcr);
  96
  97        if (tmp & AT91_SCKC_OSC32BYP)
  98                return;
  99
 100        writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
 101}
 102
 103static int clk_slow_osc_is_prepared(struct clk_hw *hw)
 104{
 105        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
 106        void __iomem *sckcr = osc->sckcr;
 107        u32 tmp = readl(sckcr);
 108
 109        if (tmp & AT91_SCKC_OSC32BYP)
 110                return 1;
 111
 112        return !!(tmp & AT91_SCKC_OSC32EN);
 113}
 114
 115static const struct clk_ops slow_osc_ops = {
 116        .prepare = clk_slow_osc_prepare,
 117        .unprepare = clk_slow_osc_unprepare,
 118        .is_prepared = clk_slow_osc_is_prepared,
 119};
 120
 121static struct clk * __init
 122at91_clk_register_slow_osc(void __iomem *sckcr,
 123                           const char *name,
 124                           const char *parent_name,
 125                           unsigned long startup,
 126                           bool bypass)
 127{
 128        struct clk_slow_osc *osc;
 129        struct clk *clk = NULL;
 130        struct clk_init_data init;
 131
 132        if (!sckcr || !name || !parent_name)
 133                return ERR_PTR(-EINVAL);
 134
 135        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 136        if (!osc)
 137                return ERR_PTR(-ENOMEM);
 138
 139        init.name = name;
 140        init.ops = &slow_osc_ops;
 141        init.parent_names = &parent_name;
 142        init.num_parents = 1;
 143        init.flags = CLK_IGNORE_UNUSED;
 144
 145        osc->hw.init = &init;
 146        osc->sckcr = sckcr;
 147        osc->startup_usec = startup;
 148
 149        if (bypass)
 150                writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
 151                       sckcr);
 152
 153        clk = clk_register(NULL, &osc->hw);
 154        if (IS_ERR(clk))
 155                kfree(osc);
 156
 157        return clk;
 158}
 159
 160void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
 161                                             void __iomem *sckcr)
 162{
 163        struct clk *clk;
 164        const char *parent_name;
 165        const char *name = np->name;
 166        u32 startup;
 167        bool bypass;
 168
 169        parent_name = of_clk_get_parent_name(np, 0);
 170        of_property_read_string(np, "clock-output-names", &name);
 171        of_property_read_u32(np, "atmel,startup-time-usec", &startup);
 172        bypass = of_property_read_bool(np, "atmel,osc-bypass");
 173
 174        clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
 175                                         bypass);
 176        if (IS_ERR(clk))
 177                return;
 178
 179        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 180}
 181
 182static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
 183                                                 unsigned long parent_rate)
 184{
 185        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 186
 187        return osc->frequency;
 188}
 189
 190static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
 191                                                     unsigned long parent_acc)
 192{
 193        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 194
 195        return osc->accuracy;
 196}
 197
 198static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
 199{
 200        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 201        void __iomem *sckcr = osc->sckcr;
 202
 203        writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
 204
 205        usleep_range(osc->startup_usec, osc->startup_usec + 1);
 206
 207        return 0;
 208}
 209
 210static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
 211{
 212        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 213        void __iomem *sckcr = osc->sckcr;
 214
 215        writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
 216}
 217
 218static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
 219{
 220        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 221
 222        return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
 223}
 224
 225static const struct clk_ops slow_rc_osc_ops = {
 226        .prepare = clk_slow_rc_osc_prepare,
 227        .unprepare = clk_slow_rc_osc_unprepare,
 228        .is_prepared = clk_slow_rc_osc_is_prepared,
 229        .recalc_rate = clk_slow_rc_osc_recalc_rate,
 230        .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
 231};
 232
 233static struct clk * __init
 234at91_clk_register_slow_rc_osc(void __iomem *sckcr,
 235                              const char *name,
 236                              unsigned long frequency,
 237                              unsigned long accuracy,
 238                              unsigned long startup)
 239{
 240        struct clk_slow_rc_osc *osc;
 241        struct clk *clk = NULL;
 242        struct clk_init_data init;
 243
 244        if (!sckcr || !name)
 245                return ERR_PTR(-EINVAL);
 246
 247        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 248        if (!osc)
 249                return ERR_PTR(-ENOMEM);
 250
 251        init.name = name;
 252        init.ops = &slow_rc_osc_ops;
 253        init.parent_names = NULL;
 254        init.num_parents = 0;
 255        init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
 256
 257        osc->hw.init = &init;
 258        osc->sckcr = sckcr;
 259        osc->frequency = frequency;
 260        osc->accuracy = accuracy;
 261        osc->startup_usec = startup;
 262
 263        clk = clk_register(NULL, &osc->hw);
 264        if (IS_ERR(clk))
 265                kfree(osc);
 266
 267        return clk;
 268}
 269
 270void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
 271                                                void __iomem *sckcr)
 272{
 273        struct clk *clk;
 274        u32 frequency = 0;
 275        u32 accuracy = 0;
 276        u32 startup = 0;
 277        const char *name = np->name;
 278
 279        of_property_read_string(np, "clock-output-names", &name);
 280        of_property_read_u32(np, "clock-frequency", &frequency);
 281        of_property_read_u32(np, "clock-accuracy", &accuracy);
 282        of_property_read_u32(np, "atmel,startup-time-usec", &startup);
 283
 284        clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
 285                                            startup);
 286        if (IS_ERR(clk))
 287                return;
 288
 289        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 290}
 291
 292static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 293{
 294        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 295        void __iomem *sckcr = slowck->sckcr;
 296        u32 tmp;
 297
 298        if (index > 1)
 299                return -EINVAL;
 300
 301        tmp = readl(sckcr);
 302
 303        if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
 304            (index && (tmp & AT91_SCKC_OSCSEL)))
 305                return 0;
 306
 307        if (index)
 308                tmp |= AT91_SCKC_OSCSEL;
 309        else
 310                tmp &= ~AT91_SCKC_OSCSEL;
 311
 312        writel(tmp, sckcr);
 313
 314        usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
 315
 316        return 0;
 317}
 318
 319static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
 320{
 321        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 322
 323        return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
 324}
 325
 326static const struct clk_ops sam9x5_slow_ops = {
 327        .set_parent = clk_sam9x5_slow_set_parent,
 328        .get_parent = clk_sam9x5_slow_get_parent,
 329};
 330
 331static struct clk * __init
 332at91_clk_register_sam9x5_slow(void __iomem *sckcr,
 333                              const char *name,
 334                              const char **parent_names,
 335                              int num_parents)
 336{
 337        struct clk_sam9x5_slow *slowck;
 338        struct clk *clk = NULL;
 339        struct clk_init_data init;
 340
 341        if (!sckcr || !name || !parent_names || !num_parents)
 342                return ERR_PTR(-EINVAL);
 343
 344        slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
 345        if (!slowck)
 346                return ERR_PTR(-ENOMEM);
 347
 348        init.name = name;
 349        init.ops = &sam9x5_slow_ops;
 350        init.parent_names = parent_names;
 351        init.num_parents = num_parents;
 352        init.flags = 0;
 353
 354        slowck->hw.init = &init;
 355        slowck->sckcr = sckcr;
 356        slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
 357
 358        clk = clk_register(NULL, &slowck->hw);
 359        if (IS_ERR(clk))
 360                kfree(slowck);
 361        else
 362                slow_clk = clk;
 363
 364        return clk;
 365}
 366
 367void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
 368                                         void __iomem *sckcr)
 369{
 370        struct clk *clk;
 371        const char *parent_names[2];
 372        int num_parents;
 373        const char *name = np->name;
 374        int i;
 375
 376        num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
 377        if (num_parents <= 0 || num_parents > 2)
 378                return;
 379
 380        for (i = 0; i < num_parents; ++i) {
 381                parent_names[i] = of_clk_get_parent_name(np, i);
 382                if (!parent_names[i])
 383                        return;
 384        }
 385
 386        of_property_read_string(np, "clock-output-names", &name);
 387
 388        clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
 389                                            num_parents);
 390        if (IS_ERR(clk))
 391                return;
 392
 393        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 394}
 395
 396static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
 397{
 398        struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
 399
 400        return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL);
 401}
 402
 403static const struct clk_ops sam9260_slow_ops = {
 404        .get_parent = clk_sam9260_slow_get_parent,
 405};
 406
 407static struct clk * __init
 408at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
 409                               const char *name,
 410                               const char **parent_names,
 411                               int num_parents)
 412{
 413        struct clk_sam9260_slow *slowck;
 414        struct clk *clk = NULL;
 415        struct clk_init_data init;
 416
 417        if (!pmc || !name)
 418                return ERR_PTR(-EINVAL);
 419
 420        if (!parent_names || !num_parents)
 421                return ERR_PTR(-EINVAL);
 422
 423        slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
 424        if (!slowck)
 425                return ERR_PTR(-ENOMEM);
 426
 427        init.name = name;
 428        init.ops = &sam9260_slow_ops;
 429        init.parent_names = parent_names;
 430        init.num_parents = num_parents;
 431        init.flags = 0;
 432
 433        slowck->hw.init = &init;
 434        slowck->pmc = pmc;
 435
 436        clk = clk_register(NULL, &slowck->hw);
 437        if (IS_ERR(clk))
 438                kfree(slowck);
 439        else
 440                slow_clk = clk;
 441
 442        return clk;
 443}
 444
 445void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
 446                                          struct at91_pmc *pmc)
 447{
 448        struct clk *clk;
 449        const char *parent_names[2];
 450        int num_parents;
 451        const char *name = np->name;
 452        int i;
 453
 454        num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
 455        if (num_parents != 2)
 456                return;
 457
 458        for (i = 0; i < num_parents; ++i) {
 459                parent_names[i] = of_clk_get_parent_name(np, i);
 460                if (!parent_names[i])
 461                        return;
 462        }
 463
 464        of_property_read_string(np, "clock-output-names", &name);
 465
 466        clk = at91_clk_register_sam9260_slow(pmc, name, parent_names,
 467                                             num_parents);
 468        if (IS_ERR(clk))
 469                return;
 470
 471        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 472}
 473
 474/*
 475 * FIXME: All slow clk users are not properly claiming it (get + prepare +
 476 * enable) before using it.
 477 * If all users properly claiming this clock decide that they don't need it
 478 * anymore (or are removed), it is disabled while faulty users are still
 479 * requiring it, and the system hangs.
 480 * Prevent this clock from being disabled until all users are properly
 481 * requesting it.
 482 * Once this is done we should remove this function and the slow_clk variable.
 483 */
 484static int __init of_at91_clk_slow_retain(void)
 485{
 486        if (!slow_clk)
 487                return 0;
 488
 489        __clk_get(slow_clk);
 490        clk_prepare_enable(slow_clk);
 491
 492        return 0;
 493}
 494arch_initcall(of_at91_clk_slow_retain);
 495