]> Pileus Git - ~andy/linux/blob - drivers/net/phy/smsc.c
Merge tag 'drm-intel-next-2012-02-07' of git://people.freedesktop.org/~danvet/drm...
[~andy/linux] / 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@smsc.com
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 static int smsc_phy_config_intr(struct phy_device *phydev)
28 {
29         int rc = phy_write (phydev, MII_LAN83C185_IM,
30                         ((PHY_INTERRUPT_ENABLED == phydev->interrupts)
31                         ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS
32                         : 0));
33
34         return rc < 0 ? rc : 0;
35 }
36
37 static int smsc_phy_ack_interrupt(struct phy_device *phydev)
38 {
39         int rc = phy_read (phydev, MII_LAN83C185_ISF);
40
41         return rc < 0 ? rc : 0;
42 }
43
44 static int smsc_phy_config_init(struct phy_device *phydev)
45 {
46         int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
47         if (rc < 0)
48                 return rc;
49
50         /* Enable energy detect mode for this SMSC Transceivers */
51         rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
52                        rc | MII_LAN83C185_EDPWRDOWN);
53         if (rc < 0)
54                 return rc;
55
56         return smsc_phy_ack_interrupt (phydev);
57 }
58
59 static int lan911x_config_init(struct phy_device *phydev)
60 {
61         return smsc_phy_ack_interrupt(phydev);
62 }
63
64 static struct phy_driver lan83c185_driver = {
65         .phy_id         = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
66         .phy_id_mask    = 0xfffffff0,
67         .name           = "SMSC LAN83C185",
68
69         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
70                                 | SUPPORTED_Asym_Pause),
71         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
72
73         /* basic functions */
74         .config_aneg    = genphy_config_aneg,
75         .read_status    = genphy_read_status,
76         .config_init    = smsc_phy_config_init,
77
78         /* IRQ related */
79         .ack_interrupt  = smsc_phy_ack_interrupt,
80         .config_intr    = smsc_phy_config_intr,
81
82         .suspend        = genphy_suspend,
83         .resume         = genphy_resume,
84
85         .driver         = { .owner = THIS_MODULE, }
86 };
87
88 static struct phy_driver lan8187_driver = {
89         .phy_id         = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
90         .phy_id_mask    = 0xfffffff0,
91         .name           = "SMSC LAN8187",
92
93         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
94                                 | SUPPORTED_Asym_Pause),
95         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
96
97         /* basic functions */
98         .config_aneg    = genphy_config_aneg,
99         .read_status    = genphy_read_status,
100         .config_init    = smsc_phy_config_init,
101
102         /* IRQ related */
103         .ack_interrupt  = smsc_phy_ack_interrupt,
104         .config_intr    = smsc_phy_config_intr,
105
106         .suspend        = genphy_suspend,
107         .resume         = genphy_resume,
108
109         .driver         = { .owner = THIS_MODULE, }
110 };
111
112 static struct phy_driver lan8700_driver = {
113         .phy_id         = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
114         .phy_id_mask    = 0xfffffff0,
115         .name           = "SMSC LAN8700",
116
117         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
118                                 | SUPPORTED_Asym_Pause),
119         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
120
121         /* basic functions */
122         .config_aneg    = genphy_config_aneg,
123         .read_status    = genphy_read_status,
124         .config_init    = smsc_phy_config_init,
125
126         /* IRQ related */
127         .ack_interrupt  = smsc_phy_ack_interrupt,
128         .config_intr    = smsc_phy_config_intr,
129
130         .suspend        = genphy_suspend,
131         .resume         = genphy_resume,
132
133         .driver         = { .owner = THIS_MODULE, }
134 };
135
136 static struct phy_driver lan911x_int_driver = {
137         .phy_id         = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
138         .phy_id_mask    = 0xfffffff0,
139         .name           = "SMSC LAN911x Internal PHY",
140
141         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
142                                 | SUPPORTED_Asym_Pause),
143         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
144
145         /* basic functions */
146         .config_aneg    = genphy_config_aneg,
147         .read_status    = genphy_read_status,
148         .config_init    = lan911x_config_init,
149
150         /* IRQ related */
151         .ack_interrupt  = smsc_phy_ack_interrupt,
152         .config_intr    = smsc_phy_config_intr,
153
154         .suspend        = genphy_suspend,
155         .resume         = genphy_resume,
156
157         .driver         = { .owner = THIS_MODULE, }
158 };
159
160 static struct phy_driver lan8710_driver = {
161         .phy_id         = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
162         .phy_id_mask    = 0xfffffff0,
163         .name           = "SMSC LAN8710/LAN8720",
164
165         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
166                                 | SUPPORTED_Asym_Pause),
167         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
168
169         /* basic functions */
170         .config_aneg    = genphy_config_aneg,
171         .read_status    = genphy_read_status,
172         .config_init    = smsc_phy_config_init,
173
174         /* IRQ related */
175         .ack_interrupt  = smsc_phy_ack_interrupt,
176         .config_intr    = smsc_phy_config_intr,
177
178         .suspend        = genphy_suspend,
179         .resume         = genphy_resume,
180
181         .driver         = { .owner = THIS_MODULE, }
182 };
183
184 static int __init smsc_init(void)
185 {
186         int ret;
187
188         ret = phy_driver_register (&lan83c185_driver);
189         if (ret)
190                 goto err1;
191
192         ret = phy_driver_register (&lan8187_driver);
193         if (ret)
194                 goto err2;
195
196         ret = phy_driver_register (&lan8700_driver);
197         if (ret)
198                 goto err3;
199
200         ret = phy_driver_register (&lan911x_int_driver);
201         if (ret)
202                 goto err4;
203
204         ret = phy_driver_register (&lan8710_driver);
205         if (ret)
206                 goto err5;
207
208         return 0;
209
210 err5:
211         phy_driver_unregister (&lan911x_int_driver);
212 err4:
213         phy_driver_unregister (&lan8700_driver);
214 err3:
215         phy_driver_unregister (&lan8187_driver);
216 err2:
217         phy_driver_unregister (&lan83c185_driver);
218 err1:
219         return ret;
220 }
221
222 static void __exit smsc_exit(void)
223 {
224         phy_driver_unregister (&lan8710_driver);
225         phy_driver_unregister (&lan911x_int_driver);
226         phy_driver_unregister (&lan8700_driver);
227         phy_driver_unregister (&lan8187_driver);
228         phy_driver_unregister (&lan83c185_driver);
229 }
230
231 MODULE_DESCRIPTION("SMSC PHY driver");
232 MODULE_AUTHOR("Herbert Valerio Riedel");
233 MODULE_LICENSE("GPL");
234
235 module_init(smsc_init);
236 module_exit(smsc_exit);
237
238 static struct mdio_device_id __maybe_unused smsc_tbl[] = {
239         { 0x0007c0a0, 0xfffffff0 },
240         { 0x0007c0b0, 0xfffffff0 },
241         { 0x0007c0c0, 0xfffffff0 },
242         { 0x0007c0d0, 0xfffffff0 },
243         { 0x0007c0f0, 0xfffffff0 },
244         { }
245 };
246
247 MODULE_DEVICE_TABLE(mdio, smsc_tbl);