0001
0002
0003
0004
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
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
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
0507
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
0639
0640
0641 for (id = 0; id < M10V_NUM_CLKS; id++)
0642 m10v_clk_data->hws[id] = ERR_PTR(-EPROBE_DEFER);
0643
0644
0645
0646
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
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);