]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/phy/phy-core.c
357a4d0d7641ea6db47dca1048ad8452fb9ea99e
[karo-tx-linux.git] / drivers / net / phy / phy-core.c
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->read_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);