]> Pileus Git - ~andy/linux/blob - drivers/net/phy/smsc.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[~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@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 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 smsc_phy_driver[] = {
65 {
66         .phy_id         = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
67         .phy_id_mask    = 0xfffffff0,
68         .name           = "SMSC LAN83C185",
69
70         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
71                                 | SUPPORTED_Asym_Pause),
72         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
73
74         /* basic functions */
75         .config_aneg    = genphy_config_aneg,
76         .read_status    = genphy_read_status,
77         .config_init    = smsc_phy_config_init,
78
79         /* IRQ related */
80         .ack_interrupt  = smsc_phy_ack_interrupt,
81         .config_intr    = smsc_phy_config_intr,
82
83         .suspend        = genphy_suspend,
84         .resume         = genphy_resume,
85
86         .driver         = { .owner = THIS_MODULE, }
87 }, {
88         .phy_id         = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
89         .phy_id_mask    = 0xfffffff0,
90         .name           = "SMSC LAN8187",
91
92         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
93                                 | SUPPORTED_Asym_Pause),
94         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
95
96         /* basic functions */
97         .config_aneg    = genphy_config_aneg,
98         .read_status    = genphy_read_status,
99         .config_init    = smsc_phy_config_init,
100
101         /* IRQ related */
102         .ack_interrupt  = smsc_phy_ack_interrupt,
103         .config_intr    = smsc_phy_config_intr,
104
105         .suspend        = genphy_suspend,
106         .resume         = genphy_resume,
107
108         .driver         = { .owner = THIS_MODULE, }
109 }, {
110         .phy_id         = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
111         .phy_id_mask    = 0xfffffff0,
112         .name           = "SMSC LAN8700",
113
114         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
115                                 | SUPPORTED_Asym_Pause),
116         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
117
118         /* basic functions */
119         .config_aneg    = genphy_config_aneg,
120         .read_status    = genphy_read_status,
121         .config_init    = smsc_phy_config_init,
122
123         /* IRQ related */
124         .ack_interrupt  = smsc_phy_ack_interrupt,
125         .config_intr    = smsc_phy_config_intr,
126
127         .suspend        = genphy_suspend,
128         .resume         = genphy_resume,
129
130         .driver         = { .owner = THIS_MODULE, }
131 }, {
132         .phy_id         = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
133         .phy_id_mask    = 0xfffffff0,
134         .name           = "SMSC LAN911x Internal PHY",
135
136         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
137                                 | SUPPORTED_Asym_Pause),
138         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
139
140         /* basic functions */
141         .config_aneg    = genphy_config_aneg,
142         .read_status    = genphy_read_status,
143         .config_init    = lan911x_config_init,
144
145         /* IRQ related */
146         .ack_interrupt  = smsc_phy_ack_interrupt,
147         .config_intr    = smsc_phy_config_intr,
148
149         .suspend        = genphy_suspend,
150         .resume         = genphy_resume,
151
152         .driver         = { .owner = THIS_MODULE, }
153 }, {
154         .phy_id         = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
155         .phy_id_mask    = 0xfffffff0,
156         .name           = "SMSC LAN8710/LAN8720",
157
158         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
159                                 | SUPPORTED_Asym_Pause),
160         .flags          = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
161
162         /* basic functions */
163         .config_aneg    = genphy_config_aneg,
164         .read_status    = genphy_read_status,
165         .config_init    = smsc_phy_config_init,
166
167         /* IRQ related */
168         .ack_interrupt  = smsc_phy_ack_interrupt,
169         .config_intr    = smsc_phy_config_intr,
170
171         .suspend        = genphy_suspend,
172         .resume         = genphy_resume,
173
174         .driver         = { .owner = THIS_MODULE, }
175 } };
176
177 static int __init smsc_init(void)
178 {
179         return phy_drivers_register(smsc_phy_driver,
180                 ARRAY_SIZE(smsc_phy_driver));
181 }
182
183 static void __exit smsc_exit(void)
184 {
185         return phy_drivers_unregister(smsc_phy_driver,
186                 ARRAY_SIZE(smsc_phy_driver));
187 }
188
189 MODULE_DESCRIPTION("SMSC PHY driver");
190 MODULE_AUTHOR("Herbert Valerio Riedel");
191 MODULE_LICENSE("GPL");
192
193 module_init(smsc_init);
194 module_exit(smsc_exit);
195
196 static struct mdio_device_id __maybe_unused smsc_tbl[] = {
197         { 0x0007c0a0, 0xfffffff0 },
198         { 0x0007c0b0, 0xfffffff0 },
199         { 0x0007c0c0, 0xfffffff0 },
200         { 0x0007c0d0, 0xfffffff0 },
201         { 0x0007c0f0, 0xfffffff0 },
202         { }
203 };
204
205 MODULE_DEVICE_TABLE(mdio, smsc_tbl);