Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018 Socionext Inc.
0004  * Copyright (C) 2016 Linaro Ltd.
0005  */
0006 
0007 #include <linux/clk-provider.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/iopoll.h>
0011 #include <linux/of_address.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/slab.h>
0014 #include <linux/spinlock.h>
0015 
0016 #define M10V_CLKSEL1        0x0
0017 #define CLKSEL(n)   (((n) - 1) * 4 + M10V_CLKSEL1)
0018 
0019 #define M10V_PLL1       "pll1"
0020 #define M10V_PLL1DIV2       "pll1-2"
0021 #define M10V_PLL2       "pll2"
0022 #define M10V_PLL2DIV2       "pll2-2"
0023 #define M10V_PLL6       "pll6"
0024 #define M10V_PLL6DIV2       "pll6-2"
0025 #define M10V_PLL6DIV3       "pll6-3"
0026 #define M10V_PLL7       "pll7"
0027 #define M10V_PLL7DIV2       "pll7-2"
0028 #define M10V_PLL7DIV5       "pll7-5"
0029 #define M10V_PLL9       "pll9"
0030 #define M10V_PLL10      "pll10"
0031 #define M10V_PLL10DIV2      "pll10-2"
0032 #define M10V_PLL11      "pll11"
0033 
0034 #define M10V_SPI_PARENT0    "spi-parent0"
0035 #define M10V_SPI_PARENT1    "spi-parent1"
0036 #define M10V_SPI_PARENT2    "spi-parent2"
0037 #define M10V_UHS1CLK2_PARENT0   "uhs1clk2-parent0"
0038 #define M10V_UHS1CLK2_PARENT1   "uhs1clk2-parent1"
0039 #define M10V_UHS1CLK2_PARENT2   "uhs1clk2-parent2"
0040 #define M10V_UHS1CLK1_PARENT0   "uhs1clk1-parent0"
0041 #define M10V_UHS1CLK1_PARENT1   "uhs1clk1-parent1"
0042 #define M10V_NFCLK_PARENT0  "nfclk-parent0"
0043 #define M10V_NFCLK_PARENT1  "nfclk-parent1"
0044 #define M10V_NFCLK_PARENT2  "nfclk-parent2"
0045 #define M10V_NFCLK_PARENT3  "nfclk-parent3"
0046 #define M10V_NFCLK_PARENT4  "nfclk-parent4"
0047 #define M10V_NFCLK_PARENT5  "nfclk-parent5"
0048 
0049 #define M10V_DCHREQ     1
0050 #define M10V_UPOLL_RATE     1
0051 #define M10V_UTIMEOUT       250
0052 
0053 #define M10V_EMMCCLK_ID     0
0054 #define M10V_ACLK_ID        1
0055 #define M10V_HCLK_ID        2
0056 #define M10V_PCLK_ID        3
0057 #define M10V_RCLK_ID        4
0058 #define M10V_SPICLK_ID      5
0059 #define M10V_NFCLK_ID       6
0060 #define M10V_UHS1CLK2_ID    7
0061 #define M10V_NUM_CLKS       8
0062 
0063 #define to_m10v_div(_hw)        container_of(_hw, struct m10v_clk_divider, hw)
0064 
0065 static struct clk_hw_onecell_data *m10v_clk_data;
0066 
0067 static DEFINE_SPINLOCK(m10v_crglock);
0068 
0069 struct m10v_clk_div_factors {
0070     const char          *name;
0071     const char          *parent_name;
0072     u32             offset;
0073     u8              shift;
0074     u8              width;
0075     const struct clk_div_table  *table;
0076     unsigned long           div_flags;
0077     int             onecell_idx;
0078 };
0079 
0080 struct m10v_clk_div_fixed_data {
0081     const char  *name;
0082     const char  *parent_name;
0083     u8      div;
0084     u8      mult;
0085     int     onecell_idx;
0086 };
0087 
0088 struct m10v_clk_mux_factors {
0089     const char      *name;
0090     const char * const  *parent_names;
0091     u8          num_parents;
0092     u32         offset;
0093     u8          shift;
0094     u8          mask;
0095     u32         *table;
0096     unsigned long       mux_flags;
0097     int         onecell_idx;
0098 };
0099 
0100 static const struct clk_div_table emmcclk_table[] = {
0101     { .val = 0, .div = 8 },
0102     { .val = 1, .div = 9 },
0103     { .val = 2, .div = 10 },
0104     { .val = 3, .div = 15 },
0105     { .div = 0 },
0106 };
0107 
0108 static const struct clk_div_table mclk400_table[] = {
0109     { .val = 1, .div = 2 },
0110     { .val = 3, .div = 4 },
0111     { .div = 0 },
0112 };
0113 
0114 static const struct clk_div_table mclk200_table[] = {
0115     { .val = 3, .div = 4 },
0116     { .val = 7, .div = 8 },
0117     { .div = 0 },
0118 };
0119 
0120 static const struct clk_div_table aclk400_table[] = {
0121     { .val = 1, .div = 2 },
0122     { .val = 3, .div = 4 },
0123     { .div = 0 },
0124 };
0125 
0126 static const struct clk_div_table aclk300_table[] = {
0127     { .val = 0, .div = 2 },
0128     { .val = 1, .div = 3 },
0129     { .div = 0 },
0130 };
0131 
0132 static const struct clk_div_table aclk_table[] = {
0133     { .val = 3, .div = 4 },
0134     { .val = 7, .div = 8 },
0135     { .div = 0 },
0136 };
0137 
0138 static const struct clk_div_table aclkexs_table[] = {
0139     { .val = 3, .div = 4 },
0140     { .val = 4, .div = 5 },
0141     { .val = 5, .div = 6 },
0142     { .val = 7, .div = 8 },
0143     { .div = 0 },
0144 };
0145 
0146 static const struct clk_div_table hclk_table[] = {
0147     { .val = 7, .div = 8 },
0148     { .val = 15, .div = 16 },
0149     { .div = 0 },
0150 };
0151 
0152 static const struct clk_div_table hclkbmh_table[] = {
0153     { .val = 3, .div = 4 },
0154     { .val = 7, .div = 8 },
0155     { .div = 0 },
0156 };
0157 
0158 static const struct clk_div_table pclk_table[] = {
0159     { .val = 15, .div = 16 },
0160     { .val = 31, .div = 32 },
0161     { .div = 0 },
0162 };
0163 
0164 static const struct clk_div_table rclk_table[] = {
0165     { .val = 0, .div = 8 },
0166     { .val = 1, .div = 16 },
0167     { .val = 2, .div = 24 },
0168     { .val = 3, .div = 32 },
0169     { .div = 0 },
0170 };
0171 
0172 static const struct clk_div_table uhs1clk0_table[] = {
0173     { .val = 0, .div = 2 },
0174     { .val = 1, .div = 3 },
0175     { .val = 2, .div = 4 },
0176     { .val = 3, .div = 8 },
0177     { .val = 4, .div = 16 },
0178     { .div = 0 },
0179 };
0180 
0181 static const struct clk_div_table uhs2clk_table[] = {
0182     { .val = 0, .div = 9 },
0183     { .val = 1, .div = 10 },
0184     { .val = 2, .div = 11 },
0185     { .val = 3, .div = 12 },
0186     { .val = 4, .div = 13 },
0187     { .val = 5, .div = 14 },
0188     { .val = 6, .div = 16 },
0189     { .val = 7, .div = 18 },
0190     { .div = 0 },
0191 };
0192 
0193 static u32 spi_mux_table[] = {0, 1, 2};
0194 static const char * const spi_mux_names[] = {
0195     M10V_SPI_PARENT0, M10V_SPI_PARENT1, M10V_SPI_PARENT2
0196 };
0197 
0198 static u32 uhs1clk2_mux_table[] = {2, 3, 4, 8};
0199 static const char * const uhs1clk2_mux_names[] = {
0200     M10V_UHS1CLK2_PARENT0, M10V_UHS1CLK2_PARENT1,
0201     M10V_UHS1CLK2_PARENT2, M10V_PLL6DIV2
0202 };
0203 
0204 static u32 uhs1clk1_mux_table[] = {3, 4, 8};
0205 static const char * const uhs1clk1_mux_names[] = {
0206     M10V_UHS1CLK1_PARENT0, M10V_UHS1CLK1_PARENT1, M10V_PLL6DIV2
0207 };
0208 
0209 static u32 nfclk_mux_table[] = {0, 1, 2, 3, 4, 8};
0210 static const char * const nfclk_mux_names[] = {
0211     M10V_NFCLK_PARENT0, M10V_NFCLK_PARENT1, M10V_NFCLK_PARENT2,
0212     M10V_NFCLK_PARENT3, M10V_NFCLK_PARENT4, M10V_NFCLK_PARENT5
0213 };
0214 
0215 static const struct m10v_clk_div_fixed_data m10v_pll_fixed_data[] = {
0216     {M10V_PLL1, NULL, 1, 40, -1},
0217     {M10V_PLL2, NULL, 1, 30, -1},
0218     {M10V_PLL6, NULL, 1, 35, -1},
0219     {M10V_PLL7, NULL, 1, 40, -1},
0220     {M10V_PLL9, NULL, 1, 33, -1},
0221     {M10V_PLL10, NULL, 5, 108, -1},
0222     {M10V_PLL10DIV2, M10V_PLL10, 2, 1, -1},
0223     {M10V_PLL11, NULL, 2, 75, -1},
0224 };
0225 
0226 static const struct m10v_clk_div_fixed_data m10v_div_fixed_data[] = {
0227     {"usb2", NULL, 2, 1, -1},
0228     {"pcisuppclk", NULL, 20, 1, -1},
0229     {M10V_PLL1DIV2, M10V_PLL1, 2, 1, -1},
0230     {M10V_PLL2DIV2, M10V_PLL2, 2, 1, -1},
0231     {M10V_PLL6DIV2, M10V_PLL6, 2, 1, -1},
0232     {M10V_PLL6DIV3, M10V_PLL6, 3, 1, -1},
0233     {M10V_PLL7DIV2, M10V_PLL7, 2, 1, -1},
0234     {M10V_PLL7DIV5, M10V_PLL7, 5, 1, -1},
0235     {"ca7wd", M10V_PLL2DIV2, 12, 1, -1},
0236     {"pclkca7wd", M10V_PLL1DIV2, 16, 1, -1},
0237     {M10V_SPI_PARENT0, M10V_PLL10DIV2, 2, 1, -1},
0238     {M10V_SPI_PARENT1, M10V_PLL10DIV2, 4, 1, -1},
0239     {M10V_SPI_PARENT2, M10V_PLL7DIV2, 8, 1, -1},
0240     {M10V_UHS1CLK2_PARENT0, M10V_PLL7, 4, 1, -1},
0241     {M10V_UHS1CLK2_PARENT1, M10V_PLL7, 8, 1, -1},
0242     {M10V_UHS1CLK2_PARENT2, M10V_PLL7, 16, 1, -1},
0243     {M10V_UHS1CLK1_PARENT0, M10V_PLL7, 8, 1, -1},
0244     {M10V_UHS1CLK1_PARENT1, M10V_PLL7, 16, 1, -1},
0245     {M10V_NFCLK_PARENT0, M10V_PLL7DIV2, 8, 1, -1},
0246     {M10V_NFCLK_PARENT1, M10V_PLL7DIV2, 10, 1, -1},
0247     {M10V_NFCLK_PARENT2, M10V_PLL7DIV2, 13, 1, -1},
0248     {M10V_NFCLK_PARENT3, M10V_PLL7DIV2, 16, 1, -1},
0249     {M10V_NFCLK_PARENT4, M10V_PLL7DIV2, 40, 1, -1},
0250     {M10V_NFCLK_PARENT5, M10V_PLL7DIV5, 10, 1, -1},
0251 };
0252 
0253 static const struct m10v_clk_div_factors m10v_div_factor_data[] = {
0254     {"emmc", M10V_PLL11, CLKSEL(1), 28, 3, emmcclk_table, 0,
0255         M10V_EMMCCLK_ID},
0256     {"mclk400", M10V_PLL1DIV2, CLKSEL(10), 7, 3, mclk400_table, 0, -1},
0257     {"mclk200", M10V_PLL1DIV2, CLKSEL(10), 3, 4, mclk200_table, 0, -1},
0258     {"aclk400", M10V_PLL1DIV2, CLKSEL(10), 0, 3, aclk400_table, 0, -1},
0259     {"aclk300", M10V_PLL2DIV2, CLKSEL(12), 0, 2, aclk300_table, 0, -1},
0260     {"aclk", M10V_PLL1DIV2, CLKSEL(9), 20, 4, aclk_table, 0, M10V_ACLK_ID},
0261     {"aclkexs", M10V_PLL1DIV2, CLKSEL(9), 16, 4, aclkexs_table, 0, -1},
0262     {"hclk", M10V_PLL1DIV2, CLKSEL(9), 7, 5, hclk_table, 0, M10V_HCLK_ID},
0263     {"hclkbmh", M10V_PLL1DIV2, CLKSEL(9), 12, 4, hclkbmh_table, 0, -1},
0264     {"pclk", M10V_PLL1DIV2, CLKSEL(9), 0, 7, pclk_table, 0, M10V_PCLK_ID},
0265     {"uhs1clk0", M10V_PLL7, CLKSEL(1), 3, 5, uhs1clk0_table, 0, -1},
0266     {"uhs2clk", M10V_PLL6DIV3, CLKSEL(1), 18, 4, uhs2clk_table, 0, -1},
0267 };
0268 
0269 static const struct m10v_clk_mux_factors m10v_mux_factor_data[] = {
0270     {"spi", spi_mux_names, ARRAY_SIZE(spi_mux_names),
0271         CLKSEL(8), 3, 7, spi_mux_table, 0, M10V_SPICLK_ID},
0272     {"uhs1clk2", uhs1clk2_mux_names, ARRAY_SIZE(uhs1clk2_mux_names),
0273         CLKSEL(1), 13, 31, uhs1clk2_mux_table, 0, M10V_UHS1CLK2_ID},
0274     {"uhs1clk1", uhs1clk1_mux_names, ARRAY_SIZE(uhs1clk1_mux_names),
0275         CLKSEL(1), 8, 31, uhs1clk1_mux_table, 0, -1},
0276     {"nfclk", nfclk_mux_names, ARRAY_SIZE(nfclk_mux_names),
0277         CLKSEL(1), 22, 127, nfclk_mux_table, 0, M10V_NFCLK_ID},
0278 };
0279 
0280 static u8 m10v_mux_get_parent(struct clk_hw *hw)
0281 {
0282     struct clk_mux *mux = to_clk_mux(hw);
0283     u32 val;
0284 
0285     val = readl(mux->reg) >> mux->shift;
0286     val &= mux->mask;
0287 
0288     return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
0289 }
0290 
0291 static int m10v_mux_set_parent(struct clk_hw *hw, u8 index)
0292 {
0293     struct clk_mux *mux = to_clk_mux(hw);
0294     u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
0295     unsigned long flags = 0;
0296     u32 reg;
0297     u32 write_en = BIT(fls(mux->mask) - 1);
0298 
0299     if (mux->lock)
0300         spin_lock_irqsave(mux->lock, flags);
0301     else
0302         __acquire(mux->lock);
0303 
0304     reg = readl(mux->reg);
0305     reg &= ~(mux->mask << mux->shift);
0306 
0307     val = (val | write_en) << mux->shift;
0308     reg |= val;
0309     writel(reg, mux->reg);
0310 
0311     if (mux->lock)
0312         spin_unlock_irqrestore(mux->lock, flags);
0313     else
0314         __release(mux->lock);
0315 
0316     return 0;
0317 }
0318 
0319 static const struct clk_ops m10v_mux_ops = {
0320     .get_parent = m10v_mux_get_parent,
0321     .set_parent = m10v_mux_set_parent,
0322     .determine_rate = __clk_mux_determine_rate,
0323 };
0324 
0325 static struct clk_hw *m10v_clk_hw_register_mux(struct device *dev,
0326             const char *name, const char * const *parent_names,
0327             u8 num_parents, unsigned long flags, void __iomem *reg,
0328             u8 shift, u32 mask, u8 clk_mux_flags, u32 *table,
0329             spinlock_t *lock)
0330 {
0331     struct clk_mux *mux;
0332     struct clk_hw *hw;
0333     struct clk_init_data init;
0334     int ret;
0335 
0336     mux = kzalloc(sizeof(*mux), GFP_KERNEL);
0337     if (!mux)
0338         return ERR_PTR(-ENOMEM);
0339 
0340     init.name = name;
0341     init.ops = &m10v_mux_ops;
0342     init.flags = flags;
0343     init.parent_names = parent_names;
0344     init.num_parents = num_parents;
0345 
0346     mux->reg = reg;
0347     mux->shift = shift;
0348     mux->mask = mask;
0349     mux->flags = clk_mux_flags;
0350     mux->lock = lock;
0351     mux->table = table;
0352     mux->hw.init = &init;
0353 
0354     hw = &mux->hw;
0355     ret = clk_hw_register(dev, hw);
0356     if (ret) {
0357         kfree(mux);
0358         hw = ERR_PTR(ret);
0359     }
0360 
0361     return hw;
0362 
0363 }
0364 
0365 struct m10v_clk_divider {
0366     struct clk_hw   hw;
0367     void __iomem    *reg;
0368     u8      shift;
0369     u8      width;
0370     u8      flags;
0371     const struct clk_div_table  *table;
0372     spinlock_t  *lock;
0373     void __iomem    *write_valid_reg;
0374 };
0375 
0376 static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw *hw,
0377         unsigned long parent_rate)
0378 {
0379     struct m10v_clk_divider *divider = to_m10v_div(hw);
0380     unsigned int val;
0381 
0382     val = readl(divider->reg) >> divider->shift;
0383     val &= clk_div_mask(divider->width);
0384 
0385     return divider_recalc_rate(hw, parent_rate, val, divider->table,
0386                    divider->flags, divider->width);
0387 }
0388 
0389 static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
0390                 unsigned long *prate)
0391 {
0392     struct m10v_clk_divider *divider = to_m10v_div(hw);
0393 
0394     /* if read only, just return current value */
0395     if (divider->flags & CLK_DIVIDER_READ_ONLY) {
0396         u32 val;
0397 
0398         val = readl(divider->reg) >> divider->shift;
0399         val &= clk_div_mask(divider->width);
0400 
0401         return divider_ro_round_rate(hw, rate, prate, divider->table,
0402                          divider->width, divider->flags,
0403                          val);
0404     }
0405 
0406     return divider_round_rate(hw, rate, prate, divider->table,
0407                   divider->width, divider->flags);
0408 }
0409 
0410 static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
0411                 unsigned long parent_rate)
0412 {
0413     struct m10v_clk_divider *divider = to_m10v_div(hw);
0414     int value;
0415     unsigned long flags = 0;
0416     u32 val;
0417     u32 write_en = BIT(divider->width - 1);
0418 
0419     value = divider_get_val(rate, parent_rate, divider->table,
0420                 divider->width, divider->flags);
0421     if (value < 0)
0422         return value;
0423 
0424     if (divider->lock)
0425         spin_lock_irqsave(divider->lock, flags);
0426     else
0427         __acquire(divider->lock);
0428 
0429     val = readl(divider->reg);
0430     val &= ~(clk_div_mask(divider->width) << divider->shift);
0431 
0432     val |= ((u32)value | write_en) << divider->shift;
0433     writel(val, divider->reg);
0434 
0435     if (divider->write_valid_reg) {
0436         writel(M10V_DCHREQ, divider->write_valid_reg);
0437         if (readl_poll_timeout(divider->write_valid_reg, val,
0438             !val, M10V_UPOLL_RATE, M10V_UTIMEOUT))
0439             pr_err("%s:%s couldn't stabilize\n",
0440                 __func__, clk_hw_get_name(hw));
0441     }
0442 
0443     if (divider->lock)
0444         spin_unlock_irqrestore(divider->lock, flags);
0445     else
0446         __release(divider->lock);
0447 
0448     return 0;
0449 }
0450 
0451 static const struct clk_ops m10v_clk_divider_ops = {
0452     .recalc_rate = m10v_clk_divider_recalc_rate,
0453     .round_rate = m10v_clk_divider_round_rate,
0454     .set_rate = m10v_clk_divider_set_rate,
0455 };
0456 
0457 static struct clk_hw *m10v_clk_hw_register_divider(struct device *dev,
0458         const char *name, const char *parent_name, unsigned long flags,
0459         void __iomem *reg, u8 shift, u8 width,
0460         u8 clk_divider_flags, const struct clk_div_table *table,
0461         spinlock_t *lock, void __iomem *write_valid_reg)
0462 {
0463     struct m10v_clk_divider *div;
0464     struct clk_hw *hw;
0465     struct clk_init_data init;
0466     int ret;
0467 
0468     div = kzalloc(sizeof(*div), GFP_KERNEL);
0469     if (!div)
0470         return ERR_PTR(-ENOMEM);
0471 
0472     init.name = name;
0473     init.ops = &m10v_clk_divider_ops;
0474     init.flags = flags;
0475     init.parent_names = &parent_name;
0476     init.num_parents = 1;
0477 
0478     div->reg = reg;
0479     div->shift = shift;
0480     div->width = width;
0481     div->flags = clk_divider_flags;
0482     div->lock = lock;
0483     div->hw.init = &init;
0484     div->table = table;
0485     div->write_valid_reg = write_valid_reg;
0486 
0487     /* register the clock */
0488     hw = &div->hw;
0489     ret = clk_hw_register(dev, hw);
0490     if (ret) {
0491         kfree(div);
0492         hw = ERR_PTR(ret);
0493     }
0494 
0495     return hw;
0496 }
0497 
0498 static void m10v_reg_div_pre(const struct m10v_clk_div_factors *factors,
0499                  struct clk_hw_onecell_data *clk_data,
0500                  void __iomem *base)
0501 {
0502     struct clk_hw *hw;
0503     void __iomem *write_valid_reg;
0504 
0505     /*
0506      * The registers on CLKSEL(9) or CLKSEL(10) need additional
0507      * writing to become valid.
0508      */
0509     if ((factors->offset == CLKSEL(9)) || (factors->offset == CLKSEL(10)))
0510         write_valid_reg = base + CLKSEL(11);
0511     else
0512         write_valid_reg = NULL;
0513 
0514     hw = m10v_clk_hw_register_divider(NULL, factors->name,
0515                       factors->parent_name,
0516                       CLK_SET_RATE_PARENT,
0517                       base + factors->offset,
0518                       factors->shift,
0519                       factors->width, factors->div_flags,
0520                       factors->table,
0521                       &m10v_crglock, write_valid_reg);
0522 
0523     if (factors->onecell_idx >= 0)
0524         clk_data->hws[factors->onecell_idx] = hw;
0525 }
0526 
0527 static void m10v_reg_fixed_pre(const struct m10v_clk_div_fixed_data *factors,
0528                    struct clk_hw_onecell_data *clk_data,
0529                    const char *parent_name)
0530 {
0531     struct clk_hw *hw;
0532     const char *pn = factors->parent_name ?
0533                 factors->parent_name : parent_name;
0534 
0535     hw = clk_hw_register_fixed_factor(NULL, factors->name, pn, 0,
0536                       factors->mult, factors->div);
0537 
0538     if (factors->onecell_idx >= 0)
0539         clk_data->hws[factors->onecell_idx] = hw;
0540 }
0541 
0542 static void m10v_reg_mux_pre(const struct m10v_clk_mux_factors *factors,
0543                    struct clk_hw_onecell_data *clk_data,
0544                    void __iomem *base)
0545 {
0546     struct clk_hw *hw;
0547 
0548     hw = m10v_clk_hw_register_mux(NULL, factors->name,
0549                       factors->parent_names,
0550                       factors->num_parents,
0551                       CLK_SET_RATE_PARENT,
0552                       base + factors->offset, factors->shift,
0553                       factors->mask, factors->mux_flags,
0554                       factors->table, &m10v_crglock);
0555 
0556     if (factors->onecell_idx >= 0)
0557         clk_data->hws[factors->onecell_idx] = hw;
0558 }
0559 
0560 static int m10v_clk_probe(struct platform_device *pdev)
0561 {
0562     int id;
0563     struct resource *res;
0564     struct device *dev = &pdev->dev;
0565     struct device_node *np = dev->of_node;
0566     void __iomem *base;
0567     const char *parent_name;
0568 
0569     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0570     base = devm_ioremap_resource(dev, res);
0571     if (IS_ERR(base))
0572         return PTR_ERR(base);
0573 
0574     parent_name = of_clk_get_parent_name(np, 0);
0575 
0576     for (id = 0; id < ARRAY_SIZE(m10v_div_factor_data); ++id)
0577         m10v_reg_div_pre(&m10v_div_factor_data[id],
0578                  m10v_clk_data, base);
0579 
0580     for (id = 0; id < ARRAY_SIZE(m10v_div_fixed_data); ++id)
0581         m10v_reg_fixed_pre(&m10v_div_fixed_data[id],
0582                    m10v_clk_data, parent_name);
0583 
0584     for (id = 0; id < ARRAY_SIZE(m10v_mux_factor_data); ++id)
0585         m10v_reg_mux_pre(&m10v_mux_factor_data[id],
0586                  m10v_clk_data, base);
0587 
0588     for (id = 0; id < M10V_NUM_CLKS; id++) {
0589         if (IS_ERR(m10v_clk_data->hws[id]))
0590             return PTR_ERR(m10v_clk_data->hws[id]);
0591     }
0592 
0593     return 0;
0594 }
0595 
0596 static const struct of_device_id m10v_clk_dt_ids[] = {
0597     { .compatible = "socionext,milbeaut-m10v-ccu", },
0598     { }
0599 };
0600 
0601 static struct platform_driver m10v_clk_driver = {
0602     .probe  = m10v_clk_probe,
0603     .driver = {
0604         .name = "m10v-ccu",
0605         .of_match_table = m10v_clk_dt_ids,
0606     },
0607 };
0608 builtin_platform_driver(m10v_clk_driver);
0609 
0610 static void __init m10v_cc_init(struct device_node *np)
0611 {
0612     int id;
0613     void __iomem *base;
0614     const char *parent_name;
0615     struct clk_hw *hw;
0616 
0617     m10v_clk_data = kzalloc(struct_size(m10v_clk_data, hws,
0618                     M10V_NUM_CLKS),
0619                     GFP_KERNEL);
0620 
0621     if (!m10v_clk_data)
0622         return;
0623 
0624     base = of_iomap(np, 0);
0625     if (!base) {
0626         kfree(m10v_clk_data);
0627         return;
0628     }
0629 
0630     parent_name = of_clk_get_parent_name(np, 0);
0631     if (!parent_name) {
0632         kfree(m10v_clk_data);
0633         iounmap(base);
0634         return;
0635     }
0636 
0637     /*
0638      * This way all clocks fetched before the platform device probes,
0639      * except those we assign here for early use, will be deferred.
0640      */
0641     for (id = 0; id < M10V_NUM_CLKS; id++)
0642         m10v_clk_data->hws[id] = ERR_PTR(-EPROBE_DEFER);
0643 
0644     /*
0645      * PLLs are set by bootloader so this driver registers them as the
0646      * fixed factor.
0647      */
0648     for (id = 0; id < ARRAY_SIZE(m10v_pll_fixed_data); ++id)
0649         m10v_reg_fixed_pre(&m10v_pll_fixed_data[id],
0650                    m10v_clk_data, parent_name);
0651 
0652     /*
0653      * timer consumes "rclk" so it needs to register here.
0654      */
0655     hw = m10v_clk_hw_register_divider(NULL, "rclk", M10V_PLL10DIV2, 0,
0656                     base + CLKSEL(1), 0, 3, 0, rclk_table,
0657                     &m10v_crglock, NULL);
0658     m10v_clk_data->hws[M10V_RCLK_ID] = hw;
0659 
0660     m10v_clk_data->num = M10V_NUM_CLKS;
0661     of_clk_add_hw_provider(np, of_clk_hw_onecell_get, m10v_clk_data);
0662 }
0663 CLK_OF_DECLARE_DRIVER(m10v_cc, "socionext,milbeaut-m10v-ccu", m10v_cc_init);