Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Nuvoton NPCM7xx Clock Generator
0004  * All the clocks are initialized by the bootloader, so this driver allow only
0005  * reading of current settings directly from the hardware.
0006  *
0007  * Copyright (C) 2018 Nuvoton Technologies tali.perry@nuvoton.com
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      * If this clock is exported via DT, set onecell_idx to constant
0140      * defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
0141      * this specific clock.  Otherwise, set to -1.
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      * If this clock is exported via DT, set onecell_idx to constant
0156      * defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
0157      * this specific clock.  Otherwise, set to -1.
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      * If this clock is exported via DT, set onecell_idx to constant
0171      * defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
0172      * this specific clock.  Otherwise, set to -1.
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      * If this clock is exported via DT, set onecell_idx to constant
0188      * defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
0189      * this specific clock.  Otherwise, set to -1.
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      * If this clock is exported via DT, set onecell_idx to constant
0201      * defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
0202      * this specific clock.  Otherwise, set to -1.
0203      */
0204     int onecell_idx;
0205 };
0206 
0207 /*
0208  * Single copy of strings used to refer to clocks within this driver indexed by
0209  * above enum.
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"  /*AKA system clock.*/
0225 #define NPCM7XX_CLK_S_MC          "mc"
0226 #define NPCM7XX_CLK_S_AXI         "axi"  /*AKA CLK2*/
0227 #define NPCM7XX_CLK_S_AHB         "ahb"  /*AKA CLK4*/
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, // divided by 2
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 /* configurable dividers: */
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     /*30-28 ADCCKDIV*/
0369     {NPCM7XX_CLKDIV1, 26, 2, NPCM7XX_CLK_S_AHB,
0370     NPCM7XX_CLK_S_AXI, 0, CLK_IS_CRITICAL, NPCM7XX_CLK_AHB},
0371     /*27-26 CLK4DIV*/
0372     {NPCM7XX_CLKDIV1, 21, 5, NPCM7XX_CLK_S_TIMER,
0373     NPCM7XX_CLK_S_TIM_MUX, 0, 0, NPCM7XX_CLK_TIMER},
0374     /*25-21 TIMCKDIV*/
0375     {NPCM7XX_CLKDIV1, 16, 5, NPCM7XX_CLK_S_UART,
0376     NPCM7XX_CLK_S_UART_MUX, 0, 0, NPCM7XX_CLK_UART},
0377     /*20-16 UARTDIV*/
0378     {NPCM7XX_CLKDIV1, 11, 5, NPCM7XX_CLK_S_MMC,
0379     NPCM7XX_CLK_S_SD_MUX, 0, 0, NPCM7XX_CLK_MMC},
0380     /*15-11 MMCCKDIV*/
0381     {NPCM7XX_CLKDIV1, 6, 5, NPCM7XX_CLK_S_SPI3,
0382     NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPI3},
0383     /*10-6 AHB3CKDIV*/
0384     {NPCM7XX_CLKDIV1, 2, 4, NPCM7XX_CLK_S_PCI,
0385     NPCM7XX_CLK_S_GFX_MUX, 0, 0, NPCM7XX_CLK_PCI},
0386     /*5-2 PCICKDIV*/
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},/*0 CLK2DIV*/
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     /*31-30 APB4CKDIV*/
0394     {NPCM7XX_CLKDIV2, 28, 2, NPCM7XX_CLK_S_APB3,
0395     NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB3},
0396     /*29-28 APB3CKDIV*/
0397     {NPCM7XX_CLKDIV2, 26, 2, NPCM7XX_CLK_S_APB2,
0398     NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB2},
0399     /*27-26 APB2CKDIV*/
0400     {NPCM7XX_CLKDIV2, 24, 2, NPCM7XX_CLK_S_APB1,
0401     NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB1},
0402     /*25-24 APB1CKDIV*/
0403     {NPCM7XX_CLKDIV2, 22, 2, NPCM7XX_CLK_S_APB5,
0404     NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB5},
0405     /*23-22 APB5CKDIV*/
0406     {NPCM7XX_CLKDIV2, 16, 5, NPCM7XX_CLK_S_CLKOUT,
0407     NPCM7XX_CLK_S_CLKOUT_MUX, 0, 0, NPCM7XX_CLK_CLKOUT},
0408     /*20-16 CLKOUTDIV*/
0409     {NPCM7XX_CLKDIV2, 13, 3, NPCM7XX_CLK_S_GFX,
0410     NPCM7XX_CLK_S_GFX_MUX, 0, 0, NPCM7XX_CLK_GFX},
0411     /*15-13 GFXCKDIV*/
0412     {NPCM7XX_CLKDIV2, 8, 5, NPCM7XX_CLK_S_USB_BRIDGE,
0413     NPCM7XX_CLK_S_SU_MUX, 0, 0, NPCM7XX_CLK_SU},
0414     /*12-8 SUCKDIV*/
0415     {NPCM7XX_CLKDIV2, 4, 4, NPCM7XX_CLK_S_USB_HOST,
0416     NPCM7XX_CLK_S_SU_MUX, 0, 0, NPCM7XX_CLK_SU48},
0417     /*7-4 SU48CKDIV*/
0418     {NPCM7XX_CLKDIV2, 0, 4, NPCM7XX_CLK_S_SDHC,
0419     NPCM7XX_CLK_S_SD_MUX, 0, 0, NPCM7XX_CLK_SDHC}
0420     ,/*3-0 SD1CKDIV*/
0421 
0422     {NPCM7XX_CLKDIV3, 6, 5, NPCM7XX_CLK_S_SPI0,
0423     NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPI0},
0424     /*10-6 SPI0CKDV*/
0425     {NPCM7XX_CLKDIV3, 1, 5, NPCM7XX_CLK_S_SPIX,
0426     NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPIX},
0427     /*5-1 SPIXCKDV*/
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     /* Register plls */
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     /* Register fixed dividers */
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     /* Register muxes */
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     /* Register clock dividers specified in npcm7xx_divs */
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);