linux/drivers/clk/sunxi/clk-mod0.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 Emilio López
   3 *
   4 * Emilio López <emilio@elopez.com.ar>
   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 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/clk.h>
  18#include <linux/clkdev.h>
  19#include <linux/clk-provider.h>
  20#include <linux/of_address.h>
  21#include <linux/platform_device.h>
  22#include <linux/slab.h>
  23
  24#include "clk-factors.h"
  25
  26/**
  27 * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
  28 * MOD0 rate is calculated as follows
  29 * rate = (parent_rate >> p) / (m + 1);
  30 */
  31
  32static void sun4i_a10_get_mod0_factors(struct factors_request *req)
  33{
  34        u8 div, calcm, calcp;
  35
  36        /* These clocks can only divide, so we will never be able to achieve
  37         * frequencies higher than the parent frequency */
  38        if (req->rate > req->parent_rate)
  39                req->rate = req->parent_rate;
  40
  41        div = DIV_ROUND_UP(req->parent_rate, req->rate);
  42
  43        if (div < 16)
  44                calcp = 0;
  45        else if (div / 2 < 16)
  46                calcp = 1;
  47        else if (div / 4 < 16)
  48                calcp = 2;
  49        else
  50                calcp = 3;
  51
  52        calcm = DIV_ROUND_UP(div, 1 << calcp);
  53
  54        req->rate = (req->parent_rate >> calcp) / calcm;
  55        req->m = calcm - 1;
  56        req->p = calcp;
  57}
  58
  59/* user manual says "n" but it's really "p" */
  60static const struct clk_factors_config sun4i_a10_mod0_config = {
  61        .mshift = 0,
  62        .mwidth = 4,
  63        .pshift = 16,
  64        .pwidth = 2,
  65};
  66
  67static const struct factors_data sun4i_a10_mod0_data = {
  68        .enable = 31,
  69        .mux = 24,
  70        .muxmask = BIT(1) | BIT(0),
  71        .table = &sun4i_a10_mod0_config,
  72        .getter = sun4i_a10_get_mod0_factors,
  73};
  74
  75static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
  76
  77static void __init sun4i_a10_mod0_setup(struct device_node *node)
  78{
  79        void __iomem *reg;
  80
  81        reg = of_iomap(node, 0);
  82        if (!reg) {
  83                /*
  84                 * This happens with mod0 clk nodes instantiated through
  85                 * mfd, as those do not have their resources assigned at
  86                 * CLK_OF_DECLARE time yet, so do not print an error.
  87                 */
  88                return;
  89        }
  90
  91        sunxi_factors_register(node, &sun4i_a10_mod0_data,
  92                               &sun4i_a10_mod0_lock, reg);
  93}
  94CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk",
  95                      sun4i_a10_mod0_setup);
  96
  97static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
  98{
  99        struct device_node *np = pdev->dev.of_node;
 100        struct resource *r;
 101        void __iomem *reg;
 102
 103        if (!np)
 104                return -ENODEV;
 105
 106        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 107        reg = devm_ioremap_resource(&pdev->dev, r);
 108        if (IS_ERR(reg))
 109                return PTR_ERR(reg);
 110
 111        sunxi_factors_register(np, &sun4i_a10_mod0_data,
 112                               &sun4i_a10_mod0_lock, reg);
 113        return 0;
 114}
 115
 116static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = {
 117        { .compatible = "allwinner,sun4i-a10-mod0-clk" },
 118        { /* sentinel */ }
 119};
 120
 121static struct platform_driver sun4i_a10_mod0_clk_driver = {
 122        .driver = {
 123                .name = "sun4i-a10-mod0-clk",
 124                .of_match_table = sun4i_a10_mod0_clk_dt_ids,
 125        },
 126        .probe = sun4i_a10_mod0_clk_probe,
 127};
 128builtin_platform_driver(sun4i_a10_mod0_clk_driver);
 129
 130static const struct factors_data sun9i_a80_mod0_data __initconst = {
 131        .enable = 31,
 132        .mux = 24,
 133        .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
 134        .table = &sun4i_a10_mod0_config,
 135        .getter = sun4i_a10_get_mod0_factors,
 136};
 137
 138static void __init sun9i_a80_mod0_setup(struct device_node *node)
 139{
 140        void __iomem *reg;
 141
 142        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
 143        if (IS_ERR(reg)) {
 144                pr_err("Could not get registers for mod0-clk: %s\n",
 145                       node->name);
 146                return;
 147        }
 148
 149        sunxi_factors_register(node, &sun9i_a80_mod0_data,
 150                               &sun4i_a10_mod0_lock, reg);
 151}
 152CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
 153
 154static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
 155
 156static void __init sun5i_a13_mbus_setup(struct device_node *node)
 157{
 158        struct clk *mbus;
 159        void __iomem *reg;
 160
 161        reg = of_iomap(node, 0);
 162        if (!reg) {
 163                pr_err("Could not get registers for a13-mbus-clk\n");
 164                return;
 165        }
 166
 167        mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data,
 168                                      &sun5i_a13_mbus_lock, reg);
 169
 170        /* The MBUS clocks needs to be always enabled */
 171        __clk_get(mbus);
 172        clk_prepare_enable(mbus);
 173}
 174CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
 175
 176struct mmc_phase {
 177        struct clk_hw           hw;
 178        u8                      offset;
 179        void __iomem            *reg;
 180        spinlock_t              *lock;
 181};
 182
 183#define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
 184
 185static int mmc_get_phase(struct clk_hw *hw)
 186{
 187        struct clk *mmc, *mmc_parent, *clk = hw->clk;
 188        struct mmc_phase *phase = to_mmc_phase(hw);
 189        unsigned int mmc_rate, mmc_parent_rate;
 190        u16 step, mmc_div;
 191        u32 value;
 192        u8 delay;
 193
 194        value = readl(phase->reg);
 195        delay = (value >> phase->offset) & 0x3;
 196
 197        if (!delay)
 198                return 180;
 199
 200        /* Get the main MMC clock */
 201        mmc = clk_get_parent(clk);
 202        if (!mmc)
 203                return -EINVAL;
 204
 205        /* And its rate */
 206        mmc_rate = clk_get_rate(mmc);
 207        if (!mmc_rate)
 208                return -EINVAL;
 209
 210        /* Now, get the MMC parent (most likely some PLL) */
 211        mmc_parent = clk_get_parent(mmc);
 212        if (!mmc_parent)
 213                return -EINVAL;
 214
 215        /* And its rate */
 216        mmc_parent_rate = clk_get_rate(mmc_parent);
 217        if (!mmc_parent_rate)
 218                return -EINVAL;
 219
 220        /* Get MMC clock divider */
 221        mmc_div = mmc_parent_rate / mmc_rate;
 222
 223        step = DIV_ROUND_CLOSEST(360, mmc_div);
 224        return delay * step;
 225}
 226
 227static int mmc_set_phase(struct clk_hw *hw, int degrees)
 228{
 229        struct clk *mmc, *mmc_parent, *clk = hw->clk;
 230        struct mmc_phase *phase = to_mmc_phase(hw);
 231        unsigned int mmc_rate, mmc_parent_rate;
 232        unsigned long flags;
 233        u32 value;
 234        u8 delay;
 235
 236        /* Get the main MMC clock */
 237        mmc = clk_get_parent(clk);
 238        if (!mmc)
 239                return -EINVAL;
 240
 241        /* And its rate */
 242        mmc_rate = clk_get_rate(mmc);
 243        if (!mmc_rate)
 244                return -EINVAL;
 245
 246        /* Now, get the MMC parent (most likely some PLL) */
 247        mmc_parent = clk_get_parent(mmc);
 248        if (!mmc_parent)
 249                return -EINVAL;
 250
 251        /* And its rate */
 252        mmc_parent_rate = clk_get_rate(mmc_parent);
 253        if (!mmc_parent_rate)
 254                return -EINVAL;
 255
 256        if (degrees != 180) {
 257                u16 step, mmc_div;
 258
 259                /* Get MMC clock divider */
 260                mmc_div = mmc_parent_rate / mmc_rate;
 261
 262                /*
 263                 * We can only outphase the clocks by multiple of the
 264                 * PLL's period.
 265                 *
 266                 * Since the MMC clock in only a divider, and the
 267                 * formula to get the outphasing in degrees is deg =
 268                 * 360 * delta / period
 269                 *
 270                 * If we simplify this formula, we can see that the
 271                 * only thing that we're concerned about is the number
 272                 * of period we want to outphase our clock from, and
 273                 * the divider set by the MMC clock.
 274                 */
 275                step = DIV_ROUND_CLOSEST(360, mmc_div);
 276                delay = DIV_ROUND_CLOSEST(degrees, step);
 277        } else {
 278                delay = 0;
 279        }
 280
 281        spin_lock_irqsave(phase->lock, flags);
 282        value = readl(phase->reg);
 283        value &= ~GENMASK(phase->offset + 3, phase->offset);
 284        value |= delay << phase->offset;
 285        writel(value, phase->reg);
 286        spin_unlock_irqrestore(phase->lock, flags);
 287
 288        return 0;
 289}
 290
 291static const struct clk_ops mmc_clk_ops = {
 292        .get_phase      = mmc_get_phase,
 293        .set_phase      = mmc_set_phase,
 294};
 295
 296/*
 297 * sunxi_mmc_setup - Common setup function for mmc module clocks
 298 *
 299 * The only difference between module clocks on different platforms is the
 300 * width of the mux register bits and the valid values, which are passed in
 301 * through struct factors_data. The phase clocks parts are identical.
 302 */
 303static void __init sunxi_mmc_setup(struct device_node *node,
 304                                   const struct factors_data *data,
 305                                   spinlock_t *lock)
 306{
 307        struct clk_onecell_data *clk_data;
 308        const char *parent;
 309        void __iomem *reg;
 310        int i;
 311
 312        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
 313        if (IS_ERR(reg)) {
 314                pr_err("Couldn't map the %s clock registers\n", node->name);
 315                return;
 316        }
 317
 318        clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
 319        if (!clk_data)
 320                return;
 321
 322        clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
 323        if (!clk_data->clks)
 324                goto err_free_data;
 325
 326        clk_data->clk_num = 3;
 327        clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg);
 328        if (!clk_data->clks[0])
 329                goto err_free_clks;
 330
 331        parent = __clk_get_name(clk_data->clks[0]);
 332
 333        for (i = 1; i < 3; i++) {
 334                struct clk_init_data init = {
 335                        .num_parents    = 1,
 336                        .parent_names   = &parent,
 337                        .ops            = &mmc_clk_ops,
 338                };
 339                struct mmc_phase *phase;
 340
 341                phase = kmalloc(sizeof(*phase), GFP_KERNEL);
 342                if (!phase)
 343                        continue;
 344
 345                phase->hw.init = &init;
 346                phase->reg = reg;
 347                phase->lock = lock;
 348
 349                if (i == 1)
 350                        phase->offset = 8;
 351                else
 352                        phase->offset = 20;
 353
 354                if (of_property_read_string_index(node, "clock-output-names",
 355                                                  i, &init.name))
 356                        init.name = node->name;
 357
 358                clk_data->clks[i] = clk_register(NULL, &phase->hw);
 359                if (IS_ERR(clk_data->clks[i])) {
 360                        kfree(phase);
 361                        continue;
 362                }
 363        }
 364
 365        of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 366
 367        return;
 368
 369err_free_clks:
 370        kfree(clk_data->clks);
 371err_free_data:
 372        kfree(clk_data);
 373}
 374
 375static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
 376
 377static void __init sun4i_a10_mmc_setup(struct device_node *node)
 378{
 379        sunxi_mmc_setup(node, &sun4i_a10_mod0_data, &sun4i_a10_mmc_lock);
 380}
 381CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
 382
 383static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
 384
 385static void __init sun9i_a80_mmc_setup(struct device_node *node)
 386{
 387        sunxi_mmc_setup(node, &sun9i_a80_mod0_data, &sun9i_a80_mmc_lock);
 388}
 389CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
 390