1 /* 2 * Core PHY library, taken from phy.c 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation; either version 2 of the License, or (at your 7 * option) any later version. 8 */ 9 #include <linux/export.h> 10 #include <linux/phy.h> 11 12 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, 13 u16 regnum) 14 { 15 /* Write the desired MMD Devad */ 16 bus->write(bus, phy_addr, MII_MMD_CTRL, devad); 17 18 /* Write the desired MMD register address */ 19 bus->write(bus, phy_addr, MII_MMD_DATA, regnum); 20 21 /* Select the Function : DATA with no post increment */ 22 bus->write(bus, phy_addr, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR); 23 } 24 25 /** 26 * phy_read_mmd - Convenience function for reading a register 27 * from an MMD on a given PHY. 28 * @phydev: The phy_device struct 29 * @devad: The MMD to read from (0..31) 30 * @regnum: The register on the MMD to read (0..65535) 31 * 32 * Same rules as for phy_read(); 33 */ 34 int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) 35 { 36 int val; 37 38 if (regnum > (u16)~0 || devad > 32) 39 return -EINVAL; 40 41 if (phydev->drv->read_mmd) { 42 val = phydev->drv->read_mmd(phydev, devad, regnum); 43 } else if (phydev->is_c45) { 44 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff); 45 46 val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr); 47 } else { 48 struct mii_bus *bus = phydev->mdio.bus; 49 int phy_addr = phydev->mdio.addr; 50 51 mutex_lock(&bus->mdio_lock); 52 mmd_phy_indirect(bus, phy_addr, devad, regnum); 53 54 /* Read the content of the MMD's selected register */ 55 val = bus->read(bus, phy_addr, MII_MMD_DATA); 56 mutex_unlock(&bus->mdio_lock); 57 } 58 return val; 59 } 60 EXPORT_SYMBOL(phy_read_mmd); 61 62 /** 63 * phy_write_mmd - Convenience function for writing a register 64 * on an MMD on a given PHY. 65 * @phydev: The phy_device struct 66 * @devad: The MMD to read from 67 * @regnum: The register on the MMD to read 68 * @val: value to write to @regnum 69 * 70 * Same rules as for phy_write(); 71 */ 72 int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) 73 { 74 int ret; 75 76 if (regnum > (u16)~0 || devad > 32) 77 return -EINVAL; 78 79 if (phydev->drv->write_mmd) { 80 ret = phydev->drv->write_mmd(phydev, devad, regnum, val); 81 } else if (phydev->is_c45) { 82 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff); 83 84 ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, 85 addr, val); 86 } else { 87 struct mii_bus *bus = phydev->mdio.bus; 88 int phy_addr = phydev->mdio.addr; 89 90 mutex_lock(&bus->mdio_lock); 91 mmd_phy_indirect(bus, phy_addr, devad, regnum); 92 93 /* Write the data into MMD's selected register */ 94 bus->write(bus, phy_addr, MII_MMD_DATA, val); 95 mutex_unlock(&bus->mdio_lock); 96 97 ret = 0; 98 } 99 return ret; 100 } 101 EXPORT_SYMBOL(phy_write_mmd); 102