4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19 * Base code from drivers/net/phy/davicom.c
20 * Copyright 2010-2011 Freescale Semiconductor, Inc.
23 * Some code get from linux kenrel
24 * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
30 #define MII_LAN83C185_CTRL_STATUS 17 /* Mode/Status Register */
31 #define MII_LAN83C185_EDPWRDOWN (1 << 13) /* EDPWRDOWN */
32 #define MII_LAN83C185_ENERGYON (1 << 1) /* ENERGYON */
34 static int smsc_parse_status(struct phy_device *phydev)
41 aneg_exp = phy_read(phydev, MDIO_DEVAD_NONE, MII_EXPANSION);
45 if (aneg_exp & EXPANSION_MFAULTS) {
46 /* second read to clear latched status */
47 aneg_exp = phy_read(phydev, MDIO_DEVAD_NONE, MII_EXPANSION);
48 if (aneg_exp & EXPANSION_MFAULTS)
52 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
55 if (bmcr & BMCR_ANENABLE) {
56 lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
59 mii_adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
64 if (!(aneg_exp & EXPANSION_NWAY)) {
65 /* parallel detection */
66 phydev->duplex = DUPLEX_HALF;
67 if (lpa & (LPA_100HALF | LPA_100FULL))
68 phydev->speed = SPEED_100;
70 phydev->speed = SPEED_10;
73 if (lpa & (LPA_100FULL | LPA_100HALF)) {
74 phydev->speed = SPEED_100;
75 if (lpa & LPA_100FULL)
76 phydev->duplex = DUPLEX_FULL;
78 phydev->duplex = DUPLEX_HALF;
79 } else if (lpa & (LPA_10FULL | LPA_10HALF)) {
80 phydev->speed = SPEED_10;
82 phydev->duplex = DUPLEX_FULL;
84 phydev->duplex = DUPLEX_HALF;
89 if (bmcr & BMCR_SPEED100)
90 phydev->speed = SPEED_100;
92 phydev->speed = SPEED_10;
94 if (bmcr & BMCR_FULLDPLX)
95 phydev->duplex = DUPLEX_FULL;
97 phydev->duplex = DUPLEX_HALF;
102 static int smsc_startup(struct phy_device *phydev)
107 /* Disable EDPD to wake up PHY */
108 ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_LAN83C185_CTRL_STATUS);
113 if (ret & MII_LAN83C185_EDPWRDOWN) {
114 ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_LAN83C185_CTRL_STATUS,
115 ret & ~MII_LAN83C185_EDPWRDOWN);
119 /* Sleep 64 ms to allow ~5 link test pulses to be sent */
124 ret = genphy_update_link(phydev);
127 return smsc_parse_status(phydev);
130 static int smsc_mdix_setup(struct phy_device *phydev)
133 static const char *mdix = "_mdi";
134 char varname[strlen(phydev->bus->name) + strlen(mdix) + 1];
137 snprintf(varname, sizeof(varname), "%s%s", phydev->bus->name, mdix);
139 val = getenv(varname);
141 if (strcasecmp(val, "auto") == 0) {
143 } else if (strcasecmp(val, "mdix") == 0) {
145 } else if (strcasecmp(val, "mdi") == 0) {
148 printf("Improper setting '%s' for %s\n", val, varname);
149 printf("Expected one of: 'auto', 'mdi', 'mdix'\n");
158 static int smsc_config(struct phy_device *phydev)
160 int mdix = smsc_mdix_setup(phydev);
165 int ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1b,
166 (1 << 15) | ((mdix & 1) << 13));
168 printf("Failed to setup MDI/MDIX mode: %d\n", ret);
172 return genphy_config_aneg(phydev);
175 static struct phy_driver lan8700_driver = {
176 .name = "SMSC LAN8700",
179 .features = PHY_BASIC_FEATURES,
180 .config = &genphy_config_aneg,
181 .startup = &smsc_startup,
182 .shutdown = &genphy_shutdown,
185 static struct phy_driver lan911x_driver = {
186 .name = "SMSC LAN911x Internal PHY",
189 .features = PHY_BASIC_FEATURES,
190 .config = &genphy_config_aneg,
191 .startup = &smsc_startup,
192 .shutdown = &genphy_shutdown,
195 static struct phy_driver lan8710_driver = {
196 .name = "SMSC LAN8710/LAN8720",
199 .features = PHY_GBIT_FEATURES,
200 .config = &smsc_config,
201 .startup = &smsc_startup,
202 .shutdown = &genphy_shutdown,
205 int phy_smsc_init(void)
207 phy_register(&lan8710_driver);
208 phy_register(&lan911x_driver);
209 phy_register(&lan8700_driver);