linux/arch/blackfin/mach-bf609/clock.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/module.h>
   3#include <linux/kernel.h>
   4#include <linux/list.h>
   5#include <linux/errno.h>
   6#include <linux/err.h>
   7#include <linux/string.h>
   8#include <linux/clk.h>
   9#include <linux/mutex.h>
  10#include <linux/spinlock.h>
  11#include <linux/debugfs.h>
  12#include <linux/device.h>
  13#include <linux/init.h>
  14#include <linux/timer.h>
  15#include <linux/io.h>
  16#include <linux/seq_file.h>
  17#include <linux/clkdev.h>
  18
  19#include <asm/clocks.h>
  20
  21#define CGU0_CTL_DF (1 << 0)
  22
  23#define CGU0_CTL_MSEL_SHIFT 8
  24#define CGU0_CTL_MSEL_MASK (0x7f << 8)
  25
  26#define CGU0_STAT_PLLEN (1 << 0)
  27#define CGU0_STAT_PLLBP (1 << 1)
  28#define CGU0_STAT_PLLLK (1 << 2)
  29#define CGU0_STAT_CLKSALGN (1 << 3)
  30#define CGU0_STAT_CCBF0 (1 << 4)
  31#define CGU0_STAT_CCBF1 (1 << 5)
  32#define CGU0_STAT_SCBF0 (1 << 6)
  33#define CGU0_STAT_SCBF1 (1 << 7)
  34#define CGU0_STAT_DCBF (1 << 8)
  35#define CGU0_STAT_OCBF (1 << 9)
  36#define CGU0_STAT_ADDRERR (1 << 16)
  37#define CGU0_STAT_LWERR (1 << 17)
  38#define CGU0_STAT_DIVERR (1 << 18)
  39#define CGU0_STAT_WDFMSERR (1 << 19)
  40#define CGU0_STAT_WDIVERR (1 << 20)
  41#define CGU0_STAT_PLOCKERR (1 << 21)
  42
  43#define CGU0_DIV_CSEL_SHIFT 0
  44#define CGU0_DIV_CSEL_MASK 0x0000001F
  45#define CGU0_DIV_S0SEL_SHIFT 5
  46#define CGU0_DIV_S0SEL_MASK (0x3 << CGU0_DIV_S0SEL_SHIFT)
  47#define CGU0_DIV_SYSSEL_SHIFT 8
  48#define CGU0_DIV_SYSSEL_MASK (0x1f << CGU0_DIV_SYSSEL_SHIFT)
  49#define CGU0_DIV_S1SEL_SHIFT 13
  50#define CGU0_DIV_S1SEL_MASK (0x3 << CGU0_DIV_S1SEL_SHIFT)
  51#define CGU0_DIV_DSEL_SHIFT 16
  52#define CGU0_DIV_DSEL_MASK (0x1f << CGU0_DIV_DSEL_SHIFT)
  53#define CGU0_DIV_OSEL_SHIFT 22
  54#define CGU0_DIV_OSEL_MASK (0x7f << CGU0_DIV_OSEL_SHIFT)
  55
  56#define CLK(_clk, _devname, _conname)                   \
  57        {                                               \
  58                .clk    = &_clk,                  \
  59                .dev_id = _devname,                     \
  60                .con_id = _conname,                     \
  61        }
  62
  63#define NEEDS_INITIALIZATION 0x11
  64
  65static LIST_HEAD(clk_list);
  66
  67static void clk_reg_write_mask(u32 reg, uint32_t val, uint32_t mask)
  68{
  69        u32 val2;
  70
  71        val2 = bfin_read32(reg);
  72        val2 &= ~mask;
  73        val2 |= val;
  74        bfin_write32(reg, val2);
  75}
  76
  77int wait_for_pll_align(void)
  78{
  79        int i = 10000;
  80        while (i-- && (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN));
  81
  82        if (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN) {
  83                printk(KERN_CRIT "fail to align clk\n");
  84                return -1;
  85        }
  86
  87        return 0;
  88}
  89
  90int clk_enable(struct clk *clk)
  91{
  92        int ret = -EIO;
  93        if (clk->ops && clk->ops->enable)
  94                ret = clk->ops->enable(clk);
  95        return ret;
  96}
  97EXPORT_SYMBOL(clk_enable);
  98
  99void clk_disable(struct clk *clk)
 100{
 101        if (!clk)
 102                return;
 103
 104        if (clk->ops && clk->ops->disable)
 105                clk->ops->disable(clk);
 106}
 107EXPORT_SYMBOL(clk_disable);
 108
 109
 110unsigned long clk_get_rate(struct clk *clk)
 111{
 112        unsigned long ret = 0;
 113        if (clk->ops && clk->ops->get_rate)
 114                ret = clk->ops->get_rate(clk);
 115        return ret;
 116}
 117EXPORT_SYMBOL(clk_get_rate);
 118
 119long clk_round_rate(struct clk *clk, unsigned long rate)
 120{
 121        long ret = 0;
 122        if (clk->ops && clk->ops->round_rate)
 123                ret = clk->ops->round_rate(clk, rate);
 124        return ret;
 125}
 126EXPORT_SYMBOL(clk_round_rate);
 127
 128int clk_set_rate(struct clk *clk, unsigned long rate)
 129{
 130        int ret = -EIO;
 131        if (clk->ops && clk->ops->set_rate)
 132                ret = clk->ops->set_rate(clk, rate);
 133        return ret;
 134}
 135EXPORT_SYMBOL(clk_set_rate);
 136
 137unsigned long vco_get_rate(struct clk *clk)
 138{
 139        return clk->rate;
 140}
 141
 142unsigned long pll_get_rate(struct clk *clk)
 143{
 144        u32 df;
 145        u32 msel;
 146        u32 ctl = bfin_read32(CGU0_CTL);
 147        u32 stat = bfin_read32(CGU0_STAT);
 148        if (stat & CGU0_STAT_PLLBP)
 149                return 0;
 150        msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
 151        df = (ctl &  CGU0_CTL_DF);
 152        clk->parent->rate = clk_get_rate(clk->parent);
 153        return clk->parent->rate / (df + 1) * msel * 2;
 154}
 155
 156unsigned long pll_round_rate(struct clk *clk, unsigned long rate)
 157{
 158        u32 div;
 159        div = rate / clk->parent->rate;
 160        return clk->parent->rate * div;
 161}
 162
 163int pll_set_rate(struct clk *clk, unsigned long rate)
 164{
 165        u32 msel;
 166        u32 stat = bfin_read32(CGU0_STAT);
 167        if (!(stat & CGU0_STAT_PLLEN))
 168                return -EBUSY;
 169        if (!(stat & CGU0_STAT_PLLLK))
 170                return -EBUSY;
 171        if (wait_for_pll_align())
 172                return -EBUSY;
 173        msel = rate / clk->parent->rate / 2;
 174        clk_reg_write_mask(CGU0_CTL, msel << CGU0_CTL_MSEL_SHIFT,
 175                CGU0_CTL_MSEL_MASK);
 176        clk->rate = rate;
 177        return 0;
 178}
 179
 180unsigned long cclk_get_rate(struct clk *clk)
 181{
 182        if (clk->parent)
 183                return clk->parent->rate;
 184        else
 185                return 0;
 186}
 187
 188unsigned long sys_clk_get_rate(struct clk *clk)
 189{
 190        unsigned long drate;
 191        u32 msel;
 192        u32 df;
 193        u32 ctl = bfin_read32(CGU0_CTL);
 194        u32 div = bfin_read32(CGU0_DIV);
 195        div = (div & clk->mask) >> clk->shift;
 196        msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
 197        df = (ctl &  CGU0_CTL_DF);
 198
 199        if (!strcmp(clk->parent->name, "SYS_CLKIN")) {
 200                drate = clk->parent->rate / (df + 1);
 201                drate *=  msel;
 202                drate /= div;
 203                return drate;
 204        } else {
 205                clk->parent->rate = clk_get_rate(clk->parent);
 206                return clk->parent->rate / div;
 207        }
 208}
 209
 210unsigned long dummy_get_rate(struct clk *clk)
 211{
 212        clk->parent->rate = clk_get_rate(clk->parent);
 213        return clk->parent->rate;
 214}
 215
 216unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate)
 217{
 218        unsigned long max_rate;
 219        unsigned long drate;
 220        int i;
 221        u32 msel;
 222        u32 df;
 223        u32 ctl = bfin_read32(CGU0_CTL);
 224
 225        msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
 226        df = (ctl &  CGU0_CTL_DF);
 227        max_rate = clk->parent->rate / (df + 1) * msel;
 228
 229        if (rate > max_rate)
 230                return 0;
 231
 232        for (i = 1; i < clk->mask; i++) {
 233                drate = max_rate / i;
 234                if (rate >= drate)
 235                        return drate;
 236        }
 237        return 0;
 238}
 239
 240int sys_clk_set_rate(struct clk *clk, unsigned long rate)
 241{
 242        u32 div = bfin_read32(CGU0_DIV);
 243        div = (div & clk->mask) >> clk->shift;
 244
 245        rate = clk_round_rate(clk, rate);
 246
 247        if (!rate)
 248                return -EINVAL;
 249
 250        div = (clk_get_rate(clk) * div) / rate;
 251
 252        if (wait_for_pll_align())
 253                return -EBUSY;
 254        clk_reg_write_mask(CGU0_DIV, div << clk->shift,
 255                        clk->mask);
 256        clk->rate = rate;
 257        return 0;
 258}
 259
 260static struct clk_ops vco_ops = {
 261        .get_rate = vco_get_rate,
 262};
 263
 264static struct clk_ops pll_ops = {
 265        .get_rate = pll_get_rate,
 266        .set_rate = pll_set_rate,
 267};
 268
 269static struct clk_ops cclk_ops = {
 270        .get_rate = cclk_get_rate,
 271};
 272
 273static struct clk_ops sys_clk_ops = {
 274        .get_rate = sys_clk_get_rate,
 275        .set_rate = sys_clk_set_rate,
 276        .round_rate = sys_clk_round_rate,
 277};
 278
 279static struct clk_ops dummy_clk_ops = {
 280        .get_rate = dummy_get_rate,
 281};
 282
 283static struct clk sys_clkin = {
 284        .name       = "SYS_CLKIN",
 285        .rate       = CONFIG_CLKIN_HZ,
 286        .ops        = &vco_ops,
 287};
 288
 289static struct clk pll_clk = {
 290        .name       = "PLLCLK",
 291        .rate       = 500000000,
 292        .parent     = &sys_clkin,
 293        .ops = &pll_ops,
 294        .flags = NEEDS_INITIALIZATION,
 295};
 296
 297static struct clk cclk = {
 298        .name       = "CCLK",
 299        .rate       = 500000000,
 300        .mask       = CGU0_DIV_CSEL_MASK,
 301        .shift      = CGU0_DIV_CSEL_SHIFT,
 302        .parent     = &sys_clkin,
 303        .ops        = &sys_clk_ops,
 304        .flags = NEEDS_INITIALIZATION,
 305};
 306
 307static struct clk cclk0 = {
 308        .name       = "CCLK0",
 309        .parent     = &cclk,
 310        .ops        = &cclk_ops,
 311};
 312
 313static struct clk cclk1 = {
 314        .name       = "CCLK1",
 315        .parent     = &cclk,
 316        .ops        = &cclk_ops,
 317};
 318
 319static struct clk sysclk = {
 320        .name       = "SYSCLK",
 321        .rate       = 500000000,
 322        .mask       = CGU0_DIV_SYSSEL_MASK,
 323        .shift      = CGU0_DIV_SYSSEL_SHIFT,
 324        .parent     = &sys_clkin,
 325        .ops        = &sys_clk_ops,
 326        .flags = NEEDS_INITIALIZATION,
 327};
 328
 329static struct clk sclk0 = {
 330        .name       = "SCLK0",
 331        .rate       = 500000000,
 332        .mask       = CGU0_DIV_S0SEL_MASK,
 333        .shift      = CGU0_DIV_S0SEL_SHIFT,
 334        .parent     = &sysclk,
 335        .ops        = &sys_clk_ops,
 336};
 337
 338static struct clk sclk1 = {
 339        .name       = "SCLK1",
 340        .rate       = 500000000,
 341        .mask       = CGU0_DIV_S1SEL_MASK,
 342        .shift      = CGU0_DIV_S1SEL_SHIFT,
 343        .parent     = &sysclk,
 344        .ops        = &sys_clk_ops,
 345};
 346
 347static struct clk dclk = {
 348        .name       = "DCLK",
 349        .rate       = 500000000,
 350        .mask       = CGU0_DIV_DSEL_MASK,
 351        .shift       = CGU0_DIV_DSEL_SHIFT,
 352        .parent     = &sys_clkin,
 353        .ops        = &sys_clk_ops,
 354};
 355
 356static struct clk oclk = {
 357        .name       = "OCLK",
 358        .rate       = 500000000,
 359        .mask       = CGU0_DIV_OSEL_MASK,
 360        .shift      = CGU0_DIV_OSEL_SHIFT,
 361        .parent     = &pll_clk,
 362};
 363
 364static struct clk ethclk = {
 365        .name       = "stmmaceth",
 366        .parent     = &sclk0,
 367        .ops        = &dummy_clk_ops,
 368};
 369
 370static struct clk ethpclk = {
 371        .name       = "pclk",
 372        .parent     = &sclk0,
 373        .ops        = &dummy_clk_ops,
 374};
 375
 376static struct clk spiclk = {
 377        .name       = "spi",
 378        .parent     = &sclk1,
 379        .ops        = &dummy_clk_ops,
 380};
 381
 382static struct clk_lookup bf609_clks[] = {
 383        CLK(sys_clkin, NULL, "SYS_CLKIN"),
 384        CLK(pll_clk, NULL, "PLLCLK"),
 385        CLK(cclk, NULL, "CCLK"),
 386        CLK(cclk0, NULL, "CCLK0"),
 387        CLK(cclk1, NULL, "CCLK1"),
 388        CLK(sysclk, NULL, "SYSCLK"),
 389        CLK(sclk0, NULL, "SCLK0"),
 390        CLK(sclk1, NULL, "SCLK1"),
 391        CLK(dclk, NULL, "DCLK"),
 392        CLK(oclk, NULL, "OCLK"),
 393        CLK(ethclk, NULL, "stmmaceth"),
 394        CLK(ethpclk, NULL, "pclk"),
 395        CLK(spiclk, NULL, "spi"),
 396};
 397
 398int __init clk_init(void)
 399{
 400        int i;
 401        struct clk *clkp;
 402        for (i = 0; i < ARRAY_SIZE(bf609_clks); i++) {
 403                clkp = bf609_clks[i].clk;
 404                if (clkp->flags & NEEDS_INITIALIZATION)
 405                        clk_get_rate(clkp);
 406        }
 407        clkdev_add_table(bf609_clks, ARRAY_SIZE(bf609_clks));
 408        return 0;
 409}
 410