577 lines · c
1// SPDX-License-Identifier: GPL-2.02 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 16struct clk_bcm63xx_table_entry {17 const char * const name;18 u8 bit;19 unsigned long flags;20};21 22struct clk_bcm63xx_hw {23 void __iomem *regs;24 spinlock_t lock;25 26 struct clk_hw_onecell_data data;27};28 29static 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 86static 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 166static 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 205static 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 248static 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 287static 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 351static 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 408static 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 484static 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;534out_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 543static 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 556static 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 568static 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};576builtin_platform_driver(clk_bcm63xx);577