linux/drivers/clk/clk-milbeaut.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2018 Socionext Inc.
   4 * Copyright (C) 2016 Linaro Ltd.
   5 */
   6
   7#include <linux/clk-provider.h>
   8#include <linux/err.h>
   9#include <linux/io.h>
  10#include <linux/iopoll.h>
  11#include <linux/of_address.h>
  12#include <linux/platform_device.h>
  13#include <linux/slab.h>
  14#include <linux/spinlock.h>
  15
  16#define M10V_CLKSEL1            0x0
  17#define CLKSEL(n)       (((n) - 1) * 4 + M10V_CLKSEL1)
  18
  19#define M10V_PLL1               "pll1"
  20#define M10V_PLL1DIV2           "pll1-2"
  21#define M10V_PLL2               "pll2"
  22#define M10V_PLL2DIV2           "pll2-2"
  23#define M10V_PLL6               "pll6"
  24#define M10V_PLL6DIV2           "pll6-2"
  25#define M10V_PLL6DIV3           "pll6-3"
  26#define M10V_PLL7               "pll7"
  27#define M10V_PLL7DIV2           "pll7-2"
  28#define M10V_PLL7DIV5           "pll7-5"
  29#define M10V_PLL9               "pll9"
  30#define M10V_PLL10              "pll10"
  31#define M10V_PLL10DIV2          "pll10-2"
  32#define M10V_PLL11              "pll11"
  33
  34#define M10V_SPI_PARENT0        "spi-parent0"
  35#define M10V_SPI_PARENT1        "spi-parent1"
  36#define M10V_SPI_PARENT2        "spi-parent2"
  37#define M10V_UHS1CLK2_PARENT0   "uhs1clk2-parent0"
  38#define M10V_UHS1CLK2_PARENT1   "uhs1clk2-parent1"
  39#define M10V_UHS1CLK2_PARENT2   "uhs1clk2-parent2"
  40#define M10V_UHS1CLK1_PARENT0   "uhs1clk1-parent0"
  41#define M10V_UHS1CLK1_PARENT1   "uhs1clk1-parent1"
  42#define M10V_NFCLK_PARENT0      "nfclk-parent0"
  43#define M10V_NFCLK_PARENT1      "nfclk-parent1"
  44#define M10V_NFCLK_PARENT2      "nfclk-parent2"
  45#define M10V_NFCLK_PARENT3      "nfclk-parent3"
  46#define M10V_NFCLK_PARENT4      "nfclk-parent4"
  47#define M10V_NFCLK_PARENT5      "nfclk-parent5"
  48
  49#define M10V_DCHREQ             1
  50#define M10V_UPOLL_RATE         1
  51#define M10V_UTIMEOUT           250
  52
  53#define M10V_EMMCCLK_ID         0
  54#define M10V_ACLK_ID            1
  55#define M10V_HCLK_ID            2
  56#define M10V_PCLK_ID            3
  57#define M10V_RCLK_ID            4
  58#define M10V_SPICLK_ID          5
  59#define M10V_NFCLK_ID           6
  60#define M10V_UHS1CLK2_ID        7
  61#define M10V_NUM_CLKS           8
  62
  63#define to_m10v_div(_hw)        container_of(_hw, struct m10v_clk_divider, hw)
  64
  65static struct clk_hw_onecell_data *m10v_clk_data;
  66
  67static DEFINE_SPINLOCK(m10v_crglock);
  68
  69struct m10v_clk_div_factors {
  70        const char                      *name;
  71        const char                      *parent_name;
  72        u32                             offset;
  73        u8                              shift;
  74        u8                              width;
  75        const struct clk_div_table      *table;
  76        unsigned long                   div_flags;
  77        int                             onecell_idx;
  78};
  79
  80struct m10v_clk_div_fixed_data {
  81        const char      *name;
  82        const char      *parent_name;
  83        u8              div;
  84        u8              mult;
  85        int             onecell_idx;
  86};
  87
  88struct m10v_clk_mux_factors {
  89        const char              *name;
  90        const char * const      *parent_names;
  91        u8                      num_parents;
  92        u32                     offset;
  93        u8                      shift;
  94        u8                      mask;
  95        u32                     *table;
  96        unsigned long           mux_flags;
  97        int                     onecell_idx;
  98};
  99
 100static const struct clk_div_table emmcclk_table[] = {
 101        { .val = 0, .div = 8 },
 102        { .val = 1, .div = 9 },
 103        { .val = 2, .div = 10 },
 104        { .val = 3, .div = 15 },
 105        { .div = 0 },
 106};
 107
 108static const struct clk_div_table mclk400_table[] = {
 109        { .val = 1, .div = 2 },
 110        { .val = 3, .div = 4 },
 111        { .div = 0 },
 112};
 113
 114static const struct clk_div_table mclk200_table[] = {
 115        { .val = 3, .div = 4 },
 116        { .val = 7, .div = 8 },
 117        { .div = 0 },
 118};
 119
 120static const struct clk_div_table aclk400_table[] = {
 121        { .val = 1, .div = 2 },
 122        { .val = 3, .div = 4 },
 123        { .div = 0 },
 124};
 125
 126static const struct clk_div_table aclk300_table[] = {
 127        { .val = 0, .div = 2 },
 128        { .val = 1, .div = 3 },
 129        { .div = 0 },
 130};
 131
 132static const struct clk_div_table aclk_table[] = {
 133        { .val = 3, .div = 4 },
 134        { .val = 7, .div = 8 },
 135        { .div = 0 },
 136};
 137
 138static const struct clk_div_table aclkexs_table[] = {
 139        { .val = 3, .div = 4 },
 140        { .val = 4, .div = 5 },
 141        { .val = 5, .div = 6 },
 142        { .val = 7, .div = 8 },
 143        { .div = 0 },
 144};
 145
 146static const struct clk_div_table hclk_table[] = {
 147        { .val = 7, .div = 8 },
 148        { .val = 15, .div = 16 },
 149        { .div = 0 },
 150};
 151
 152static const struct clk_div_table hclkbmh_table[] = {
 153        { .val = 3, .div = 4 },
 154        { .val = 7, .div = 8 },
 155        { .div = 0 },
 156};
 157
 158static const struct clk_div_table pclk_table[] = {
 159        { .val = 15, .div = 16 },
 160        { .val = 31, .div = 32 },
 161        { .div = 0 },
 162};
 163
 164static const struct clk_div_table rclk_table[] = {
 165        { .val = 0, .div = 8 },
 166        { .val = 1, .div = 16 },
 167        { .val = 2, .div = 24 },
 168        { .val = 3, .div = 32 },
 169        { .div = 0 },
 170};
 171
 172static const struct clk_div_table uhs1clk0_table[] = {
 173        { .val = 0, .div = 2 },
 174        { .val = 1, .div = 3 },
 175        { .val = 2, .div = 4 },
 176        { .val = 3, .div = 8 },
 177        { .val = 4, .div = 16 },
 178        { .div = 0 },
 179};
 180
 181static const struct clk_div_table uhs2clk_table[] = {
 182        { .val = 0, .div = 9 },
 183        { .val = 1, .div = 10 },
 184        { .val = 2, .div = 11 },
 185        { .val = 3, .div = 12 },
 186        { .val = 4, .div = 13 },
 187        { .val = 5, .div = 14 },
 188        { .val = 6, .div = 16 },
 189        { .val = 7, .div = 18 },
 190        { .div = 0 },
 191};
 192
 193static u32 spi_mux_table[] = {0, 1, 2};
 194static const char * const spi_mux_names[] = {
 195        M10V_SPI_PARENT0, M10V_SPI_PARENT1, M10V_SPI_PARENT2
 196};
 197
 198static u32 uhs1clk2_mux_table[] = {2, 3, 4, 8};
 199static const char * const uhs1clk2_mux_names[] = {
 200        M10V_UHS1CLK2_PARENT0, M10V_UHS1CLK2_PARENT1,
 201        M10V_UHS1CLK2_PARENT2, M10V_PLL6DIV2
 202};
 203
 204static u32 uhs1clk1_mux_table[] = {3, 4, 8};
 205static const char * const uhs1clk1_mux_names[] = {
 206        M10V_UHS1CLK1_PARENT0, M10V_UHS1CLK1_PARENT1, M10V_PLL6DIV2
 207};
 208
 209static u32 nfclk_mux_table[] = {0, 1, 2, 3, 4, 8};
 210static const char * const nfclk_mux_names[] = {
 211        M10V_NFCLK_PARENT0, M10V_NFCLK_PARENT1, M10V_NFCLK_PARENT2,
 212        M10V_NFCLK_PARENT3, M10V_NFCLK_PARENT4, M10V_NFCLK_PARENT5
 213};
 214
 215static const struct m10v_clk_div_fixed_data m10v_pll_fixed_data[] = {
 216        {M10V_PLL1, NULL, 1, 40, -1},
 217        {M10V_PLL2, NULL, 1, 30, -1},
 218        {M10V_PLL6, NULL, 1, 35, -1},
 219        {M10V_PLL7, NULL, 1, 40, -1},
 220        {M10V_PLL9, NULL, 1, 33, -1},
 221        {M10V_PLL10, NULL, 5, 108, -1},
 222        {M10V_PLL10DIV2, M10V_PLL10, 2, 1, -1},
 223        {M10V_PLL11, NULL, 2, 75, -1},
 224};
 225
 226static const struct m10v_clk_div_fixed_data m10v_div_fixed_data[] = {
 227        {"usb2", NULL, 2, 1, -1},
 228        {"pcisuppclk", NULL, 20, 1, -1},
 229        {M10V_PLL1DIV2, M10V_PLL1, 2, 1, -1},
 230        {M10V_PLL2DIV2, M10V_PLL2, 2, 1, -1},
 231        {M10V_PLL6DIV2, M10V_PLL6, 2, 1, -1},
 232        {M10V_PLL6DIV3, M10V_PLL6, 3, 1, -1},
 233        {M10V_PLL7DIV2, M10V_PLL7, 2, 1, -1},
 234        {M10V_PLL7DIV5, M10V_PLL7, 5, 1, -1},
 235        {"ca7wd", M10V_PLL2DIV2, 12, 1, -1},
 236        {"pclkca7wd", M10V_PLL1DIV2, 16, 1, -1},
 237        {M10V_SPI_PARENT0, M10V_PLL10DIV2, 2, 1, -1},
 238        {M10V_SPI_PARENT1, M10V_PLL10DIV2, 4, 1, -1},
 239        {M10V_SPI_PARENT2, M10V_PLL7DIV2, 8, 1, -1},
 240        {M10V_UHS1CLK2_PARENT0, M10V_PLL7, 4, 1, -1},
 241        {M10V_UHS1CLK2_PARENT1, M10V_PLL7, 8, 1, -1},
 242        {M10V_UHS1CLK2_PARENT2, M10V_PLL7, 16, 1, -1},
 243        {M10V_UHS1CLK1_PARENT0, M10V_PLL7, 8, 1, -1},
 244        {M10V_UHS1CLK1_PARENT1, M10V_PLL7, 16, 1, -1},
 245        {M10V_NFCLK_PARENT0, M10V_PLL7DIV2, 8, 1, -1},
 246        {M10V_NFCLK_PARENT1, M10V_PLL7DIV2, 10, 1, -1},
 247        {M10V_NFCLK_PARENT2, M10V_PLL7DIV2, 13, 1, -1},
 248        {M10V_NFCLK_PARENT3, M10V_PLL7DIV2, 16, 1, -1},
 249        {M10V_NFCLK_PARENT4, M10V_PLL7DIV2, 40, 1, -1},
 250        {M10V_NFCLK_PARENT5, M10V_PLL7DIV5, 10, 1, -1},
 251};
 252
 253static const struct m10v_clk_div_factors m10v_div_factor_data[] = {
 254        {"emmc", M10V_PLL11, CLKSEL(1), 28, 3, emmcclk_table, 0,
 255                M10V_EMMCCLK_ID},
 256        {"mclk400", M10V_PLL1DIV2, CLKSEL(10), 7, 3, mclk400_table, 0, -1},
 257        {"mclk200", M10V_PLL1DIV2, CLKSEL(10), 3, 4, mclk200_table, 0, -1},
 258        {"aclk400", M10V_PLL1DIV2, CLKSEL(10), 0, 3, aclk400_table, 0, -1},
 259        {"aclk300", M10V_PLL2DIV2, CLKSEL(12), 0, 2, aclk300_table, 0, -1},
 260        {"aclk", M10V_PLL1DIV2, CLKSEL(9), 20, 4, aclk_table, 0, M10V_ACLK_ID},
 261        {"aclkexs", M10V_PLL1DIV2, CLKSEL(9), 16, 4, aclkexs_table, 0, -1},
 262        {"hclk", M10V_PLL1DIV2, CLKSEL(9), 7, 5, hclk_table, 0, M10V_HCLK_ID},
 263        {"hclkbmh", M10V_PLL1DIV2, CLKSEL(9), 12, 4, hclkbmh_table, 0, -1},
 264        {"pclk", M10V_PLL1DIV2, CLKSEL(9), 0, 7, pclk_table, 0, M10V_PCLK_ID},
 265        {"uhs1clk0", M10V_PLL7, CLKSEL(1), 3, 5, uhs1clk0_table, 0, -1},
 266        {"uhs2clk", M10V_PLL6DIV3, CLKSEL(1), 18, 4, uhs2clk_table, 0, -1},
 267};
 268
 269static const struct m10v_clk_mux_factors m10v_mux_factor_data[] = {
 270        {"spi", spi_mux_names, ARRAY_SIZE(spi_mux_names),
 271                CLKSEL(8), 3, 7, spi_mux_table, 0, M10V_SPICLK_ID},
 272        {"uhs1clk2", uhs1clk2_mux_names, ARRAY_SIZE(uhs1clk2_mux_names),
 273                CLKSEL(1), 13, 31, uhs1clk2_mux_table, 0, M10V_UHS1CLK2_ID},
 274        {"uhs1clk1", uhs1clk1_mux_names, ARRAY_SIZE(uhs1clk1_mux_names),
 275                CLKSEL(1), 8, 31, uhs1clk1_mux_table, 0, -1},
 276        {"nfclk", nfclk_mux_names, ARRAY_SIZE(nfclk_mux_names),
 277                CLKSEL(1), 22, 127, nfclk_mux_table, 0, M10V_NFCLK_ID},
 278};
 279
 280static u8 m10v_mux_get_parent(struct clk_hw *hw)
 281{
 282        struct clk_mux *mux = to_clk_mux(hw);
 283        u32 val;
 284
 285        val = readl(mux->reg) >> mux->shift;
 286        val &= mux->mask;
 287
 288        return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
 289}
 290
 291static int m10v_mux_set_parent(struct clk_hw *hw, u8 index)
 292{
 293        struct clk_mux *mux = to_clk_mux(hw);
 294        u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
 295        unsigned long flags = 0;
 296        u32 reg;
 297        u32 write_en = BIT(fls(mux->mask) - 1);
 298
 299        if (mux->lock)
 300                spin_lock_irqsave(mux->lock, flags);
 301        else
 302                __acquire(mux->lock);
 303
 304        reg = readl(mux->reg);
 305        reg &= ~(mux->mask << mux->shift);
 306
 307        val = (val | write_en) << mux->shift;
 308        reg |= val;
 309        writel(reg, mux->reg);
 310
 311        if (mux->lock)
 312                spin_unlock_irqrestore(mux->lock, flags);
 313        else
 314                __release(mux->lock);
 315
 316        return 0;
 317}
 318
 319static const struct clk_ops m10v_mux_ops = {
 320        .get_parent = m10v_mux_get_parent,
 321        .set_parent = m10v_mux_set_parent,
 322        .determine_rate = __clk_mux_determine_rate,
 323};
 324
 325static struct clk_hw *m10v_clk_hw_register_mux(struct device *dev,
 326                        const char *name, const char * const *parent_names,
 327                        u8 num_parents, unsigned long flags, void __iomem *reg,
 328                        u8 shift, u32 mask, u8 clk_mux_flags, u32 *table,
 329                        spinlock_t *lock)
 330{
 331        struct clk_mux *mux;
 332        struct clk_hw *hw;
 333        struct clk_init_data init;
 334        int ret;
 335
 336        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 337        if (!mux)
 338                return ERR_PTR(-ENOMEM);
 339
 340        init.name = name;
 341        init.ops = &m10v_mux_ops;
 342        init.flags = flags;
 343        init.parent_names = parent_names;
 344        init.num_parents = num_parents;
 345
 346        mux->reg = reg;
 347        mux->shift = shift;
 348        mux->mask = mask;
 349        mux->flags = clk_mux_flags;
 350        mux->lock = lock;
 351        mux->table = table;
 352        mux->hw.init = &init;
 353
 354        hw = &mux->hw;
 355        ret = clk_hw_register(dev, hw);
 356        if (ret) {
 357                kfree(mux);
 358                hw = ERR_PTR(ret);
 359        }
 360
 361        return hw;
 362
 363}
 364
 365struct m10v_clk_divider {
 366        struct clk_hw   hw;
 367        void __iomem    *reg;
 368        u8              shift;
 369        u8              width;
 370        u8              flags;
 371        const struct clk_div_table      *table;
 372        spinlock_t      *lock;
 373        void __iomem    *write_valid_reg;
 374};
 375
 376static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw *hw,
 377                unsigned long parent_rate)
 378{
 379        struct m10v_clk_divider *divider = to_m10v_div(hw);
 380        unsigned int val;
 381
 382        val = readl(divider->reg) >> divider->shift;
 383        val &= clk_div_mask(divider->width);
 384
 385        return divider_recalc_rate(hw, parent_rate, val, divider->table,
 386                                   divider->flags, divider->width);
 387}
 388
 389static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
 390                                unsigned long *prate)
 391{
 392        struct m10v_clk_divider *divider = to_m10v_div(hw);
 393
 394        /* if read only, just return current value */
 395        if (divider->flags & CLK_DIVIDER_READ_ONLY) {
 396                u32 val;
 397
 398                val = readl(divider->reg) >> divider->shift;
 399                val &= clk_div_mask(divider->width);
 400
 401                return divider_ro_round_rate(hw, rate, prate, divider->table,
 402                                             divider->width, divider->flags,
 403                                             val);
 404        }
 405
 406        return divider_round_rate(hw, rate, prate, divider->table,
 407                                  divider->width, divider->flags);
 408}
 409
 410static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 411                                unsigned long parent_rate)
 412{
 413        struct m10v_clk_divider *divider = to_m10v_div(hw);
 414        int value;
 415        unsigned long flags = 0;
 416        u32 val;
 417        u32 write_en = BIT(divider->width - 1);
 418
 419        value = divider_get_val(rate, parent_rate, divider->table,
 420                                divider->width, divider->flags);
 421        if (value < 0)
 422                return value;
 423
 424        if (divider->lock)
 425                spin_lock_irqsave(divider->lock, flags);
 426        else
 427                __acquire(divider->lock);
 428
 429        val = readl(divider->reg);
 430        val &= ~(clk_div_mask(divider->width) << divider->shift);
 431
 432        val |= ((u32)value | write_en) << divider->shift;
 433        writel(val, divider->reg);
 434
 435        if (divider->write_valid_reg) {
 436                writel(M10V_DCHREQ, divider->write_valid_reg);
 437                if (readl_poll_timeout(divider->write_valid_reg, val,
 438                        !val, M10V_UPOLL_RATE, M10V_UTIMEOUT))
 439                        pr_err("%s:%s couldn't stabilize\n",
 440                                __func__, clk_hw_get_name(hw));
 441        }
 442
 443        if (divider->lock)
 444                spin_unlock_irqrestore(divider->lock, flags);
 445        else
 446                __release(divider->lock);
 447
 448        return 0;
 449}
 450
 451static const struct clk_ops m10v_clk_divider_ops = {
 452        .recalc_rate = m10v_clk_divider_recalc_rate,
 453        .round_rate = m10v_clk_divider_round_rate,
 454        .set_rate = m10v_clk_divider_set_rate,
 455};
 456
 457static struct clk_hw *m10v_clk_hw_register_divider(struct device *dev,
 458                const char *name, const char *parent_name, unsigned long flags,
 459                void __iomem *reg, u8 shift, u8 width,
 460                u8 clk_divider_flags, const struct clk_div_table *table,
 461                spinlock_t *lock, void __iomem *write_valid_reg)
 462{
 463        struct m10v_clk_divider *div;
 464        struct clk_hw *hw;
 465        struct clk_init_data init;
 466        int ret;
 467
 468        div = kzalloc(sizeof(*div), GFP_KERNEL);
 469        if (!div)
 470                return ERR_PTR(-ENOMEM);
 471
 472        init.name = name;
 473        init.ops = &m10v_clk_divider_ops;
 474        init.flags = flags;
 475        init.parent_names = &parent_name;
 476        init.num_parents = 1;
 477
 478        div->reg = reg;
 479        div->shift = shift;
 480        div->width = width;
 481        div->flags = clk_divider_flags;
 482        div->lock = lock;
 483        div->hw.init = &init;
 484        div->table = table;
 485        div->write_valid_reg = write_valid_reg;
 486
 487        /* register the clock */
 488        hw = &div->hw;
 489        ret = clk_hw_register(dev, hw);
 490        if (ret) {
 491                kfree(div);
 492                hw = ERR_PTR(ret);
 493        }
 494
 495        return hw;
 496}
 497
 498static void m10v_reg_div_pre(const struct m10v_clk_div_factors *factors,
 499                             struct clk_hw_onecell_data *clk_data,
 500                             void __iomem *base)
 501{
 502        struct clk_hw *hw;
 503        void __iomem *write_valid_reg;
 504
 505        /*
 506         * The registers on CLKSEL(9) or CLKSEL(10) need additional
 507         * writing to become valid.
 508         */
 509        if ((factors->offset == CLKSEL(9)) || (factors->offset == CLKSEL(10)))
 510                write_valid_reg = base + CLKSEL(11);
 511        else
 512                write_valid_reg = NULL;
 513
 514        hw = m10v_clk_hw_register_divider(NULL, factors->name,
 515                                          factors->parent_name,
 516                                          CLK_SET_RATE_PARENT,
 517                                          base + factors->offset,
 518                                          factors->shift,
 519                                          factors->width, factors->div_flags,
 520                                          factors->table,
 521                                          &m10v_crglock, write_valid_reg);
 522
 523        if (factors->onecell_idx >= 0)
 524                clk_data->hws[factors->onecell_idx] = hw;
 525}
 526
 527static void m10v_reg_fixed_pre(const struct m10v_clk_div_fixed_data *factors,
 528                               struct clk_hw_onecell_data *clk_data,
 529                               const char *parent_name)
 530{
 531        struct clk_hw *hw;
 532        const char *pn = factors->parent_name ?
 533                                factors->parent_name : parent_name;
 534
 535        hw = clk_hw_register_fixed_factor(NULL, factors->name, pn, 0,
 536                                          factors->mult, factors->div);
 537
 538        if (factors->onecell_idx >= 0)
 539                clk_data->hws[factors->onecell_idx] = hw;
 540}
 541
 542static void m10v_reg_mux_pre(const struct m10v_clk_mux_factors *factors,
 543                               struct clk_hw_onecell_data *clk_data,
 544                               void __iomem *base)
 545{
 546        struct clk_hw *hw;
 547
 548        hw = m10v_clk_hw_register_mux(NULL, factors->name,
 549                                      factors->parent_names,
 550                                      factors->num_parents,
 551                                      CLK_SET_RATE_PARENT,
 552                                      base + factors->offset, factors->shift,
 553                                      factors->mask, factors->mux_flags,
 554                                      factors->table, &m10v_crglock);
 555
 556        if (factors->onecell_idx >= 0)
 557                clk_data->hws[factors->onecell_idx] = hw;
 558}
 559
 560static int m10v_clk_probe(struct platform_device *pdev)
 561{
 562        int id;
 563        struct resource *res;
 564        struct device *dev = &pdev->dev;
 565        struct device_node *np = dev->of_node;
 566        void __iomem *base;
 567        const char *parent_name;
 568
 569        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 570        base = devm_ioremap_resource(dev, res);
 571        if (IS_ERR(base))
 572                return PTR_ERR(base);
 573
 574        parent_name = of_clk_get_parent_name(np, 0);
 575
 576        for (id = 0; id < ARRAY_SIZE(m10v_div_factor_data); ++id)
 577                m10v_reg_div_pre(&m10v_div_factor_data[id],
 578                                 m10v_clk_data, base);
 579
 580        for (id = 0; id < ARRAY_SIZE(m10v_div_fixed_data); ++id)
 581                m10v_reg_fixed_pre(&m10v_div_fixed_data[id],
 582                                   m10v_clk_data, parent_name);
 583
 584        for (id = 0; id < ARRAY_SIZE(m10v_mux_factor_data); ++id)
 585                m10v_reg_mux_pre(&m10v_mux_factor_data[id],
 586                                 m10v_clk_data, base);
 587
 588        for (id = 0; id < M10V_NUM_CLKS; id++) {
 589                if (IS_ERR(m10v_clk_data->hws[id]))
 590                        return PTR_ERR(m10v_clk_data->hws[id]);
 591        }
 592
 593        return 0;
 594}
 595
 596static const struct of_device_id m10v_clk_dt_ids[] = {
 597        { .compatible = "socionext,milbeaut-m10v-ccu", },
 598        { }
 599};
 600
 601static struct platform_driver m10v_clk_driver = {
 602        .probe  = m10v_clk_probe,
 603        .driver = {
 604                .name = "m10v-ccu",
 605                .of_match_table = m10v_clk_dt_ids,
 606        },
 607};
 608builtin_platform_driver(m10v_clk_driver);
 609
 610static void __init m10v_cc_init(struct device_node *np)
 611{
 612        int id;
 613        void __iomem *base;
 614        const char *parent_name;
 615        struct clk_hw *hw;
 616
 617        m10v_clk_data = kzalloc(struct_size(m10v_clk_data, hws,
 618                                        M10V_NUM_CLKS),
 619                                        GFP_KERNEL);
 620
 621        if (!m10v_clk_data)
 622                return;
 623
 624        base = of_iomap(np, 0);
 625        if (!base) {
 626                kfree(m10v_clk_data);
 627                return;
 628        }
 629
 630        parent_name = of_clk_get_parent_name(np, 0);
 631        if (!parent_name) {
 632                kfree(m10v_clk_data);
 633                iounmap(base);
 634                return;
 635        }
 636
 637        /*
 638         * This way all clocks fetched before the platform device probes,
 639         * except those we assign here for early use, will be deferred.
 640         */
 641        for (id = 0; id < M10V_NUM_CLKS; id++)
 642                m10v_clk_data->hws[id] = ERR_PTR(-EPROBE_DEFER);
 643
 644        /*
 645         * PLLs are set by bootloader so this driver registers them as the
 646         * fixed factor.
 647         */
 648        for (id = 0; id < ARRAY_SIZE(m10v_pll_fixed_data); ++id)
 649                m10v_reg_fixed_pre(&m10v_pll_fixed_data[id],
 650                                   m10v_clk_data, parent_name);
 651
 652        /*
 653         * timer consumes "rclk" so it needs to register here.
 654         */
 655        hw = m10v_clk_hw_register_divider(NULL, "rclk", M10V_PLL10DIV2, 0,
 656                                        base + CLKSEL(1), 0, 3, 0, rclk_table,
 657                                        &m10v_crglock, NULL);
 658        m10v_clk_data->hws[M10V_RCLK_ID] = hw;
 659
 660        m10v_clk_data->num = M10V_NUM_CLKS;
 661        of_clk_add_hw_provider(np, of_clk_hw_onecell_get, m10v_clk_data);
 662}
 663CLK_OF_DECLARE_DRIVER(m10v_cc, "socionext,milbeaut-m10v-ccu", m10v_cc_init);
 664