diff options
Diffstat (limited to 'drivers/net/phy/microchip.c')
-rw-r--r-- | drivers/net/phy/microchip.c | 126 |
1 files changed, 125 insertions, 1 deletions
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index 0b88635f4fbc..d3273bc0da4a 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -12,8 +12,14 @@ #include <linux/of.h> #include <dt-bindings/net/microchip-lan78xx.h> +#define PHY_ID_LAN937X_TX 0x0007c190 + +#define LAN937X_MODE_CTRL_STATUS_REG 0x11 +#define LAN937X_AUTOMDIX_EN BIT(7) +#define LAN937X_MDI_MODE BIT(6) + #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" -#define DRIVER_DESC "Microchip LAN88XX PHY driver" +#define DRIVER_DESC "Microchip LAN88XX/LAN937X TX PHY driver" struct lan88xx_priv { int chip_id; @@ -373,6 +379,115 @@ static void lan88xx_link_change_notify(struct phy_device *phydev) } } +/** + * lan937x_tx_read_mdix_status - Read the MDIX status for the LAN937x TX PHY. + * @phydev: Pointer to the phy_device structure. + * + * This function reads the MDIX status of the LAN937x TX PHY and sets the + * mdix_ctrl and mdix fields of the phy_device structure accordingly. + * Note that MDIX status is not supported in AUTO mode, and will be set + * to invalid in such cases. + * + * Return: 0 on success, a negative error code on failure. + */ +static int lan937x_tx_read_mdix_status(struct phy_device *phydev) +{ + int ret; + + ret = phy_read(phydev, LAN937X_MODE_CTRL_STATUS_REG); + if (ret < 0) + return ret; + + if (ret & LAN937X_AUTOMDIX_EN) { + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + /* MDI/MDIX status is unknown */ + phydev->mdix = ETH_TP_MDI_INVALID; + } else if (ret & LAN937X_MDI_MODE) { + phydev->mdix_ctrl = ETH_TP_MDI_X; + phydev->mdix = ETH_TP_MDI_X; + } else { + phydev->mdix_ctrl = ETH_TP_MDI; + phydev->mdix = ETH_TP_MDI; + } + + return 0; +} + +/** + * lan937x_tx_read_status - Read the status for the LAN937x TX PHY. + * @phydev: Pointer to the phy_device structure. + * + * This function reads the status of the LAN937x TX PHY and updates the + * phy_device structure accordingly. + * + * Return: 0 on success, a negative error code on failure. + */ +static int lan937x_tx_read_status(struct phy_device *phydev) +{ + int ret; + + ret = genphy_read_status(phydev); + if (ret < 0) + return ret; + + return lan937x_tx_read_mdix_status(phydev); +} + +/** + * lan937x_tx_set_mdix - Set the MDIX mode for the LAN937x TX PHY. + * @phydev: Pointer to the phy_device structure. + * + * This function configures the MDIX mode of the LAN937x TX PHY based on the + * mdix_ctrl field of the phy_device structure. The MDIX mode can be set to + * MDI (straight-through), MDIX (crossover), or AUTO (auto-MDIX). If the mode + * is not recognized, it returns 0 without making any changes. + * + * Return: 0 on success, a negative error code on failure. + */ +static int lan937x_tx_set_mdix(struct phy_device *phydev) +{ + u16 val; + + switch (phydev->mdix_ctrl) { + case ETH_TP_MDI: + val = 0; + break; + case ETH_TP_MDI_X: + val = LAN937X_MDI_MODE; + break; + case ETH_TP_MDI_AUTO: + val = LAN937X_AUTOMDIX_EN; + break; + default: + return 0; + } + + return phy_modify(phydev, LAN937X_MODE_CTRL_STATUS_REG, + LAN937X_AUTOMDIX_EN | LAN937X_MDI_MODE, val); +} + +/** + * lan937x_tx_config_aneg - Configure auto-negotiation and fixed modes for the + * LAN937x TX PHY. + * @phydev: Pointer to the phy_device structure. + * + * This function configures the MDIX mode for the LAN937x TX PHY and then + * proceeds to configure the auto-negotiation or fixed mode settings + * based on the phy_device structure. + * + * Return: 0 on success, a negative error code on failure. + */ +static int lan937x_tx_config_aneg(struct phy_device *phydev) +{ + int ret; + + ret = lan937x_tx_set_mdix(phydev); + if (ret < 0) + return ret; + + return genphy_config_aneg(phydev); +} + static struct phy_driver microchip_phy_driver[] = { { .phy_id = 0x0007c132, @@ -400,12 +515,21 @@ static struct phy_driver microchip_phy_driver[] = { .set_wol = lan88xx_set_wol, .read_page = lan88xx_read_page, .write_page = lan88xx_write_page, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX), + .name = "Microchip LAN937x TX", + .suspend = genphy_suspend, + .resume = genphy_resume, + .config_aneg = lan937x_tx_config_aneg, + .read_status = lan937x_tx_read_status, } }; module_phy_driver(microchip_phy_driver); static struct mdio_device_id __maybe_unused microchip_tbl[] = { { 0x0007c132, 0xfffffff2 }, + { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX) }, { } }; |