diff options
author | Choi, David <David.Choi@Micrel.Com> | 2010-06-28 11:23:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-29 03:58:32 -0400 |
commit | 51f932c4870f785d73d5fd5fed33306e63cf4efc (patch) | |
tree | fe827902e1feccc037fcc76b1f6fcbbd35f09537 /drivers/net/phy | |
parent | deaec0f65b9a9b536bc5951f4908ab1408421ffb (diff) |
micrel phy driver - updated(1)
Hello all:
This patch fixes what Ben mentioned, namely duplicated ids.
From: David J. Choi <david.choi@micrel.com>
Body of the explanation: This patch has changes as followings;
-support the interrupt from phy devices from Micrel Inc.
-support more phy devices, ks8737, ks8721, ks8041, ks8051 from Micrel.
-remove vsc8201 because this device was used only internal test at Micrel.
Signed-off-by: David J. Choi <david.choi@micrel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/micrel.c | 167 |
1 files changed, 148 insertions, 19 deletions
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 0692f750c404..8bb7db676a5c 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c | |||
@@ -12,7 +12,8 @@ | |||
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | 14 | * |
15 | * Support : ksz9021 , vsc8201, ks8001 | 15 | * Support : ksz9021 1000/100/10 phy from Micrel |
16 | * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy | ||
16 | */ | 17 | */ |
17 | 18 | ||
18 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
@@ -20,37 +21,146 @@ | |||
20 | #include <linux/phy.h> | 21 | #include <linux/phy.h> |
21 | 22 | ||
22 | #define PHY_ID_KSZ9021 0x00221611 | 23 | #define PHY_ID_KSZ9021 0x00221611 |
23 | #define PHY_ID_VSC8201 0x000FC413 | 24 | #define PHY_ID_KS8737 0x00221720 |
25 | #define PHY_ID_KS8041 0x00221510 | ||
26 | #define PHY_ID_KS8051 0x00221550 | ||
27 | /* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */ | ||
24 | #define PHY_ID_KS8001 0x0022161A | 28 | #define PHY_ID_KS8001 0x0022161A |
25 | 29 | ||
30 | /* general Interrupt control/status reg in vendor specific block. */ | ||
31 | #define MII_KSZPHY_INTCS 0x1B | ||
32 | #define KSZPHY_INTCS_JABBER (1 << 15) | ||
33 | #define KSZPHY_INTCS_RECEIVE_ERR (1 << 14) | ||
34 | #define KSZPHY_INTCS_PAGE_RECEIVE (1 << 13) | ||
35 | #define KSZPHY_INTCS_PARELLEL (1 << 12) | ||
36 | #define KSZPHY_INTCS_LINK_PARTNER_ACK (1 << 11) | ||
37 | #define KSZPHY_INTCS_LINK_DOWN (1 << 10) | ||
38 | #define KSZPHY_INTCS_REMOTE_FAULT (1 << 9) | ||
39 | #define KSZPHY_INTCS_LINK_UP (1 << 8) | ||
40 | #define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\ | ||
41 | KSZPHY_INTCS_LINK_DOWN) | ||
42 | |||
43 | /* general PHY control reg in vendor specific block. */ | ||
44 | #define MII_KSZPHY_CTRL 0x1F | ||
45 | /* bitmap of PHY register to set interrupt mode */ | ||
46 | #define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9) | ||
47 | #define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14) | ||
48 | #define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14) | ||
49 | |||
50 | static int kszphy_ack_interrupt(struct phy_device *phydev) | ||
51 | { | ||
52 | /* bit[7..0] int status, which is a read and clear register. */ | ||
53 | int rc; | ||
54 | |||
55 | rc = phy_read(phydev, MII_KSZPHY_INTCS); | ||
56 | |||
57 | return (rc < 0) ? rc : 0; | ||
58 | } | ||
59 | |||
60 | static int kszphy_set_interrupt(struct phy_device *phydev) | ||
61 | { | ||
62 | int temp; | ||
63 | temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ? | ||
64 | KSZPHY_INTCS_ALL : 0; | ||
65 | return phy_write(phydev, MII_KSZPHY_INTCS, temp); | ||
66 | } | ||
67 | |||
68 | static int kszphy_config_intr(struct phy_device *phydev) | ||
69 | { | ||
70 | int temp, rc; | ||
71 | |||
72 | /* set the interrupt pin active low */ | ||
73 | temp = phy_read(phydev, MII_KSZPHY_CTRL); | ||
74 | temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; | ||
75 | phy_write(phydev, MII_KSZPHY_CTRL, temp); | ||
76 | rc = kszphy_set_interrupt(phydev); | ||
77 | return rc < 0 ? rc : 0; | ||
78 | } | ||
79 | |||
80 | static int ksz9021_config_intr(struct phy_device *phydev) | ||
81 | { | ||
82 | int temp, rc; | ||
83 | |||
84 | /* set the interrupt pin active low */ | ||
85 | temp = phy_read(phydev, MII_KSZPHY_CTRL); | ||
86 | temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; | ||
87 | phy_write(phydev, MII_KSZPHY_CTRL, temp); | ||
88 | rc = kszphy_set_interrupt(phydev); | ||
89 | return rc < 0 ? rc : 0; | ||
90 | } | ||
91 | |||
92 | static int ks8737_config_intr(struct phy_device *phydev) | ||
93 | { | ||
94 | int temp, rc; | ||
95 | |||
96 | /* set the interrupt pin active low */ | ||
97 | temp = phy_read(phydev, MII_KSZPHY_CTRL); | ||
98 | temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH; | ||
99 | phy_write(phydev, MII_KSZPHY_CTRL, temp); | ||
100 | rc = kszphy_set_interrupt(phydev); | ||
101 | return rc < 0 ? rc : 0; | ||
102 | } | ||
26 | 103 | ||
27 | static int kszphy_config_init(struct phy_device *phydev) | 104 | static int kszphy_config_init(struct phy_device *phydev) |
28 | { | 105 | { |
29 | return 0; | 106 | return 0; |
30 | } | 107 | } |
31 | 108 | ||
109 | static struct phy_driver ks8737_driver = { | ||
110 | .phy_id = PHY_ID_KS8737, | ||
111 | .phy_id_mask = 0x00fffff0, | ||
112 | .name = "Micrel KS8737", | ||
113 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), | ||
114 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
115 | .config_init = kszphy_config_init, | ||
116 | .config_aneg = genphy_config_aneg, | ||
117 | .read_status = genphy_read_status, | ||
118 | .ack_interrupt = kszphy_ack_interrupt, | ||
119 | .config_intr = ks8737_config_intr, | ||
120 | .driver = { .owner = THIS_MODULE,}, | ||
121 | }; | ||
122 | |||
123 | static struct phy_driver ks8041_driver = { | ||
124 | .phy_id = PHY_ID_KS8041, | ||
125 | .phy_id_mask = 0x00fffff0, | ||
126 | .name = "Micrel KS8041", | ||
127 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | ||
128 | | SUPPORTED_Asym_Pause), | ||
129 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
130 | .config_init = kszphy_config_init, | ||
131 | .config_aneg = genphy_config_aneg, | ||
132 | .read_status = genphy_read_status, | ||
133 | .ack_interrupt = kszphy_ack_interrupt, | ||
134 | .config_intr = kszphy_config_intr, | ||
135 | .driver = { .owner = THIS_MODULE,}, | ||
136 | }; | ||
32 | 137 | ||
33 | static struct phy_driver ks8001_driver = { | 138 | static struct phy_driver ks8051_driver = { |
34 | .phy_id = PHY_ID_KS8001, | 139 | .phy_id = PHY_ID_KS8051, |
35 | .name = "Micrel KS8001", | ||
36 | .phy_id_mask = 0x00fffff0, | 140 | .phy_id_mask = 0x00fffff0, |
37 | .features = PHY_BASIC_FEATURES, | 141 | .name = "Micrel KS8051", |
38 | .flags = PHY_POLL, | 142 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
143 | | SUPPORTED_Asym_Pause), | ||
144 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
39 | .config_init = kszphy_config_init, | 145 | .config_init = kszphy_config_init, |
40 | .config_aneg = genphy_config_aneg, | 146 | .config_aneg = genphy_config_aneg, |
41 | .read_status = genphy_read_status, | 147 | .read_status = genphy_read_status, |
148 | .ack_interrupt = kszphy_ack_interrupt, | ||
149 | .config_intr = kszphy_config_intr, | ||
42 | .driver = { .owner = THIS_MODULE,}, | 150 | .driver = { .owner = THIS_MODULE,}, |
43 | }; | 151 | }; |
44 | 152 | ||
45 | static struct phy_driver vsc8201_driver = { | 153 | static struct phy_driver ks8001_driver = { |
46 | .phy_id = PHY_ID_VSC8201, | 154 | .phy_id = PHY_ID_KS8001, |
47 | .name = "Micrel VSC8201", | 155 | .name = "Micrel KS8001 or KS8721", |
48 | .phy_id_mask = 0x00fffff0, | 156 | .phy_id_mask = 0x00fffff0, |
49 | .features = PHY_BASIC_FEATURES, | 157 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), |
50 | .flags = PHY_POLL, | 158 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
51 | .config_init = kszphy_config_init, | 159 | .config_init = kszphy_config_init, |
52 | .config_aneg = genphy_config_aneg, | 160 | .config_aneg = genphy_config_aneg, |
53 | .read_status = genphy_read_status, | 161 | .read_status = genphy_read_status, |
162 | .ack_interrupt = kszphy_ack_interrupt, | ||
163 | .config_intr = kszphy_config_intr, | ||
54 | .driver = { .owner = THIS_MODULE,}, | 164 | .driver = { .owner = THIS_MODULE,}, |
55 | }; | 165 | }; |
56 | 166 | ||
@@ -58,11 +168,14 @@ static struct phy_driver ksz9021_driver = { | |||
58 | .phy_id = PHY_ID_KSZ9021, | 168 | .phy_id = PHY_ID_KSZ9021, |
59 | .phy_id_mask = 0x000fff10, | 169 | .phy_id_mask = 0x000fff10, |
60 | .name = "Micrel KSZ9021 Gigabit PHY", | 170 | .name = "Micrel KSZ9021 Gigabit PHY", |
61 | .features = PHY_GBIT_FEATURES | SUPPORTED_Pause, | 171 | .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause |
62 | .flags = PHY_POLL, | 172 | | SUPPORTED_Asym_Pause), |
173 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
63 | .config_init = kszphy_config_init, | 174 | .config_init = kszphy_config_init, |
64 | .config_aneg = genphy_config_aneg, | 175 | .config_aneg = genphy_config_aneg, |
65 | .read_status = genphy_read_status, | 176 | .read_status = genphy_read_status, |
177 | .ack_interrupt = kszphy_ack_interrupt, | ||
178 | .config_intr = ksz9021_config_intr, | ||
66 | .driver = { .owner = THIS_MODULE, }, | 179 | .driver = { .owner = THIS_MODULE, }, |
67 | }; | 180 | }; |
68 | 181 | ||
@@ -73,17 +186,29 @@ static int __init ksphy_init(void) | |||
73 | ret = phy_driver_register(&ks8001_driver); | 186 | ret = phy_driver_register(&ks8001_driver); |
74 | if (ret) | 187 | if (ret) |
75 | goto err1; | 188 | goto err1; |
76 | ret = phy_driver_register(&vsc8201_driver); | 189 | |
190 | ret = phy_driver_register(&ksz9021_driver); | ||
77 | if (ret) | 191 | if (ret) |
78 | goto err2; | 192 | goto err2; |
79 | 193 | ||
80 | ret = phy_driver_register(&ksz9021_driver); | 194 | ret = phy_driver_register(&ks8737_driver); |
81 | if (ret) | 195 | if (ret) |
82 | goto err3; | 196 | goto err3; |
197 | ret = phy_driver_register(&ks8041_driver); | ||
198 | if (ret) | ||
199 | goto err4; | ||
200 | ret = phy_driver_register(&ks8051_driver); | ||
201 | if (ret) | ||
202 | goto err5; | ||
203 | |||
83 | return 0; | 204 | return 0; |
84 | 205 | ||
206 | err5: | ||
207 | phy_driver_unregister(&ks8041_driver); | ||
208 | err4: | ||
209 | phy_driver_unregister(&ks8737_driver); | ||
85 | err3: | 210 | err3: |
86 | phy_driver_unregister(&vsc8201_driver); | 211 | phy_driver_unregister(&ksz9021_driver); |
87 | err2: | 212 | err2: |
88 | phy_driver_unregister(&ks8001_driver); | 213 | phy_driver_unregister(&ks8001_driver); |
89 | err1: | 214 | err1: |
@@ -93,8 +218,10 @@ err1: | |||
93 | static void __exit ksphy_exit(void) | 218 | static void __exit ksphy_exit(void) |
94 | { | 219 | { |
95 | phy_driver_unregister(&ks8001_driver); | 220 | phy_driver_unregister(&ks8001_driver); |
96 | phy_driver_unregister(&vsc8201_driver); | 221 | phy_driver_unregister(&ks8737_driver); |
97 | phy_driver_unregister(&ksz9021_driver); | 222 | phy_driver_unregister(&ksz9021_driver); |
223 | phy_driver_unregister(&ks8041_driver); | ||
224 | phy_driver_unregister(&ks8051_driver); | ||
98 | } | 225 | } |
99 | 226 | ||
100 | module_init(ksphy_init); | 227 | module_init(ksphy_init); |
@@ -106,8 +233,10 @@ MODULE_LICENSE("GPL"); | |||
106 | 233 | ||
107 | static struct mdio_device_id micrel_tbl[] = { | 234 | static struct mdio_device_id micrel_tbl[] = { |
108 | { PHY_ID_KSZ9021, 0x000fff10 }, | 235 | { PHY_ID_KSZ9021, 0x000fff10 }, |
109 | { PHY_ID_VSC8201, 0x00fffff0 }, | ||
110 | { PHY_ID_KS8001, 0x00fffff0 }, | 236 | { PHY_ID_KS8001, 0x00fffff0 }, |
237 | { PHY_ID_KS8737, 0x00fffff0 }, | ||
238 | { PHY_ID_KS8041, 0x00fffff0 }, | ||
239 | { PHY_ID_KS8051, 0x00fffff0 }, | ||
111 | { } | 240 | { } |
112 | }; | 241 | }; |
113 | 242 | ||