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
  73
  74static int clk_slow_osc_prepare(struct clk_hw *hw)
  75{
  76        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  77        void __iomem *sckcr = osc->sckcr;
  78        u32 tmp = readl(sckcr);
  79
  80        if (tmp & AT91_SCKC_OSC32BYP)
  81                return 0;
  82
  83        writel(tmp | AT91_SCKC_OSC32EN, sckcr);
  84
  85        usleep_range(osc->startup_usec, osc->startup_usec + 1);
  86
  87        return 0;
  88}
  89
  90static void clk_slow_osc_unprepare(struct clk_hw *hw)
  91{
  92        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  93        void __iomem *sckcr = osc->sckcr;
  94        u32 tmp = readl(sckcr);
  95
  96        if (tmp & AT91_SCKC_OSC32BYP)
  97                return;
  98
  99        writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
 100}
 101
 102static int clk_slow_osc_is_prepared(struct clk_hw *hw)
 103{
 104        struct clk_slow_osc *osc = to_clk_slow_osc(hw);
 105        void __iomem *sckcr = osc->sckcr;
 106        u32 tmp = readl(sckcr);
 107
 108        if (tmp & AT91_SCKC_OSC32BYP)
 109                return 1;
 110
 111        return !!(tmp & AT91_SCKC_OSC32EN);
 112}
 113
 114static const struct clk_ops slow_osc_ops = {
 115        .prepare = clk_slow_osc_prepare,
 116        .unprepare = clk_slow_osc_unprepare,
 117        .is_prepared = clk_slow_osc_is_prepared,
 118};
 119
 120static struct clk * __init
 121at91_clk_register_slow_osc(void __iomem *sckcr,
 122                           const char *name,
 123                           const char *parent_name,
 124                           unsigned long startup,
 125                           bool bypass)
 126{
 127        struct clk_slow_osc *osc;
 128        struct clk *clk = NULL;
 129        struct clk_init_data init;
 130
 131        if (!sckcr || !name || !parent_name)
 132                return ERR_PTR(-EINVAL);
 133
 134        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 135        if (!osc)
 136                return ERR_PTR(-ENOMEM);
 137
 138        init.name = name;
 139        init.ops = &slow_osc_ops;
 140        init.parent_names = &parent_name;
 141        init.num_parents = 1;
 142        init.flags = CLK_IGNORE_UNUSED;
 143
 144        osc->hw.init = &init;
 145        osc->sckcr = sckcr;
 146        osc->startup_usec = startup;
 147
 148        if (bypass)
 149                writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
 150                       sckcr);
 151
 152        clk = clk_register(NULL, &osc->hw);
 153        if (IS_ERR(clk))
 154                kfree(osc);
 155
 156        return clk;
 157}
 158
 159void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
 160                                             void __iomem *sckcr)
 161{
 162        struct clk *clk;
 163        const char *parent_name;
 164        const char *name = np->name;
 165        u32 startup;
 166        bool bypass;
 167
 168        parent_name = of_clk_get_parent_name(np, 0);
 169        of_property_read_string(np, "clock-output-names", &name);
 170        of_property_read_u32(np, "atmel,startup-time-usec", &startup);
 171        bypass = of_property_read_bool(np, "atmel,osc-bypass");
 172
 173        clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
 174                                         bypass);
 175        if (IS_ERR(clk))
 176                return;
 177
 178        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 179}
 180
 181static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
 182                                                 unsigned long parent_rate)
 183{
 184        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 185
 186        return osc->frequency;
 187}
 188
 189static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
 190                                                     unsigned long parent_acc)
 191{
 192        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 193
 194        return osc->accuracy;
 195}
 196
 197static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
 198{
 199        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 200        void __iomem *sckcr = osc->sckcr;
 201
 202        writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
 203
 204        usleep_range(osc->startup_usec, osc->startup_usec + 1);
 205
 206        return 0;
 207}
 208
 209static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
 210{
 211        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 212        void __iomem *sckcr = osc->sckcr;
 213
 214        writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
 215}
 216
 217static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
 218{
 219        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 220
 221        return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
 222}
 223
 224static const struct clk_ops slow_rc_osc_ops = {
 225        .prepare = clk_slow_rc_osc_prepare,
 226        .unprepare = clk_slow_rc_osc_unprepare,
 227        .is_prepared = clk_slow_rc_osc_is_prepared,
 228        .recalc_rate = clk_slow_rc_osc_recalc_rate,
 229        .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
 230};
 231
 232static struct clk * __init
 233at91_clk_register_slow_rc_osc(void __iomem *sckcr,
 234                              const char *name,
 235                              unsigned long frequency,
 236                              unsigned long accuracy,
 237                              unsigned long startup)
 238{
 239        struct clk_slow_rc_osc *osc;
 240        struct clk *clk = NULL;
 241        struct clk_init_data init;
 242
 243        if (!sckcr || !name)
 244                return ERR_PTR(-EINVAL);
 245
 246        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
 247        if (!osc)
 248                return ERR_PTR(-ENOMEM);
 249
 250        init.name = name;
 251        init.ops = &slow_rc_osc_ops;
 252        init.parent_names = NULL;
 253        init.num_parents = 0;
 254        init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
 255
 256        osc->hw.init = &init;
 257        osc->sckcr = sckcr;
 258        osc->frequency = frequency;
 259        osc->accuracy = accuracy;
 260        osc->startup_usec = startup;
 261
 262        clk = clk_register(NULL, &osc->hw);
 263        if (IS_ERR(clk))
 264                kfree(osc);
 265
 266        return clk;
 267}
 268
 269void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
 270                                                void __iomem *sckcr)
 271{
 272        struct clk *clk;
 273        u32 frequency = 0;
 274        u32 accuracy = 0;
 275        u32 startup = 0;
 276        const char *name = np->name;
 277
 278        of_property_read_string(np, "clock-output-names", &name);
 279        of_property_read_u32(np, "clock-frequency", &frequency);
 280        of_property_read_u32(np, "clock-accuracy", &accuracy);
 281        of_property_read_u32(np, "atmel,startup-time-usec", &startup);
 282
 283        clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
 284                                            startup);
 285        if (IS_ERR(clk))
 286                return;
 287
 288        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 289}
 290
 291static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 292{
 293        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 294        void __iomem *sckcr = slowck->sckcr;
 295        u32 tmp;
 296
 297        if (index > 1)
 298                return -EINVAL;
 299
 300        tmp = readl(sckcr);
 301
 302        if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
 303            (index && (tmp & AT91_SCKC_OSCSEL)))
 304                return 0;
 305
 306        if (index)
 307                tmp |= AT91_SCKC_OSCSEL;
 308        else
 309                tmp &= ~AT91_SCKC_OSCSEL;
 310
 311        writel(tmp, sckcr);
 312
 313        usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
 314
 315        return 0;
 316}
 317
 318static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
 319{
 320        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 321
 322        return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
 323}
 324
 325static const struct clk_ops sam9x5_slow_ops = {
 326        .set_parent = clk_sam9x5_slow_set_parent,
 327        .get_parent = clk_sam9x5_slow_get_parent,
 328};
 329
 330static struct clk * __init
 331at91_clk_register_sam9x5_slow(void __iomem *sckcr,
 332                              const char *name,
 333                              const char **parent_names,
 334                              int num_parents)
 335{
 336        struct clk_sam9x5_slow *slowck;
 337        struct clk *clk = NULL;
 338        struct clk_init_data init;
 339
 340        if (!sckcr || !name || !parent_names || !num_parents)
 341                return ERR_PTR(-EINVAL);
 342
 343        slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
 344        if (!slowck)
 345                return ERR_PTR(-ENOMEM);
 346
 347        init.name = name;
 348        init.ops = &sam9x5_slow_ops;
 349        init.parent_names = parent_names;
 350        init.num_parents = num_parents;
 351        init.flags = 0;
 352
 353        slowck->hw.init = &init;
 354        slowck->sckcr = sckcr;
 355        slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
 356
 357        clk = clk_register(NULL, &slowck->hw);
 358        if (IS_ERR(clk))
 359                kfree(slowck);
 360
 361        return clk;
 362}
 363
 364void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
 365                                         void __iomem *sckcr)
 366{
 367        struct clk *clk;
 368        const char *parent_names[2];
 369        int num_parents;
 370        const char *name = np->name;
 371        int i;
 372
 373        num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
 374        if (num_parents <= 0 || num_parents > 2)
 375                return;
 376
 377        for (i = 0; i < num_parents; ++i) {
 378                parent_names[i] = of_clk_get_parent_name(np, i);
 379                if (!parent_names[i])
 380                        return;
 381        }
 382
 383        of_property_read_string(np, "clock-output-names", &name);
 384
 385        clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
 386                                            num_parents);
 387        if (IS_ERR(clk))
 388                return;
 389
 390        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 391}
 392
 393static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
 394{
 395        struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
 396
 397        return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL);
 398}
 399
 400static const struct clk_ops sam9260_slow_ops = {
 401        .get_parent = clk_sam9260_slow_get_parent,
 402};
 403
 404static struct clk * __init
 405at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
 406                               const char *name,
 407                               const char **parent_names,
 408                               int num_parents)
 409{
 410        struct clk_sam9260_slow *slowck;
 411        struct clk *clk = NULL;
 412        struct clk_init_data init;
 413
 414        if (!pmc || !name)
 415                return ERR_PTR(-EINVAL);
 416
 417        if (!parent_names || !num_parents)
 418                return ERR_PTR(-EINVAL);
 419
 420        slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
 421        if (!slowck)
 422                return ERR_PTR(-ENOMEM);
 423
 424        init.name = name;
 425        init.ops = &sam9260_slow_ops;
 426        init.parent_names = parent_names;
 427        init.num_parents = num_parents;
 428        init.flags = 0;
 429
 430        slowck->hw.init = &init;
 431        slowck->pmc = pmc;
 432
 433        clk = clk_register(NULL, &slowck->hw);
 434        if (IS_ERR(clk))
 435                kfree(slowck);
 436
 437        return clk;
 438}
 439
 440void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
 441                                          struct at91_pmc *pmc)
 442{
 443        struct clk *clk;
 444        const char *parent_names[2];
 445        int num_parents;
 446        const char *name = np->name;
 447        int i;
 448
 449        num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
 450        if (num_parents != 2)
 451                return;
 452
 453        for (i = 0; i < num_parents; ++i) {
 454                parent_names[i] = of_clk_get_parent_name(np, i);
 455                if (!parent_names[i])
 456                        return;
 457        }
 458
 459        of_property_read_string(np, "clock-output-names", &name);
 460
 461        clk = at91_clk_register_sam9260_slow(pmc, name, parent_names,
 462                                             num_parents);
 463        if (IS_ERR(clk))
 464                return;
 465
 466        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 467}
 468