1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+ 20ca7111aSMatus Ujhelyi /* 30ca7111aSMatus Ujhelyi * drivers/net/phy/at803x.c 40ca7111aSMatus Ujhelyi * 596c36712SMichael Walle * Driver for Qualcomm Atheros AR803x PHY 60ca7111aSMatus Ujhelyi * 70ca7111aSMatus Ujhelyi * Author: Matus Ujhelyi <ujhelyi.m@gmail.com> 80ca7111aSMatus Ujhelyi */ 90ca7111aSMatus Ujhelyi 100ca7111aSMatus Ujhelyi #include <linux/phy.h> 110ca7111aSMatus Ujhelyi #include <linux/module.h> 120ca7111aSMatus Ujhelyi #include <linux/string.h> 130ca7111aSMatus Ujhelyi #include <linux/netdevice.h> 140ca7111aSMatus Ujhelyi #include <linux/etherdevice.h> 156cb75767SMichael Walle #include <linux/ethtool_netlink.h> 1613a56b44SDaniel Mack #include <linux/of_gpio.h> 172f664823SMichael Walle #include <linux/bitfield.h> 1813a56b44SDaniel Mack #include <linux/gpio/consumer.h> 192f664823SMichael Walle #include <linux/regulator/of_regulator.h> 202f664823SMichael Walle #include <linux/regulator/driver.h> 212f664823SMichael Walle #include <linux/regulator/consumer.h> 222f664823SMichael Walle #include <dt-bindings/net/qca-ar803x.h> 230ca7111aSMatus Ujhelyi 2406d5f344SRussell King #define AT803X_SPECIFIC_STATUS 0x11 2506d5f344SRussell King #define AT803X_SS_SPEED_MASK (3 << 14) 2606d5f344SRussell King #define AT803X_SS_SPEED_1000 (2 << 14) 2706d5f344SRussell King #define AT803X_SS_SPEED_100 (1 << 14) 2806d5f344SRussell King #define AT803X_SS_SPEED_10 (0 << 14) 2906d5f344SRussell King #define AT803X_SS_DUPLEX BIT(13) 3006d5f344SRussell King #define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) 3106d5f344SRussell King #define AT803X_SS_MDIX BIT(6) 3206d5f344SRussell King 330ca7111aSMatus Ujhelyi #define AT803X_INTR_ENABLE 0x12 34e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) 35e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) 36e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) 37e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) 38e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) 39e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) 40e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) 41e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) 42e6e4a556SMartin Blumenstingl #define AT803X_INTR_ENABLE_WOL BIT(0) 43e6e4a556SMartin Blumenstingl 440ca7111aSMatus Ujhelyi #define AT803X_INTR_STATUS 0x13 45a46bd63bSMartin Blumenstingl 4613a56b44SDaniel Mack #define AT803X_SMART_SPEED 0x14 47cde0f4f8SMichael Walle #define AT803X_SMART_SPEED_ENABLE BIT(5) 48cde0f4f8SMichael Walle #define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) 49cde0f4f8SMichael Walle #define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) 506cb75767SMichael Walle #define AT803X_CDT 0x16 516cb75767SMichael Walle #define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) 526cb75767SMichael Walle #define AT803X_CDT_ENABLE_TEST BIT(0) 536cb75767SMichael Walle #define AT803X_CDT_STATUS 0x1c 546cb75767SMichael Walle #define AT803X_CDT_STATUS_STAT_NORMAL 0 556cb75767SMichael Walle #define AT803X_CDT_STATUS_STAT_SHORT 1 566cb75767SMichael Walle #define AT803X_CDT_STATUS_STAT_OPEN 2 576cb75767SMichael Walle #define AT803X_CDT_STATUS_STAT_FAIL 3 586cb75767SMichael Walle #define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) 596cb75767SMichael Walle #define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) 6013a56b44SDaniel Mack #define AT803X_LED_CONTROL 0x18 61a46bd63bSMartin Blumenstingl 620ca7111aSMatus Ujhelyi #define AT803X_DEVICE_ADDR 0x03 630ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C 640ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B 650ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A 66f62265b5SZefir Kurtisi #define AT803X_REG_CHIP_CONFIG 0x1f 67f62265b5SZefir Kurtisi #define AT803X_BT_BX_REG_SEL 0x8000 68a46bd63bSMartin Blumenstingl 691ca6d1b1SMugunthan V N #define AT803X_DEBUG_ADDR 0x1D 701ca6d1b1SMugunthan V N #define AT803X_DEBUG_DATA 0x1E 71a46bd63bSMartin Blumenstingl 72f62265b5SZefir Kurtisi #define AT803X_MODE_CFG_MASK 0x0F 73f62265b5SZefir Kurtisi #define AT803X_MODE_CFG_SGMII 0x01 74f62265b5SZefir Kurtisi 75f62265b5SZefir Kurtisi #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ 76f62265b5SZefir Kurtisi #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 77f62265b5SZefir Kurtisi 782e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_REG_0 0x00 792e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) 80a46bd63bSMartin Blumenstingl 812e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_REG_5 0x05 822e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) 830ca7111aSMatus Ujhelyi 842f664823SMichael Walle #define AT803X_DEBUG_REG_1F 0x1F 852f664823SMichael Walle #define AT803X_DEBUG_PLL_ON BIT(2) 862f664823SMichael Walle #define AT803X_DEBUG_RGMII_1V8 BIT(3) 872f664823SMichael Walle 882f664823SMichael Walle /* AT803x supports either the XTAL input pad, an internal PLL or the 892f664823SMichael Walle * DSP as clock reference for the clock output pad. The XTAL reference 902f664823SMichael Walle * is only used for 25 MHz output, all other frequencies need the PLL. 912f664823SMichael Walle * The DSP as a clock reference is used in synchronous ethernet 922f664823SMichael Walle * applications. 932f664823SMichael Walle * 942f664823SMichael Walle * By default the PLL is only enabled if there is a link. Otherwise 952f664823SMichael Walle * the PHY will go into low power state and disabled the PLL. You can 962f664823SMichael Walle * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always 972f664823SMichael Walle * enabled. 982f664823SMichael Walle */ 992f664823SMichael Walle #define AT803X_MMD7_CLK25M 0x8016 1002f664823SMichael Walle #define AT803X_CLK_OUT_MASK GENMASK(4, 2) 1012f664823SMichael Walle #define AT803X_CLK_OUT_25MHZ_XTAL 0 1022f664823SMichael Walle #define AT803X_CLK_OUT_25MHZ_DSP 1 1032f664823SMichael Walle #define AT803X_CLK_OUT_50MHZ_PLL 2 1042f664823SMichael Walle #define AT803X_CLK_OUT_50MHZ_DSP 3 1052f664823SMichael Walle #define AT803X_CLK_OUT_62_5MHZ_PLL 4 1062f664823SMichael Walle #define AT803X_CLK_OUT_62_5MHZ_DSP 5 1072f664823SMichael Walle #define AT803X_CLK_OUT_125MHZ_PLL 6 1082f664823SMichael Walle #define AT803X_CLK_OUT_125MHZ_DSP 7 1092f664823SMichael Walle 110428061f7SMichael Walle /* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask 111428061f7SMichael Walle * but doesn't support choosing between XTAL/PLL and DSP. 1122f664823SMichael Walle */ 1132f664823SMichael Walle #define AT8035_CLK_OUT_MASK GENMASK(4, 3) 1142f664823SMichael Walle 1152f664823SMichael Walle #define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7) 1162f664823SMichael Walle #define AT803X_CLK_OUT_STRENGTH_FULL 0 1172f664823SMichael Walle #define AT803X_CLK_OUT_STRENGTH_HALF 1 1182f664823SMichael Walle #define AT803X_CLK_OUT_STRENGTH_QUARTER 2 1192f664823SMichael Walle 120cde0f4f8SMichael Walle #define AT803X_DEFAULT_DOWNSHIFT 5 121cde0f4f8SMichael Walle #define AT803X_MIN_DOWNSHIFT 2 122cde0f4f8SMichael Walle #define AT803X_MAX_DOWNSHIFT 9 123cde0f4f8SMichael Walle 1247908d2ceSOleksij Rempel #define ATH9331_PHY_ID 0x004dd041 125bd8ca17fSDaniel Mack #define ATH8030_PHY_ID 0x004dd076 126bd8ca17fSDaniel Mack #define ATH8031_PHY_ID 0x004dd074 1275800091aSDavid Bauer #define ATH8032_PHY_ID 0x004dd023 128bd8ca17fSDaniel Mack #define ATH8035_PHY_ID 0x004dd072 1290465d8f8SMichael Walle #define AT8030_PHY_ID_MASK 0xffffffef 130bd8ca17fSDaniel Mack 13196c36712SMichael Walle MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver"); 1320ca7111aSMatus Ujhelyi MODULE_AUTHOR("Matus Ujhelyi"); 1330ca7111aSMatus Ujhelyi MODULE_LICENSE("GPL"); 1340ca7111aSMatus Ujhelyi 1352f664823SMichael Walle struct at803x_priv { 1362f664823SMichael Walle int flags; 1372f664823SMichael Walle #define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */ 1382f664823SMichael Walle u16 clk_25m_reg; 1392f664823SMichael Walle u16 clk_25m_mask; 1402f664823SMichael Walle struct regulator_dev *vddio_rdev; 1412f664823SMichael Walle struct regulator_dev *vddh_rdev; 1422f664823SMichael Walle struct regulator *vddio; 1432f664823SMichael Walle }; 1442f664823SMichael Walle 14513a56b44SDaniel Mack struct at803x_context { 14613a56b44SDaniel Mack u16 bmcr; 14713a56b44SDaniel Mack u16 advertise; 14813a56b44SDaniel Mack u16 control1000; 14913a56b44SDaniel Mack u16 int_enable; 15013a56b44SDaniel Mack u16 smart_speed; 15113a56b44SDaniel Mack u16 led_control; 15213a56b44SDaniel Mack }; 15313a56b44SDaniel Mack 1542e5f9f28SMartin Blumenstingl static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) 1552e5f9f28SMartin Blumenstingl { 1562e5f9f28SMartin Blumenstingl int ret; 1572e5f9f28SMartin Blumenstingl 1582e5f9f28SMartin Blumenstingl ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); 1592e5f9f28SMartin Blumenstingl if (ret < 0) 1602e5f9f28SMartin Blumenstingl return ret; 1612e5f9f28SMartin Blumenstingl 1622e5f9f28SMartin Blumenstingl return phy_read(phydev, AT803X_DEBUG_DATA); 1632e5f9f28SMartin Blumenstingl } 1642e5f9f28SMartin Blumenstingl 1652e5f9f28SMartin Blumenstingl static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, 1662e5f9f28SMartin Blumenstingl u16 clear, u16 set) 1672e5f9f28SMartin Blumenstingl { 1682e5f9f28SMartin Blumenstingl u16 val; 1692e5f9f28SMartin Blumenstingl int ret; 1702e5f9f28SMartin Blumenstingl 1712e5f9f28SMartin Blumenstingl ret = at803x_debug_reg_read(phydev, reg); 1722e5f9f28SMartin Blumenstingl if (ret < 0) 1732e5f9f28SMartin Blumenstingl return ret; 1742e5f9f28SMartin Blumenstingl 1752e5f9f28SMartin Blumenstingl val = ret & 0xffff; 1762e5f9f28SMartin Blumenstingl val &= ~clear; 1772e5f9f28SMartin Blumenstingl val |= set; 1782e5f9f28SMartin Blumenstingl 1792e5f9f28SMartin Blumenstingl return phy_write(phydev, AT803X_DEBUG_DATA, val); 1802e5f9f28SMartin Blumenstingl } 1812e5f9f28SMartin Blumenstingl 1826d4cd041SVinod Koul static int at803x_enable_rx_delay(struct phy_device *phydev) 1836d4cd041SVinod Koul { 1846d4cd041SVinod Koul return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0, 1856d4cd041SVinod Koul AT803X_DEBUG_RX_CLK_DLY_EN); 1866d4cd041SVinod Koul } 1876d4cd041SVinod Koul 1886d4cd041SVinod Koul static int at803x_enable_tx_delay(struct phy_device *phydev) 1896d4cd041SVinod Koul { 1906d4cd041SVinod Koul return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0, 1916d4cd041SVinod Koul AT803X_DEBUG_TX_CLK_DLY_EN); 1926d4cd041SVinod Koul } 1936d4cd041SVinod Koul 19443f2ebd5SVinod Koul static int at803x_disable_rx_delay(struct phy_device *phydev) 1952e5f9f28SMartin Blumenstingl { 196cd28d1d6SVinod Koul return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 197cd28d1d6SVinod Koul AT803X_DEBUG_RX_CLK_DLY_EN, 0); 1982e5f9f28SMartin Blumenstingl } 1992e5f9f28SMartin Blumenstingl 20043f2ebd5SVinod Koul static int at803x_disable_tx_delay(struct phy_device *phydev) 2012e5f9f28SMartin Blumenstingl { 202cd28d1d6SVinod Koul return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 203cd28d1d6SVinod Koul AT803X_DEBUG_TX_CLK_DLY_EN, 0); 2042e5f9f28SMartin Blumenstingl } 2052e5f9f28SMartin Blumenstingl 20613a56b44SDaniel Mack /* save relevant PHY registers to private copy */ 20713a56b44SDaniel Mack static void at803x_context_save(struct phy_device *phydev, 20813a56b44SDaniel Mack struct at803x_context *context) 20913a56b44SDaniel Mack { 21013a56b44SDaniel Mack context->bmcr = phy_read(phydev, MII_BMCR); 21113a56b44SDaniel Mack context->advertise = phy_read(phydev, MII_ADVERTISE); 21213a56b44SDaniel Mack context->control1000 = phy_read(phydev, MII_CTRL1000); 21313a56b44SDaniel Mack context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE); 21413a56b44SDaniel Mack context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED); 21513a56b44SDaniel Mack context->led_control = phy_read(phydev, AT803X_LED_CONTROL); 21613a56b44SDaniel Mack } 21713a56b44SDaniel Mack 21813a56b44SDaniel Mack /* restore relevant PHY registers from private copy */ 21913a56b44SDaniel Mack static void at803x_context_restore(struct phy_device *phydev, 22013a56b44SDaniel Mack const struct at803x_context *context) 22113a56b44SDaniel Mack { 22213a56b44SDaniel Mack phy_write(phydev, MII_BMCR, context->bmcr); 22313a56b44SDaniel Mack phy_write(phydev, MII_ADVERTISE, context->advertise); 22413a56b44SDaniel Mack phy_write(phydev, MII_CTRL1000, context->control1000); 22513a56b44SDaniel Mack phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable); 22613a56b44SDaniel Mack phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed); 22713a56b44SDaniel Mack phy_write(phydev, AT803X_LED_CONTROL, context->led_control); 22813a56b44SDaniel Mack } 22913a56b44SDaniel Mack 230ea13c9eeSMugunthan V N static int at803x_set_wol(struct phy_device *phydev, 231ea13c9eeSMugunthan V N struct ethtool_wolinfo *wol) 2320ca7111aSMatus Ujhelyi { 2330ca7111aSMatus Ujhelyi struct net_device *ndev = phydev->attached_dev; 2340ca7111aSMatus Ujhelyi const u8 *mac; 235ea13c9eeSMugunthan V N int ret; 236ea13c9eeSMugunthan V N u32 value; 2370ca7111aSMatus Ujhelyi unsigned int i, offsets[] = { 2380ca7111aSMatus Ujhelyi AT803X_LOC_MAC_ADDR_32_47_OFFSET, 2390ca7111aSMatus Ujhelyi AT803X_LOC_MAC_ADDR_16_31_OFFSET, 2400ca7111aSMatus Ujhelyi AT803X_LOC_MAC_ADDR_0_15_OFFSET, 2410ca7111aSMatus Ujhelyi }; 2420ca7111aSMatus Ujhelyi 2430ca7111aSMatus Ujhelyi if (!ndev) 244ea13c9eeSMugunthan V N return -ENODEV; 2450ca7111aSMatus Ujhelyi 246ea13c9eeSMugunthan V N if (wol->wolopts & WAKE_MAGIC) { 2470ca7111aSMatus Ujhelyi mac = (const u8 *) ndev->dev_addr; 2480ca7111aSMatus Ujhelyi 2490ca7111aSMatus Ujhelyi if (!is_valid_ether_addr(mac)) 250fc755687SDan Murphy return -EINVAL; 2510ca7111aSMatus Ujhelyi 2520e021396SCarlo Caione for (i = 0; i < 3; i++) 2530e021396SCarlo Caione phy_write_mmd(phydev, AT803X_DEVICE_ADDR, offsets[i], 2540ca7111aSMatus Ujhelyi mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); 255ea13c9eeSMugunthan V N 256ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_ENABLE); 257e6e4a556SMartin Blumenstingl value |= AT803X_INTR_ENABLE_WOL; 258ea13c9eeSMugunthan V N ret = phy_write(phydev, AT803X_INTR_ENABLE, value); 259ea13c9eeSMugunthan V N if (ret) 260ea13c9eeSMugunthan V N return ret; 261ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_STATUS); 262ea13c9eeSMugunthan V N } else { 263ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_ENABLE); 264e6e4a556SMartin Blumenstingl value &= (~AT803X_INTR_ENABLE_WOL); 265ea13c9eeSMugunthan V N ret = phy_write(phydev, AT803X_INTR_ENABLE, value); 266ea13c9eeSMugunthan V N if (ret) 267ea13c9eeSMugunthan V N return ret; 268ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_STATUS); 269ea13c9eeSMugunthan V N } 270ea13c9eeSMugunthan V N 271ea13c9eeSMugunthan V N return ret; 272ea13c9eeSMugunthan V N } 273ea13c9eeSMugunthan V N 274ea13c9eeSMugunthan V N static void at803x_get_wol(struct phy_device *phydev, 275ea13c9eeSMugunthan V N struct ethtool_wolinfo *wol) 276ea13c9eeSMugunthan V N { 277ea13c9eeSMugunthan V N u32 value; 278ea13c9eeSMugunthan V N 279ea13c9eeSMugunthan V N wol->supported = WAKE_MAGIC; 280ea13c9eeSMugunthan V N wol->wolopts = 0; 281ea13c9eeSMugunthan V N 282ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_ENABLE); 283e6e4a556SMartin Blumenstingl if (value & AT803X_INTR_ENABLE_WOL) 284ea13c9eeSMugunthan V N wol->wolopts |= WAKE_MAGIC; 2850ca7111aSMatus Ujhelyi } 2860ca7111aSMatus Ujhelyi 2876229ed1fSDaniel Mack static int at803x_suspend(struct phy_device *phydev) 2886229ed1fSDaniel Mack { 2896229ed1fSDaniel Mack int value; 2906229ed1fSDaniel Mack int wol_enabled; 2916229ed1fSDaniel Mack 2926229ed1fSDaniel Mack value = phy_read(phydev, AT803X_INTR_ENABLE); 293e6e4a556SMartin Blumenstingl wol_enabled = value & AT803X_INTR_ENABLE_WOL; 2946229ed1fSDaniel Mack 2956229ed1fSDaniel Mack if (wol_enabled) 296fea23fb5SRussell King value = BMCR_ISOLATE; 2976229ed1fSDaniel Mack else 298fea23fb5SRussell King value = BMCR_PDOWN; 2996229ed1fSDaniel Mack 300fea23fb5SRussell King phy_modify(phydev, MII_BMCR, 0, value); 3016229ed1fSDaniel Mack 3026229ed1fSDaniel Mack return 0; 3036229ed1fSDaniel Mack } 3046229ed1fSDaniel Mack 3056229ed1fSDaniel Mack static int at803x_resume(struct phy_device *phydev) 3066229ed1fSDaniel Mack { 307f102852fSRussell King return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); 3086229ed1fSDaniel Mack } 3096229ed1fSDaniel Mack 3102f664823SMichael Walle static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev, 3112f664823SMichael Walle unsigned int selector) 3122f664823SMichael Walle { 3132f664823SMichael Walle struct phy_device *phydev = rdev_get_drvdata(rdev); 3142f664823SMichael Walle 3152f664823SMichael Walle if (selector) 3162f664823SMichael Walle return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, 3172f664823SMichael Walle 0, AT803X_DEBUG_RGMII_1V8); 3182f664823SMichael Walle else 3192f664823SMichael Walle return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, 3202f664823SMichael Walle AT803X_DEBUG_RGMII_1V8, 0); 3212f664823SMichael Walle } 3222f664823SMichael Walle 3232f664823SMichael Walle static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) 3242f664823SMichael Walle { 3252f664823SMichael Walle struct phy_device *phydev = rdev_get_drvdata(rdev); 3262f664823SMichael Walle int val; 3272f664823SMichael Walle 3282f664823SMichael Walle val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F); 3292f664823SMichael Walle if (val < 0) 3302f664823SMichael Walle return val; 3312f664823SMichael Walle 3322f664823SMichael Walle return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; 3332f664823SMichael Walle } 3342f664823SMichael Walle 3352f664823SMichael Walle static struct regulator_ops vddio_regulator_ops = { 3362f664823SMichael Walle .list_voltage = regulator_list_voltage_table, 3372f664823SMichael Walle .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel, 3382f664823SMichael Walle .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel, 3392f664823SMichael Walle }; 3402f664823SMichael Walle 3412f664823SMichael Walle static const unsigned int vddio_voltage_table[] = { 3422f664823SMichael Walle 1500000, 3432f664823SMichael Walle 1800000, 3442f664823SMichael Walle }; 3452f664823SMichael Walle 3462f664823SMichael Walle static const struct regulator_desc vddio_desc = { 3472f664823SMichael Walle .name = "vddio", 3482f664823SMichael Walle .of_match = of_match_ptr("vddio-regulator"), 3492f664823SMichael Walle .n_voltages = ARRAY_SIZE(vddio_voltage_table), 3502f664823SMichael Walle .volt_table = vddio_voltage_table, 3512f664823SMichael Walle .ops = &vddio_regulator_ops, 3522f664823SMichael Walle .type = REGULATOR_VOLTAGE, 3532f664823SMichael Walle .owner = THIS_MODULE, 3542f664823SMichael Walle }; 3552f664823SMichael Walle 3562f664823SMichael Walle static struct regulator_ops vddh_regulator_ops = { 3572f664823SMichael Walle }; 3582f664823SMichael Walle 3592f664823SMichael Walle static const struct regulator_desc vddh_desc = { 3602f664823SMichael Walle .name = "vddh", 3612f664823SMichael Walle .of_match = of_match_ptr("vddh-regulator"), 3622f664823SMichael Walle .n_voltages = 1, 3632f664823SMichael Walle .fixed_uV = 2500000, 3642f664823SMichael Walle .ops = &vddh_regulator_ops, 3652f664823SMichael Walle .type = REGULATOR_VOLTAGE, 3662f664823SMichael Walle .owner = THIS_MODULE, 3672f664823SMichael Walle }; 3682f664823SMichael Walle 3692f664823SMichael Walle static int at8031_register_regulators(struct phy_device *phydev) 3702f664823SMichael Walle { 3712f664823SMichael Walle struct at803x_priv *priv = phydev->priv; 3722f664823SMichael Walle struct device *dev = &phydev->mdio.dev; 3732f664823SMichael Walle struct regulator_config config = { }; 3742f664823SMichael Walle 3752f664823SMichael Walle config.dev = dev; 3762f664823SMichael Walle config.driver_data = phydev; 3772f664823SMichael Walle 3782f664823SMichael Walle priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config); 3792f664823SMichael Walle if (IS_ERR(priv->vddio_rdev)) { 3802f664823SMichael Walle phydev_err(phydev, "failed to register VDDIO regulator\n"); 3812f664823SMichael Walle return PTR_ERR(priv->vddio_rdev); 3822f664823SMichael Walle } 3832f664823SMichael Walle 3842f664823SMichael Walle priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config); 3852f664823SMichael Walle if (IS_ERR(priv->vddh_rdev)) { 3862f664823SMichael Walle phydev_err(phydev, "failed to register VDDH regulator\n"); 3872f664823SMichael Walle return PTR_ERR(priv->vddh_rdev); 3882f664823SMichael Walle } 3892f664823SMichael Walle 3902f664823SMichael Walle return 0; 3912f664823SMichael Walle } 3922f664823SMichael Walle 3932f664823SMichael Walle static bool at803x_match_phy_id(struct phy_device *phydev, u32 phy_id) 3942f664823SMichael Walle { 3952f664823SMichael Walle return (phydev->phy_id & phydev->drv->phy_id_mask) 3962f664823SMichael Walle == (phy_id & phydev->drv->phy_id_mask); 3972f664823SMichael Walle } 3982f664823SMichael Walle 3992f664823SMichael Walle static int at803x_parse_dt(struct phy_device *phydev) 4002f664823SMichael Walle { 4012f664823SMichael Walle struct device_node *node = phydev->mdio.dev.of_node; 4022f664823SMichael Walle struct at803x_priv *priv = phydev->priv; 4032f664823SMichael Walle unsigned int sel, mask; 4042f664823SMichael Walle u32 freq, strength; 4052f664823SMichael Walle int ret; 4062f664823SMichael Walle 4072f664823SMichael Walle if (!IS_ENABLED(CONFIG_OF_MDIO)) 4082f664823SMichael Walle return 0; 4092f664823SMichael Walle 4102f664823SMichael Walle ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq); 4112f664823SMichael Walle if (!ret) { 4122f664823SMichael Walle mask = AT803X_CLK_OUT_MASK; 4132f664823SMichael Walle switch (freq) { 4142f664823SMichael Walle case 25000000: 4152f664823SMichael Walle sel = AT803X_CLK_OUT_25MHZ_XTAL; 4162f664823SMichael Walle break; 4172f664823SMichael Walle case 50000000: 4182f664823SMichael Walle sel = AT803X_CLK_OUT_50MHZ_PLL; 4192f664823SMichael Walle break; 4202f664823SMichael Walle case 62500000: 4212f664823SMichael Walle sel = AT803X_CLK_OUT_62_5MHZ_PLL; 4222f664823SMichael Walle break; 4232f664823SMichael Walle case 125000000: 4242f664823SMichael Walle sel = AT803X_CLK_OUT_125MHZ_PLL; 4252f664823SMichael Walle break; 4262f664823SMichael Walle default: 4272f664823SMichael Walle phydev_err(phydev, "invalid qca,clk-out-frequency\n"); 4282f664823SMichael Walle return -EINVAL; 4292f664823SMichael Walle } 4302f664823SMichael Walle 4312f664823SMichael Walle priv->clk_25m_reg |= FIELD_PREP(mask, sel); 4322f664823SMichael Walle priv->clk_25m_mask |= mask; 4332f664823SMichael Walle 4342f664823SMichael Walle /* Fixup for the AR8030/AR8035. This chip has another mask and 4352f664823SMichael Walle * doesn't support the DSP reference. Eg. the lowest bit of the 4362f664823SMichael Walle * mask. The upper two bits select the same frequencies. Mask 4372f664823SMichael Walle * the lowest bit here. 4382f664823SMichael Walle * 4392f664823SMichael Walle * Warning: 4402f664823SMichael Walle * There was no datasheet for the AR8030 available so this is 4412f664823SMichael Walle * just a guess. But the AR8035 is listed as pin compatible 4422f664823SMichael Walle * to the AR8030 so there might be a good chance it works on 4432f664823SMichael Walle * the AR8030 too. 4442f664823SMichael Walle */ 4452f664823SMichael Walle if (at803x_match_phy_id(phydev, ATH8030_PHY_ID) || 4462f664823SMichael Walle at803x_match_phy_id(phydev, ATH8035_PHY_ID)) { 447b1f4c209SOleksij Rempel priv->clk_25m_reg &= AT8035_CLK_OUT_MASK; 448b1f4c209SOleksij Rempel priv->clk_25m_mask &= AT8035_CLK_OUT_MASK; 4492f664823SMichael Walle } 4502f664823SMichael Walle } 4512f664823SMichael Walle 4522f664823SMichael Walle ret = of_property_read_u32(node, "qca,clk-out-strength", &strength); 4532f664823SMichael Walle if (!ret) { 4542f664823SMichael Walle priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK; 4552f664823SMichael Walle switch (strength) { 4562f664823SMichael Walle case AR803X_STRENGTH_FULL: 4572f664823SMichael Walle priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL; 4582f664823SMichael Walle break; 4592f664823SMichael Walle case AR803X_STRENGTH_HALF: 4602f664823SMichael Walle priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF; 4612f664823SMichael Walle break; 4622f664823SMichael Walle case AR803X_STRENGTH_QUARTER: 4632f664823SMichael Walle priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER; 4642f664823SMichael Walle break; 4652f664823SMichael Walle default: 4662f664823SMichael Walle phydev_err(phydev, "invalid qca,clk-out-strength\n"); 4672f664823SMichael Walle return -EINVAL; 4682f664823SMichael Walle } 4692f664823SMichael Walle } 4702f664823SMichael Walle 471428061f7SMichael Walle /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping 472428061f7SMichael Walle * options. 473428061f7SMichael Walle */ 4742f664823SMichael Walle if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { 4752f664823SMichael Walle if (of_property_read_bool(node, "qca,keep-pll-enabled")) 4762f664823SMichael Walle priv->flags |= AT803X_KEEP_PLL_ENABLED; 4772f664823SMichael Walle 4782f664823SMichael Walle ret = at8031_register_regulators(phydev); 4792f664823SMichael Walle if (ret < 0) 4802f664823SMichael Walle return ret; 4812f664823SMichael Walle 4822f664823SMichael Walle priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev, 4832f664823SMichael Walle "vddio"); 4842f664823SMichael Walle if (IS_ERR(priv->vddio)) { 4852f664823SMichael Walle phydev_err(phydev, "failed to get VDDIO regulator\n"); 4862f664823SMichael Walle return PTR_ERR(priv->vddio); 4872f664823SMichael Walle } 4882f664823SMichael Walle 4892f664823SMichael Walle ret = regulator_enable(priv->vddio); 4902f664823SMichael Walle if (ret < 0) 4912f664823SMichael Walle return ret; 4922f664823SMichael Walle } 4932f664823SMichael Walle 4942f664823SMichael Walle return 0; 4952f664823SMichael Walle } 4962f664823SMichael Walle 4972f664823SMichael Walle static int at803x_probe(struct phy_device *phydev) 4982f664823SMichael Walle { 4992f664823SMichael Walle struct device *dev = &phydev->mdio.dev; 5002f664823SMichael Walle struct at803x_priv *priv; 5012f664823SMichael Walle 5022f664823SMichael Walle priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 5032f664823SMichael Walle if (!priv) 5042f664823SMichael Walle return -ENOMEM; 5052f664823SMichael Walle 5062f664823SMichael Walle phydev->priv = priv; 5072f664823SMichael Walle 5082f664823SMichael Walle return at803x_parse_dt(phydev); 5092f664823SMichael Walle } 5102f664823SMichael Walle 5112318ca8aSMichael Walle static void at803x_remove(struct phy_device *phydev) 5122318ca8aSMichael Walle { 5132318ca8aSMichael Walle struct at803x_priv *priv = phydev->priv; 5142318ca8aSMichael Walle 5152318ca8aSMichael Walle if (priv->vddio) 5162318ca8aSMichael Walle regulator_disable(priv->vddio); 5172318ca8aSMichael Walle } 5182318ca8aSMichael Walle 5192f664823SMichael Walle static int at803x_clk_out_config(struct phy_device *phydev) 5202f664823SMichael Walle { 5212f664823SMichael Walle struct at803x_priv *priv = phydev->priv; 5222f664823SMichael Walle int val; 5232f664823SMichael Walle 5242f664823SMichael Walle if (!priv->clk_25m_mask) 5252f664823SMichael Walle return 0; 5262f664823SMichael Walle 5272f664823SMichael Walle val = phy_read_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M); 5282f664823SMichael Walle if (val < 0) 5292f664823SMichael Walle return val; 5302f664823SMichael Walle 5312f664823SMichael Walle val &= ~priv->clk_25m_mask; 5322f664823SMichael Walle val |= priv->clk_25m_reg; 5332f664823SMichael Walle 5342f664823SMichael Walle return phy_write_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, val); 5352f664823SMichael Walle } 5362f664823SMichael Walle 5372f664823SMichael Walle static int at8031_pll_config(struct phy_device *phydev) 5382f664823SMichael Walle { 5392f664823SMichael Walle struct at803x_priv *priv = phydev->priv; 5402f664823SMichael Walle 5412f664823SMichael Walle /* The default after hardware reset is PLL OFF. After a soft reset, the 5422f664823SMichael Walle * values are retained. 5432f664823SMichael Walle */ 5442f664823SMichael Walle if (priv->flags & AT803X_KEEP_PLL_ENABLED) 5452f664823SMichael Walle return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, 5462f664823SMichael Walle 0, AT803X_DEBUG_PLL_ON); 5472f664823SMichael Walle else 5482f664823SMichael Walle return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, 5492f664823SMichael Walle AT803X_DEBUG_PLL_ON, 0); 5502f664823SMichael Walle } 5512f664823SMichael Walle 5520ca7111aSMatus Ujhelyi static int at803x_config_init(struct phy_device *phydev) 5530ca7111aSMatus Ujhelyi { 5541ca6d1b1SMugunthan V N int ret; 5550ca7111aSMatus Ujhelyi 5566d4cd041SVinod Koul /* The RX and TX delay default is: 5576d4cd041SVinod Koul * after HW reset: RX delay enabled and TX delay disabled 5586d4cd041SVinod Koul * after SW reset: RX delay enabled, while TX delay retains the 5596d4cd041SVinod Koul * value before reset. 5606d4cd041SVinod Koul */ 561bb0ce4c1SAndré Draszik if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 562bb0ce4c1SAndré Draszik phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 563bb0ce4c1SAndré Draszik ret = at803x_enable_rx_delay(phydev); 564bb0ce4c1SAndré Draszik else 565cd28d1d6SVinod Koul ret = at803x_disable_rx_delay(phydev); 5662e5f9f28SMartin Blumenstingl if (ret < 0) 5671ca6d1b1SMugunthan V N return ret; 5686d4cd041SVinod Koul 5696d4cd041SVinod Koul if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 570bb0ce4c1SAndré Draszik phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 5716d4cd041SVinod Koul ret = at803x_enable_tx_delay(phydev); 572bb0ce4c1SAndré Draszik else 573bb0ce4c1SAndré Draszik ret = at803x_disable_tx_delay(phydev); 5742f664823SMichael Walle if (ret < 0) 5756d4cd041SVinod Koul return ret; 5762f664823SMichael Walle 5772f664823SMichael Walle ret = at803x_clk_out_config(phydev); 5782f664823SMichael Walle if (ret < 0) 5792f664823SMichael Walle return ret; 5802f664823SMichael Walle 5812f664823SMichael Walle if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { 5822f664823SMichael Walle ret = at8031_pll_config(phydev); 5832f664823SMichael Walle if (ret < 0) 5842f664823SMichael Walle return ret; 5852f664823SMichael Walle } 5862f664823SMichael Walle 5872f664823SMichael Walle return 0; 5880ca7111aSMatus Ujhelyi } 5890ca7111aSMatus Ujhelyi 59077a99394SZhao Qiang static int at803x_ack_interrupt(struct phy_device *phydev) 59177a99394SZhao Qiang { 59277a99394SZhao Qiang int err; 59377a99394SZhao Qiang 594a46bd63bSMartin Blumenstingl err = phy_read(phydev, AT803X_INTR_STATUS); 59577a99394SZhao Qiang 59677a99394SZhao Qiang return (err < 0) ? err : 0; 59777a99394SZhao Qiang } 59877a99394SZhao Qiang 59977a99394SZhao Qiang static int at803x_config_intr(struct phy_device *phydev) 60077a99394SZhao Qiang { 60177a99394SZhao Qiang int err; 60277a99394SZhao Qiang int value; 60377a99394SZhao Qiang 604a46bd63bSMartin Blumenstingl value = phy_read(phydev, AT803X_INTR_ENABLE); 60577a99394SZhao Qiang 606e6e4a556SMartin Blumenstingl if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 607e6e4a556SMartin Blumenstingl value |= AT803X_INTR_ENABLE_AUTONEG_ERR; 608e6e4a556SMartin Blumenstingl value |= AT803X_INTR_ENABLE_SPEED_CHANGED; 609e6e4a556SMartin Blumenstingl value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; 610e6e4a556SMartin Blumenstingl value |= AT803X_INTR_ENABLE_LINK_FAIL; 611e6e4a556SMartin Blumenstingl value |= AT803X_INTR_ENABLE_LINK_SUCCESS; 612e6e4a556SMartin Blumenstingl 613e6e4a556SMartin Blumenstingl err = phy_write(phydev, AT803X_INTR_ENABLE, value); 614e6e4a556SMartin Blumenstingl } 61577a99394SZhao Qiang else 616a46bd63bSMartin Blumenstingl err = phy_write(phydev, AT803X_INTR_ENABLE, 0); 61777a99394SZhao Qiang 61877a99394SZhao Qiang return err; 61977a99394SZhao Qiang } 62077a99394SZhao Qiang 62113a56b44SDaniel Mack static void at803x_link_change_notify(struct phy_device *phydev) 62213a56b44SDaniel Mack { 62313a56b44SDaniel Mack /* 62413a56b44SDaniel Mack * Conduct a hardware reset for AT8030 every time a link loss is 62513a56b44SDaniel Mack * signalled. This is necessary to circumvent a hardware bug that 62613a56b44SDaniel Mack * occurs when the cable is unplugged while TX packets are pending 62713a56b44SDaniel Mack * in the FIFO. In such cases, the FIFO enters an error mode it 62813a56b44SDaniel Mack * cannot recover from by software. 62913a56b44SDaniel Mack */ 6306110ed2dSDavid Bauer if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) { 63113a56b44SDaniel Mack struct at803x_context context; 63213a56b44SDaniel Mack 63313a56b44SDaniel Mack at803x_context_save(phydev, &context); 63413a56b44SDaniel Mack 635bafbdd52SSergei Shtylyov phy_device_reset(phydev, 1); 63613a56b44SDaniel Mack msleep(1); 637bafbdd52SSergei Shtylyov phy_device_reset(phydev, 0); 638d57019d1SSergei Shtylyov msleep(1); 63913a56b44SDaniel Mack 64013a56b44SDaniel Mack at803x_context_restore(phydev, &context); 64113a56b44SDaniel Mack 6425c5f626bSHeiner Kallweit phydev_dbg(phydev, "%s(): phy was reset\n", __func__); 64313a56b44SDaniel Mack } 64413a56b44SDaniel Mack } 64513a56b44SDaniel Mack 646f62265b5SZefir Kurtisi static int at803x_aneg_done(struct phy_device *phydev) 647f62265b5SZefir Kurtisi { 648f62265b5SZefir Kurtisi int ccr; 649f62265b5SZefir Kurtisi 650f62265b5SZefir Kurtisi int aneg_done = genphy_aneg_done(phydev); 651f62265b5SZefir Kurtisi if (aneg_done != BMSR_ANEGCOMPLETE) 652f62265b5SZefir Kurtisi return aneg_done; 653f62265b5SZefir Kurtisi 654f62265b5SZefir Kurtisi /* 655f62265b5SZefir Kurtisi * in SGMII mode, if copper side autoneg is successful, 656f62265b5SZefir Kurtisi * also check SGMII side autoneg result 657f62265b5SZefir Kurtisi */ 658f62265b5SZefir Kurtisi ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); 659f62265b5SZefir Kurtisi if ((ccr & AT803X_MODE_CFG_MASK) != AT803X_MODE_CFG_SGMII) 660f62265b5SZefir Kurtisi return aneg_done; 661f62265b5SZefir Kurtisi 662f62265b5SZefir Kurtisi /* switch to SGMII/fiber page */ 663f62265b5SZefir Kurtisi phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL); 664f62265b5SZefir Kurtisi 665f62265b5SZefir Kurtisi /* check if the SGMII link is OK. */ 666f62265b5SZefir Kurtisi if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) { 667ab2a605fSAndrew Lunn phydev_warn(phydev, "803x_aneg_done: SGMII link is not ok\n"); 668f62265b5SZefir Kurtisi aneg_done = 0; 669f62265b5SZefir Kurtisi } 670f62265b5SZefir Kurtisi /* switch back to copper page */ 671f62265b5SZefir Kurtisi phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL); 672f62265b5SZefir Kurtisi 673f62265b5SZefir Kurtisi return aneg_done; 674f62265b5SZefir Kurtisi } 675f62265b5SZefir Kurtisi 67606d5f344SRussell King static int at803x_read_status(struct phy_device *phydev) 67706d5f344SRussell King { 67806d5f344SRussell King int ss, err, old_link = phydev->link; 67906d5f344SRussell King 68006d5f344SRussell King /* Update the link, but return if there was an error */ 68106d5f344SRussell King err = genphy_update_link(phydev); 68206d5f344SRussell King if (err) 68306d5f344SRussell King return err; 68406d5f344SRussell King 68506d5f344SRussell King /* why bother the PHY if nothing can have changed */ 68606d5f344SRussell King if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) 68706d5f344SRussell King return 0; 68806d5f344SRussell King 68906d5f344SRussell King phydev->speed = SPEED_UNKNOWN; 69006d5f344SRussell King phydev->duplex = DUPLEX_UNKNOWN; 69106d5f344SRussell King phydev->pause = 0; 69206d5f344SRussell King phydev->asym_pause = 0; 69306d5f344SRussell King 69406d5f344SRussell King err = genphy_read_lpa(phydev); 69506d5f344SRussell King if (err < 0) 69606d5f344SRussell King return err; 69706d5f344SRussell King 69806d5f344SRussell King /* Read the AT8035 PHY-Specific Status register, which indicates the 69906d5f344SRussell King * speed and duplex that the PHY is actually using, irrespective of 70006d5f344SRussell King * whether we are in autoneg mode or not. 70106d5f344SRussell King */ 70206d5f344SRussell King ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); 70306d5f344SRussell King if (ss < 0) 70406d5f344SRussell King return ss; 70506d5f344SRussell King 70606d5f344SRussell King if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { 70706d5f344SRussell King switch (ss & AT803X_SS_SPEED_MASK) { 70806d5f344SRussell King case AT803X_SS_SPEED_10: 70906d5f344SRussell King phydev->speed = SPEED_10; 71006d5f344SRussell King break; 71106d5f344SRussell King case AT803X_SS_SPEED_100: 71206d5f344SRussell King phydev->speed = SPEED_100; 71306d5f344SRussell King break; 71406d5f344SRussell King case AT803X_SS_SPEED_1000: 71506d5f344SRussell King phydev->speed = SPEED_1000; 71606d5f344SRussell King break; 71706d5f344SRussell King } 71806d5f344SRussell King if (ss & AT803X_SS_DUPLEX) 71906d5f344SRussell King phydev->duplex = DUPLEX_FULL; 72006d5f344SRussell King else 72106d5f344SRussell King phydev->duplex = DUPLEX_HALF; 72206d5f344SRussell King if (ss & AT803X_SS_MDIX) 72306d5f344SRussell King phydev->mdix = ETH_TP_MDI_X; 72406d5f344SRussell King else 72506d5f344SRussell King phydev->mdix = ETH_TP_MDI; 72606d5f344SRussell King } 72706d5f344SRussell King 72806d5f344SRussell King if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) 72906d5f344SRussell King phy_resolve_aneg_pause(phydev); 73006d5f344SRussell King 73106d5f344SRussell King return 0; 73206d5f344SRussell King } 73306d5f344SRussell King 734cde0f4f8SMichael Walle static int at803x_get_downshift(struct phy_device *phydev, u8 *d) 735cde0f4f8SMichael Walle { 736cde0f4f8SMichael Walle int val; 737cde0f4f8SMichael Walle 738cde0f4f8SMichael Walle val = phy_read(phydev, AT803X_SMART_SPEED); 739cde0f4f8SMichael Walle if (val < 0) 740cde0f4f8SMichael Walle return val; 741cde0f4f8SMichael Walle 742cde0f4f8SMichael Walle if (val & AT803X_SMART_SPEED_ENABLE) 743cde0f4f8SMichael Walle *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; 744cde0f4f8SMichael Walle else 745cde0f4f8SMichael Walle *d = DOWNSHIFT_DEV_DISABLE; 746cde0f4f8SMichael Walle 747cde0f4f8SMichael Walle return 0; 748cde0f4f8SMichael Walle } 749cde0f4f8SMichael Walle 750cde0f4f8SMichael Walle static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) 751cde0f4f8SMichael Walle { 752cde0f4f8SMichael Walle u16 mask, set; 753cde0f4f8SMichael Walle int ret; 754cde0f4f8SMichael Walle 755cde0f4f8SMichael Walle switch (cnt) { 756cde0f4f8SMichael Walle case DOWNSHIFT_DEV_DEFAULT_COUNT: 757cde0f4f8SMichael Walle cnt = AT803X_DEFAULT_DOWNSHIFT; 758cde0f4f8SMichael Walle fallthrough; 759cde0f4f8SMichael Walle case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: 760cde0f4f8SMichael Walle set = AT803X_SMART_SPEED_ENABLE | 761cde0f4f8SMichael Walle AT803X_SMART_SPEED_BYPASS_TIMER | 762cde0f4f8SMichael Walle FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); 763cde0f4f8SMichael Walle mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; 764cde0f4f8SMichael Walle break; 765cde0f4f8SMichael Walle case DOWNSHIFT_DEV_DISABLE: 766cde0f4f8SMichael Walle set = 0; 767cde0f4f8SMichael Walle mask = AT803X_SMART_SPEED_ENABLE | 768cde0f4f8SMichael Walle AT803X_SMART_SPEED_BYPASS_TIMER; 769cde0f4f8SMichael Walle break; 770cde0f4f8SMichael Walle default: 771cde0f4f8SMichael Walle return -EINVAL; 772cde0f4f8SMichael Walle } 773cde0f4f8SMichael Walle 774cde0f4f8SMichael Walle ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); 775cde0f4f8SMichael Walle 776cde0f4f8SMichael Walle /* After changing the smart speed settings, we need to perform a 777cde0f4f8SMichael Walle * software reset, use phy_init_hw() to make sure we set the 778cde0f4f8SMichael Walle * reapply any values which might got lost during software reset. 779cde0f4f8SMichael Walle */ 780cde0f4f8SMichael Walle if (ret == 1) 781cde0f4f8SMichael Walle ret = phy_init_hw(phydev); 782cde0f4f8SMichael Walle 783cde0f4f8SMichael Walle return ret; 784cde0f4f8SMichael Walle } 785cde0f4f8SMichael Walle 786cde0f4f8SMichael Walle static int at803x_get_tunable(struct phy_device *phydev, 787cde0f4f8SMichael Walle struct ethtool_tunable *tuna, void *data) 788cde0f4f8SMichael Walle { 789cde0f4f8SMichael Walle switch (tuna->id) { 790cde0f4f8SMichael Walle case ETHTOOL_PHY_DOWNSHIFT: 791cde0f4f8SMichael Walle return at803x_get_downshift(phydev, data); 792cde0f4f8SMichael Walle default: 793cde0f4f8SMichael Walle return -EOPNOTSUPP; 794cde0f4f8SMichael Walle } 795cde0f4f8SMichael Walle } 796cde0f4f8SMichael Walle 797cde0f4f8SMichael Walle static int at803x_set_tunable(struct phy_device *phydev, 798cde0f4f8SMichael Walle struct ethtool_tunable *tuna, const void *data) 799cde0f4f8SMichael Walle { 800cde0f4f8SMichael Walle switch (tuna->id) { 801cde0f4f8SMichael Walle case ETHTOOL_PHY_DOWNSHIFT: 802cde0f4f8SMichael Walle return at803x_set_downshift(phydev, *(const u8 *)data); 803cde0f4f8SMichael Walle default: 804cde0f4f8SMichael Walle return -EOPNOTSUPP; 805cde0f4f8SMichael Walle } 806cde0f4f8SMichael Walle } 807cde0f4f8SMichael Walle 8086cb75767SMichael Walle static int at803x_cable_test_result_trans(u16 status) 8096cb75767SMichael Walle { 8106cb75767SMichael Walle switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { 8116cb75767SMichael Walle case AT803X_CDT_STATUS_STAT_NORMAL: 8126cb75767SMichael Walle return ETHTOOL_A_CABLE_RESULT_CODE_OK; 8136cb75767SMichael Walle case AT803X_CDT_STATUS_STAT_SHORT: 8146cb75767SMichael Walle return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 8156cb75767SMichael Walle case AT803X_CDT_STATUS_STAT_OPEN: 8166cb75767SMichael Walle return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 8176cb75767SMichael Walle case AT803X_CDT_STATUS_STAT_FAIL: 8186cb75767SMichael Walle default: 8196cb75767SMichael Walle return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 8206cb75767SMichael Walle } 8216cb75767SMichael Walle } 8226cb75767SMichael Walle 8236cb75767SMichael Walle static bool at803x_cdt_test_failed(u16 status) 8246cb75767SMichael Walle { 8256cb75767SMichael Walle return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) == 8266cb75767SMichael Walle AT803X_CDT_STATUS_STAT_FAIL; 8276cb75767SMichael Walle } 8286cb75767SMichael Walle 8296cb75767SMichael Walle static bool at803x_cdt_fault_length_valid(u16 status) 8306cb75767SMichael Walle { 8316cb75767SMichael Walle switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { 8326cb75767SMichael Walle case AT803X_CDT_STATUS_STAT_OPEN: 8336cb75767SMichael Walle case AT803X_CDT_STATUS_STAT_SHORT: 8346cb75767SMichael Walle return true; 8356cb75767SMichael Walle } 8366cb75767SMichael Walle return false; 8376cb75767SMichael Walle } 8386cb75767SMichael Walle 8396cb75767SMichael Walle static int at803x_cdt_fault_length(u16 status) 8406cb75767SMichael Walle { 8416cb75767SMichael Walle int dt; 8426cb75767SMichael Walle 8436cb75767SMichael Walle /* According to the datasheet the distance to the fault is 8446cb75767SMichael Walle * DELTA_TIME * 0.824 meters. 8456cb75767SMichael Walle * 8466cb75767SMichael Walle * The author suspect the correct formula is: 8476cb75767SMichael Walle * 8486cb75767SMichael Walle * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 8496cb75767SMichael Walle * 8506cb75767SMichael Walle * where c is the speed of light, VF is the velocity factor of 8516cb75767SMichael Walle * the twisted pair cable, 125MHz the counter frequency and 8526cb75767SMichael Walle * we need to divide by 2 because the hardware will measure the 8536cb75767SMichael Walle * round trip time to the fault and back to the PHY. 8546cb75767SMichael Walle * 8556cb75767SMichael Walle * With a VF of 0.69 we get the factor 0.824 mentioned in the 8566cb75767SMichael Walle * datasheet. 8576cb75767SMichael Walle */ 8586cb75767SMichael Walle dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status); 8596cb75767SMichael Walle 8606cb75767SMichael Walle return (dt * 824) / 10; 8616cb75767SMichael Walle } 8626cb75767SMichael Walle 8636cb75767SMichael Walle static int at803x_cdt_start(struct phy_device *phydev, int pair) 8646cb75767SMichael Walle { 8656cb75767SMichael Walle u16 cdt; 8666cb75767SMichael Walle 8676cb75767SMichael Walle cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) | 8686cb75767SMichael Walle AT803X_CDT_ENABLE_TEST; 8696cb75767SMichael Walle 8706cb75767SMichael Walle return phy_write(phydev, AT803X_CDT, cdt); 8716cb75767SMichael Walle } 8726cb75767SMichael Walle 8736cb75767SMichael Walle static int at803x_cdt_wait_for_completion(struct phy_device *phydev) 8746cb75767SMichael Walle { 8756cb75767SMichael Walle int val, ret; 8766cb75767SMichael Walle 8776cb75767SMichael Walle /* One test run takes about 25ms */ 8786cb75767SMichael Walle ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, 8796cb75767SMichael Walle !(val & AT803X_CDT_ENABLE_TEST), 8806cb75767SMichael Walle 30000, 100000, true); 8816cb75767SMichael Walle 8826cb75767SMichael Walle return ret < 0 ? ret : 0; 8836cb75767SMichael Walle } 8846cb75767SMichael Walle 8856cb75767SMichael Walle static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) 8866cb75767SMichael Walle { 8876cb75767SMichael Walle static const int ethtool_pair[] = { 8886cb75767SMichael Walle ETHTOOL_A_CABLE_PAIR_A, 8896cb75767SMichael Walle ETHTOOL_A_CABLE_PAIR_B, 8906cb75767SMichael Walle ETHTOOL_A_CABLE_PAIR_C, 8916cb75767SMichael Walle ETHTOOL_A_CABLE_PAIR_D, 8926cb75767SMichael Walle }; 8936cb75767SMichael Walle int ret, val; 8946cb75767SMichael Walle 8956cb75767SMichael Walle ret = at803x_cdt_start(phydev, pair); 8966cb75767SMichael Walle if (ret) 8976cb75767SMichael Walle return ret; 8986cb75767SMichael Walle 8996cb75767SMichael Walle ret = at803x_cdt_wait_for_completion(phydev); 9006cb75767SMichael Walle if (ret) 9016cb75767SMichael Walle return ret; 9026cb75767SMichael Walle 9036cb75767SMichael Walle val = phy_read(phydev, AT803X_CDT_STATUS); 9046cb75767SMichael Walle if (val < 0) 9056cb75767SMichael Walle return val; 9066cb75767SMichael Walle 9076cb75767SMichael Walle if (at803x_cdt_test_failed(val)) 9086cb75767SMichael Walle return 0; 9096cb75767SMichael Walle 9106cb75767SMichael Walle ethnl_cable_test_result(phydev, ethtool_pair[pair], 9116cb75767SMichael Walle at803x_cable_test_result_trans(val)); 9126cb75767SMichael Walle 9136cb75767SMichael Walle if (at803x_cdt_fault_length_valid(val)) 9146cb75767SMichael Walle ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], 9156cb75767SMichael Walle at803x_cdt_fault_length(val)); 9166cb75767SMichael Walle 9176cb75767SMichael Walle return 1; 9186cb75767SMichael Walle } 9196cb75767SMichael Walle 9206cb75767SMichael Walle static int at803x_cable_test_get_status(struct phy_device *phydev, 9216cb75767SMichael Walle bool *finished) 9226cb75767SMichael Walle { 923dc0f3ed1SOleksij Rempel unsigned long pair_mask; 9246cb75767SMichael Walle int retries = 20; 9256cb75767SMichael Walle int pair, ret; 9266cb75767SMichael Walle 927dc0f3ed1SOleksij Rempel if (phydev->phy_id == ATH9331_PHY_ID || 928dc0f3ed1SOleksij Rempel phydev->phy_id == ATH8032_PHY_ID) 929dc0f3ed1SOleksij Rempel pair_mask = 0x3; 930dc0f3ed1SOleksij Rempel else 931dc0f3ed1SOleksij Rempel pair_mask = 0xf; 932dc0f3ed1SOleksij Rempel 9336cb75767SMichael Walle *finished = false; 9346cb75767SMichael Walle 9356cb75767SMichael Walle /* According to the datasheet the CDT can be performed when 9366cb75767SMichael Walle * there is no link partner or when the link partner is 9376cb75767SMichael Walle * auto-negotiating. Starting the test will restart the AN 9386cb75767SMichael Walle * automatically. It seems that doing this repeatedly we will 9396cb75767SMichael Walle * get a slot where our link partner won't disturb our 9406cb75767SMichael Walle * measurement. 9416cb75767SMichael Walle */ 9426cb75767SMichael Walle while (pair_mask && retries--) { 9436cb75767SMichael Walle for_each_set_bit(pair, &pair_mask, 4) { 9446cb75767SMichael Walle ret = at803x_cable_test_one_pair(phydev, pair); 9456cb75767SMichael Walle if (ret < 0) 9466cb75767SMichael Walle return ret; 9476cb75767SMichael Walle if (ret) 9486cb75767SMichael Walle clear_bit(pair, &pair_mask); 9496cb75767SMichael Walle } 9506cb75767SMichael Walle if (pair_mask) 9516cb75767SMichael Walle msleep(250); 9526cb75767SMichael Walle } 9536cb75767SMichael Walle 9546cb75767SMichael Walle *finished = true; 9556cb75767SMichael Walle 9566cb75767SMichael Walle return 0; 9576cb75767SMichael Walle } 9586cb75767SMichael Walle 9596cb75767SMichael Walle static int at803x_cable_test_start(struct phy_device *phydev) 9606cb75767SMichael Walle { 9616cb75767SMichael Walle /* Enable auto-negotiation, but advertise no capabilities, no link 9626cb75767SMichael Walle * will be established. A restart of the auto-negotiation is not 9636cb75767SMichael Walle * required, because the cable test will automatically break the link. 9646cb75767SMichael Walle */ 9656cb75767SMichael Walle phy_write(phydev, MII_BMCR, BMCR_ANENABLE); 9666cb75767SMichael Walle phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); 967dc0f3ed1SOleksij Rempel if (phydev->phy_id != ATH9331_PHY_ID && 968dc0f3ed1SOleksij Rempel phydev->phy_id != ATH8032_PHY_ID) 9696cb75767SMichael Walle phy_write(phydev, MII_CTRL1000, 0); 9706cb75767SMichael Walle 9716cb75767SMichael Walle /* we do all the (time consuming) work later */ 9726cb75767SMichael Walle return 0; 9736cb75767SMichael Walle } 9746cb75767SMichael Walle 975317420abSMugunthan V N static struct phy_driver at803x_driver[] = { 976317420abSMugunthan V N { 97796c36712SMichael Walle /* Qualcomm Atheros AR8035 */ 9780465d8f8SMichael Walle PHY_ID_MATCH_EXACT(ATH8035_PHY_ID), 97996c36712SMichael Walle .name = "Qualcomm Atheros AR8035", 9806cb75767SMichael Walle .flags = PHY_POLL_CABLE_TEST, 9812f664823SMichael Walle .probe = at803x_probe, 9822318ca8aSMichael Walle .remove = at803x_remove, 9830ca7111aSMatus Ujhelyi .config_init = at803x_config_init, 984cde0f4f8SMichael Walle .soft_reset = genphy_soft_reset, 985ea13c9eeSMugunthan V N .set_wol = at803x_set_wol, 986ea13c9eeSMugunthan V N .get_wol = at803x_get_wol, 9876229ed1fSDaniel Mack .suspend = at803x_suspend, 9886229ed1fSDaniel Mack .resume = at803x_resume, 989dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 99006d5f344SRussell King .read_status = at803x_read_status, 9910eae5982SMåns Rullgård .ack_interrupt = at803x_ack_interrupt, 9920eae5982SMåns Rullgård .config_intr = at803x_config_intr, 993cde0f4f8SMichael Walle .get_tunable = at803x_get_tunable, 994cde0f4f8SMichael Walle .set_tunable = at803x_set_tunable, 9956cb75767SMichael Walle .cable_test_start = at803x_cable_test_start, 9966cb75767SMichael Walle .cable_test_get_status = at803x_cable_test_get_status, 997317420abSMugunthan V N }, { 99896c36712SMichael Walle /* Qualcomm Atheros AR8030 */ 999bd8ca17fSDaniel Mack .phy_id = ATH8030_PHY_ID, 100096c36712SMichael Walle .name = "Qualcomm Atheros AR8030", 10010465d8f8SMichael Walle .phy_id_mask = AT8030_PHY_ID_MASK, 10022f664823SMichael Walle .probe = at803x_probe, 10032318ca8aSMichael Walle .remove = at803x_remove, 10040ca7111aSMatus Ujhelyi .config_init = at803x_config_init, 100513a56b44SDaniel Mack .link_change_notify = at803x_link_change_notify, 1006ea13c9eeSMugunthan V N .set_wol = at803x_set_wol, 1007ea13c9eeSMugunthan V N .get_wol = at803x_get_wol, 10086229ed1fSDaniel Mack .suspend = at803x_suspend, 10096229ed1fSDaniel Mack .resume = at803x_resume, 1010dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 10110eae5982SMåns Rullgård .ack_interrupt = at803x_ack_interrupt, 10120eae5982SMåns Rullgård .config_intr = at803x_config_intr, 101305d7cce8SMugunthan V N }, { 101496c36712SMichael Walle /* Qualcomm Atheros AR8031/AR8033 */ 10150465d8f8SMichael Walle PHY_ID_MATCH_EXACT(ATH8031_PHY_ID), 101696c36712SMichael Walle .name = "Qualcomm Atheros AR8031/AR8033", 10176cb75767SMichael Walle .flags = PHY_POLL_CABLE_TEST, 10182f664823SMichael Walle .probe = at803x_probe, 10192318ca8aSMichael Walle .remove = at803x_remove, 102005d7cce8SMugunthan V N .config_init = at803x_config_init, 1021cde0f4f8SMichael Walle .soft_reset = genphy_soft_reset, 102205d7cce8SMugunthan V N .set_wol = at803x_set_wol, 102305d7cce8SMugunthan V N .get_wol = at803x_get_wol, 10246229ed1fSDaniel Mack .suspend = at803x_suspend, 10256229ed1fSDaniel Mack .resume = at803x_resume, 1026dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 102706d5f344SRussell King .read_status = at803x_read_status, 1028f62265b5SZefir Kurtisi .aneg_done = at803x_aneg_done, 102977a99394SZhao Qiang .ack_interrupt = &at803x_ack_interrupt, 103077a99394SZhao Qiang .config_intr = &at803x_config_intr, 1031cde0f4f8SMichael Walle .get_tunable = at803x_get_tunable, 1032cde0f4f8SMichael Walle .set_tunable = at803x_set_tunable, 10336cb75767SMichael Walle .cable_test_start = at803x_cable_test_start, 10346cb75767SMichael Walle .cable_test_get_status = at803x_cable_test_get_status, 10357908d2ceSOleksij Rempel }, { 10365800091aSDavid Bauer /* Qualcomm Atheros AR8032 */ 10375800091aSDavid Bauer PHY_ID_MATCH_EXACT(ATH8032_PHY_ID), 10385800091aSDavid Bauer .name = "Qualcomm Atheros AR8032", 10395800091aSDavid Bauer .probe = at803x_probe, 10405800091aSDavid Bauer .remove = at803x_remove, 1041dc0f3ed1SOleksij Rempel .flags = PHY_POLL_CABLE_TEST, 10425800091aSDavid Bauer .config_init = at803x_config_init, 10435800091aSDavid Bauer .link_change_notify = at803x_link_change_notify, 10445800091aSDavid Bauer .set_wol = at803x_set_wol, 10455800091aSDavid Bauer .get_wol = at803x_get_wol, 10465800091aSDavid Bauer .suspend = at803x_suspend, 10475800091aSDavid Bauer .resume = at803x_resume, 10485800091aSDavid Bauer /* PHY_BASIC_FEATURES */ 10495800091aSDavid Bauer .ack_interrupt = at803x_ack_interrupt, 10505800091aSDavid Bauer .config_intr = at803x_config_intr, 1051dc0f3ed1SOleksij Rempel .cable_test_start = at803x_cable_test_start, 1052dc0f3ed1SOleksij Rempel .cable_test_get_status = at803x_cable_test_get_status, 10535800091aSDavid Bauer }, { 10547908d2ceSOleksij Rempel /* ATHEROS AR9331 */ 10557908d2ceSOleksij Rempel PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), 105696c36712SMichael Walle .name = "Qualcomm Atheros AR9331 built-in PHY", 10577908d2ceSOleksij Rempel .suspend = at803x_suspend, 10587908d2ceSOleksij Rempel .resume = at803x_resume, 1059dc0f3ed1SOleksij Rempel .flags = PHY_POLL_CABLE_TEST, 10607908d2ceSOleksij Rempel /* PHY_BASIC_FEATURES */ 10617908d2ceSOleksij Rempel .ack_interrupt = &at803x_ack_interrupt, 10627908d2ceSOleksij Rempel .config_intr = &at803x_config_intr, 1063dc0f3ed1SOleksij Rempel .cable_test_start = at803x_cable_test_start, 1064dc0f3ed1SOleksij Rempel .cable_test_get_status = at803x_cable_test_get_status, 1065317420abSMugunthan V N } }; 10660ca7111aSMatus Ujhelyi 106750fd7150SJohan Hovold module_phy_driver(at803x_driver); 10680ca7111aSMatus Ujhelyi 10690ca7111aSMatus Ujhelyi static struct mdio_device_id __maybe_unused atheros_tbl[] = { 10700465d8f8SMichael Walle { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, 10710465d8f8SMichael Walle { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, 10725800091aSDavid Bauer { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, 10730465d8f8SMichael Walle { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, 10747908d2ceSOleksij Rempel { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, 10750ca7111aSMatus Ujhelyi { } 10760ca7111aSMatus Ujhelyi }; 10770ca7111aSMatus Ujhelyi 10780ca7111aSMatus Ujhelyi MODULE_DEVICE_TABLE(mdio, atheros_tbl); 1079