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