1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20b56e9a7SVivek Gautam /* 30b56e9a7SVivek Gautam * Broadcom Northstar USB 3.0 PHY Driver 40b56e9a7SVivek Gautam * 50b56e9a7SVivek Gautam * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl> 60b56e9a7SVivek Gautam * Copyright (C) 2016 Broadcom 70b56e9a7SVivek Gautam * 80b56e9a7SVivek Gautam * All magic values used for initialization (and related comments) were obtained 90b56e9a7SVivek Gautam * from Broadcom's SDK: 100b56e9a7SVivek Gautam * Copyright (c) Broadcom Corp, 2012 110b56e9a7SVivek Gautam */ 120b56e9a7SVivek Gautam 130b56e9a7SVivek Gautam #include <linux/bcma/bcma.h> 140b56e9a7SVivek Gautam #include <linux/delay.h> 150b56e9a7SVivek Gautam #include <linux/err.h> 1647da6aa7SChunfeng Yun #include <linux/iopoll.h> 17af850e14SRafał Miłecki #include <linux/mdio.h> 180b56e9a7SVivek Gautam #include <linux/module.h> 19af850e14SRafał Miłecki #include <linux/of_address.h> 200b56e9a7SVivek Gautam #include <linux/of_platform.h> 210b56e9a7SVivek Gautam #include <linux/platform_device.h> 220b56e9a7SVivek Gautam #include <linux/phy/phy.h> 230b56e9a7SVivek Gautam #include <linux/slab.h> 240b56e9a7SVivek Gautam 250b56e9a7SVivek Gautam #define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */ 260b56e9a7SVivek Gautam 270b56e9a7SVivek Gautam #define BCM_NS_USB3_PHY_BASE_ADDR_REG 0x1f 280b56e9a7SVivek Gautam #define BCM_NS_USB3_PHY_PLL30_BLOCK 0x8000 290b56e9a7SVivek Gautam #define BCM_NS_USB3_PHY_TX_PMD_BLOCK 0x8040 300b56e9a7SVivek Gautam #define BCM_NS_USB3_PHY_PIPE_BLOCK 0x8060 310b56e9a7SVivek Gautam 320b56e9a7SVivek Gautam /* Registers of PLL30 block */ 330b56e9a7SVivek Gautam #define BCM_NS_USB3_PLL_CONTROL 0x01 340b56e9a7SVivek Gautam #define BCM_NS_USB3_PLLA_CONTROL0 0x0a 350b56e9a7SVivek Gautam #define BCM_NS_USB3_PLLA_CONTROL1 0x0b 360b56e9a7SVivek Gautam 370b56e9a7SVivek Gautam /* Registers of TX PMD block */ 380b56e9a7SVivek Gautam #define BCM_NS_USB3_TX_PMD_CONTROL1 0x01 390b56e9a7SVivek Gautam 400b56e9a7SVivek Gautam /* Registers of PIPE block */ 410b56e9a7SVivek Gautam #define BCM_NS_USB3_LFPS_CMP 0x02 420b56e9a7SVivek Gautam #define BCM_NS_USB3_LFPS_DEGLITCH 0x03 430b56e9a7SVivek Gautam 440b56e9a7SVivek Gautam enum bcm_ns_family { 450b56e9a7SVivek Gautam BCM_NS_UNKNOWN, 460b56e9a7SVivek Gautam BCM_NS_AX, 470b56e9a7SVivek Gautam BCM_NS_BX, 480b56e9a7SVivek Gautam }; 490b56e9a7SVivek Gautam 500b56e9a7SVivek Gautam struct bcm_ns_usb3 { 510b56e9a7SVivek Gautam struct device *dev; 520b56e9a7SVivek Gautam enum bcm_ns_family family; 530b56e9a7SVivek Gautam void __iomem *dmp; 540b56e9a7SVivek Gautam void __iomem *ccb_mii; 55af850e14SRafał Miłecki struct mdio_device *mdiodev; 560b56e9a7SVivek Gautam struct phy *phy; 57b20f506fSRafał Miłecki 58b20f506fSRafał Miłecki int (*phy_write)(struct bcm_ns_usb3 *usb3, u16 reg, u16 value); 590b56e9a7SVivek Gautam }; 600b56e9a7SVivek Gautam 610b56e9a7SVivek Gautam static const struct of_device_id bcm_ns_usb3_id_table[] = { 620b56e9a7SVivek Gautam { 630b56e9a7SVivek Gautam .compatible = "brcm,ns-ax-usb3-phy", 640b56e9a7SVivek Gautam .data = (int *)BCM_NS_AX, 650b56e9a7SVivek Gautam }, 660b56e9a7SVivek Gautam { 670b56e9a7SVivek Gautam .compatible = "brcm,ns-bx-usb3-phy", 680b56e9a7SVivek Gautam .data = (int *)BCM_NS_BX, 690b56e9a7SVivek Gautam }, 700b56e9a7SVivek Gautam {}, 710b56e9a7SVivek Gautam }; 720b56e9a7SVivek Gautam MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); 730b56e9a7SVivek Gautam 740b56e9a7SVivek Gautam static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, 750b56e9a7SVivek Gautam u16 value) 760b56e9a7SVivek Gautam { 77b20f506fSRafał Miłecki return usb3->phy_write(usb3, reg, value); 780b56e9a7SVivek Gautam } 790b56e9a7SVivek Gautam 800b56e9a7SVivek Gautam static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) 810b56e9a7SVivek Gautam { 820b56e9a7SVivek Gautam int err; 830b56e9a7SVivek Gautam 840b56e9a7SVivek Gautam /* USB3 PLL Block */ 850b56e9a7SVivek Gautam err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 860b56e9a7SVivek Gautam BCM_NS_USB3_PHY_PLL30_BLOCK); 870b56e9a7SVivek Gautam if (err < 0) 880b56e9a7SVivek Gautam return err; 890b56e9a7SVivek Gautam 900b56e9a7SVivek Gautam /* Assert Ana_Pllseq start */ 910b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x1000); 920b56e9a7SVivek Gautam 930b56e9a7SVivek Gautam /* Assert CML Divider ratio to 26 */ 940b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400); 950b56e9a7SVivek Gautam 960b56e9a7SVivek Gautam /* Asserting PLL Reset */ 970b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0xc000); 980b56e9a7SVivek Gautam 990b56e9a7SVivek Gautam /* Deaaserting PLL Reset */ 1000b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0x8000); 1010b56e9a7SVivek Gautam 1020b56e9a7SVivek Gautam /* Deasserting USB3 system reset */ 1030b56e9a7SVivek Gautam writel(0, usb3->dmp + BCMA_RESET_CTL); 1040b56e9a7SVivek Gautam 1050b56e9a7SVivek Gautam /* PLL frequency monitor enable */ 1060b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x9000); 1070b56e9a7SVivek Gautam 1080b56e9a7SVivek Gautam /* PIPE Block */ 1090b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 1100b56e9a7SVivek Gautam BCM_NS_USB3_PHY_PIPE_BLOCK); 1110b56e9a7SVivek Gautam 1120b56e9a7SVivek Gautam /* CMPMAX & CMPMINTH setting */ 1130b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_CMP, 0xf30d); 1140b56e9a7SVivek Gautam 1150b56e9a7SVivek Gautam /* DEGLITCH MIN & MAX setting */ 1160b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_DEGLITCH, 0x6302); 1170b56e9a7SVivek Gautam 1180b56e9a7SVivek Gautam /* TXPMD block */ 1190b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 1200b56e9a7SVivek Gautam BCM_NS_USB3_PHY_TX_PMD_BLOCK); 1210b56e9a7SVivek Gautam 1220b56e9a7SVivek Gautam /* Enabling SSC */ 1230b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003); 1240b56e9a7SVivek Gautam 1250b56e9a7SVivek Gautam return 0; 1260b56e9a7SVivek Gautam } 1270b56e9a7SVivek Gautam 1280b56e9a7SVivek Gautam static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3) 1290b56e9a7SVivek Gautam { 1300b56e9a7SVivek Gautam int err; 1310b56e9a7SVivek Gautam 1320b56e9a7SVivek Gautam /* PLL30 block */ 1330b56e9a7SVivek Gautam err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 1340b56e9a7SVivek Gautam BCM_NS_USB3_PHY_PLL30_BLOCK); 1350b56e9a7SVivek Gautam if (err < 0) 1360b56e9a7SVivek Gautam return err; 1370b56e9a7SVivek Gautam 1380b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400); 1390b56e9a7SVivek Gautam 1400b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 0x80e0); 1410b56e9a7SVivek Gautam 1420b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x009c); 1430b56e9a7SVivek Gautam 1440b56e9a7SVivek Gautam /* Enable SSC */ 1450b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 1460b56e9a7SVivek Gautam BCM_NS_USB3_PHY_TX_PMD_BLOCK); 1470b56e9a7SVivek Gautam 1480b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x21d3); 1490b56e9a7SVivek Gautam 1500b56e9a7SVivek Gautam bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003); 1510b56e9a7SVivek Gautam 1520b56e9a7SVivek Gautam /* Deasserting USB3 system reset */ 1530b56e9a7SVivek Gautam writel(0, usb3->dmp + BCMA_RESET_CTL); 1540b56e9a7SVivek Gautam 1550b56e9a7SVivek Gautam return 0; 1560b56e9a7SVivek Gautam } 1570b56e9a7SVivek Gautam 1580b56e9a7SVivek Gautam static int bcm_ns_usb3_phy_init(struct phy *phy) 1590b56e9a7SVivek Gautam { 1600b56e9a7SVivek Gautam struct bcm_ns_usb3 *usb3 = phy_get_drvdata(phy); 1610b56e9a7SVivek Gautam int err; 1620b56e9a7SVivek Gautam 1630b56e9a7SVivek Gautam /* Perform USB3 system soft reset */ 1640b56e9a7SVivek Gautam writel(BCMA_RESET_CTL_RESET, usb3->dmp + BCMA_RESET_CTL); 1650b56e9a7SVivek Gautam 1660b56e9a7SVivek Gautam switch (usb3->family) { 1670b56e9a7SVivek Gautam case BCM_NS_AX: 1680b56e9a7SVivek Gautam err = bcm_ns_usb3_phy_init_ns_ax(usb3); 1690b56e9a7SVivek Gautam break; 1700b56e9a7SVivek Gautam case BCM_NS_BX: 1710b56e9a7SVivek Gautam err = bcm_ns_usb3_phy_init_ns_bx(usb3); 1720b56e9a7SVivek Gautam break; 1730b56e9a7SVivek Gautam default: 1740b56e9a7SVivek Gautam WARN_ON(1); 1750b56e9a7SVivek Gautam err = -ENOTSUPP; 1760b56e9a7SVivek Gautam } 1770b56e9a7SVivek Gautam 1780b56e9a7SVivek Gautam return err; 1790b56e9a7SVivek Gautam } 1800b56e9a7SVivek Gautam 1810b56e9a7SVivek Gautam static const struct phy_ops ops = { 1820b56e9a7SVivek Gautam .init = bcm_ns_usb3_phy_init, 1830b56e9a7SVivek Gautam .owner = THIS_MODULE, 1840b56e9a7SVivek Gautam }; 1850b56e9a7SVivek Gautam 186b20f506fSRafał Miłecki /************************************************** 187af850e14SRafał Miłecki * MDIO driver code 188af850e14SRafał Miłecki **************************************************/ 189af850e14SRafał Miłecki 190af850e14SRafał Miłecki static int bcm_ns_usb3_mdiodev_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, 191af850e14SRafał Miłecki u16 value) 192af850e14SRafał Miłecki { 193af850e14SRafał Miłecki struct mdio_device *mdiodev = usb3->mdiodev; 194af850e14SRafał Miłecki 195af850e14SRafał Miłecki return mdiobus_write(mdiodev->bus, mdiodev->addr, reg, value); 196af850e14SRafał Miłecki } 197af850e14SRafał Miłecki 198af850e14SRafał Miłecki static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev) 199af850e14SRafał Miłecki { 200af850e14SRafał Miłecki struct device *dev = &mdiodev->dev; 201af850e14SRafał Miłecki const struct of_device_id *of_id; 202af850e14SRafał Miłecki struct phy_provider *phy_provider; 203af850e14SRafał Miłecki struct device_node *syscon_np; 204af850e14SRafał Miłecki struct bcm_ns_usb3 *usb3; 205af850e14SRafał Miłecki struct resource res; 206af850e14SRafał Miłecki int err; 207af850e14SRafał Miłecki 208af850e14SRafał Miłecki usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL); 209af850e14SRafał Miłecki if (!usb3) 210af850e14SRafał Miłecki return -ENOMEM; 211af850e14SRafał Miłecki 212af850e14SRafał Miłecki usb3->dev = dev; 213af850e14SRafał Miłecki usb3->mdiodev = mdiodev; 214af850e14SRafał Miłecki 215af850e14SRafał Miłecki of_id = of_match_device(bcm_ns_usb3_id_table, dev); 216af850e14SRafał Miłecki if (!of_id) 217af850e14SRafał Miłecki return -EINVAL; 218af850e14SRafał Miłecki usb3->family = (enum bcm_ns_family)of_id->data; 219af850e14SRafał Miłecki 220af850e14SRafał Miłecki syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0); 221af850e14SRafał Miłecki err = of_address_to_resource(syscon_np, 0, &res); 222af850e14SRafał Miłecki of_node_put(syscon_np); 223af850e14SRafał Miłecki if (err) 224af850e14SRafał Miłecki return err; 225af850e14SRafał Miłecki 226af850e14SRafał Miłecki usb3->dmp = devm_ioremap_resource(dev, &res); 227af850e14SRafał Miłecki if (IS_ERR(usb3->dmp)) { 228af850e14SRafał Miłecki dev_err(dev, "Failed to map DMP regs\n"); 229af850e14SRafał Miłecki return PTR_ERR(usb3->dmp); 230af850e14SRafał Miłecki } 231af850e14SRafał Miłecki 232af850e14SRafał Miłecki usb3->phy_write = bcm_ns_usb3_mdiodev_phy_write; 233af850e14SRafał Miłecki 234af850e14SRafał Miłecki usb3->phy = devm_phy_create(dev, NULL, &ops); 235af850e14SRafał Miłecki if (IS_ERR(usb3->phy)) { 236af850e14SRafał Miłecki dev_err(dev, "Failed to create PHY\n"); 237af850e14SRafał Miłecki return PTR_ERR(usb3->phy); 238af850e14SRafał Miłecki } 239af850e14SRafał Miłecki 240af850e14SRafał Miłecki phy_set_drvdata(usb3->phy, usb3); 241af850e14SRafał Miłecki 242af850e14SRafał Miłecki phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 243af850e14SRafał Miłecki 244af850e14SRafał Miłecki return PTR_ERR_OR_ZERO(phy_provider); 245af850e14SRafał Miłecki } 246af850e14SRafał Miłecki 247af850e14SRafał Miłecki static struct mdio_driver bcm_ns_usb3_mdio_driver = { 248af850e14SRafał Miłecki .mdiodrv = { 249af850e14SRafał Miłecki .driver = { 250af850e14SRafał Miłecki .name = "bcm_ns_mdio_usb3", 251af850e14SRafał Miłecki .of_match_table = bcm_ns_usb3_id_table, 252af850e14SRafał Miłecki }, 253af850e14SRafał Miłecki }, 254af850e14SRafał Miłecki .probe = bcm_ns_usb3_mdio_probe, 255af850e14SRafał Miłecki }; 256af850e14SRafał Miłecki 257af850e14SRafał Miłecki /************************************************** 258b20f506fSRafał Miłecki * Platform driver code 259b20f506fSRafał Miłecki **************************************************/ 260b20f506fSRafał Miłecki 261b20f506fSRafał Miłecki static int bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr, 26247da6aa7SChunfeng Yun u32 mask, u32 value, int usec) 263b20f506fSRafał Miłecki { 264b20f506fSRafał Miłecki u32 val; 26547da6aa7SChunfeng Yun int ret; 266b20f506fSRafał Miłecki 26747da6aa7SChunfeng Yun ret = readl_poll_timeout_atomic(addr, val, ((val & mask) == value), 26847da6aa7SChunfeng Yun 10, usec); 26947da6aa7SChunfeng Yun if (ret) 270b20f506fSRafał Miłecki dev_err(usb3->dev, "Timeout waiting for register %p\n", addr); 271b20f506fSRafał Miłecki 27247da6aa7SChunfeng Yun return ret; 273b20f506fSRafał Miłecki } 274b20f506fSRafał Miłecki 275b20f506fSRafał Miłecki static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3) 276b20f506fSRafał Miłecki { 277b20f506fSRafał Miłecki return bcm_ns_usb3_wait_reg(usb3, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL, 278b20f506fSRafał Miłecki 0x0100, 0x0000, 27947da6aa7SChunfeng Yun BCM_NS_USB3_MII_MNG_TIMEOUT_US); 280b20f506fSRafał Miłecki } 281b20f506fSRafał Miłecki 282b20f506fSRafał Miłecki static int bcm_ns_usb3_platform_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, 283b20f506fSRafał Miłecki u16 value) 284b20f506fSRafał Miłecki { 285b20f506fSRafał Miłecki u32 tmp = 0; 286b20f506fSRafał Miłecki int err; 287b20f506fSRafał Miłecki 288b20f506fSRafał Miłecki err = bcm_ns_usb3_mii_mng_wait_idle(usb3); 289b20f506fSRafał Miłecki if (err < 0) { 290b20f506fSRafał Miłecki dev_err(usb3->dev, "Couldn't write 0x%08x value\n", value); 291b20f506fSRafał Miłecki return err; 292b20f506fSRafał Miłecki } 293b20f506fSRafał Miłecki 294b20f506fSRafał Miłecki /* TODO: Use a proper MDIO bus layer */ 295b20f506fSRafał Miłecki tmp |= 0x58020000; /* Magic value for MDIO PHY write */ 296b20f506fSRafał Miłecki tmp |= reg << 18; 297b20f506fSRafał Miłecki tmp |= value; 298b20f506fSRafał Miłecki writel(tmp, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA); 299b20f506fSRafał Miłecki 300b20f506fSRafał Miłecki return bcm_ns_usb3_mii_mng_wait_idle(usb3); 301b20f506fSRafał Miłecki } 302b20f506fSRafał Miłecki 3030b56e9a7SVivek Gautam static int bcm_ns_usb3_probe(struct platform_device *pdev) 3040b56e9a7SVivek Gautam { 3050b56e9a7SVivek Gautam struct device *dev = &pdev->dev; 3060b56e9a7SVivek Gautam const struct of_device_id *of_id; 3070b56e9a7SVivek Gautam struct bcm_ns_usb3 *usb3; 3080b56e9a7SVivek Gautam struct resource *res; 3090b56e9a7SVivek Gautam struct phy_provider *phy_provider; 3100b56e9a7SVivek Gautam 3110b56e9a7SVivek Gautam usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL); 3120b56e9a7SVivek Gautam if (!usb3) 3130b56e9a7SVivek Gautam return -ENOMEM; 3140b56e9a7SVivek Gautam 3150b56e9a7SVivek Gautam usb3->dev = dev; 3160b56e9a7SVivek Gautam 3170b56e9a7SVivek Gautam of_id = of_match_device(bcm_ns_usb3_id_table, dev); 3180b56e9a7SVivek Gautam if (!of_id) 3190b56e9a7SVivek Gautam return -EINVAL; 3200b56e9a7SVivek Gautam usb3->family = (enum bcm_ns_family)of_id->data; 3210b56e9a7SVivek Gautam 3220b56e9a7SVivek Gautam res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmp"); 3230b56e9a7SVivek Gautam usb3->dmp = devm_ioremap_resource(dev, res); 3240b56e9a7SVivek Gautam if (IS_ERR(usb3->dmp)) { 3250b56e9a7SVivek Gautam dev_err(dev, "Failed to map DMP regs\n"); 3260b56e9a7SVivek Gautam return PTR_ERR(usb3->dmp); 3270b56e9a7SVivek Gautam } 3280b56e9a7SVivek Gautam 3290b56e9a7SVivek Gautam res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccb-mii"); 3300b56e9a7SVivek Gautam usb3->ccb_mii = devm_ioremap_resource(dev, res); 3310b56e9a7SVivek Gautam if (IS_ERR(usb3->ccb_mii)) { 3320b56e9a7SVivek Gautam dev_err(dev, "Failed to map ChipCommon B MII regs\n"); 3330b56e9a7SVivek Gautam return PTR_ERR(usb3->ccb_mii); 3340b56e9a7SVivek Gautam } 3350b56e9a7SVivek Gautam 3364536adeeSRafał Miłecki /* Enable MDIO. Setting MDCDIV as 26 */ 3374536adeeSRafał Miłecki writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); 3384536adeeSRafał Miłecki 3394536adeeSRafał Miłecki /* Wait for MDIO? */ 3404536adeeSRafał Miłecki udelay(2); 3414536adeeSRafał Miłecki 342b20f506fSRafał Miłecki usb3->phy_write = bcm_ns_usb3_platform_phy_write; 343b20f506fSRafał Miłecki 3440b56e9a7SVivek Gautam usb3->phy = devm_phy_create(dev, NULL, &ops); 3450b56e9a7SVivek Gautam if (IS_ERR(usb3->phy)) { 3460b56e9a7SVivek Gautam dev_err(dev, "Failed to create PHY\n"); 3470b56e9a7SVivek Gautam return PTR_ERR(usb3->phy); 3480b56e9a7SVivek Gautam } 3490b56e9a7SVivek Gautam 3500b56e9a7SVivek Gautam phy_set_drvdata(usb3->phy, usb3); 3510b56e9a7SVivek Gautam platform_set_drvdata(pdev, usb3); 3520b56e9a7SVivek Gautam 3530b56e9a7SVivek Gautam phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 3540b56e9a7SVivek Gautam if (!IS_ERR(phy_provider)) 3550b56e9a7SVivek Gautam dev_info(dev, "Registered Broadcom Northstar USB 3.0 PHY driver\n"); 3560b56e9a7SVivek Gautam 3570b56e9a7SVivek Gautam return PTR_ERR_OR_ZERO(phy_provider); 3580b56e9a7SVivek Gautam } 3590b56e9a7SVivek Gautam 3600b56e9a7SVivek Gautam static struct platform_driver bcm_ns_usb3_driver = { 3610b56e9a7SVivek Gautam .probe = bcm_ns_usb3_probe, 3620b56e9a7SVivek Gautam .driver = { 3630b56e9a7SVivek Gautam .name = "bcm_ns_usb3", 3640b56e9a7SVivek Gautam .of_match_table = bcm_ns_usb3_id_table, 3650b56e9a7SVivek Gautam }, 3660b56e9a7SVivek Gautam }; 367af850e14SRafał Miłecki 368af850e14SRafał Miłecki static int __init bcm_ns_usb3_module_init(void) 369af850e14SRafał Miłecki { 370af850e14SRafał Miłecki int err; 371af850e14SRafał Miłecki 372af850e14SRafał Miłecki /* 373af850e14SRafał Miłecki * For backward compatibility we register as MDIO and platform driver. 374af850e14SRafał Miłecki * After getting MDIO binding commonly used (e.g. switching all DT files 375af850e14SRafał Miłecki * to use it) we should deprecate the old binding and eventually drop 376af850e14SRafał Miłecki * support for it. 377af850e14SRafał Miłecki */ 378af850e14SRafał Miłecki 379af850e14SRafał Miłecki err = mdio_driver_register(&bcm_ns_usb3_mdio_driver); 380af850e14SRafał Miłecki if (err) 381af850e14SRafał Miłecki return err; 382af850e14SRafał Miłecki 383af850e14SRafał Miłecki err = platform_driver_register(&bcm_ns_usb3_driver); 384af850e14SRafał Miłecki if (err) 385af850e14SRafał Miłecki mdio_driver_unregister(&bcm_ns_usb3_mdio_driver); 386af850e14SRafał Miłecki 387af850e14SRafał Miłecki return err; 388af850e14SRafał Miłecki } 389af850e14SRafał Miłecki module_init(bcm_ns_usb3_module_init); 390af850e14SRafał Miłecki 391af850e14SRafał Miłecki static void __exit bcm_ns_usb3_module_exit(void) 392af850e14SRafał Miłecki { 393af850e14SRafał Miłecki platform_driver_unregister(&bcm_ns_usb3_driver); 394af850e14SRafał Miłecki mdio_driver_unregister(&bcm_ns_usb3_mdio_driver); 395af850e14SRafał Miłecki } 396af850e14SRafał Miłecki module_exit(bcm_ns_usb3_module_exit) 3970b56e9a7SVivek Gautam 3980b56e9a7SVivek Gautam MODULE_LICENSE("GPL v2"); 399