1*acc0ccffSYinbo Zhu // SPDX-License-Identifier: GPL-2.0+ 2*acc0ccffSYinbo Zhu /* 3*acc0ccffSYinbo Zhu * Author: Yinbo Zhu <zhuyinbo@loongson.cn> 4*acc0ccffSYinbo Zhu * Copyright (C) 2022-2023 Loongson Technology Corporation Limited 5*acc0ccffSYinbo Zhu */ 6*acc0ccffSYinbo Zhu 7*acc0ccffSYinbo Zhu #include <linux/err.h> 8*acc0ccffSYinbo Zhu #include <linux/init.h> 9*acc0ccffSYinbo Zhu #include <linux/clk-provider.h> 10*acc0ccffSYinbo Zhu #include <linux/slab.h> 11*acc0ccffSYinbo Zhu #include <linux/module.h> 12*acc0ccffSYinbo Zhu #include <linux/platform_device.h> 13*acc0ccffSYinbo Zhu #include <linux/io-64-nonatomic-lo-hi.h> 14*acc0ccffSYinbo Zhu #include <dt-bindings/clock/loongson,ls2k-clk.h> 15*acc0ccffSYinbo Zhu 16*acc0ccffSYinbo Zhu #define LOONGSON2_PLL_MULT_SHIFT 32 17*acc0ccffSYinbo Zhu #define LOONGSON2_PLL_MULT_WIDTH 10 18*acc0ccffSYinbo Zhu #define LOONGSON2_PLL_DIV_SHIFT 26 19*acc0ccffSYinbo Zhu #define LOONGSON2_PLL_DIV_WIDTH 6 20*acc0ccffSYinbo Zhu #define LOONGSON2_APB_FREQSCALE_SHIFT 20 21*acc0ccffSYinbo Zhu #define LOONGSON2_APB_FREQSCALE_WIDTH 3 22*acc0ccffSYinbo Zhu #define LOONGSON2_USB_FREQSCALE_SHIFT 16 23*acc0ccffSYinbo Zhu #define LOONGSON2_USB_FREQSCALE_WIDTH 3 24*acc0ccffSYinbo Zhu #define LOONGSON2_SATA_FREQSCALE_SHIFT 12 25*acc0ccffSYinbo Zhu #define LOONGSON2_SATA_FREQSCALE_WIDTH 3 26*acc0ccffSYinbo Zhu #define LOONGSON2_BOOT_FREQSCALE_SHIFT 8 27*acc0ccffSYinbo Zhu #define LOONGSON2_BOOT_FREQSCALE_WIDTH 3 28*acc0ccffSYinbo Zhu 29*acc0ccffSYinbo Zhu static void __iomem *loongson2_pll_base; 30*acc0ccffSYinbo Zhu 31*acc0ccffSYinbo Zhu static const struct clk_parent_data pdata[] = { 32*acc0ccffSYinbo Zhu { .fw_name = "ref_100m",}, 33*acc0ccffSYinbo Zhu }; 34*acc0ccffSYinbo Zhu 35*acc0ccffSYinbo Zhu static struct clk_hw *loongson2_clk_register(struct device *dev, 36*acc0ccffSYinbo Zhu const char *name, 37*acc0ccffSYinbo Zhu const char *parent_name, 38*acc0ccffSYinbo Zhu const struct clk_ops *ops, 39*acc0ccffSYinbo Zhu unsigned long flags) 40*acc0ccffSYinbo Zhu { 41*acc0ccffSYinbo Zhu int ret; 42*acc0ccffSYinbo Zhu struct clk_hw *hw; 43*acc0ccffSYinbo Zhu struct clk_init_data init; 44*acc0ccffSYinbo Zhu 45*acc0ccffSYinbo Zhu hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 46*acc0ccffSYinbo Zhu if (!hw) 47*acc0ccffSYinbo Zhu return ERR_PTR(-ENOMEM); 48*acc0ccffSYinbo Zhu 49*acc0ccffSYinbo Zhu init.name = name; 50*acc0ccffSYinbo Zhu init.ops = ops; 51*acc0ccffSYinbo Zhu init.flags = flags; 52*acc0ccffSYinbo Zhu init.num_parents = 1; 53*acc0ccffSYinbo Zhu 54*acc0ccffSYinbo Zhu if (!parent_name) 55*acc0ccffSYinbo Zhu init.parent_data = pdata; 56*acc0ccffSYinbo Zhu else 57*acc0ccffSYinbo Zhu init.parent_names = &parent_name; 58*acc0ccffSYinbo Zhu 59*acc0ccffSYinbo Zhu hw->init = &init; 60*acc0ccffSYinbo Zhu 61*acc0ccffSYinbo Zhu ret = devm_clk_hw_register(dev, hw); 62*acc0ccffSYinbo Zhu if (ret) 63*acc0ccffSYinbo Zhu hw = ERR_PTR(ret); 64*acc0ccffSYinbo Zhu 65*acc0ccffSYinbo Zhu return hw; 66*acc0ccffSYinbo Zhu } 67*acc0ccffSYinbo Zhu 68*acc0ccffSYinbo Zhu static unsigned long loongson2_calc_pll_rate(int offset, unsigned long rate) 69*acc0ccffSYinbo Zhu { 70*acc0ccffSYinbo Zhu u64 val; 71*acc0ccffSYinbo Zhu u32 mult, div; 72*acc0ccffSYinbo Zhu 73*acc0ccffSYinbo Zhu val = readq(loongson2_pll_base + offset); 74*acc0ccffSYinbo Zhu 75*acc0ccffSYinbo Zhu mult = (val >> LOONGSON2_PLL_MULT_SHIFT) & 76*acc0ccffSYinbo Zhu clk_div_mask(LOONGSON2_PLL_MULT_WIDTH); 77*acc0ccffSYinbo Zhu div = (val >> LOONGSON2_PLL_DIV_SHIFT) & 78*acc0ccffSYinbo Zhu clk_div_mask(LOONGSON2_PLL_DIV_WIDTH); 79*acc0ccffSYinbo Zhu 80*acc0ccffSYinbo Zhu return div_u64((u64)rate * mult, div); 81*acc0ccffSYinbo Zhu } 82*acc0ccffSYinbo Zhu 83*acc0ccffSYinbo Zhu static unsigned long loongson2_node_recalc_rate(struct clk_hw *hw, 84*acc0ccffSYinbo Zhu unsigned long parent_rate) 85*acc0ccffSYinbo Zhu { 86*acc0ccffSYinbo Zhu return loongson2_calc_pll_rate(0x0, parent_rate); 87*acc0ccffSYinbo Zhu } 88*acc0ccffSYinbo Zhu 89*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_node_clk_ops = { 90*acc0ccffSYinbo Zhu .recalc_rate = loongson2_node_recalc_rate, 91*acc0ccffSYinbo Zhu }; 92*acc0ccffSYinbo Zhu 93*acc0ccffSYinbo Zhu static unsigned long loongson2_ddr_recalc_rate(struct clk_hw *hw, 94*acc0ccffSYinbo Zhu unsigned long parent_rate) 95*acc0ccffSYinbo Zhu { 96*acc0ccffSYinbo Zhu return loongson2_calc_pll_rate(0x10, parent_rate); 97*acc0ccffSYinbo Zhu } 98*acc0ccffSYinbo Zhu 99*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_ddr_clk_ops = { 100*acc0ccffSYinbo Zhu .recalc_rate = loongson2_ddr_recalc_rate, 101*acc0ccffSYinbo Zhu }; 102*acc0ccffSYinbo Zhu 103*acc0ccffSYinbo Zhu static unsigned long loongson2_dc_recalc_rate(struct clk_hw *hw, 104*acc0ccffSYinbo Zhu unsigned long parent_rate) 105*acc0ccffSYinbo Zhu { 106*acc0ccffSYinbo Zhu return loongson2_calc_pll_rate(0x20, parent_rate); 107*acc0ccffSYinbo Zhu } 108*acc0ccffSYinbo Zhu 109*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_dc_clk_ops = { 110*acc0ccffSYinbo Zhu .recalc_rate = loongson2_dc_recalc_rate, 111*acc0ccffSYinbo Zhu }; 112*acc0ccffSYinbo Zhu 113*acc0ccffSYinbo Zhu static unsigned long loongson2_pix0_recalc_rate(struct clk_hw *hw, 114*acc0ccffSYinbo Zhu unsigned long parent_rate) 115*acc0ccffSYinbo Zhu { 116*acc0ccffSYinbo Zhu return loongson2_calc_pll_rate(0x30, parent_rate); 117*acc0ccffSYinbo Zhu } 118*acc0ccffSYinbo Zhu 119*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_pix0_clk_ops = { 120*acc0ccffSYinbo Zhu .recalc_rate = loongson2_pix0_recalc_rate, 121*acc0ccffSYinbo Zhu }; 122*acc0ccffSYinbo Zhu 123*acc0ccffSYinbo Zhu static unsigned long loongson2_pix1_recalc_rate(struct clk_hw *hw, 124*acc0ccffSYinbo Zhu unsigned long parent_rate) 125*acc0ccffSYinbo Zhu { 126*acc0ccffSYinbo Zhu return loongson2_calc_pll_rate(0x40, parent_rate); 127*acc0ccffSYinbo Zhu } 128*acc0ccffSYinbo Zhu 129*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_pix1_clk_ops = { 130*acc0ccffSYinbo Zhu .recalc_rate = loongson2_pix1_recalc_rate, 131*acc0ccffSYinbo Zhu }; 132*acc0ccffSYinbo Zhu 133*acc0ccffSYinbo Zhu static unsigned long loongson2_calc_rate(unsigned long rate, 134*acc0ccffSYinbo Zhu int shift, int width) 135*acc0ccffSYinbo Zhu { 136*acc0ccffSYinbo Zhu u64 val; 137*acc0ccffSYinbo Zhu u32 mult; 138*acc0ccffSYinbo Zhu 139*acc0ccffSYinbo Zhu val = readq(loongson2_pll_base + 0x50); 140*acc0ccffSYinbo Zhu 141*acc0ccffSYinbo Zhu mult = (val >> shift) & clk_div_mask(width); 142*acc0ccffSYinbo Zhu 143*acc0ccffSYinbo Zhu return div_u64((u64)rate * (mult + 1), 8); 144*acc0ccffSYinbo Zhu } 145*acc0ccffSYinbo Zhu 146*acc0ccffSYinbo Zhu static unsigned long loongson2_boot_recalc_rate(struct clk_hw *hw, 147*acc0ccffSYinbo Zhu unsigned long parent_rate) 148*acc0ccffSYinbo Zhu { 149*acc0ccffSYinbo Zhu return loongson2_calc_rate(parent_rate, 150*acc0ccffSYinbo Zhu LOONGSON2_BOOT_FREQSCALE_SHIFT, 151*acc0ccffSYinbo Zhu LOONGSON2_BOOT_FREQSCALE_WIDTH); 152*acc0ccffSYinbo Zhu } 153*acc0ccffSYinbo Zhu 154*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_boot_clk_ops = { 155*acc0ccffSYinbo Zhu .recalc_rate = loongson2_boot_recalc_rate, 156*acc0ccffSYinbo Zhu }; 157*acc0ccffSYinbo Zhu 158*acc0ccffSYinbo Zhu static unsigned long loongson2_apb_recalc_rate(struct clk_hw *hw, 159*acc0ccffSYinbo Zhu unsigned long parent_rate) 160*acc0ccffSYinbo Zhu { 161*acc0ccffSYinbo Zhu return loongson2_calc_rate(parent_rate, 162*acc0ccffSYinbo Zhu LOONGSON2_APB_FREQSCALE_SHIFT, 163*acc0ccffSYinbo Zhu LOONGSON2_APB_FREQSCALE_WIDTH); 164*acc0ccffSYinbo Zhu } 165*acc0ccffSYinbo Zhu 166*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_apb_clk_ops = { 167*acc0ccffSYinbo Zhu .recalc_rate = loongson2_apb_recalc_rate, 168*acc0ccffSYinbo Zhu }; 169*acc0ccffSYinbo Zhu 170*acc0ccffSYinbo Zhu static unsigned long loongson2_usb_recalc_rate(struct clk_hw *hw, 171*acc0ccffSYinbo Zhu unsigned long parent_rate) 172*acc0ccffSYinbo Zhu { 173*acc0ccffSYinbo Zhu return loongson2_calc_rate(parent_rate, 174*acc0ccffSYinbo Zhu LOONGSON2_USB_FREQSCALE_SHIFT, 175*acc0ccffSYinbo Zhu LOONGSON2_USB_FREQSCALE_WIDTH); 176*acc0ccffSYinbo Zhu } 177*acc0ccffSYinbo Zhu 178*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_usb_clk_ops = { 179*acc0ccffSYinbo Zhu .recalc_rate = loongson2_usb_recalc_rate, 180*acc0ccffSYinbo Zhu }; 181*acc0ccffSYinbo Zhu 182*acc0ccffSYinbo Zhu static unsigned long loongson2_sata_recalc_rate(struct clk_hw *hw, 183*acc0ccffSYinbo Zhu unsigned long parent_rate) 184*acc0ccffSYinbo Zhu { 185*acc0ccffSYinbo Zhu return loongson2_calc_rate(parent_rate, 186*acc0ccffSYinbo Zhu LOONGSON2_SATA_FREQSCALE_SHIFT, 187*acc0ccffSYinbo Zhu LOONGSON2_SATA_FREQSCALE_WIDTH); 188*acc0ccffSYinbo Zhu } 189*acc0ccffSYinbo Zhu 190*acc0ccffSYinbo Zhu static const struct clk_ops loongson2_sata_clk_ops = { 191*acc0ccffSYinbo Zhu .recalc_rate = loongson2_sata_recalc_rate, 192*acc0ccffSYinbo Zhu }; 193*acc0ccffSYinbo Zhu 194*acc0ccffSYinbo Zhu static inline int loongson2_check_clk_hws(struct clk_hw *clks[], unsigned int count) 195*acc0ccffSYinbo Zhu { 196*acc0ccffSYinbo Zhu unsigned int i; 197*acc0ccffSYinbo Zhu 198*acc0ccffSYinbo Zhu for (i = 0; i < count; i++) 199*acc0ccffSYinbo Zhu if (IS_ERR(clks[i])) { 200*acc0ccffSYinbo Zhu pr_err("Loongson2 clk %u: register failed with %ld\n", 201*acc0ccffSYinbo Zhu i, PTR_ERR(clks[i])); 202*acc0ccffSYinbo Zhu return PTR_ERR(clks[i]); 203*acc0ccffSYinbo Zhu } 204*acc0ccffSYinbo Zhu 205*acc0ccffSYinbo Zhu return 0; 206*acc0ccffSYinbo Zhu } 207*acc0ccffSYinbo Zhu 208*acc0ccffSYinbo Zhu static int loongson2_clk_probe(struct platform_device *pdev) 209*acc0ccffSYinbo Zhu { 210*acc0ccffSYinbo Zhu int ret; 211*acc0ccffSYinbo Zhu struct clk_hw **hws; 212*acc0ccffSYinbo Zhu struct clk_hw_onecell_data *clk_hw_data; 213*acc0ccffSYinbo Zhu spinlock_t loongson2_clk_lock; 214*acc0ccffSYinbo Zhu struct device *dev = &pdev->dev; 215*acc0ccffSYinbo Zhu 216*acc0ccffSYinbo Zhu loongson2_pll_base = devm_platform_ioremap_resource(pdev, 0); 217*acc0ccffSYinbo Zhu if (IS_ERR(loongson2_pll_base)) 218*acc0ccffSYinbo Zhu return PTR_ERR(loongson2_pll_base); 219*acc0ccffSYinbo Zhu 220*acc0ccffSYinbo Zhu clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, LOONGSON2_CLK_END), 221*acc0ccffSYinbo Zhu GFP_KERNEL); 222*acc0ccffSYinbo Zhu if (WARN_ON(!clk_hw_data)) 223*acc0ccffSYinbo Zhu return -ENOMEM; 224*acc0ccffSYinbo Zhu 225*acc0ccffSYinbo Zhu clk_hw_data->num = LOONGSON2_CLK_END; 226*acc0ccffSYinbo Zhu hws = clk_hw_data->hws; 227*acc0ccffSYinbo Zhu 228*acc0ccffSYinbo Zhu hws[LOONGSON2_NODE_PLL] = loongson2_clk_register(dev, "node_pll", 229*acc0ccffSYinbo Zhu NULL, 230*acc0ccffSYinbo Zhu &loongson2_node_clk_ops, 0); 231*acc0ccffSYinbo Zhu 232*acc0ccffSYinbo Zhu hws[LOONGSON2_DDR_PLL] = loongson2_clk_register(dev, "ddr_pll", 233*acc0ccffSYinbo Zhu NULL, 234*acc0ccffSYinbo Zhu &loongson2_ddr_clk_ops, 0); 235*acc0ccffSYinbo Zhu 236*acc0ccffSYinbo Zhu hws[LOONGSON2_DC_PLL] = loongson2_clk_register(dev, "dc_pll", 237*acc0ccffSYinbo Zhu NULL, 238*acc0ccffSYinbo Zhu &loongson2_dc_clk_ops, 0); 239*acc0ccffSYinbo Zhu 240*acc0ccffSYinbo Zhu hws[LOONGSON2_PIX0_PLL] = loongson2_clk_register(dev, "pix0_pll", 241*acc0ccffSYinbo Zhu NULL, 242*acc0ccffSYinbo Zhu &loongson2_pix0_clk_ops, 0); 243*acc0ccffSYinbo Zhu 244*acc0ccffSYinbo Zhu hws[LOONGSON2_PIX1_PLL] = loongson2_clk_register(dev, "pix1_pll", 245*acc0ccffSYinbo Zhu NULL, 246*acc0ccffSYinbo Zhu &loongson2_pix1_clk_ops, 0); 247*acc0ccffSYinbo Zhu 248*acc0ccffSYinbo Zhu hws[LOONGSON2_BOOT_CLK] = loongson2_clk_register(dev, "boot", 249*acc0ccffSYinbo Zhu NULL, 250*acc0ccffSYinbo Zhu &loongson2_boot_clk_ops, 0); 251*acc0ccffSYinbo Zhu 252*acc0ccffSYinbo Zhu hws[LOONGSON2_NODE_CLK] = devm_clk_hw_register_divider(dev, "node", 253*acc0ccffSYinbo Zhu "node_pll", 0, 254*acc0ccffSYinbo Zhu loongson2_pll_base + 0x8, 0, 255*acc0ccffSYinbo Zhu 6, CLK_DIVIDER_ONE_BASED, 256*acc0ccffSYinbo Zhu &loongson2_clk_lock); 257*acc0ccffSYinbo Zhu 258*acc0ccffSYinbo Zhu /* 259*acc0ccffSYinbo Zhu * The hda clk divisor in the upper 32bits and the clk-prodiver 260*acc0ccffSYinbo Zhu * layer code doesn't support 64bit io operation thus a conversion 261*acc0ccffSYinbo Zhu * is required that subtract shift by 32 and add 4byte to the hda 262*acc0ccffSYinbo Zhu * address 263*acc0ccffSYinbo Zhu */ 264*acc0ccffSYinbo Zhu hws[LOONGSON2_HDA_CLK] = devm_clk_hw_register_divider(dev, "hda", 265*acc0ccffSYinbo Zhu "ddr_pll", 0, 266*acc0ccffSYinbo Zhu loongson2_pll_base + 0x22, 12, 267*acc0ccffSYinbo Zhu 7, CLK_DIVIDER_ONE_BASED, 268*acc0ccffSYinbo Zhu &loongson2_clk_lock); 269*acc0ccffSYinbo Zhu 270*acc0ccffSYinbo Zhu hws[LOONGSON2_GPU_CLK] = devm_clk_hw_register_divider(dev, "gpu", 271*acc0ccffSYinbo Zhu "ddr_pll", 0, 272*acc0ccffSYinbo Zhu loongson2_pll_base + 0x18, 22, 273*acc0ccffSYinbo Zhu 6, CLK_DIVIDER_ONE_BASED, 274*acc0ccffSYinbo Zhu &loongson2_clk_lock); 275*acc0ccffSYinbo Zhu 276*acc0ccffSYinbo Zhu hws[LOONGSON2_DDR_CLK] = devm_clk_hw_register_divider(dev, "ddr", 277*acc0ccffSYinbo Zhu "ddr_pll", 0, 278*acc0ccffSYinbo Zhu loongson2_pll_base + 0x18, 0, 279*acc0ccffSYinbo Zhu 6, CLK_DIVIDER_ONE_BASED, 280*acc0ccffSYinbo Zhu &loongson2_clk_lock); 281*acc0ccffSYinbo Zhu 282*acc0ccffSYinbo Zhu hws[LOONGSON2_GMAC_CLK] = devm_clk_hw_register_divider(dev, "gmac", 283*acc0ccffSYinbo Zhu "dc_pll", 0, 284*acc0ccffSYinbo Zhu loongson2_pll_base + 0x28, 22, 285*acc0ccffSYinbo Zhu 6, CLK_DIVIDER_ONE_BASED, 286*acc0ccffSYinbo Zhu &loongson2_clk_lock); 287*acc0ccffSYinbo Zhu 288*acc0ccffSYinbo Zhu hws[LOONGSON2_DC_CLK] = devm_clk_hw_register_divider(dev, "dc", 289*acc0ccffSYinbo Zhu "dc_pll", 0, 290*acc0ccffSYinbo Zhu loongson2_pll_base + 0x28, 0, 291*acc0ccffSYinbo Zhu 6, CLK_DIVIDER_ONE_BASED, 292*acc0ccffSYinbo Zhu &loongson2_clk_lock); 293*acc0ccffSYinbo Zhu 294*acc0ccffSYinbo Zhu hws[LOONGSON2_APB_CLK] = loongson2_clk_register(dev, "apb", 295*acc0ccffSYinbo Zhu "gmac", 296*acc0ccffSYinbo Zhu &loongson2_apb_clk_ops, 0); 297*acc0ccffSYinbo Zhu 298*acc0ccffSYinbo Zhu hws[LOONGSON2_USB_CLK] = loongson2_clk_register(dev, "usb", 299*acc0ccffSYinbo Zhu "gmac", 300*acc0ccffSYinbo Zhu &loongson2_usb_clk_ops, 0); 301*acc0ccffSYinbo Zhu 302*acc0ccffSYinbo Zhu hws[LOONGSON2_SATA_CLK] = loongson2_clk_register(dev, "sata", 303*acc0ccffSYinbo Zhu "gmac", 304*acc0ccffSYinbo Zhu &loongson2_sata_clk_ops, 0); 305*acc0ccffSYinbo Zhu 306*acc0ccffSYinbo Zhu hws[LOONGSON2_PIX0_CLK] = clk_hw_register_divider(NULL, "pix0", 307*acc0ccffSYinbo Zhu "pix0_pll", 0, 308*acc0ccffSYinbo Zhu loongson2_pll_base + 0x38, 0, 6, 309*acc0ccffSYinbo Zhu CLK_DIVIDER_ONE_BASED, 310*acc0ccffSYinbo Zhu &loongson2_clk_lock); 311*acc0ccffSYinbo Zhu 312*acc0ccffSYinbo Zhu hws[LOONGSON2_PIX1_CLK] = clk_hw_register_divider(NULL, "pix1", 313*acc0ccffSYinbo Zhu "pix1_pll", 0, 314*acc0ccffSYinbo Zhu loongson2_pll_base + 0x48, 0, 6, 315*acc0ccffSYinbo Zhu CLK_DIVIDER_ONE_BASED, 316*acc0ccffSYinbo Zhu &loongson2_clk_lock); 317*acc0ccffSYinbo Zhu 318*acc0ccffSYinbo Zhu ret = loongson2_check_clk_hws(hws, LOONGSON2_CLK_END); 319*acc0ccffSYinbo Zhu if (ret) 320*acc0ccffSYinbo Zhu return ret; 321*acc0ccffSYinbo Zhu 322*acc0ccffSYinbo Zhu return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); 323*acc0ccffSYinbo Zhu } 324*acc0ccffSYinbo Zhu 325*acc0ccffSYinbo Zhu static const struct of_device_id loongson2_clk_match_table[] = { 326*acc0ccffSYinbo Zhu { .compatible = "loongson,ls2k-clk" }, 327*acc0ccffSYinbo Zhu { } 328*acc0ccffSYinbo Zhu }; 329*acc0ccffSYinbo Zhu MODULE_DEVICE_TABLE(of, loongson2_clk_match_table); 330*acc0ccffSYinbo Zhu 331*acc0ccffSYinbo Zhu static struct platform_driver loongson2_clk_driver = { 332*acc0ccffSYinbo Zhu .probe = loongson2_clk_probe, 333*acc0ccffSYinbo Zhu .driver = { 334*acc0ccffSYinbo Zhu .name = "loongson2-clk", 335*acc0ccffSYinbo Zhu .of_match_table = loongson2_clk_match_table, 336*acc0ccffSYinbo Zhu }, 337*acc0ccffSYinbo Zhu }; 338*acc0ccffSYinbo Zhu module_platform_driver(loongson2_clk_driver); 339*acc0ccffSYinbo Zhu 340*acc0ccffSYinbo Zhu MODULE_DESCRIPTION("Loongson2 clock driver"); 341*acc0ccffSYinbo Zhu MODULE_LICENSE("GPL"); 342