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 1499df54ddaSFlorian Fainelli static int bcm7xxx_apd_enable(struct phy_device *phydev) 1509df54ddaSFlorian Fainelli { 1519df54ddaSFlorian Fainelli int val; 1529df54ddaSFlorian Fainelli 1539df54ddaSFlorian Fainelli /* Enable powering down of the DLL during auto-power down */ 1549df54ddaSFlorian Fainelli val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3); 1559df54ddaSFlorian Fainelli if (val < 0) 1569df54ddaSFlorian Fainelli return val; 1579df54ddaSFlorian Fainelli 1589df54ddaSFlorian Fainelli val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 1599df54ddaSFlorian Fainelli bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); 1609df54ddaSFlorian Fainelli 1619df54ddaSFlorian Fainelli /* Enable auto-power down */ 1629df54ddaSFlorian Fainelli val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); 1639df54ddaSFlorian Fainelli if (val < 0) 1649df54ddaSFlorian Fainelli return val; 1659df54ddaSFlorian Fainelli 1669df54ddaSFlorian Fainelli val |= BCM54XX_SHD_APD_EN; 1679df54ddaSFlorian Fainelli return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); 1689df54ddaSFlorian Fainelli } 1699df54ddaSFlorian Fainelli 170b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 171b560a58cSFlorian Fainelli { 172b560a58cSFlorian Fainelli int ret; 173b560a58cSFlorian Fainelli 174b560a58cSFlorian Fainelli ret = bcm7445_config_init(phydev); 175b560a58cSFlorian Fainelli if (ret) 176b560a58cSFlorian Fainelli return ret; 177b560a58cSFlorian Fainelli 1789df54ddaSFlorian Fainelli ret = bcm7xxx_28nm_afe_config_init(phydev); 1799df54ddaSFlorian Fainelli if (ret) 1809df54ddaSFlorian Fainelli return ret; 1819df54ddaSFlorian Fainelli 1829df54ddaSFlorian Fainelli return bcm7xxx_apd_enable(phydev); 183b560a58cSFlorian Fainelli } 184b560a58cSFlorian Fainelli 1854fd14e0bSFlorian Fainelli static int bcm7xxx_28nm_resume(struct phy_device *phydev) 1864fd14e0bSFlorian Fainelli { 1874fd14e0bSFlorian Fainelli int ret; 1884fd14e0bSFlorian Fainelli 1894fd14e0bSFlorian Fainelli /* Re-apply workarounds coming out suspend/resume */ 1904fd14e0bSFlorian Fainelli ret = bcm7xxx_28nm_config_init(phydev); 1914fd14e0bSFlorian Fainelli if (ret) 1924fd14e0bSFlorian Fainelli return ret; 1934fd14e0bSFlorian Fainelli 1944fd14e0bSFlorian Fainelli /* 28nm Gigabit PHYs come out of reset without any half-duplex 1954fd14e0bSFlorian Fainelli * or "hub" compliant advertised mode, fix that. This does not 1964fd14e0bSFlorian Fainelli * cause any problems with the PHY library since genphy_config_aneg() 1974fd14e0bSFlorian Fainelli * gracefully handles auto-negotiated and forced modes. 1984fd14e0bSFlorian Fainelli */ 1994fd14e0bSFlorian Fainelli return genphy_config_aneg(phydev); 2004fd14e0bSFlorian Fainelli } 2014fd14e0bSFlorian Fainelli 202b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location, 203b560a58cSFlorian Fainelli int set_mask, int clr_mask) 204b560a58cSFlorian Fainelli { 205b560a58cSFlorian Fainelli int v, ret; 206b560a58cSFlorian Fainelli 207b560a58cSFlorian Fainelli v = phy_read(dev, location); 208b560a58cSFlorian Fainelli if (v < 0) 209b560a58cSFlorian Fainelli return v; 210b560a58cSFlorian Fainelli 211b560a58cSFlorian Fainelli v &= ~clr_mask; 212b560a58cSFlorian Fainelli v |= set_mask; 213b560a58cSFlorian Fainelli 214b560a58cSFlorian Fainelli ret = phy_write(dev, location, v); 215b560a58cSFlorian Fainelli if (ret < 0) 216b560a58cSFlorian Fainelli return ret; 217b560a58cSFlorian Fainelli 218b560a58cSFlorian Fainelli return v; 219b560a58cSFlorian Fainelli } 220b560a58cSFlorian Fainelli 221b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev) 222b560a58cSFlorian Fainelli { 223b560a58cSFlorian Fainelli int ret; 224b560a58cSFlorian Fainelli 225b560a58cSFlorian Fainelli /* Enable 64 clock MDIO */ 226b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); 227b560a58cSFlorian Fainelli phy_read(phydev, MII_BCM7XXX_AUX_MODE); 228b560a58cSFlorian Fainelli 229b560a58cSFlorian Fainelli /* Workaround only required for 100Mbits/sec */ 230b560a58cSFlorian Fainelli if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) 231b560a58cSFlorian Fainelli return 0; 232b560a58cSFlorian Fainelli 233b560a58cSFlorian Fainelli /* set shadow mode 2 */ 234b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 235b560a58cSFlorian Fainelli MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); 236b560a58cSFlorian Fainelli if (ret < 0) 237b560a58cSFlorian Fainelli return ret; 238b560a58cSFlorian Fainelli 239b560a58cSFlorian Fainelli /* set iddq_clkbias */ 240b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); 241b560a58cSFlorian Fainelli udelay(10); 242b560a58cSFlorian Fainelli 243b560a58cSFlorian Fainelli /* reset iddq_clkbias */ 244b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); 245b560a58cSFlorian Fainelli 246b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); 247b560a58cSFlorian Fainelli 248b560a58cSFlorian Fainelli /* reset shadow mode 2 */ 249b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); 250b560a58cSFlorian Fainelli if (ret < 0) 251b560a58cSFlorian Fainelli return ret; 252b560a58cSFlorian Fainelli 253b560a58cSFlorian Fainelli return 0; 254b560a58cSFlorian Fainelli } 255b560a58cSFlorian Fainelli 256b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required 25782c084f5SFlorian Fainelli * for all BCM7XXX 40nm and 65nm PHYs 258b560a58cSFlorian Fainelli */ 259b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev) 260b560a58cSFlorian Fainelli { 261b560a58cSFlorian Fainelli int ret; 262b560a58cSFlorian Fainelli const struct bcm7xxx_regs { 263b560a58cSFlorian Fainelli int reg; 264b560a58cSFlorian Fainelli u16 value; 265b560a58cSFlorian Fainelli } bcm7xxx_suspend_cfg[] = { 266b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x008b }, 267b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, 268b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_DISC, 0x7000 }, 269b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000f }, 270b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, 271b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000b }, 272b560a58cSFlorian Fainelli }; 273b560a58cSFlorian Fainelli unsigned int i; 274b560a58cSFlorian Fainelli 275b560a58cSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { 276b560a58cSFlorian Fainelli ret = phy_write(phydev, 277b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].reg, 278b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].value); 279b560a58cSFlorian Fainelli if (ret) 280b560a58cSFlorian Fainelli return ret; 281b560a58cSFlorian Fainelli } 282b560a58cSFlorian Fainelli 283b560a58cSFlorian Fainelli return 0; 284b560a58cSFlorian Fainelli } 285b560a58cSFlorian Fainelli 286b560a58cSFlorian Fainelli static int bcm7xxx_dummy_config_init(struct phy_device *phydev) 287b560a58cSFlorian Fainelli { 288b560a58cSFlorian Fainelli return 0; 289b560a58cSFlorian Fainelli } 290b560a58cSFlorian Fainelli 291b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = { 292b560a58cSFlorian Fainelli { 293b560a58cSFlorian Fainelli .phy_id = PHY_ID_BCM7366, 294b560a58cSFlorian Fainelli .phy_id_mask = 0xfffffff0, 295b560a58cSFlorian Fainelli .name = "Broadcom BCM7366", 296b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 297b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 298b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 299b560a58cSFlorian Fainelli .config_init = bcm7xxx_28nm_afe_config_init, 300b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 301b560a58cSFlorian Fainelli .read_status = genphy_read_status, 3024fd14e0bSFlorian Fainelli .resume = bcm7xxx_28nm_resume, 303b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 304b560a58cSFlorian Fainelli }, { 305b560a58cSFlorian Fainelli .phy_id = PHY_ID_BCM7439, 306b560a58cSFlorian Fainelli .phy_id_mask = 0xfffffff0, 307b560a58cSFlorian Fainelli .name = "Broadcom BCM7439", 308b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 309b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 310b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 311b560a58cSFlorian Fainelli .config_init = bcm7xxx_28nm_afe_config_init, 312b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 313b560a58cSFlorian Fainelli .read_status = genphy_read_status, 3144fd14e0bSFlorian Fainelli .resume = bcm7xxx_28nm_resume, 315b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 316b560a58cSFlorian Fainelli }, { 317b560a58cSFlorian Fainelli .phy_id = PHY_ID_BCM7445, 318b560a58cSFlorian Fainelli .phy_id_mask = 0xfffffff0, 319b560a58cSFlorian Fainelli .name = "Broadcom BCM7445", 320b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 321b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 322b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 323b560a58cSFlorian Fainelli .config_init = bcm7xxx_28nm_config_init, 324b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 325b560a58cSFlorian Fainelli .read_status = genphy_read_status, 3264fd14e0bSFlorian Fainelli .resume = bcm7xxx_28nm_afe_config_init, 327b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 328b560a58cSFlorian Fainelli }, { 329b560a58cSFlorian Fainelli .phy_id = PHY_BCM_OUI_4, 330b560a58cSFlorian Fainelli .phy_id_mask = 0xffff0000, 331b560a58cSFlorian Fainelli .name = "Broadcom BCM7XXX 40nm", 332b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 333b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 334b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 335b560a58cSFlorian Fainelli .config_init = bcm7xxx_config_init, 336b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 337b560a58cSFlorian Fainelli .read_status = genphy_read_status, 338b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 339b560a58cSFlorian Fainelli .resume = bcm7xxx_config_init, 340b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 341b560a58cSFlorian Fainelli }, { 342b560a58cSFlorian Fainelli .phy_id = PHY_BCM_OUI_5, 343b560a58cSFlorian Fainelli .phy_id_mask = 0xffffff00, 344b560a58cSFlorian Fainelli .name = "Broadcom BCM7XXX 65nm", 345b560a58cSFlorian Fainelli .features = PHY_BASIC_FEATURES | 346b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 347b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 348b560a58cSFlorian Fainelli .config_init = bcm7xxx_dummy_config_init, 349b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 350b560a58cSFlorian Fainelli .read_status = genphy_read_status, 351b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 352b560a58cSFlorian Fainelli .resume = bcm7xxx_config_init, 353b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 354b560a58cSFlorian Fainelli } }; 355b560a58cSFlorian Fainelli 356b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { 357b560a58cSFlorian Fainelli { PHY_ID_BCM7366, 0xfffffff0, }, 358b560a58cSFlorian Fainelli { PHY_ID_BCM7439, 0xfffffff0, }, 359b560a58cSFlorian Fainelli { PHY_ID_BCM7445, 0xfffffff0, }, 360b560a58cSFlorian Fainelli { PHY_BCM_OUI_4, 0xffff0000 }, 361b560a58cSFlorian Fainelli { PHY_BCM_OUI_5, 0xffffff00 }, 362b560a58cSFlorian Fainelli { } 363b560a58cSFlorian Fainelli }; 364b560a58cSFlorian Fainelli 365b560a58cSFlorian Fainelli static int __init bcm7xxx_phy_init(void) 366b560a58cSFlorian Fainelli { 367b560a58cSFlorian Fainelli return phy_drivers_register(bcm7xxx_driver, 368b560a58cSFlorian Fainelli ARRAY_SIZE(bcm7xxx_driver)); 369b560a58cSFlorian Fainelli } 370b560a58cSFlorian Fainelli 371b560a58cSFlorian Fainelli static void __exit bcm7xxx_phy_exit(void) 372b560a58cSFlorian Fainelli { 373b560a58cSFlorian Fainelli phy_drivers_unregister(bcm7xxx_driver, 374b560a58cSFlorian Fainelli ARRAY_SIZE(bcm7xxx_driver)); 375b560a58cSFlorian Fainelli } 376b560a58cSFlorian Fainelli 377b560a58cSFlorian Fainelli module_init(bcm7xxx_phy_init); 378b560a58cSFlorian Fainelli module_exit(bcm7xxx_phy_exit); 379b560a58cSFlorian Fainelli 380b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); 381b560a58cSFlorian Fainelli 382b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); 383b560a58cSFlorian Fainelli MODULE_LICENSE("GPL"); 384b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation"); 385