0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/clk-provider.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/of.h>
0015 #include <linux/of_address.h>
0016 #include <linux/slab.h>
0017 #include <linux/err.h>
0018 #include <linux/bitfield.h>
0019
0020 #include <dt-bindings/clock/nuvoton,npcm7xx-clock.h>
0021
0022 struct npcm7xx_clk_pll {
0023 struct clk_hw hw;
0024 void __iomem *pllcon;
0025 u8 flags;
0026 };
0027
0028 #define to_npcm7xx_clk_pll(_hw) container_of(_hw, struct npcm7xx_clk_pll, hw)
0029
0030 #define PLLCON_LOKI BIT(31)
0031 #define PLLCON_LOKS BIT(30)
0032 #define PLLCON_FBDV GENMASK(27, 16)
0033 #define PLLCON_OTDV2 GENMASK(15, 13)
0034 #define PLLCON_PWDEN BIT(12)
0035 #define PLLCON_OTDV1 GENMASK(10, 8)
0036 #define PLLCON_INDV GENMASK(5, 0)
0037
0038 static unsigned long npcm7xx_clk_pll_recalc_rate(struct clk_hw *hw,
0039 unsigned long parent_rate)
0040 {
0041 struct npcm7xx_clk_pll *pll = to_npcm7xx_clk_pll(hw);
0042 unsigned long fbdv, indv, otdv1, otdv2;
0043 unsigned int val;
0044 u64 ret;
0045
0046 if (parent_rate == 0) {
0047 pr_err("%s: parent rate is zero", __func__);
0048 return 0;
0049 }
0050
0051 val = readl_relaxed(pll->pllcon);
0052
0053 indv = FIELD_GET(PLLCON_INDV, val);
0054 fbdv = FIELD_GET(PLLCON_FBDV, val);
0055 otdv1 = FIELD_GET(PLLCON_OTDV1, val);
0056 otdv2 = FIELD_GET(PLLCON_OTDV2, val);
0057
0058 ret = (u64)parent_rate * fbdv;
0059 do_div(ret, indv * otdv1 * otdv2);
0060
0061 return ret;
0062 }
0063
0064 static const struct clk_ops npcm7xx_clk_pll_ops = {
0065 .recalc_rate = npcm7xx_clk_pll_recalc_rate,
0066 };
0067
0068 static struct clk_hw *
0069 npcm7xx_clk_register_pll(void __iomem *pllcon, const char *name,
0070 const char *parent_name, unsigned long flags)
0071 {
0072 struct npcm7xx_clk_pll *pll;
0073 struct clk_init_data init;
0074 struct clk_hw *hw;
0075 int ret;
0076
0077 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
0078 if (!pll)
0079 return ERR_PTR(-ENOMEM);
0080
0081 pr_debug("%s reg, name=%s, p=%s\n", __func__, name, parent_name);
0082
0083 init.name = name;
0084 init.ops = &npcm7xx_clk_pll_ops;
0085 init.parent_names = &parent_name;
0086 init.num_parents = 1;
0087 init.flags = flags;
0088
0089 pll->pllcon = pllcon;
0090 pll->hw.init = &init;
0091
0092 hw = &pll->hw;
0093
0094 ret = clk_hw_register(NULL, hw);
0095 if (ret) {
0096 kfree(pll);
0097 hw = ERR_PTR(ret);
0098 }
0099
0100 return hw;
0101 }
0102
0103 #define NPCM7XX_CLKEN1 (0x00)
0104 #define NPCM7XX_CLKEN2 (0x28)
0105 #define NPCM7XX_CLKEN3 (0x30)
0106 #define NPCM7XX_CLKSEL (0x04)
0107 #define NPCM7XX_CLKDIV1 (0x08)
0108 #define NPCM7XX_CLKDIV2 (0x2C)
0109 #define NPCM7XX_CLKDIV3 (0x58)
0110 #define NPCM7XX_PLLCON0 (0x0C)
0111 #define NPCM7XX_PLLCON1 (0x10)
0112 #define NPCM7XX_PLLCON2 (0x54)
0113 #define NPCM7XX_SWRSTR (0x14)
0114 #define NPCM7XX_IRQWAKECON (0x18)
0115 #define NPCM7XX_IRQWAKEFLAG (0x1C)
0116 #define NPCM7XX_IPSRST1 (0x20)
0117 #define NPCM7XX_IPSRST2 (0x24)
0118 #define NPCM7XX_IPSRST3 (0x34)
0119 #define NPCM7XX_WD0RCR (0x38)
0120 #define NPCM7XX_WD1RCR (0x3C)
0121 #define NPCM7XX_WD2RCR (0x40)
0122 #define NPCM7XX_SWRSTC1 (0x44)
0123 #define NPCM7XX_SWRSTC2 (0x48)
0124 #define NPCM7XX_SWRSTC3 (0x4C)
0125 #define NPCM7XX_SWRSTC4 (0x50)
0126 #define NPCM7XX_CORSTC (0x5C)
0127 #define NPCM7XX_PLLCONG (0x60)
0128 #define NPCM7XX_AHBCKFI (0x64)
0129 #define NPCM7XX_SECCNT (0x68)
0130 #define NPCM7XX_CNTR25M (0x6C)
0131
0132 struct npcm7xx_clk_gate_data {
0133 u32 reg;
0134 u8 bit_idx;
0135 const char *name;
0136 const char *parent_name;
0137 unsigned long flags;
0138
0139
0140
0141
0142
0143 int onecell_idx;
0144 };
0145
0146 struct npcm7xx_clk_mux_data {
0147 u8 shift;
0148 u8 mask;
0149 u32 *table;
0150 const char *name;
0151 const char * const *parent_names;
0152 u8 num_parents;
0153 unsigned long flags;
0154
0155
0156
0157
0158
0159 int onecell_idx;
0160
0161 };
0162
0163 struct npcm7xx_clk_div_fixed_data {
0164 u8 mult;
0165 u8 div;
0166 const char *name;
0167 const char *parent_name;
0168 u8 clk_divider_flags;
0169
0170
0171
0172
0173
0174 int onecell_idx;
0175 };
0176
0177
0178 struct npcm7xx_clk_div_data {
0179 u32 reg;
0180 u8 shift;
0181 u8 width;
0182 const char *name;
0183 const char *parent_name;
0184 u8 clk_divider_flags;
0185 unsigned long flags;
0186
0187
0188
0189
0190
0191 int onecell_idx;
0192 };
0193
0194 struct npcm7xx_clk_pll_data {
0195 u32 reg;
0196 const char *name;
0197 const char *parent_name;
0198 unsigned long flags;
0199
0200
0201
0202
0203
0204 int onecell_idx;
0205 };
0206
0207
0208
0209
0210
0211 #define NPCM7XX_CLK_S_REFCLK "refclk"
0212 #define NPCM7XX_CLK_S_SYSBYPCK "sysbypck"
0213 #define NPCM7XX_CLK_S_MCBYPCK "mcbypck"
0214 #define NPCM7XX_CLK_S_GFXBYPCK "gfxbypck"
0215 #define NPCM7XX_CLK_S_PLL0 "pll0"
0216 #define NPCM7XX_CLK_S_PLL1 "pll1"
0217 #define NPCM7XX_CLK_S_PLL1_DIV2 "pll1_div2"
0218 #define NPCM7XX_CLK_S_PLL2 "pll2"
0219 #define NPCM7XX_CLK_S_PLL_GFX "pll_gfx"
0220 #define NPCM7XX_CLK_S_PLL2_DIV2 "pll2_div2"
0221 #define NPCM7XX_CLK_S_PIX_MUX "gfx_pixel"
0222 #define NPCM7XX_CLK_S_GPRFSEL_MUX "gprfsel_mux"
0223 #define NPCM7XX_CLK_S_MC_MUX "mc_phy"
0224 #define NPCM7XX_CLK_S_CPU_MUX "cpu"
0225 #define NPCM7XX_CLK_S_MC "mc"
0226 #define NPCM7XX_CLK_S_AXI "axi"
0227 #define NPCM7XX_CLK_S_AHB "ahb"
0228 #define NPCM7XX_CLK_S_CLKOUT_MUX "clkout_mux"
0229 #define NPCM7XX_CLK_S_UART_MUX "uart_mux"
0230 #define NPCM7XX_CLK_S_TIM_MUX "timer_mux"
0231 #define NPCM7XX_CLK_S_SD_MUX "sd_mux"
0232 #define NPCM7XX_CLK_S_GFXM_MUX "gfxm_mux"
0233 #define NPCM7XX_CLK_S_SU_MUX "serial_usb_mux"
0234 #define NPCM7XX_CLK_S_DVC_MUX "dvc_mux"
0235 #define NPCM7XX_CLK_S_GFX_MUX "gfx_mux"
0236 #define NPCM7XX_CLK_S_GFX_PIXEL "gfx_pixel"
0237 #define NPCM7XX_CLK_S_SPI0 "spi0"
0238 #define NPCM7XX_CLK_S_SPI3 "spi3"
0239 #define NPCM7XX_CLK_S_SPIX "spix"
0240 #define NPCM7XX_CLK_S_APB1 "apb1"
0241 #define NPCM7XX_CLK_S_APB2 "apb2"
0242 #define NPCM7XX_CLK_S_APB3 "apb3"
0243 #define NPCM7XX_CLK_S_APB4 "apb4"
0244 #define NPCM7XX_CLK_S_APB5 "apb5"
0245 #define NPCM7XX_CLK_S_TOCK "tock"
0246 #define NPCM7XX_CLK_S_CLKOUT "clkout"
0247 #define NPCM7XX_CLK_S_UART "uart"
0248 #define NPCM7XX_CLK_S_TIMER "timer"
0249 #define NPCM7XX_CLK_S_MMC "mmc"
0250 #define NPCM7XX_CLK_S_SDHC "sdhc"
0251 #define NPCM7XX_CLK_S_ADC "adc"
0252 #define NPCM7XX_CLK_S_GFX "gfx0_gfx1_mem"
0253 #define NPCM7XX_CLK_S_USBIF "serial_usbif"
0254 #define NPCM7XX_CLK_S_USB_HOST "usb_host"
0255 #define NPCM7XX_CLK_S_USB_BRIDGE "usb_bridge"
0256 #define NPCM7XX_CLK_S_PCI "pci"
0257
0258 static u32 pll_mux_table[] = {0, 1, 2, 3};
0259 static const char * const pll_mux_parents[] __initconst = {
0260 NPCM7XX_CLK_S_PLL0,
0261 NPCM7XX_CLK_S_PLL1_DIV2,
0262 NPCM7XX_CLK_S_REFCLK,
0263 NPCM7XX_CLK_S_PLL2_DIV2,
0264 };
0265
0266 static u32 cpuck_mux_table[] = {0, 1, 2, 3};
0267 static const char * const cpuck_mux_parents[] __initconst = {
0268 NPCM7XX_CLK_S_PLL0,
0269 NPCM7XX_CLK_S_PLL1_DIV2,
0270 NPCM7XX_CLK_S_REFCLK,
0271 NPCM7XX_CLK_S_SYSBYPCK,
0272 };
0273
0274 static u32 pixcksel_mux_table[] = {0, 2};
0275 static const char * const pixcksel_mux_parents[] __initconst = {
0276 NPCM7XX_CLK_S_PLL_GFX,
0277 NPCM7XX_CLK_S_REFCLK,
0278 };
0279
0280 static u32 sucksel_mux_table[] = {2, 3};
0281 static const char * const sucksel_mux_parents[] __initconst = {
0282 NPCM7XX_CLK_S_REFCLK,
0283 NPCM7XX_CLK_S_PLL2_DIV2,
0284 };
0285
0286 static u32 mccksel_mux_table[] = {0, 2, 3};
0287 static const char * const mccksel_mux_parents[] __initconst = {
0288 NPCM7XX_CLK_S_PLL1_DIV2,
0289 NPCM7XX_CLK_S_REFCLK,
0290 NPCM7XX_CLK_S_MCBYPCK,
0291 };
0292
0293 static u32 clkoutsel_mux_table[] = {0, 1, 2, 3, 4};
0294 static const char * const clkoutsel_mux_parents[] __initconst = {
0295 NPCM7XX_CLK_S_PLL0,
0296 NPCM7XX_CLK_S_PLL1_DIV2,
0297 NPCM7XX_CLK_S_REFCLK,
0298 NPCM7XX_CLK_S_PLL_GFX,
0299 NPCM7XX_CLK_S_PLL2_DIV2,
0300 };
0301
0302 static u32 gfxmsel_mux_table[] = {2, 3};
0303 static const char * const gfxmsel_mux_parents[] __initconst = {
0304 NPCM7XX_CLK_S_REFCLK,
0305 NPCM7XX_CLK_S_PLL2_DIV2,
0306 };
0307
0308 static u32 dvcssel_mux_table[] = {2, 3};
0309 static const char * const dvcssel_mux_parents[] __initconst = {
0310 NPCM7XX_CLK_S_REFCLK,
0311 NPCM7XX_CLK_S_PLL2,
0312 };
0313
0314 static const struct npcm7xx_clk_pll_data npcm7xx_plls[] __initconst = {
0315 {NPCM7XX_PLLCON0, NPCM7XX_CLK_S_PLL0, NPCM7XX_CLK_S_REFCLK, 0, -1},
0316
0317 {NPCM7XX_PLLCON1, NPCM7XX_CLK_S_PLL1,
0318 NPCM7XX_CLK_S_REFCLK, 0, -1},
0319
0320 {NPCM7XX_PLLCON2, NPCM7XX_CLK_S_PLL2,
0321 NPCM7XX_CLK_S_REFCLK, 0, -1},
0322
0323 {NPCM7XX_PLLCONG, NPCM7XX_CLK_S_PLL_GFX,
0324 NPCM7XX_CLK_S_REFCLK, 0, -1},
0325 };
0326
0327 static const struct npcm7xx_clk_mux_data npcm7xx_muxes[] __initconst = {
0328 {0, GENMASK(1, 0), cpuck_mux_table, NPCM7XX_CLK_S_CPU_MUX,
0329 cpuck_mux_parents, ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL,
0330 NPCM7XX_CLK_CPU},
0331
0332 {4, GENMASK(1, 0), pixcksel_mux_table, NPCM7XX_CLK_S_PIX_MUX,
0333 pixcksel_mux_parents, ARRAY_SIZE(pixcksel_mux_parents), 0,
0334 NPCM7XX_CLK_GFX_PIXEL},
0335
0336 {6, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_SD_MUX,
0337 pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
0338
0339 {8, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_UART_MUX,
0340 pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
0341
0342 {10, GENMASK(1, 0), sucksel_mux_table, NPCM7XX_CLK_S_SU_MUX,
0343 sucksel_mux_parents, ARRAY_SIZE(sucksel_mux_parents), 0, -1},
0344
0345 {12, GENMASK(1, 0), mccksel_mux_table, NPCM7XX_CLK_S_MC_MUX,
0346 mccksel_mux_parents, ARRAY_SIZE(mccksel_mux_parents), 0, -1},
0347
0348 {14, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_TIM_MUX,
0349 pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
0350
0351 {16, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_GFX_MUX,
0352 pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
0353
0354 {18, GENMASK(2, 0), clkoutsel_mux_table, NPCM7XX_CLK_S_CLKOUT_MUX,
0355 clkoutsel_mux_parents, ARRAY_SIZE(clkoutsel_mux_parents), 0, -1},
0356
0357 {21, GENMASK(1, 0), gfxmsel_mux_table, NPCM7XX_CLK_S_GFXM_MUX,
0358 gfxmsel_mux_parents, ARRAY_SIZE(gfxmsel_mux_parents), 0, -1},
0359
0360 {23, GENMASK(1, 0), dvcssel_mux_table, NPCM7XX_CLK_S_DVC_MUX,
0361 dvcssel_mux_parents, ARRAY_SIZE(dvcssel_mux_parents), 0, -1},
0362 };
0363
0364
0365 static const struct npcm7xx_clk_div_data npcm7xx_divs[] __initconst = {
0366 {NPCM7XX_CLKDIV1, 28, 3, NPCM7XX_CLK_S_ADC,
0367 NPCM7XX_CLK_S_TIMER, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_ADC},
0368
0369 {NPCM7XX_CLKDIV1, 26, 2, NPCM7XX_CLK_S_AHB,
0370 NPCM7XX_CLK_S_AXI, 0, CLK_IS_CRITICAL, NPCM7XX_CLK_AHB},
0371
0372 {NPCM7XX_CLKDIV1, 21, 5, NPCM7XX_CLK_S_TIMER,
0373 NPCM7XX_CLK_S_TIM_MUX, 0, 0, NPCM7XX_CLK_TIMER},
0374
0375 {NPCM7XX_CLKDIV1, 16, 5, NPCM7XX_CLK_S_UART,
0376 NPCM7XX_CLK_S_UART_MUX, 0, 0, NPCM7XX_CLK_UART},
0377
0378 {NPCM7XX_CLKDIV1, 11, 5, NPCM7XX_CLK_S_MMC,
0379 NPCM7XX_CLK_S_SD_MUX, 0, 0, NPCM7XX_CLK_MMC},
0380
0381 {NPCM7XX_CLKDIV1, 6, 5, NPCM7XX_CLK_S_SPI3,
0382 NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPI3},
0383
0384 {NPCM7XX_CLKDIV1, 2, 4, NPCM7XX_CLK_S_PCI,
0385 NPCM7XX_CLK_S_GFX_MUX, 0, 0, NPCM7XX_CLK_PCI},
0386
0387 {NPCM7XX_CLKDIV1, 0, 1, NPCM7XX_CLK_S_AXI,
0388 NPCM7XX_CLK_S_CPU_MUX, CLK_DIVIDER_POWER_OF_TWO, CLK_IS_CRITICAL,
0389 NPCM7XX_CLK_AXI},
0390
0391 {NPCM7XX_CLKDIV2, 30, 2, NPCM7XX_CLK_S_APB4,
0392 NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB4},
0393
0394 {NPCM7XX_CLKDIV2, 28, 2, NPCM7XX_CLK_S_APB3,
0395 NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB3},
0396
0397 {NPCM7XX_CLKDIV2, 26, 2, NPCM7XX_CLK_S_APB2,
0398 NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB2},
0399
0400 {NPCM7XX_CLKDIV2, 24, 2, NPCM7XX_CLK_S_APB1,
0401 NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB1},
0402
0403 {NPCM7XX_CLKDIV2, 22, 2, NPCM7XX_CLK_S_APB5,
0404 NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB5},
0405
0406 {NPCM7XX_CLKDIV2, 16, 5, NPCM7XX_CLK_S_CLKOUT,
0407 NPCM7XX_CLK_S_CLKOUT_MUX, 0, 0, NPCM7XX_CLK_CLKOUT},
0408
0409 {NPCM7XX_CLKDIV2, 13, 3, NPCM7XX_CLK_S_GFX,
0410 NPCM7XX_CLK_S_GFX_MUX, 0, 0, NPCM7XX_CLK_GFX},
0411
0412 {NPCM7XX_CLKDIV2, 8, 5, NPCM7XX_CLK_S_USB_BRIDGE,
0413 NPCM7XX_CLK_S_SU_MUX, 0, 0, NPCM7XX_CLK_SU},
0414
0415 {NPCM7XX_CLKDIV2, 4, 4, NPCM7XX_CLK_S_USB_HOST,
0416 NPCM7XX_CLK_S_SU_MUX, 0, 0, NPCM7XX_CLK_SU48},
0417
0418 {NPCM7XX_CLKDIV2, 0, 4, NPCM7XX_CLK_S_SDHC,
0419 NPCM7XX_CLK_S_SD_MUX, 0, 0, NPCM7XX_CLK_SDHC}
0420 ,
0421
0422 {NPCM7XX_CLKDIV3, 6, 5, NPCM7XX_CLK_S_SPI0,
0423 NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPI0},
0424
0425 {NPCM7XX_CLKDIV3, 1, 5, NPCM7XX_CLK_S_SPIX,
0426 NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPIX},
0427
0428
0429 };
0430
0431 static DEFINE_SPINLOCK(npcm7xx_clk_lock);
0432
0433 static void __init npcm7xx_clk_init(struct device_node *clk_np)
0434 {
0435 struct clk_hw_onecell_data *npcm7xx_clk_data;
0436 void __iomem *clk_base;
0437 struct resource res;
0438 struct clk_hw *hw;
0439 int ret;
0440 int i;
0441
0442 ret = of_address_to_resource(clk_np, 0, &res);
0443 if (ret) {
0444 pr_err("%pOFn: failed to get resource, ret %d\n", clk_np,
0445 ret);
0446 return;
0447 }
0448
0449 clk_base = ioremap(res.start, resource_size(&res));
0450 if (!clk_base)
0451 goto npcm7xx_init_error;
0452
0453 npcm7xx_clk_data = kzalloc(struct_size(npcm7xx_clk_data, hws,
0454 NPCM7XX_NUM_CLOCKS), GFP_KERNEL);
0455 if (!npcm7xx_clk_data)
0456 goto npcm7xx_init_np_err;
0457
0458 npcm7xx_clk_data->num = NPCM7XX_NUM_CLOCKS;
0459
0460 for (i = 0; i < NPCM7XX_NUM_CLOCKS; i++)
0461 npcm7xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
0462
0463
0464 for (i = 0; i < ARRAY_SIZE(npcm7xx_plls); i++) {
0465 const struct npcm7xx_clk_pll_data *pll_data = &npcm7xx_plls[i];
0466
0467 hw = npcm7xx_clk_register_pll(clk_base + pll_data->reg,
0468 pll_data->name, pll_data->parent_name, pll_data->flags);
0469 if (IS_ERR(hw)) {
0470 pr_err("npcm7xx_clk: Can't register pll\n");
0471 goto npcm7xx_init_fail;
0472 }
0473
0474 if (pll_data->onecell_idx >= 0)
0475 npcm7xx_clk_data->hws[pll_data->onecell_idx] = hw;
0476 }
0477
0478
0479 hw = clk_hw_register_fixed_factor(NULL, NPCM7XX_CLK_S_PLL1_DIV2,
0480 NPCM7XX_CLK_S_PLL1, 0, 1, 2);
0481 if (IS_ERR(hw)) {
0482 pr_err("npcm7xx_clk: Can't register fixed div\n");
0483 goto npcm7xx_init_fail;
0484 }
0485
0486 hw = clk_hw_register_fixed_factor(NULL, NPCM7XX_CLK_S_PLL2_DIV2,
0487 NPCM7XX_CLK_S_PLL2, 0, 1, 2);
0488 if (IS_ERR(hw)) {
0489 pr_err("npcm7xx_clk: Can't register div2\n");
0490 goto npcm7xx_init_fail;
0491 }
0492
0493
0494 for (i = 0; i < ARRAY_SIZE(npcm7xx_muxes); i++) {
0495 const struct npcm7xx_clk_mux_data *mux_data = &npcm7xx_muxes[i];
0496
0497 hw = clk_hw_register_mux_table(NULL,
0498 mux_data->name,
0499 mux_data->parent_names, mux_data->num_parents,
0500 mux_data->flags, clk_base + NPCM7XX_CLKSEL,
0501 mux_data->shift, mux_data->mask, 0,
0502 mux_data->table, &npcm7xx_clk_lock);
0503
0504 if (IS_ERR(hw)) {
0505 pr_err("npcm7xx_clk: Can't register mux\n");
0506 goto npcm7xx_init_fail;
0507 }
0508
0509 if (mux_data->onecell_idx >= 0)
0510 npcm7xx_clk_data->hws[mux_data->onecell_idx] = hw;
0511 }
0512
0513
0514 for (i = 0; i < ARRAY_SIZE(npcm7xx_divs); i++) {
0515 const struct npcm7xx_clk_div_data *div_data = &npcm7xx_divs[i];
0516
0517 hw = clk_hw_register_divider(NULL, div_data->name,
0518 div_data->parent_name,
0519 div_data->flags,
0520 clk_base + div_data->reg,
0521 div_data->shift, div_data->width,
0522 div_data->clk_divider_flags, &npcm7xx_clk_lock);
0523 if (IS_ERR(hw)) {
0524 pr_err("npcm7xx_clk: Can't register div table\n");
0525 goto npcm7xx_init_fail;
0526 }
0527
0528 if (div_data->onecell_idx >= 0)
0529 npcm7xx_clk_data->hws[div_data->onecell_idx] = hw;
0530 }
0531
0532 ret = of_clk_add_hw_provider(clk_np, of_clk_hw_onecell_get,
0533 npcm7xx_clk_data);
0534 if (ret)
0535 pr_err("failed to add DT provider: %d\n", ret);
0536
0537 of_node_put(clk_np);
0538
0539 return;
0540
0541 npcm7xx_init_fail:
0542 kfree(npcm7xx_clk_data->hws);
0543 npcm7xx_init_np_err:
0544 iounmap(clk_base);
0545 npcm7xx_init_error:
0546 of_node_put(clk_np);
0547 }
0548 CLK_OF_DECLARE(npcm7xx_clk_init, "nuvoton,npcm750-clk", npcm7xx_clk_init);