1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Author: Yinbo Zhu <zhuyinbo@loongson.cn> 4 * Copyright (C) 2022-2023 Loongson Technology Corporation Limited 5 */ 6 7 #include <linux/err.h> 8 #include <linux/init.h> 9 #include <linux/clk-provider.h> 10 #include <linux/slab.h> 11 #include <linux/module.h> 12 #include <linux/platform_device.h> 13 #include <linux/io-64-nonatomic-lo-hi.h> 14 #include <dt-bindings/clock/loongson,ls2k-clk.h> 15 16 enum loongson2_clk_type { 17 CLK_TYPE_PLL, 18 CLK_TYPE_SCALE, 19 CLK_TYPE_DIVIDER, 20 CLK_TYPE_GATE, 21 CLK_TYPE_FIXED, 22 CLK_TYPE_NONE, 23 }; 24 25 struct loongson2_clk_provider { 26 void __iomem *base; 27 struct device *dev; 28 spinlock_t clk_lock; /* protect access to DIV registers */ 29 30 /* Must be last --ends in a flexible-array member. */ 31 struct clk_hw_onecell_data clk_data; 32 }; 33 34 struct loongson2_clk_data { 35 struct clk_hw hw; 36 void __iomem *reg; 37 u8 div_shift; 38 u8 div_width; 39 u8 mult_shift; 40 u8 mult_width; 41 u8 bit_idx; 42 }; 43 44 struct loongson2_clk_board_info { 45 u8 id; 46 enum loongson2_clk_type type; 47 const char *name; 48 const char *parent_name; 49 unsigned long fixed_rate; 50 unsigned long flags; 51 u8 reg_offset; 52 u8 div_shift; 53 u8 div_width; 54 u8 mult_shift; 55 u8 mult_width; 56 u8 bit_idx; 57 }; 58 59 #define CLK_DIV(_id, _name, _pname, _offset, _dshift, _dwidth) \ 60 { \ 61 .id = _id, \ 62 .type = CLK_TYPE_DIVIDER, \ 63 .name = _name, \ 64 .parent_name = _pname, \ 65 .reg_offset = _offset, \ 66 .div_shift = _dshift, \ 67 .div_width = _dwidth, \ 68 } 69 70 #define CLK_PLL(_id, _name, _offset, _mshift, _mwidth, \ 71 _dshift, _dwidth) \ 72 { \ 73 .id = _id, \ 74 .type = CLK_TYPE_PLL, \ 75 .name = _name, \ 76 .parent_name = NULL, \ 77 .reg_offset = _offset, \ 78 .mult_shift = _mshift, \ 79 .mult_width = _mwidth, \ 80 .div_shift = _dshift, \ 81 .div_width = _dwidth, \ 82 } 83 84 #define CLK_SCALE(_id, _name, _pname, _offset, \ 85 _dshift, _dwidth) \ 86 { \ 87 .id = _id, \ 88 .type = CLK_TYPE_SCALE, \ 89 .name = _name, \ 90 .parent_name = _pname, \ 91 .reg_offset = _offset, \ 92 .div_shift = _dshift, \ 93 .div_width = _dwidth, \ 94 } 95 96 #define CLK_SCALE_MODE(_id, _name, _pname, _offset, \ 97 _dshift, _dwidth, _midx) \ 98 { \ 99 .id = _id, \ 100 .type = CLK_TYPE_SCALE, \ 101 .name = _name, \ 102 .parent_name = _pname, \ 103 .reg_offset = _offset, \ 104 .div_shift = _dshift, \ 105 .div_width = _dwidth, \ 106 .bit_idx = _midx + 1, \ 107 } 108 109 #define CLK_GATE(_id, _name, _pname, _offset, _bidx) \ 110 { \ 111 .id = _id, \ 112 .type = CLK_TYPE_GATE, \ 113 .name = _name, \ 114 .parent_name = _pname, \ 115 .reg_offset = _offset, \ 116 .bit_idx = _bidx, \ 117 } 118 119 #define CLK_GATE_FLAGS(_id, _name, _pname, _offset, _bidx, \ 120 _flags) \ 121 { \ 122 .id = _id, \ 123 .type = CLK_TYPE_GATE, \ 124 .name = _name, \ 125 .parent_name = _pname, \ 126 .reg_offset = _offset, \ 127 .bit_idx = _bidx, \ 128 .flags = _flags \ 129 } 130 131 #define CLK_FIXED(_id, _name, _pname, _rate) \ 132 { \ 133 .id = _id, \ 134 .type = CLK_TYPE_FIXED, \ 135 .name = _name, \ 136 .parent_name = _pname, \ 137 .fixed_rate = _rate, \ 138 } 139 140 static const struct loongson2_clk_board_info ls2k0300_clks[] = { 141 /* Reference Clock */ 142 CLK_PLL(LS2K0300_NODE_PLL, "pll_node", 0x00, 15, 9, 8, 7), 143 CLK_PLL(LS2K0300_DDR_PLL, "pll_ddr", 0x08, 15, 9, 8, 7), 144 CLK_PLL(LS2K0300_PIX_PLL, "pll_pix", 0x10, 15, 9, 8, 7), 145 CLK_FIXED(LS2K0300_CLK_STABLE, "clk_stable", NULL, 100000000), 146 CLK_FIXED(LS2K0300_CLK_THSENS, "clk_thsens", NULL, 10000000), 147 /* Node PLL */ 148 CLK_DIV(LS2K0300_CLK_NODE_DIV, "clk_node_div", "pll_node", 0x00, 24, 7), 149 CLK_DIV(LS2K0300_CLK_GMAC_DIV, "clk_gmac_div", "pll_node", 0x04, 0, 7), 150 CLK_DIV(LS2K0300_CLK_I2S_DIV, "clk_i2s_div", "pll_node", 0x04, 8, 7), 151 CLK_GATE(LS2K0300_CLK_NODE_PLL_GATE, "clk_node_pll_gate", "clk_node_div", 0x00, 0), 152 CLK_GATE(LS2K0300_CLK_GMAC_GATE, "clk_gmac_gate", "clk_gmac_div", 0x00, 1), 153 CLK_GATE(LS2K0300_CLK_I2S_GATE, "clk_i2s_gate", "clk_i2s_div", 0x00, 2), 154 CLK_GATE_FLAGS(LS2K0300_CLK_NODE_GATE, "clk_node_gate", "clk_node_scale", 0x24, 0, 155 CLK_IS_CRITICAL), 156 CLK_SCALE_MODE(LS2K0300_CLK_NODE_SCALE, "clk_node_scale", "clk_node_pll_gate", 0x20, 0, 3, 157 3), 158 /* DDR PLL */ 159 CLK_DIV(LS2K0300_CLK_DDR_DIV, "clk_ddr_div", "pll_ddr", 0x08, 24, 7), 160 CLK_DIV(LS2K0300_CLK_NET_DIV, "clk_net_div", "pll_ddr", 0x0c, 0, 7), 161 CLK_DIV(LS2K0300_CLK_DEV_DIV, "clk_dev_div", "pll_ddr", 0x0c, 8, 7), 162 CLK_GATE(LS2K0300_CLK_NET_GATE, "clk_net_gate", "clk_net_div", 0x08, 1), 163 CLK_GATE(LS2K0300_CLK_DEV_GATE, "clk_dev_gate", "clk_dev_div", 0x08, 2), 164 CLK_GATE_FLAGS(LS2K0300_CLK_DDR_GATE, "clk_ddr_gate", "clk_ddr_div", 0x08, 0, 165 CLK_IS_CRITICAL), 166 /* PIX PLL */ 167 CLK_DIV(LS2K0300_CLK_PIX_DIV, "clk_pix_div", "pll_pix", 0x10, 24, 7), 168 CLK_DIV(LS2K0300_CLK_GMACBP_DIV, "clk_gmacbp_div", "pll_pix", 0x14, 0, 7), 169 CLK_GATE(LS2K0300_CLK_PIX_PLL_GATE, "clk_pix_pll_gate", "clk_pix_div", 0x10, 0), 170 CLK_GATE(LS2K0300_CLK_PIX_GATE, "clk_pix_gate", "clk_pix_scale", 0x24, 6), 171 CLK_GATE(LS2K0300_CLK_GMACBP_GATE, "clk_gmacbp_gate", "clk_gmacbp_div", 0x10, 1), 172 CLK_SCALE_MODE(LS2K0300_CLK_PIX_SCALE, "clk_pix_scale", "clk_pix_pll_gate", 0x20, 4, 3, 7), 173 /* clk_dev_gate */ 174 CLK_DIV(LS2K0300_CLK_SDIO_SCALE, "clk_sdio_scale", "clk_dev_gate", 0x20, 24, 4), 175 CLK_GATE(LS2K0300_CLK_USB_GATE, "clk_usb_gate", "clk_usb_scale", 0x24, 2), 176 CLK_GATE(LS2K0300_CLK_SDIO_GATE, "clk_sdio_gate", "clk_sdio_scale", 0x24, 4), 177 CLK_GATE(LS2K0300_CLK_APB_GATE, "clk_apb_gate", "clk_apb_scale", 0x24, 3), 178 CLK_GATE_FLAGS(LS2K0300_CLK_BOOT_GATE, "clk_boot_gate", "clk_boot_scale", 0x24, 1, 179 CLK_IS_CRITICAL), 180 CLK_SCALE_MODE(LS2K0300_CLK_USB_SCALE, "clk_usb_scale", "clk_dev_gate", 0x20, 12, 3, 15), 181 CLK_SCALE_MODE(LS2K0300_CLK_APB_SCALE, "clk_apb_scale", "clk_dev_gate", 0x20, 16, 3, 19), 182 CLK_SCALE_MODE(LS2K0300_CLK_BOOT_SCALE, "clk_boot_scale", "clk_dev_gate", 0x20, 8, 3, 11), 183 }; 184 185 static const struct loongson2_clk_board_info ls2k0500_clks[] = { 186 CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 16, 8, 8, 6), 187 CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x8, 16, 8, 8, 6), 188 CLK_PLL(LOONGSON2_DC_PLL, "pll_soc", 0x10, 16, 8, 8, 6), 189 CLK_PLL(LOONGSON2_PIX0_PLL, "pll_pix0", 0x18, 16, 8, 8, 6), 190 CLK_PLL(LOONGSON2_PIX1_PLL, "pll_pix1", 0x20, 16, 8, 8, 6), 191 CLK_DIV(LOONGSON2_NODE_CLK, "clk_node", "pll_node", 0, 24, 6), 192 CLK_DIV(LOONGSON2_DDR_CLK, "clk_ddr", "pll_ddr", 0x8, 24, 6), 193 CLK_DIV(LOONGSON2_HDA_CLK, "clk_hda", "pll_ddr", 0xc, 8, 6), 194 CLK_DIV(LOONGSON2_GPU_CLK, "clk_gpu", "pll_soc", 0x10, 24, 6), 195 CLK_DIV(LOONGSON2_DC_CLK, "clk_sb", "pll_soc", 0x14, 0, 6), 196 CLK_DIV(LOONGSON2_GMAC_CLK, "clk_gmac", "pll_soc", 0x14, 8, 6), 197 CLK_DIV(LOONGSON2_PIX0_CLK, "clk_pix0", "pll_pix0", 0x18, 24, 6), 198 CLK_DIV(LOONGSON2_PIX1_CLK, "clk_pix1", "pll_pix1", 0x20, 24, 6), 199 CLK_SCALE(LOONGSON2_BOOT_CLK, "clk_boot", "clk_sb", 0x28, 8, 3), 200 CLK_SCALE(LOONGSON2_SATA_CLK, "clk_sata", "clk_sb", 0x28, 12, 3), 201 CLK_SCALE(LOONGSON2_USB_CLK, "clk_usb", "clk_sb", 0x28, 16, 3), 202 CLK_SCALE(LOONGSON2_APB_CLK, "clk_apb", "clk_sb", 0x28, 20, 3), 203 { /* Sentinel */ }, 204 }; 205 206 static const struct loongson2_clk_board_info ls2k1000_clks[] = { 207 CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 32, 10, 26, 6), 208 CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x10, 32, 10, 26, 6), 209 CLK_PLL(LOONGSON2_DC_PLL, "pll_dc", 0x20, 32, 10, 26, 6), 210 CLK_PLL(LOONGSON2_PIX0_PLL, "pll_pix0", 0x30, 32, 10, 26, 6), 211 CLK_PLL(LOONGSON2_PIX1_PLL, "pll_pix1", 0x40, 32, 10, 26, 6), 212 CLK_DIV(LOONGSON2_NODE_CLK, "clk_node", "pll_node", 0x8, 0, 6), 213 CLK_DIV(LOONGSON2_DDR_CLK, "clk_ddr", "pll_ddr", 0x18, 0, 6), 214 CLK_DIV(LOONGSON2_GPU_CLK, "clk_gpu", "pll_ddr", 0x18, 22, 6), 215 /* 216 * The hda clk divisor in the upper 32bits and the clk-prodiver 217 * layer code doesn't support 64bit io operation thus a conversion 218 * is required that subtract shift by 32 and add 4byte to the hda 219 * address 220 */ 221 CLK_DIV(LOONGSON2_HDA_CLK, "clk_hda", "pll_ddr", 0x22, 12, 7), 222 CLK_DIV(LOONGSON2_DC_CLK, "clk_dc", "pll_dc", 0x28, 0, 6), 223 CLK_DIV(LOONGSON2_GMAC_CLK, "clk_gmac", "pll_dc", 0x28, 22, 6), 224 CLK_DIV(LOONGSON2_PIX0_CLK, "clk_pix0", "pll_pix0", 0x38, 0, 6), 225 CLK_DIV(LOONGSON2_PIX1_CLK, "clk_pix1", "pll_pix1", 0x38, 0, 6), 226 CLK_SCALE(LOONGSON2_BOOT_CLK, "clk_boot", NULL, 0x50, 8, 3), 227 CLK_SCALE(LOONGSON2_SATA_CLK, "clk_sata", "clk_gmac", 0x50, 12, 3), 228 CLK_SCALE(LOONGSON2_USB_CLK, "clk_usb", "clk_gmac", 0x50, 16, 3), 229 CLK_SCALE(LOONGSON2_APB_CLK, "clk_apb", "clk_gmac", 0x50, 20, 3), 230 { /* Sentinel */ }, 231 }; 232 233 static const struct loongson2_clk_board_info ls2k2000_clks[] = { 234 CLK_PLL(LOONGSON2_DC_PLL, "pll_0", 0, 21, 9, 32, 6), 235 CLK_PLL(LOONGSON2_DDR_PLL, "pll_1", 0x10, 21, 9, 32, 6), 236 CLK_PLL(LOONGSON2_NODE_PLL, "pll_2", 0x20, 21, 9, 32, 6), 237 CLK_PLL(LOONGSON2_PIX0_PLL, "pll_pix0", 0x30, 21, 9, 32, 6), 238 CLK_PLL(LOONGSON2_PIX1_PLL, "pll_pix1", 0x40, 21, 9, 32, 6), 239 CLK_GATE(LOONGSON2_OUT0_GATE, "out0_gate", "pll_0", 0, 40), 240 CLK_GATE(LOONGSON2_GMAC_GATE, "gmac_gate", "pll_0", 0, 41), 241 CLK_GATE(LOONGSON2_RIO_GATE, "rio_gate", "pll_0", 0, 42), 242 CLK_GATE(LOONGSON2_DC_GATE, "dc_gate", "pll_1", 0x10, 40), 243 CLK_GATE(LOONGSON2_DDR_GATE, "ddr_gate", "pll_1", 0x10, 41), 244 CLK_GATE(LOONGSON2_GPU_GATE, "gpu_gate", "pll_1", 0x10, 42), 245 CLK_GATE(LOONGSON2_HDA_GATE, "hda_gate", "pll_2", 0x20, 40), 246 CLK_GATE(LOONGSON2_NODE_GATE, "node_gate", "pll_2", 0x20, 41), 247 CLK_GATE(LOONGSON2_EMMC_GATE, "emmc_gate", "pll_2", 0x20, 42), 248 CLK_GATE(LOONGSON2_PIX0_GATE, "pix0_gate", "pll_pix0", 0x30, 40), 249 CLK_GATE(LOONGSON2_PIX1_GATE, "pix1_gate", "pll_pix1", 0x40, 40), 250 CLK_DIV(LOONGSON2_OUT0_CLK, "clk_out0", "out0_gate", 0, 0, 6), 251 CLK_DIV(LOONGSON2_GMAC_CLK, "clk_gmac", "gmac_gate", 0, 7, 6), 252 CLK_DIV(LOONGSON2_RIO_CLK, "clk_rio", "rio_gate", 0, 14, 6), 253 CLK_DIV(LOONGSON2_DC_CLK, "clk_dc", "dc_gate", 0x10, 0, 6), 254 CLK_DIV(LOONGSON2_GPU_CLK, "clk_gpu", "gpu_gate", 0x10, 7, 6), 255 CLK_DIV(LOONGSON2_DDR_CLK, "clk_ddr", "ddr_gate", 0x10, 14, 6), 256 CLK_DIV(LOONGSON2_HDA_CLK, "clk_hda", "hda_gate", 0x20, 0, 6), 257 CLK_DIV(LOONGSON2_NODE_CLK, "clk_node", "node_gate", 0x20, 7, 6), 258 CLK_DIV(LOONGSON2_EMMC_CLK, "clk_emmc", "emmc_gate", 0x20, 14, 6), 259 CLK_DIV(LOONGSON2_PIX0_CLK, "clk_pix0", "pll_pix0", 0x30, 0, 6), 260 CLK_DIV(LOONGSON2_PIX1_CLK, "clk_pix1", "pll_pix1", 0x40, 0, 6), 261 CLK_SCALE(LOONGSON2_SATA_CLK, "clk_sata", "clk_out0", 0x50, 12, 3), 262 CLK_SCALE(LOONGSON2_USB_CLK, "clk_usb", "clk_out0", 0x50, 16, 3), 263 CLK_SCALE(LOONGSON2_APB_CLK, "clk_apb", "clk_node", 0x50, 20, 3), 264 CLK_SCALE(LOONGSON2_BOOT_CLK, "clk_boot", NULL, 0x50, 23, 3), 265 CLK_SCALE(LOONGSON2_DES_CLK, "clk_des", "clk_node", 0x50, 40, 3), 266 CLK_SCALE(LOONGSON2_I2S_CLK, "clk_i2s", "clk_node", 0x50, 44, 3), 267 CLK_FIXED(LOONGSON2_MISC_CLK, "clk_misc", NULL, 50000000), 268 { /* Sentinel */ }, 269 }; 270 271 static inline struct loongson2_clk_data *to_loongson2_clk(struct clk_hw *hw) 272 { 273 return container_of(hw, struct loongson2_clk_data, hw); 274 } 275 276 static inline unsigned long loongson2_rate_part(u64 val, u8 shift, u8 width) 277 { 278 return (val & GENMASK(shift + width - 1, shift)) >> shift; 279 } 280 281 static unsigned long loongson2_pll_recalc_rate(struct clk_hw *hw, 282 unsigned long parent_rate) 283 { 284 u64 val, mult, div; 285 struct loongson2_clk_data *clk = to_loongson2_clk(hw); 286 287 val = readq(clk->reg); 288 mult = loongson2_rate_part(val, clk->mult_shift, clk->mult_width); 289 div = loongson2_rate_part(val, clk->div_shift, clk->div_width); 290 291 return div_u64((u64)parent_rate * mult, div); 292 } 293 294 static const struct clk_ops loongson2_pll_recalc_ops = { 295 .recalc_rate = loongson2_pll_recalc_rate, 296 }; 297 298 static unsigned long loongson2_freqscale_recalc_rate(struct clk_hw *hw, 299 unsigned long parent_rate) 300 { 301 u64 val, scale; 302 u32 mode = 0; 303 struct loongson2_clk_data *clk = to_loongson2_clk(hw); 304 305 val = readq(clk->reg); 306 scale = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1; 307 308 if (clk->bit_idx) 309 mode = val & BIT(clk->bit_idx - 1); 310 311 return mode == 0 ? div_u64((u64)parent_rate * scale, 8) : 312 div_u64((u64)parent_rate, scale); 313 } 314 315 static const struct clk_ops loongson2_freqscale_recalc_ops = { 316 .recalc_rate = loongson2_freqscale_recalc_rate, 317 }; 318 319 static struct clk_hw *loongson2_clk_register(const char *parent, 320 struct loongson2_clk_provider *clp, 321 const struct loongson2_clk_board_info *cld, 322 const struct clk_ops *ops) 323 { 324 int ret; 325 struct clk_hw *hw; 326 struct loongson2_clk_data *clk; 327 struct clk_init_data init = { }; 328 329 clk = devm_kzalloc(clp->dev, sizeof(*clk), GFP_KERNEL); 330 if (!clk) 331 return ERR_PTR(-ENOMEM); 332 333 init.name = cld->name; 334 init.ops = ops; 335 init.flags = 0; 336 init.num_parents = 1; 337 init.parent_names = &parent; 338 339 clk->reg = clp->base + cld->reg_offset; 340 clk->div_shift = cld->div_shift; 341 clk->div_width = cld->div_width; 342 clk->mult_shift = cld->mult_shift; 343 clk->mult_width = cld->mult_width; 344 clk->bit_idx = cld->bit_idx; 345 clk->hw.init = &init; 346 347 hw = &clk->hw; 348 ret = devm_clk_hw_register(clp->dev, hw); 349 if (ret) 350 clk = ERR_PTR(ret); 351 352 return hw; 353 } 354 355 static int loongson2_clk_probe(struct platform_device *pdev) 356 { 357 int i, clks_num = 0; 358 struct clk_hw *hw; 359 struct device *dev = &pdev->dev; 360 struct loongson2_clk_provider *clp; 361 const struct loongson2_clk_board_info *p, *data; 362 const char *refclk_name, *parent_name; 363 364 data = device_get_match_data(dev); 365 if (!data) 366 return -EINVAL; 367 368 refclk_name = of_clk_get_parent_name(dev->of_node, 0); 369 if (IS_ERR(refclk_name)) 370 return dev_err_probe(dev, PTR_ERR(refclk_name), 371 "failed to get refclk name\n"); 372 373 for (p = data; p->name; p++) 374 clks_num = max(clks_num, p->id + 1); 375 376 clp = devm_kzalloc(dev, struct_size(clp, clk_data.hws, clks_num), 377 GFP_KERNEL); 378 if (!clp) 379 return -ENOMEM; 380 381 clp->base = devm_platform_ioremap_resource(pdev, 0); 382 if (IS_ERR(clp->base)) 383 return PTR_ERR(clp->base); 384 385 spin_lock_init(&clp->clk_lock); 386 clp->clk_data.num = clks_num; 387 clp->dev = dev; 388 389 /* Avoid returning NULL for unused id */ 390 memset_p((void **)clp->clk_data.hws, ERR_PTR(-ENOENT), clks_num); 391 392 for (i = 0; i < clks_num; i++) { 393 p = &data[i]; 394 parent_name = p->parent_name ? p->parent_name : refclk_name; 395 396 switch (p->type) { 397 case CLK_TYPE_PLL: 398 hw = loongson2_clk_register(parent_name, clp, p, 399 &loongson2_pll_recalc_ops); 400 break; 401 case CLK_TYPE_SCALE: 402 hw = loongson2_clk_register(parent_name, clp, p, 403 &loongson2_freqscale_recalc_ops); 404 break; 405 case CLK_TYPE_DIVIDER: 406 hw = devm_clk_hw_register_divider(dev, p->name, 407 parent_name, 0, 408 clp->base + p->reg_offset, 409 p->div_shift, p->div_width, 410 CLK_DIVIDER_ONE_BASED | 411 CLK_DIVIDER_ALLOW_ZERO, 412 &clp->clk_lock); 413 break; 414 case CLK_TYPE_GATE: 415 hw = devm_clk_hw_register_gate(dev, p->name, parent_name, 416 p->flags, 417 clp->base + p->reg_offset, 418 p->bit_idx, 0, 419 &clp->clk_lock); 420 break; 421 case CLK_TYPE_FIXED: 422 hw = devm_clk_hw_register_fixed_rate(dev, p->name, parent_name, 423 0, p->fixed_rate); 424 break; 425 default: 426 return dev_err_probe(dev, -EINVAL, "Invalid clk type\n"); 427 } 428 429 if (IS_ERR(hw)) 430 return dev_err_probe(dev, PTR_ERR(hw), 431 "Register clk: %s, type: %u failed!\n", 432 p->name, p->type); 433 434 clp->clk_data.hws[p->id] = hw; 435 } 436 437 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clp->clk_data); 438 } 439 440 static const struct of_device_id loongson2_clk_match_table[] = { 441 { .compatible = "loongson,ls2k0300-clk", .data = &ls2k0300_clks }, 442 { .compatible = "loongson,ls2k0500-clk", .data = &ls2k0500_clks }, 443 { .compatible = "loongson,ls2k-clk", .data = &ls2k1000_clks }, 444 { .compatible = "loongson,ls2k2000-clk", .data = &ls2k2000_clks }, 445 { } 446 }; 447 MODULE_DEVICE_TABLE(of, loongson2_clk_match_table); 448 449 static struct platform_driver loongson2_clk_driver = { 450 .probe = loongson2_clk_probe, 451 .driver = { 452 .name = "loongson2-clk", 453 .of_match_table = loongson2_clk_match_table, 454 }, 455 }; 456 module_platform_driver(loongson2_clk_driver); 457 458 MODULE_DESCRIPTION("Loongson2 clock driver"); 459 MODULE_AUTHOR("Loongson Technology Corporation Limited"); 460 MODULE_LICENSE("GPL"); 461