1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/clk-provider.h> 4 #include <linux/init.h> 5 #include <linux/of.h> 6 #include <linux/of_device.h> 7 #include <linux/platform_device.h> 8 9 #include <dt-bindings/clock/bcm3368-clock.h> 10 #include <dt-bindings/clock/bcm6318-clock.h> 11 #include <dt-bindings/clock/bcm6328-clock.h> 12 #include <dt-bindings/clock/bcm6358-clock.h> 13 #include <dt-bindings/clock/bcm6362-clock.h> 14 #include <dt-bindings/clock/bcm6368-clock.h> 15 #include <dt-bindings/clock/bcm63268-clock.h> 16 17 struct clk_bcm63xx_table_entry { 18 const char * const name; 19 u8 bit; 20 unsigned long flags; 21 }; 22 23 struct clk_bcm63xx_hw { 24 void __iomem *regs; 25 spinlock_t lock; 26 27 struct clk_hw_onecell_data data; 28 }; 29 30 static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = { 31 { 32 .name = "mac", 33 .bit = BCM3368_CLK_MAC, 34 }, { 35 .name = "tc", 36 .bit = BCM3368_CLK_TC, 37 }, { 38 .name = "us_top", 39 .bit = BCM3368_CLK_US_TOP, 40 }, { 41 .name = "ds_top", 42 .bit = BCM3368_CLK_DS_TOP, 43 }, { 44 .name = "acm", 45 .bit = BCM3368_CLK_ACM, 46 }, { 47 .name = "spi", 48 .bit = BCM3368_CLK_SPI, 49 }, { 50 .name = "usbs", 51 .bit = BCM3368_CLK_USBS, 52 }, { 53 .name = "bmu", 54 .bit = BCM3368_CLK_BMU, 55 }, { 56 .name = "pcm", 57 .bit = BCM3368_CLK_PCM, 58 }, { 59 .name = "ntp", 60 .bit = BCM3368_CLK_NTP, 61 }, { 62 .name = "acp_b", 63 .bit = BCM3368_CLK_ACP_B, 64 }, { 65 .name = "acp_a", 66 .bit = BCM3368_CLK_ACP_A, 67 }, { 68 .name = "emusb", 69 .bit = BCM3368_CLK_EMUSB, 70 }, { 71 .name = "enet0", 72 .bit = BCM3368_CLK_ENET0, 73 }, { 74 .name = "enet1", 75 .bit = BCM3368_CLK_ENET1, 76 }, { 77 .name = "usbsu", 78 .bit = BCM3368_CLK_USBSU, 79 }, { 80 .name = "ephy", 81 .bit = BCM3368_CLK_EPHY, 82 }, { 83 /* sentinel */ 84 }, 85 }; 86 87 static const struct clk_bcm63xx_table_entry bcm6318_clocks[] = { 88 { 89 .name = "adsl_asb", 90 .bit = BCM6318_CLK_ADSL_ASB, 91 }, { 92 .name = "usb_asb", 93 .bit = BCM6318_CLK_USB_ASB, 94 }, { 95 .name = "mips_asb", 96 .bit = BCM6318_CLK_MIPS_ASB, 97 }, { 98 .name = "pcie_asb", 99 .bit = BCM6318_CLK_PCIE_ASB, 100 }, { 101 .name = "phymips_asb", 102 .bit = BCM6318_CLK_PHYMIPS_ASB, 103 }, { 104 .name = "robosw_asb", 105 .bit = BCM6318_CLK_ROBOSW_ASB, 106 }, { 107 .name = "sar_asb", 108 .bit = BCM6318_CLK_SAR_ASB, 109 }, { 110 .name = "sdr_asb", 111 .bit = BCM6318_CLK_SDR_ASB, 112 }, { 113 .name = "swreg_asb", 114 .bit = BCM6318_CLK_SWREG_ASB, 115 }, { 116 .name = "periph_asb", 117 .bit = BCM6318_CLK_PERIPH_ASB, 118 }, { 119 .name = "cpubus160", 120 .bit = BCM6318_CLK_CPUBUS160, 121 }, { 122 .name = "adsl", 123 .bit = BCM6318_CLK_ADSL, 124 }, { 125 .name = "sar125", 126 .bit = BCM6318_CLK_SAR125, 127 }, { 128 .name = "mips", 129 .bit = BCM6318_CLK_MIPS, 130 .flags = CLK_IS_CRITICAL, 131 }, { 132 .name = "pcie", 133 .bit = BCM6318_CLK_PCIE, 134 }, { 135 .name = "robosw250", 136 .bit = BCM6318_CLK_ROBOSW250, 137 }, { 138 .name = "robosw025", 139 .bit = BCM6318_CLK_ROBOSW025, 140 }, { 141 .name = "sdr", 142 .bit = BCM6318_CLK_SDR, 143 .flags = CLK_IS_CRITICAL, 144 }, { 145 .name = "usbd", 146 .bit = BCM6318_CLK_USBD, 147 }, { 148 .name = "hsspi", 149 .bit = BCM6318_CLK_HSSPI, 150 }, { 151 .name = "pcie25", 152 .bit = BCM6318_CLK_PCIE25, 153 }, { 154 .name = "phymips", 155 .bit = BCM6318_CLK_PHYMIPS, 156 }, { 157 .name = "afe", 158 .bit = BCM6318_CLK_AFE, 159 }, { 160 .name = "qproc", 161 .bit = BCM6318_CLK_QPROC, 162 }, { 163 /* sentinel */ 164 }, 165 }; 166 167 static const struct clk_bcm63xx_table_entry bcm6318_ubus_clocks[] = { 168 { 169 .name = "adsl-ubus", 170 .bit = BCM6318_UCLK_ADSL, 171 }, { 172 .name = "arb-ubus", 173 .bit = BCM6318_UCLK_ARB, 174 .flags = CLK_IS_CRITICAL, 175 }, { 176 .name = "mips-ubus", 177 .bit = BCM6318_UCLK_MIPS, 178 .flags = CLK_IS_CRITICAL, 179 }, { 180 .name = "pcie-ubus", 181 .bit = BCM6318_UCLK_PCIE, 182 }, { 183 .name = "periph-ubus", 184 .bit = BCM6318_UCLK_PERIPH, 185 .flags = CLK_IS_CRITICAL, 186 }, { 187 .name = "phymips-ubus", 188 .bit = BCM6318_UCLK_PHYMIPS, 189 }, { 190 .name = "robosw-ubus", 191 .bit = BCM6318_UCLK_ROBOSW, 192 }, { 193 .name = "sar-ubus", 194 .bit = BCM6318_UCLK_SAR, 195 }, { 196 .name = "sdr-ubus", 197 .bit = BCM6318_UCLK_SDR, 198 }, { 199 .name = "usb-ubus", 200 .bit = BCM6318_UCLK_USB, 201 }, { 202 /* sentinel */ 203 }, 204 }; 205 206 static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = { 207 { 208 .name = "phy_mips", 209 .bit = BCM6328_CLK_PHYMIPS, 210 }, { 211 .name = "adsl_qproc", 212 .bit = BCM6328_CLK_ADSL_QPROC, 213 }, { 214 .name = "adsl_afe", 215 .bit = BCM6328_CLK_ADSL_AFE, 216 }, { 217 .name = "adsl", 218 .bit = BCM6328_CLK_ADSL, 219 }, { 220 .name = "mips", 221 .bit = BCM6328_CLK_MIPS, 222 .flags = CLK_IS_CRITICAL, 223 }, { 224 .name = "sar", 225 .bit = BCM6328_CLK_SAR, 226 }, { 227 .name = "pcm", 228 .bit = BCM6328_CLK_PCM, 229 }, { 230 .name = "usbd", 231 .bit = BCM6328_CLK_USBD, 232 }, { 233 .name = "usbh", 234 .bit = BCM6328_CLK_USBH, 235 }, { 236 .name = "hsspi", 237 .bit = BCM6328_CLK_HSSPI, 238 }, { 239 .name = "pcie", 240 .bit = BCM6328_CLK_PCIE, 241 }, { 242 .name = "robosw", 243 .bit = BCM6328_CLK_ROBOSW, 244 }, { 245 /* sentinel */ 246 }, 247 }; 248 249 static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = { 250 { 251 .name = "enet", 252 .bit = BCM6358_CLK_ENET, 253 }, { 254 .name = "adslphy", 255 .bit = BCM6358_CLK_ADSLPHY, 256 }, { 257 .name = "pcm", 258 .bit = BCM6358_CLK_PCM, 259 }, { 260 .name = "spi", 261 .bit = BCM6358_CLK_SPI, 262 }, { 263 .name = "usbs", 264 .bit = BCM6358_CLK_USBS, 265 }, { 266 .name = "sar", 267 .bit = BCM6358_CLK_SAR, 268 }, { 269 .name = "emusb", 270 .bit = BCM6358_CLK_EMUSB, 271 }, { 272 .name = "enet0", 273 .bit = BCM6358_CLK_ENET0, 274 }, { 275 .name = "enet1", 276 .bit = BCM6358_CLK_ENET1, 277 }, { 278 .name = "usbsu", 279 .bit = BCM6358_CLK_USBSU, 280 }, { 281 .name = "ephy", 282 .bit = BCM6358_CLK_EPHY, 283 }, { 284 /* sentinel */ 285 }, 286 }; 287 288 static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = { 289 { 290 .name = "adsl_qproc", 291 .bit = BCM6362_CLK_ADSL_QPROC, 292 }, { 293 .name = "adsl_afe", 294 .bit = BCM6362_CLK_ADSL_AFE, 295 }, { 296 .name = "adsl", 297 .bit = BCM6362_CLK_ADSL, 298 }, { 299 .name = "mips", 300 .bit = BCM6362_CLK_MIPS, 301 .flags = CLK_IS_CRITICAL, 302 }, { 303 .name = "wlan_ocp", 304 .bit = BCM6362_CLK_WLAN_OCP, 305 }, { 306 .name = "swpkt_usb", 307 .bit = BCM6362_CLK_SWPKT_USB, 308 }, { 309 .name = "swpkt_sar", 310 .bit = BCM6362_CLK_SWPKT_SAR, 311 }, { 312 .name = "sar", 313 .bit = BCM6362_CLK_SAR, 314 }, { 315 .name = "robosw", 316 .bit = BCM6362_CLK_ROBOSW, 317 }, { 318 .name = "pcm", 319 .bit = BCM6362_CLK_PCM, 320 }, { 321 .name = "usbd", 322 .bit = BCM6362_CLK_USBD, 323 }, { 324 .name = "usbh", 325 .bit = BCM6362_CLK_USBH, 326 }, { 327 .name = "ipsec", 328 .bit = BCM6362_CLK_IPSEC, 329 }, { 330 .name = "spi", 331 .bit = BCM6362_CLK_SPI, 332 }, { 333 .name = "hsspi", 334 .bit = BCM6362_CLK_HSSPI, 335 }, { 336 .name = "pcie", 337 .bit = BCM6362_CLK_PCIE, 338 }, { 339 .name = "fap", 340 .bit = BCM6362_CLK_FAP, 341 }, { 342 .name = "phymips", 343 .bit = BCM6362_CLK_PHYMIPS, 344 }, { 345 .name = "nand", 346 .bit = BCM6362_CLK_NAND, 347 }, { 348 /* sentinel */ 349 }, 350 }; 351 352 static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = { 353 { 354 .name = "vdsl_qproc", 355 .bit = BCM6368_CLK_VDSL_QPROC, 356 }, { 357 .name = "vdsl_afe", 358 .bit = BCM6368_CLK_VDSL_AFE, 359 }, { 360 .name = "vdsl_bonding", 361 .bit = BCM6368_CLK_VDSL_BONDING, 362 }, { 363 .name = "vdsl", 364 .bit = BCM6368_CLK_VDSL, 365 }, { 366 .name = "phymips", 367 .bit = BCM6368_CLK_PHYMIPS, 368 }, { 369 .name = "swpkt_usb", 370 .bit = BCM6368_CLK_SWPKT_USB, 371 }, { 372 .name = "swpkt_sar", 373 .bit = BCM6368_CLK_SWPKT_SAR, 374 }, { 375 .name = "spi", 376 .bit = BCM6368_CLK_SPI, 377 }, { 378 .name = "usbd", 379 .bit = BCM6368_CLK_USBD, 380 }, { 381 .name = "sar", 382 .bit = BCM6368_CLK_SAR, 383 }, { 384 .name = "robosw", 385 .bit = BCM6368_CLK_ROBOSW, 386 }, { 387 .name = "utopia", 388 .bit = BCM6368_CLK_UTOPIA, 389 }, { 390 .name = "pcm", 391 .bit = BCM6368_CLK_PCM, 392 }, { 393 .name = "usbh", 394 .bit = BCM6368_CLK_USBH, 395 }, { 396 .name = "disable_gless", 397 .bit = BCM6368_CLK_DIS_GLESS, 398 }, { 399 .name = "nand", 400 .bit = BCM6368_CLK_NAND, 401 }, { 402 .name = "ipsec", 403 .bit = BCM6368_CLK_IPSEC, 404 }, { 405 /* sentinel */ 406 }, 407 }; 408 409 static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = { 410 { 411 .name = "disable_gless", 412 .bit = BCM63268_CLK_DIS_GLESS, 413 }, { 414 .name = "vdsl_qproc", 415 .bit = BCM63268_CLK_VDSL_QPROC, 416 }, { 417 .name = "vdsl_afe", 418 .bit = BCM63268_CLK_VDSL_AFE, 419 }, { 420 .name = "vdsl", 421 .bit = BCM63268_CLK_VDSL, 422 }, { 423 .name = "mips", 424 .bit = BCM63268_CLK_MIPS, 425 .flags = CLK_IS_CRITICAL, 426 }, { 427 .name = "wlan_ocp", 428 .bit = BCM63268_CLK_WLAN_OCP, 429 }, { 430 .name = "dect", 431 .bit = BCM63268_CLK_DECT, 432 }, { 433 .name = "fap0", 434 .bit = BCM63268_CLK_FAP0, 435 }, { 436 .name = "fap1", 437 .bit = BCM63268_CLK_FAP1, 438 }, { 439 .name = "sar", 440 .bit = BCM63268_CLK_SAR, 441 }, { 442 .name = "robosw", 443 .bit = BCM63268_CLK_ROBOSW, 444 }, { 445 .name = "pcm", 446 .bit = BCM63268_CLK_PCM, 447 }, { 448 .name = "usbd", 449 .bit = BCM63268_CLK_USBD, 450 }, { 451 .name = "usbh", 452 .bit = BCM63268_CLK_USBH, 453 }, { 454 .name = "ipsec", 455 .bit = BCM63268_CLK_IPSEC, 456 }, { 457 .name = "spi", 458 .bit = BCM63268_CLK_SPI, 459 }, { 460 .name = "hsspi", 461 .bit = BCM63268_CLK_HSSPI, 462 }, { 463 .name = "pcie", 464 .bit = BCM63268_CLK_PCIE, 465 }, { 466 .name = "phymips", 467 .bit = BCM63268_CLK_PHYMIPS, 468 }, { 469 .name = "gmac", 470 .bit = BCM63268_CLK_GMAC, 471 }, { 472 .name = "nand", 473 .bit = BCM63268_CLK_NAND, 474 }, { 475 .name = "tbus", 476 .bit = BCM63268_CLK_TBUS, 477 }, { 478 .name = "robosw250", 479 .bit = BCM63268_CLK_ROBOSW250, 480 }, { 481 /* sentinel */ 482 }, 483 }; 484 485 static int clk_bcm63xx_probe(struct platform_device *pdev) 486 { 487 const struct clk_bcm63xx_table_entry *entry, *table; 488 struct clk_bcm63xx_hw *hw; 489 u8 maxbit = 0; 490 int i, ret; 491 492 table = of_device_get_match_data(&pdev->dev); 493 if (!table) 494 return -EINVAL; 495 496 for (entry = table; entry->name; entry++) 497 maxbit = max_t(u8, maxbit, entry->bit); 498 maxbit++; 499 500 hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit), 501 GFP_KERNEL); 502 if (!hw) 503 return -ENOMEM; 504 505 platform_set_drvdata(pdev, hw); 506 507 spin_lock_init(&hw->lock); 508 509 hw->data.num = maxbit; 510 for (i = 0; i < maxbit; i++) 511 hw->data.hws[i] = ERR_PTR(-ENODEV); 512 513 hw->regs = devm_platform_ioremap_resource(pdev, 0); 514 if (IS_ERR(hw->regs)) 515 return PTR_ERR(hw->regs); 516 517 for (entry = table; entry->name; entry++) { 518 struct clk_hw *clk; 519 520 clk = clk_hw_register_gate(&pdev->dev, entry->name, NULL, 521 entry->flags, hw->regs, entry->bit, 522 CLK_GATE_BIG_ENDIAN, &hw->lock); 523 if (IS_ERR(clk)) { 524 ret = PTR_ERR(clk); 525 goto out_err; 526 } 527 528 hw->data.hws[entry->bit] = clk; 529 } 530 531 ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, 532 &hw->data); 533 if (!ret) 534 return 0; 535 out_err: 536 for (i = 0; i < hw->data.num; i++) { 537 if (!IS_ERR(hw->data.hws[i])) 538 clk_hw_unregister_gate(hw->data.hws[i]); 539 } 540 541 return ret; 542 } 543 544 static int clk_bcm63xx_remove(struct platform_device *pdev) 545 { 546 struct clk_bcm63xx_hw *hw = platform_get_drvdata(pdev); 547 int i; 548 549 of_clk_del_provider(pdev->dev.of_node); 550 551 for (i = 0; i < hw->data.num; i++) { 552 if (!IS_ERR(hw->data.hws[i])) 553 clk_hw_unregister_gate(hw->data.hws[i]); 554 } 555 556 return 0; 557 } 558 559 static const struct of_device_id clk_bcm63xx_dt_ids[] = { 560 { .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, }, 561 { .compatible = "brcm,bcm6318-clocks", .data = &bcm6318_clocks, }, 562 { .compatible = "brcm,bcm6318-ubus-clocks", .data = &bcm6318_ubus_clocks, }, 563 { .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, }, 564 { .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, }, 565 { .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, }, 566 { .compatible = "brcm,bcm6368-clocks", .data = &bcm6368_clocks, }, 567 { .compatible = "brcm,bcm63268-clocks", .data = &bcm63268_clocks, }, 568 { } 569 }; 570 571 static struct platform_driver clk_bcm63xx = { 572 .probe = clk_bcm63xx_probe, 573 .remove = clk_bcm63xx_remove, 574 .driver = { 575 .name = "bcm63xx-clock", 576 .of_match_table = clk_bcm63xx_dt_ids, 577 }, 578 }; 579 builtin_platform_driver(clk_bcm63xx); 580