1b560a58cSFlorian Fainelli /* 2b560a58cSFlorian Fainelli * Broadcom BCM7xxx internal transceivers support. 3b560a58cSFlorian Fainelli * 4b560a58cSFlorian Fainelli * Copyright (C) 2014, Broadcom Corporation 5b560a58cSFlorian Fainelli * 6b560a58cSFlorian Fainelli * This program is free software; you can redistribute it and/or 7b560a58cSFlorian Fainelli * modify it under the terms of the GNU General Public License 8b560a58cSFlorian Fainelli * as published by the Free Software Foundation; either version 9b560a58cSFlorian Fainelli * 2 of the License, or (at your option) any later version. 10b560a58cSFlorian Fainelli */ 11b560a58cSFlorian Fainelli 12b560a58cSFlorian Fainelli #include <linux/module.h> 13b560a58cSFlorian Fainelli #include <linux/phy.h> 14b560a58cSFlorian Fainelli #include <linux/delay.h> 15b560a58cSFlorian Fainelli #include <linux/bitops.h> 16b560a58cSFlorian Fainelli #include <linux/brcmphy.h> 17b560a58cSFlorian Fainelli 18b560a58cSFlorian Fainelli /* Broadcom BCM7xxx internal PHY registers */ 19b560a58cSFlorian Fainelli #define MII_BCM7XXX_CHANNEL_WIDTH 0x2000 20b560a58cSFlorian Fainelli 21b560a58cSFlorian Fainelli /* 40nm only register definitions */ 22b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_AUX_CTL 0x10 23b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_FALSE_CAR 0x13 24b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_DISC 0x14 25b560a58cSFlorian Fainelli #define MII_BCM7XXX_AUX_MODE 0x1d 26b560a58cSFlorian Fainelli #define MII_BCM7XX_64CLK_MDIO BIT(12) 27b560a58cSFlorian Fainelli #define MII_BCM7XXX_CORE_BASE1E 0x1e 28b560a58cSFlorian Fainelli #define MII_BCM7XXX_TEST 0x1f 29b560a58cSFlorian Fainelli #define MII_BCM7XXX_SHD_MODE_2 BIT(2) 30b560a58cSFlorian Fainelli 31a3622f2cSFlorian Fainelli /* 28nm only register definitions */ 32a3622f2cSFlorian Fainelli #define MISC_ADDR(base, channel) base, channel 33a3622f2cSFlorian Fainelli 34a3622f2cSFlorian Fainelli #define DSP_TAP10 MISC_ADDR(0x0a, 0) 35a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) 36a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) 37a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) 38a3622f2cSFlorian Fainelli 39a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) 40a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) 41a3622f2cSFlorian Fainelli #define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) 42a3622f2cSFlorian Fainelli #define AFE_TX_CONFIG MISC_ADDR(0x39, 0) 43a3622f2cSFlorian Fainelli #define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) 44a3622f2cSFlorian Fainelli 45a3622f2cSFlorian Fainelli #define CORE_EXPB0 0xb0 46a3622f2cSFlorian Fainelli 47b560a58cSFlorian Fainelli static int bcm7445_config_init(struct phy_device *phydev) 48b560a58cSFlorian Fainelli { 49b560a58cSFlorian Fainelli int ret; 50b560a58cSFlorian Fainelli const struct bcm7445_regs { 51b560a58cSFlorian Fainelli int reg; 52b560a58cSFlorian Fainelli u16 value; 53b560a58cSFlorian Fainelli } bcm7445_regs_cfg[] = { 54b560a58cSFlorian Fainelli /* increases ADC latency by 24ns */ 55b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x0038 }, 56b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0xAB95 }, 57b560a58cSFlorian Fainelli /* increases internal 1V LDO voltage by 5% */ 58b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x2038 }, 59b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0xBB22 }, 60b560a58cSFlorian Fainelli /* reduce RX low pass filter corner frequency */ 61b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x6038 }, 62b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0xFFC5 }, 63b560a58cSFlorian Fainelli /* reduce RX high pass filter corner frequency */ 64b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x003a }, 65b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0x2002 }, 66b560a58cSFlorian Fainelli }; 67b560a58cSFlorian Fainelli unsigned int i; 68b560a58cSFlorian Fainelli 69b560a58cSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) { 70b560a58cSFlorian Fainelli ret = phy_write(phydev, 71b560a58cSFlorian Fainelli bcm7445_regs_cfg[i].reg, 72b560a58cSFlorian Fainelli bcm7445_regs_cfg[i].value); 73b560a58cSFlorian Fainelli if (ret) 74b560a58cSFlorian Fainelli return ret; 75b560a58cSFlorian Fainelli } 76b560a58cSFlorian Fainelli 77b560a58cSFlorian Fainelli return 0; 78b560a58cSFlorian Fainelli } 79b560a58cSFlorian Fainelli 80b560a58cSFlorian Fainelli static void phy_write_exp(struct phy_device *phydev, 81b560a58cSFlorian Fainelli u16 reg, u16 value) 82b560a58cSFlorian Fainelli { 83b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg); 84b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_DATA, value); 85b560a58cSFlorian Fainelli } 86b560a58cSFlorian Fainelli 87b560a58cSFlorian Fainelli static void phy_write_misc(struct phy_device *phydev, 88b560a58cSFlorian Fainelli u16 reg, u16 chl, u16 value) 89b560a58cSFlorian Fainelli { 90b560a58cSFlorian Fainelli int tmp; 91b560a58cSFlorian Fainelli 92b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 93b560a58cSFlorian Fainelli 94b560a58cSFlorian Fainelli tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); 95b560a58cSFlorian Fainelli tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; 96b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); 97b560a58cSFlorian Fainelli 98b560a58cSFlorian Fainelli tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg; 99b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp); 100b560a58cSFlorian Fainelli 101b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_DATA, value); 102b560a58cSFlorian Fainelli } 103b560a58cSFlorian Fainelli 104b560a58cSFlorian Fainelli static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev) 105b560a58cSFlorian Fainelli { 106b560a58cSFlorian Fainelli /* Increase VCO range to prevent unlocking problem of PLL at low 107b560a58cSFlorian Fainelli * temp 108b560a58cSFlorian Fainelli */ 109a3622f2cSFlorian Fainelli phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 110b560a58cSFlorian Fainelli 111b560a58cSFlorian Fainelli /* Change Ki to 011 */ 112a3622f2cSFlorian Fainelli phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 113b560a58cSFlorian Fainelli 114b560a58cSFlorian Fainelli /* Disable loading of TVCO buffer to bandgap, set bandgap trim 115b560a58cSFlorian Fainelli * to 111 116b560a58cSFlorian Fainelli */ 117a3622f2cSFlorian Fainelli phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 118b560a58cSFlorian Fainelli 119b560a58cSFlorian Fainelli /* Adjust bias current trim by -3 */ 120a3622f2cSFlorian Fainelli phy_write_misc(phydev, DSP_TAP10, 0x690b); 121b560a58cSFlorian Fainelli 122b560a58cSFlorian Fainelli /* Switch to CORE_BASE1E */ 123b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd); 124b560a58cSFlorian Fainelli 125b560a58cSFlorian Fainelli /* Reset R_CAL/RC_CAL Engine */ 126a3622f2cSFlorian Fainelli phy_write_exp(phydev, CORE_EXPB0, 0x0010); 127b560a58cSFlorian Fainelli 128b560a58cSFlorian Fainelli /* Disable Reset R_CAL/RC_CAL Engine */ 129a3622f2cSFlorian Fainelli phy_write_exp(phydev, CORE_EXPB0, 0x0000); 130b560a58cSFlorian Fainelli 1319918542eSFlorian Fainelli /* write AFE_RXCONFIG_0 */ 1329918542eSFlorian Fainelli phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 1339918542eSFlorian Fainelli 1349918542eSFlorian Fainelli /* write AFE_RXCONFIG_1 */ 1359918542eSFlorian Fainelli phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 1369918542eSFlorian Fainelli 1379918542eSFlorian Fainelli /* write AFE_RX_LP_COUNTER */ 138a62ea5a7SFlorian Fainelli phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 1399918542eSFlorian Fainelli 1409918542eSFlorian Fainelli /* write AFE_HPF_TRIM_OTHERS */ 1419918542eSFlorian Fainelli phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 1429918542eSFlorian Fainelli 1439918542eSFlorian Fainelli /* write AFTE_TX_CONFIG */ 1449918542eSFlorian Fainelli phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 1459918542eSFlorian Fainelli 146b560a58cSFlorian Fainelli return 0; 147b560a58cSFlorian Fainelli } 148b560a58cSFlorian Fainelli 149b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 150b560a58cSFlorian Fainelli { 151b560a58cSFlorian Fainelli int ret; 152b560a58cSFlorian Fainelli 153b560a58cSFlorian Fainelli ret = bcm7445_config_init(phydev); 154b560a58cSFlorian Fainelli if (ret) 155b560a58cSFlorian Fainelli return ret; 156b560a58cSFlorian Fainelli 157b560a58cSFlorian Fainelli return bcm7xxx_28nm_afe_config_init(phydev); 158b560a58cSFlorian Fainelli } 159b560a58cSFlorian Fainelli 1604fd14e0bSFlorian Fainelli static int bcm7xxx_28nm_resume(struct phy_device *phydev) 1614fd14e0bSFlorian Fainelli { 1624fd14e0bSFlorian Fainelli int ret; 1634fd14e0bSFlorian Fainelli 1644fd14e0bSFlorian Fainelli /* Re-apply workarounds coming out suspend/resume */ 1654fd14e0bSFlorian Fainelli ret = bcm7xxx_28nm_config_init(phydev); 1664fd14e0bSFlorian Fainelli if (ret) 1674fd14e0bSFlorian Fainelli return ret; 1684fd14e0bSFlorian Fainelli 1694fd14e0bSFlorian Fainelli /* 28nm Gigabit PHYs come out of reset without any half-duplex 1704fd14e0bSFlorian Fainelli * or "hub" compliant advertised mode, fix that. This does not 1714fd14e0bSFlorian Fainelli * cause any problems with the PHY library since genphy_config_aneg() 1724fd14e0bSFlorian Fainelli * gracefully handles auto-negotiated and forced modes. 1734fd14e0bSFlorian Fainelli */ 1744fd14e0bSFlorian Fainelli return genphy_config_aneg(phydev); 1754fd14e0bSFlorian Fainelli } 1764fd14e0bSFlorian Fainelli 177b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location, 178b560a58cSFlorian Fainelli int set_mask, int clr_mask) 179b560a58cSFlorian Fainelli { 180b560a58cSFlorian Fainelli int v, ret; 181b560a58cSFlorian Fainelli 182b560a58cSFlorian Fainelli v = phy_read(dev, location); 183b560a58cSFlorian Fainelli if (v < 0) 184b560a58cSFlorian Fainelli return v; 185b560a58cSFlorian Fainelli 186b560a58cSFlorian Fainelli v &= ~clr_mask; 187b560a58cSFlorian Fainelli v |= set_mask; 188b560a58cSFlorian Fainelli 189b560a58cSFlorian Fainelli ret = phy_write(dev, location, v); 190b560a58cSFlorian Fainelli if (ret < 0) 191b560a58cSFlorian Fainelli return ret; 192b560a58cSFlorian Fainelli 193b560a58cSFlorian Fainelli return v; 194b560a58cSFlorian Fainelli } 195b560a58cSFlorian Fainelli 196b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev) 197b560a58cSFlorian Fainelli { 198b560a58cSFlorian Fainelli int ret; 199b560a58cSFlorian Fainelli 200b560a58cSFlorian Fainelli /* Enable 64 clock MDIO */ 201b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); 202b560a58cSFlorian Fainelli phy_read(phydev, MII_BCM7XXX_AUX_MODE); 203b560a58cSFlorian Fainelli 204b560a58cSFlorian Fainelli /* Workaround only required for 100Mbits/sec */ 205b560a58cSFlorian Fainelli if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) 206b560a58cSFlorian Fainelli return 0; 207b560a58cSFlorian Fainelli 208b560a58cSFlorian Fainelli /* set shadow mode 2 */ 209b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 210b560a58cSFlorian Fainelli MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); 211b560a58cSFlorian Fainelli if (ret < 0) 212b560a58cSFlorian Fainelli return ret; 213b560a58cSFlorian Fainelli 214b560a58cSFlorian Fainelli /* set iddq_clkbias */ 215b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); 216b560a58cSFlorian Fainelli udelay(10); 217b560a58cSFlorian Fainelli 218b560a58cSFlorian Fainelli /* reset iddq_clkbias */ 219b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); 220b560a58cSFlorian Fainelli 221b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); 222b560a58cSFlorian Fainelli 223b560a58cSFlorian Fainelli /* reset shadow mode 2 */ 224b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); 225b560a58cSFlorian Fainelli if (ret < 0) 226b560a58cSFlorian Fainelli return ret; 227b560a58cSFlorian Fainelli 228b560a58cSFlorian Fainelli return 0; 229b560a58cSFlorian Fainelli } 230b560a58cSFlorian Fainelli 231b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required 232b560a58cSFlorian Fainelli * for all BCM7XXX PHYs 233b560a58cSFlorian Fainelli */ 234b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev) 235b560a58cSFlorian Fainelli { 236b560a58cSFlorian Fainelli int ret; 237b560a58cSFlorian Fainelli const struct bcm7xxx_regs { 238b560a58cSFlorian Fainelli int reg; 239b560a58cSFlorian Fainelli u16 value; 240b560a58cSFlorian Fainelli } bcm7xxx_suspend_cfg[] = { 241b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x008b }, 242b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, 243b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_DISC, 0x7000 }, 244b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000f }, 245b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, 246b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000b }, 247b560a58cSFlorian Fainelli }; 248b560a58cSFlorian Fainelli unsigned int i; 249b560a58cSFlorian Fainelli 250b560a58cSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { 251b560a58cSFlorian Fainelli ret = phy_write(phydev, 252b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].reg, 253b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].value); 254b560a58cSFlorian Fainelli if (ret) 255b560a58cSFlorian Fainelli return ret; 256b560a58cSFlorian Fainelli } 257b560a58cSFlorian Fainelli 258b560a58cSFlorian Fainelli return 0; 259b560a58cSFlorian Fainelli } 260b560a58cSFlorian Fainelli 261b560a58cSFlorian Fainelli static int bcm7xxx_dummy_config_init(struct phy_device *phydev) 262b560a58cSFlorian Fainelli { 263b560a58cSFlorian Fainelli return 0; 264b560a58cSFlorian Fainelli } 265b560a58cSFlorian Fainelli 266b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = { 267b560a58cSFlorian Fainelli { 268b560a58cSFlorian Fainelli .phy_id = PHY_ID_BCM7366, 269b560a58cSFlorian Fainelli .phy_id_mask = 0xfffffff0, 270b560a58cSFlorian Fainelli .name = "Broadcom BCM7366", 271b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 272b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 273b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 274b560a58cSFlorian Fainelli .config_init = bcm7xxx_28nm_afe_config_init, 275b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 276b560a58cSFlorian Fainelli .read_status = genphy_read_status, 277b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 2784fd14e0bSFlorian Fainelli .resume = bcm7xxx_28nm_resume, 279b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 280b560a58cSFlorian Fainelli }, { 281b560a58cSFlorian Fainelli .phy_id = PHY_ID_BCM7439, 282b560a58cSFlorian Fainelli .phy_id_mask = 0xfffffff0, 283b560a58cSFlorian Fainelli .name = "Broadcom BCM7439", 284b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 285b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 286b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 287b560a58cSFlorian Fainelli .config_init = bcm7xxx_28nm_afe_config_init, 288b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 289b560a58cSFlorian Fainelli .read_status = genphy_read_status, 290b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 2914fd14e0bSFlorian Fainelli .resume = bcm7xxx_28nm_resume, 292b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 293b560a58cSFlorian Fainelli }, { 294b560a58cSFlorian Fainelli .phy_id = PHY_ID_BCM7445, 295b560a58cSFlorian Fainelli .phy_id_mask = 0xfffffff0, 296b560a58cSFlorian Fainelli .name = "Broadcom BCM7445", 297b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 298b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 299b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 300b560a58cSFlorian Fainelli .config_init = bcm7xxx_28nm_config_init, 301b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 302b560a58cSFlorian Fainelli .read_status = genphy_read_status, 303b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 3044fd14e0bSFlorian Fainelli .resume = bcm7xxx_28nm_afe_config_init, 305b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 306b560a58cSFlorian Fainelli }, { 307b560a58cSFlorian Fainelli .phy_id = PHY_BCM_OUI_4, 308b560a58cSFlorian Fainelli .phy_id_mask = 0xffff0000, 309b560a58cSFlorian Fainelli .name = "Broadcom BCM7XXX 40nm", 310b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 311b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 312b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 313b560a58cSFlorian Fainelli .config_init = bcm7xxx_config_init, 314b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 315b560a58cSFlorian Fainelli .read_status = genphy_read_status, 316b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 317b560a58cSFlorian Fainelli .resume = bcm7xxx_config_init, 318b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 319b560a58cSFlorian Fainelli }, { 320b560a58cSFlorian Fainelli .phy_id = PHY_BCM_OUI_5, 321b560a58cSFlorian Fainelli .phy_id_mask = 0xffffff00, 322b560a58cSFlorian Fainelli .name = "Broadcom BCM7XXX 65nm", 323b560a58cSFlorian Fainelli .features = PHY_BASIC_FEATURES | 324b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 325b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 326b560a58cSFlorian Fainelli .config_init = bcm7xxx_dummy_config_init, 327b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 328b560a58cSFlorian Fainelli .read_status = genphy_read_status, 329b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 330b560a58cSFlorian Fainelli .resume = bcm7xxx_config_init, 331b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 332b560a58cSFlorian Fainelli } }; 333b560a58cSFlorian Fainelli 334b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { 335b560a58cSFlorian Fainelli { PHY_ID_BCM7366, 0xfffffff0, }, 336b560a58cSFlorian Fainelli { PHY_ID_BCM7439, 0xfffffff0, }, 337b560a58cSFlorian Fainelli { PHY_ID_BCM7445, 0xfffffff0, }, 338b560a58cSFlorian Fainelli { PHY_BCM_OUI_4, 0xffff0000 }, 339b560a58cSFlorian Fainelli { PHY_BCM_OUI_5, 0xffffff00 }, 340b560a58cSFlorian Fainelli { } 341b560a58cSFlorian Fainelli }; 342b560a58cSFlorian Fainelli 343b560a58cSFlorian Fainelli static int __init bcm7xxx_phy_init(void) 344b560a58cSFlorian Fainelli { 345b560a58cSFlorian Fainelli return phy_drivers_register(bcm7xxx_driver, 346b560a58cSFlorian Fainelli ARRAY_SIZE(bcm7xxx_driver)); 347b560a58cSFlorian Fainelli } 348b560a58cSFlorian Fainelli 349b560a58cSFlorian Fainelli static void __exit bcm7xxx_phy_exit(void) 350b560a58cSFlorian Fainelli { 351b560a58cSFlorian Fainelli phy_drivers_unregister(bcm7xxx_driver, 352b560a58cSFlorian Fainelli ARRAY_SIZE(bcm7xxx_driver)); 353b560a58cSFlorian Fainelli } 354b560a58cSFlorian Fainelli 355b560a58cSFlorian Fainelli module_init(bcm7xxx_phy_init); 356b560a58cSFlorian Fainelli module_exit(bcm7xxx_phy_exit); 357b560a58cSFlorian Fainelli 358b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); 359b560a58cSFlorian Fainelli 360b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); 361b560a58cSFlorian Fainelli MODULE_LICENSE("GPL"); 362b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation"); 363