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