]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/net/phy/smsc.c
net: phy: phy drivers should not set SUPPORTED_[Asym_]Pause
[linux.git] / drivers / net / phy / smsc.c
1 /*
2  * drivers/net/phy/smsc.c
3  *
4  * Driver for SMSC PHYs
5  *
6  * Author: Herbert Valerio Riedel
7  *
8  * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
9  *
10  * This program is free software; you can redistribute  it and/or modify it
11  * under  the terms of  the GNU General  Public License as published by the
12  * Free Software Foundation;  either version 2 of the  License, or (at your
13  * option) any later version.
14  *
15  * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net
16  *
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/mii.h>
22 #include <linux/ethtool.h>
23 #include <linux/phy.h>
24 #include <linux/netdevice.h>
25 #include <linux/smscphy.h>
26
27 struct smsc_phy_priv {
28         bool energy_enable;
29 };
30
31 static int smsc_phy_config_intr(struct phy_device *phydev)
32 {
33         int rc = phy_write (phydev, MII_LAN83C185_IM,
34                         ((PHY_INTERRUPT_ENABLED == phydev->interrupts)
35                         ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS
36                         : 0));
37
38         return rc < 0 ? rc : 0;
39 }
40
41 static int smsc_phy_ack_interrupt(struct phy_device *phydev)
42 {
43         int rc = phy_read (phydev, MII_LAN83C185_ISF);
44
45         return rc < 0 ? rc : 0;
46 }
47
48 static int smsc_phy_config_init(struct phy_device *phydev)
49 {
50         struct smsc_phy_priv *priv = phydev->priv;
51
52         int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
53
54         if (rc < 0)
55                 return rc;
56
57         if (priv->energy_enable) {
58                 /* Enable energy detect mode for this SMSC Transceivers */
59                 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
60                                rc | MII_LAN83C185_EDPWRDOWN);
61                 if (rc < 0)
62                         return rc;
63         }
64
65         return smsc_phy_ack_interrupt(phydev);
66 }
67
68 static int smsc_phy_reset(struct phy_device *phydev)
69 {
70         int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
71         if (rc < 0)
72                 return rc;
73
74         /* If the SMSC PHY is in power down mode, then set it
75          * in all capable mode before using it.
76          */
77         if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {
78                 /* set "all capable" mode */
79                 rc |= MII_LAN83C185_MODE_ALL;
80                 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
81         }
82
83         /* reset the phy */
84         return genphy_soft_reset(phydev);
85 }
86
87 static int lan911x_config_init(struct phy_device *phydev)
88 {
89         return smsc_phy_ack_interrupt(phydev);
90 }
91
92 /*
93  * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
94  * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
95  * unstable detection of plugging in Ethernet cable.
96  * This workaround disables Energy Detect Power-Down mode and waiting for
97  * response on link pulses to detect presence of plugged Ethernet cable.
98  * The Energy Detect Power-Down mode is enabled again in the end of procedure to
99  * save approximately 220 mW of power if cable is unplugged.
100  */
101 static int lan87xx_read_status(struct phy_device *phydev)
102 {
103         struct smsc_phy_priv *priv = phydev->priv;
104
105         int err = genphy_read_status(phydev);
106
107         if (!phydev->link && priv->energy_enable) {
108                 int i;
109
110                 /* Disable EDPD to wake up PHY */
111                 int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
112                 if (rc < 0)
113                         return rc;
114
115                 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
116                                rc & ~MII_LAN83C185_EDPWRDOWN);
117                 if (rc < 0)
118                         return rc;
119
120                 /* Wait max 640 ms to detect energy */
121                 for (i = 0; i < 64; i++) {
122                         /* Sleep to allow link test pulses to be sent */
123                         msleep(10);
124                         rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
125                         if (rc < 0)
126                                 return rc;
127                         if (rc & MII_LAN83C185_ENERGYON)
128                                 break;
129                 }
130
131                 /* Re-enable EDPD */
132                 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
133                 if (rc < 0)
134                         return rc;
135
136                 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
137                                rc | MII_LAN83C185_EDPWRDOWN);
138                 if (rc < 0)
139                         return rc;
140         }
141
142         return err;
143 }
144
145 static int smsc_phy_probe(struct phy_device *phydev)
146 {
147         struct device *dev = &phydev->mdio.dev;
148         struct device_node *of_node = dev->of_node;
149         struct smsc_phy_priv *priv;
150
151         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
152         if (!priv)
153                 return -ENOMEM;
154
155         priv->energy_enable = true;
156
157         if (of_property_read_bool(of_node, "smsc,disable-energy-detect"))
158                 priv->energy_enable = false;
159
160         phydev->priv = priv;
161
162         return 0;
163 }
164
165 static struct phy_driver smsc_phy_driver[] = {
166 {
167         .phy_id         = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
168         .phy_id_mask    = 0xfffffff0,
169         .name           = "SMSC LAN83C185",
170
171         .features       = PHY_BASIC_FEATURES,
172         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
173
174         .probe          = smsc_phy_probe,
175
176         /* basic functions */
177         .config_aneg    = genphy_config_aneg,
178         .read_status    = genphy_read_status,
179         .config_init    = smsc_phy_config_init,
180         .soft_reset     = smsc_phy_reset,
181
182         /* IRQ related */
183         .ack_interrupt  = smsc_phy_ack_interrupt,
184         .config_intr    = smsc_phy_config_intr,
185
186         .suspend        = genphy_suspend,
187         .resume         = genphy_resume,
188 }, {
189         .phy_id         = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
190         .phy_id_mask    = 0xfffffff0,
191         .name           = "SMSC LAN8187",
192
193         .features       = PHY_BASIC_FEATURES,
194         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
195
196         .probe          = smsc_phy_probe,
197
198         /* basic functions */
199         .config_aneg    = genphy_config_aneg,
200         .read_status    = genphy_read_status,
201         .config_init    = smsc_phy_config_init,
202         .soft_reset     = smsc_phy_reset,
203
204         /* IRQ related */
205         .ack_interrupt  = smsc_phy_ack_interrupt,
206         .config_intr    = smsc_phy_config_intr,
207
208         .suspend        = genphy_suspend,
209         .resume         = genphy_resume,
210 }, {
211         .phy_id         = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
212         .phy_id_mask    = 0xfffffff0,
213         .name           = "SMSC LAN8700",
214
215         .features       = PHY_BASIC_FEATURES,
216         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
217
218         .probe          = smsc_phy_probe,
219
220         /* basic functions */
221         .config_aneg    = genphy_config_aneg,
222         .read_status    = lan87xx_read_status,
223         .config_init    = smsc_phy_config_init,
224         .soft_reset     = smsc_phy_reset,
225
226         /* IRQ related */
227         .ack_interrupt  = smsc_phy_ack_interrupt,
228         .config_intr    = smsc_phy_config_intr,
229
230         .suspend        = genphy_suspend,
231         .resume         = genphy_resume,
232 }, {
233         .phy_id         = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
234         .phy_id_mask    = 0xfffffff0,
235         .name           = "SMSC LAN911x Internal PHY",
236
237         .features       = PHY_BASIC_FEATURES,
238         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
239
240         .probe          = smsc_phy_probe,
241
242         /* basic functions */
243         .config_aneg    = genphy_config_aneg,
244         .read_status    = genphy_read_status,
245         .config_init    = lan911x_config_init,
246
247         /* IRQ related */
248         .ack_interrupt  = smsc_phy_ack_interrupt,
249         .config_intr    = smsc_phy_config_intr,
250
251         .suspend        = genphy_suspend,
252         .resume         = genphy_resume,
253 }, {
254         .phy_id         = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
255         .phy_id_mask    = 0xfffffff0,
256         .name           = "SMSC LAN8710/LAN8720",
257
258         .features       = PHY_BASIC_FEATURES,
259         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
260
261         .probe          = smsc_phy_probe,
262
263         /* basic functions */
264         .config_aneg    = genphy_config_aneg,
265         .read_status    = lan87xx_read_status,
266         .config_init    = smsc_phy_config_init,
267         .soft_reset     = smsc_phy_reset,
268
269         /* IRQ related */
270         .ack_interrupt  = smsc_phy_ack_interrupt,
271         .config_intr    = smsc_phy_config_intr,
272
273         .suspend        = genphy_suspend,
274         .resume         = genphy_resume,
275 }, {
276         .phy_id         = 0x0007c110,
277         .phy_id_mask    = 0xfffffff0,
278         .name           = "SMSC LAN8740",
279
280         .features       = PHY_BASIC_FEATURES,
281         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
282
283         .probe          = smsc_phy_probe,
284
285         /* basic functions */
286         .config_aneg    = genphy_config_aneg,
287         .read_status    = lan87xx_read_status,
288         .config_init    = smsc_phy_config_init,
289         .soft_reset     = smsc_phy_reset,
290
291         /* IRQ related */
292         .ack_interrupt  = smsc_phy_ack_interrupt,
293         .config_intr    = smsc_phy_config_intr,
294
295         .suspend        = genphy_suspend,
296         .resume         = genphy_resume,
297 } };
298
299 module_phy_driver(smsc_phy_driver);
300
301 MODULE_DESCRIPTION("SMSC PHY driver");
302 MODULE_AUTHOR("Herbert Valerio Riedel");
303 MODULE_LICENSE("GPL");
304
305 static struct mdio_device_id __maybe_unused smsc_tbl[] = {
306         { 0x0007c0a0, 0xfffffff0 },
307         { 0x0007c0b0, 0xfffffff0 },
308         { 0x0007c0c0, 0xfffffff0 },
309         { 0x0007c0d0, 0xfffffff0 },
310         { 0x0007c0f0, 0xfffffff0 },
311         { 0x0007c110, 0xfffffff0 },
312         { }
313 };
314
315 MODULE_DEVICE_TABLE(mdio, smsc_tbl);