root/drivers/clk/clk-milbeaut.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. m10v_mux_get_parent
  2. m10v_mux_set_parent
  3. m10v_clk_hw_register_mux
  4. m10v_clk_divider_recalc_rate
  5. m10v_clk_divider_round_rate
  6. m10v_clk_divider_set_rate
  7. m10v_clk_hw_register_divider
  8. m10v_reg_div_pre
  9. m10v_reg_fixed_pre
  10. m10v_reg_mux_pre
  11. m10v_clk_probe
  12. m10v_cc_init

   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 
  65 static struct clk_hw_onecell_data *m10v_clk_data;
  66 
  67 static DEFINE_SPINLOCK(m10v_crglock);
  68 
  69 struct 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 
  80 struct 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 
  88 struct 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 
 100 static 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 
 108 static const struct clk_div_table mclk400_table[] = {
 109         { .val = 1, .div = 2 },
 110         { .val = 3, .div = 4 },
 111         { .div = 0 },
 112 };
 113 
 114 static const struct clk_div_table mclk200_table[] = {
 115         { .val = 3, .div = 4 },
 116         { .val = 7, .div = 8 },
 117         { .div = 0 },
 118 };
 119 
 120 static const struct clk_div_table aclk400_table[] = {
 121         { .val = 1, .div = 2 },
 122         { .val = 3, .div = 4 },
 123         { .div = 0 },
 124 };
 125 
 126 static const struct clk_div_table aclk300_table[] = {
 127         { .val = 0, .div = 2 },
 128         { .val = 1, .div = 3 },
 129         { .div = 0 },
 130 };
 131 
 132 static const struct clk_div_table aclk_table[] = {
 133         { .val = 3, .div = 4 },
 134         { .val = 7, .div = 8 },
 135         { .div = 0 },
 136 };
 137 
 138 static 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 
 146 static const struct clk_div_table hclk_table[] = {
 147         { .val = 7, .div = 8 },
 148         { .val = 15, .div = 16 },
 149         { .div = 0 },
 150 };
 151 
 152 static const struct clk_div_table hclkbmh_table[] = {
 153         { .val = 3, .div = 4 },
 154         { .val = 7, .div = 8 },
 155         { .div = 0 },
 156 };
 157 
 158 static const struct clk_div_table pclk_table[] = {
 159         { .val = 15, .div = 16 },
 160         { .val = 31, .div = 32 },
 161         { .div = 0 },
 162 };
 163 
 164 static 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 
 172 static 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 
 181 static 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 
 193 static u32 spi_mux_table[] = {0, 1, 2};
 194 static const char * const spi_mux_names[] = {
 195         M10V_SPI_PARENT0, M10V_SPI_PARENT1, M10V_SPI_PARENT2
 196 };
 197 
 198 static u32 uhs1clk2_mux_table[] = {2, 3, 4, 8};
 199 static const char * const uhs1clk2_mux_names[] = {
 200         M10V_UHS1CLK2_PARENT0, M10V_UHS1CLK2_PARENT1,
 201         M10V_UHS1CLK2_PARENT2, M10V_PLL6DIV2
 202 };
 203 
 204 static u32 uhs1clk1_mux_table[] = {3, 4, 8};
 205 static const char * const uhs1clk1_mux_names[] = {
 206         M10V_UHS1CLK1_PARENT0, M10V_UHS1CLK1_PARENT1, M10V_PLL6DIV2
 207 };
 208 
 209 static u32 nfclk_mux_table[] = {0, 1, 2, 3, 4, 8};
 210 static 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 
 215 static 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 
 226 static 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 
 253 static 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 
 269 static 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 
 280 static 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 
 291 static 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 
 319 static 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 
 325 static 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 
 365 struct 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 
 376 static 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 
 389 static 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 
 410 static 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 
 451 static 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 
 457 static 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 
 498 static 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 
 527 static 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 
 542 static 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 
 560 static 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 
 596 static const struct of_device_id m10v_clk_dt_ids[] = {
 597         { .compatible = "socionext,milbeaut-m10v-ccu", },
 598         { }
 599 };
 600 
 601 static 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 };
 608 builtin_platform_driver(m10v_clk_driver);
 609 
 610 static 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 }
 663 CLK_OF_DECLARE_DRIVER(m10v_cc, "socionext,milbeaut-m10v-ccu", m10v_cc_init);

/* [<][>][^][v][top][bottom][index][help] */