Merge tag 'nfs-for-3.11-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[cascardo/linux.git] / drivers / net / phy / micrel.c
1 /*
2  * drivers/net/phy/micrel.c
3  *
4  * Driver for Micrel PHYs
5  *
6  * Author: David J. Choi
7  *
8  * Copyright (c) 2010-2013 Micrel, Inc.
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 : Micrel Phys:
16  *              Giga phys: ksz9021, ksz9031
17  *              100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
18  *                         ksz8021, ksz8031, ksz8051,
19  *                         ksz8081, ksz8091,
20  *                         ksz8061,
21  *              Switch : ksz8873, ksz886x
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/phy.h>
27 #include <linux/micrel_phy.h>
28
29 /* Operation Mode Strap Override */
30 #define MII_KSZPHY_OMSO                         0x16
31 #define KSZPHY_OMSO_B_CAST_OFF                  (1 << 9)
32 #define KSZPHY_OMSO_RMII_OVERRIDE               (1 << 1)
33 #define KSZPHY_OMSO_MII_OVERRIDE                (1 << 0)
34
35 /* general Interrupt control/status reg in vendor specific block. */
36 #define MII_KSZPHY_INTCS                        0x1B
37 #define KSZPHY_INTCS_JABBER                     (1 << 15)
38 #define KSZPHY_INTCS_RECEIVE_ERR                (1 << 14)
39 #define KSZPHY_INTCS_PAGE_RECEIVE               (1 << 13)
40 #define KSZPHY_INTCS_PARELLEL                   (1 << 12)
41 #define KSZPHY_INTCS_LINK_PARTNER_ACK           (1 << 11)
42 #define KSZPHY_INTCS_LINK_DOWN                  (1 << 10)
43 #define KSZPHY_INTCS_REMOTE_FAULT               (1 << 9)
44 #define KSZPHY_INTCS_LINK_UP                    (1 << 8)
45 #define KSZPHY_INTCS_ALL                        (KSZPHY_INTCS_LINK_UP |\
46                                                 KSZPHY_INTCS_LINK_DOWN)
47
48 /* general PHY control reg in vendor specific block. */
49 #define MII_KSZPHY_CTRL                 0x1F
50 /* bitmap of PHY register to set interrupt mode */
51 #define KSZPHY_CTRL_INT_ACTIVE_HIGH             (1 << 9)
52 #define KSZ9021_CTRL_INT_ACTIVE_HIGH            (1 << 14)
53 #define KS8737_CTRL_INT_ACTIVE_HIGH             (1 << 14)
54 #define KSZ8051_RMII_50MHZ_CLK                  (1 << 7)
55
56 static int ksz_config_flags(struct phy_device *phydev)
57 {
58         int regval;
59
60         if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
61                 regval = phy_read(phydev, MII_KSZPHY_CTRL);
62                 regval |= KSZ8051_RMII_50MHZ_CLK;
63                 return phy_write(phydev, MII_KSZPHY_CTRL, regval);
64         }
65         return 0;
66 }
67
68 static int kszphy_ack_interrupt(struct phy_device *phydev)
69 {
70         /* bit[7..0] int status, which is a read and clear register. */
71         int rc;
72
73         rc = phy_read(phydev, MII_KSZPHY_INTCS);
74
75         return (rc < 0) ? rc : 0;
76 }
77
78 static int kszphy_set_interrupt(struct phy_device *phydev)
79 {
80         int temp;
81         temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
82                 KSZPHY_INTCS_ALL : 0;
83         return phy_write(phydev, MII_KSZPHY_INTCS, temp);
84 }
85
86 static int kszphy_config_intr(struct phy_device *phydev)
87 {
88         int temp, rc;
89
90         /* set the interrupt pin active low */
91         temp = phy_read(phydev, MII_KSZPHY_CTRL);
92         temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
93         phy_write(phydev, MII_KSZPHY_CTRL, temp);
94         rc = kszphy_set_interrupt(phydev);
95         return rc < 0 ? rc : 0;
96 }
97
98 static int ksz9021_config_intr(struct phy_device *phydev)
99 {
100         int temp, rc;
101
102         /* set the interrupt pin active low */
103         temp = phy_read(phydev, MII_KSZPHY_CTRL);
104         temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
105         phy_write(phydev, MII_KSZPHY_CTRL, temp);
106         rc = kszphy_set_interrupt(phydev);
107         return rc < 0 ? rc : 0;
108 }
109
110 static int ks8737_config_intr(struct phy_device *phydev)
111 {
112         int temp, rc;
113
114         /* set the interrupt pin active low */
115         temp = phy_read(phydev, MII_KSZPHY_CTRL);
116         temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
117         phy_write(phydev, MII_KSZPHY_CTRL, temp);
118         rc = kszphy_set_interrupt(phydev);
119         return rc < 0 ? rc : 0;
120 }
121
122 static int kszphy_config_init(struct phy_device *phydev)
123 {
124         return 0;
125 }
126
127 static int ksz8021_config_init(struct phy_device *phydev)
128 {
129         int rc;
130         const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
131         phy_write(phydev, MII_KSZPHY_OMSO, val);
132         rc = ksz_config_flags(phydev);
133         return rc < 0 ? rc : 0;
134 }
135
136 static int ks8051_config_init(struct phy_device *phydev)
137 {
138         int rc;
139
140         rc = ksz_config_flags(phydev);
141         return rc < 0 ? rc : 0;
142 }
143
144 #define KSZ8873MLL_GLOBAL_CONTROL_4     0x06
145 #define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX      (1 << 6)
146 #define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED       (1 << 4)
147 int ksz8873mll_read_status(struct phy_device *phydev)
148 {
149         int regval;
150
151         /* dummy read */
152         regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
153
154         regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
155
156         if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX)
157                 phydev->duplex = DUPLEX_HALF;
158         else
159                 phydev->duplex = DUPLEX_FULL;
160
161         if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED)
162                 phydev->speed = SPEED_10;
163         else
164                 phydev->speed = SPEED_100;
165
166         phydev->link = 1;
167         phydev->pause = phydev->asym_pause = 0;
168
169         return 0;
170 }
171
172 static int ksz8873mll_config_aneg(struct phy_device *phydev)
173 {
174         return 0;
175 }
176
177 static struct phy_driver ksphy_driver[] = {
178 {
179         .phy_id         = PHY_ID_KS8737,
180         .phy_id_mask    = 0x00fffff0,
181         .name           = "Micrel KS8737",
182         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
183         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
184         .config_init    = kszphy_config_init,
185         .config_aneg    = genphy_config_aneg,
186         .read_status    = genphy_read_status,
187         .ack_interrupt  = kszphy_ack_interrupt,
188         .config_intr    = ks8737_config_intr,
189         .driver         = { .owner = THIS_MODULE,},
190 }, {
191         .phy_id         = PHY_ID_KSZ8021,
192         .phy_id_mask    = 0x00ffffff,
193         .name           = "Micrel KSZ8021 or KSZ8031",
194         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
195                            SUPPORTED_Asym_Pause),
196         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
197         .config_init    = ksz8021_config_init,
198         .config_aneg    = genphy_config_aneg,
199         .read_status    = genphy_read_status,
200         .ack_interrupt  = kszphy_ack_interrupt,
201         .config_intr    = kszphy_config_intr,
202         .driver         = { .owner = THIS_MODULE,},
203 }, {
204         .phy_id         = PHY_ID_KSZ8031,
205         .phy_id_mask    = 0x00ffffff,
206         .name           = "Micrel KSZ8031",
207         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
208                            SUPPORTED_Asym_Pause),
209         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
210         .config_init    = ksz8021_config_init,
211         .config_aneg    = genphy_config_aneg,
212         .read_status    = genphy_read_status,
213         .ack_interrupt  = kszphy_ack_interrupt,
214         .config_intr    = kszphy_config_intr,
215         .driver         = { .owner = THIS_MODULE,},
216 }, {
217         .phy_id         = PHY_ID_KSZ8041,
218         .phy_id_mask    = 0x00fffff0,
219         .name           = "Micrel KSZ8041",
220         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
221                                 | SUPPORTED_Asym_Pause),
222         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
223         .config_init    = kszphy_config_init,
224         .config_aneg    = genphy_config_aneg,
225         .read_status    = genphy_read_status,
226         .ack_interrupt  = kszphy_ack_interrupt,
227         .config_intr    = kszphy_config_intr,
228         .driver         = { .owner = THIS_MODULE,},
229 }, {
230         .phy_id         = PHY_ID_KSZ8051,
231         .phy_id_mask    = 0x00fffff0,
232         .name           = "Micrel KSZ8051",
233         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
234                                 | SUPPORTED_Asym_Pause),
235         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
236         .config_init    = ks8051_config_init,
237         .config_aneg    = genphy_config_aneg,
238         .read_status    = genphy_read_status,
239         .ack_interrupt  = kszphy_ack_interrupt,
240         .config_intr    = kszphy_config_intr,
241         .driver         = { .owner = THIS_MODULE,},
242 }, {
243         .phy_id         = PHY_ID_KSZ8001,
244         .name           = "Micrel KSZ8001 or KS8721",
245         .phy_id_mask    = 0x00ffffff,
246         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
247         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
248         .config_init    = kszphy_config_init,
249         .config_aneg    = genphy_config_aneg,
250         .read_status    = genphy_read_status,
251         .ack_interrupt  = kszphy_ack_interrupt,
252         .config_intr    = kszphy_config_intr,
253         .driver         = { .owner = THIS_MODULE,},
254 }, {
255         .phy_id         = PHY_ID_KSZ8081,
256         .name           = "Micrel KSZ8081 or KSZ8091",
257         .phy_id_mask    = 0x00fffff0,
258         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
259         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
260         .config_init    = kszphy_config_init,
261         .config_aneg    = genphy_config_aneg,
262         .read_status    = genphy_read_status,
263         .ack_interrupt  = kszphy_ack_interrupt,
264         .config_intr    = kszphy_config_intr,
265         .driver         = { .owner = THIS_MODULE,},
266 }, {
267         .phy_id         = PHY_ID_KSZ8061,
268         .name           = "Micrel KSZ8061",
269         .phy_id_mask    = 0x00fffff0,
270         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
271         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
272         .config_init    = kszphy_config_init,
273         .config_aneg    = genphy_config_aneg,
274         .read_status    = genphy_read_status,
275         .ack_interrupt  = kszphy_ack_interrupt,
276         .config_intr    = kszphy_config_intr,
277         .driver         = { .owner = THIS_MODULE,},
278 }, {
279         .phy_id         = PHY_ID_KSZ9021,
280         .phy_id_mask    = 0x000ffffe,
281         .name           = "Micrel KSZ9021 Gigabit PHY",
282         .features       = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
283         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
284         .config_init    = kszphy_config_init,
285         .config_aneg    = genphy_config_aneg,
286         .read_status    = genphy_read_status,
287         .ack_interrupt  = kszphy_ack_interrupt,
288         .config_intr    = ksz9021_config_intr,
289         .driver         = { .owner = THIS_MODULE, },
290 }, {
291         .phy_id         = PHY_ID_KSZ9031,
292         .phy_id_mask    = 0x00fffff0,
293         .name           = "Micrel KSZ9031 Gigabit PHY",
294         .features       = (PHY_GBIT_FEATURES | SUPPORTED_Pause
295                                 | SUPPORTED_Asym_Pause),
296         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
297         .config_init    = kszphy_config_init,
298         .config_aneg    = genphy_config_aneg,
299         .read_status    = genphy_read_status,
300         .ack_interrupt  = kszphy_ack_interrupt,
301         .config_intr    = ksz9021_config_intr,
302         .driver         = { .owner = THIS_MODULE, },
303 }, {
304         .phy_id         = PHY_ID_KSZ8873MLL,
305         .phy_id_mask    = 0x00fffff0,
306         .name           = "Micrel KSZ8873MLL Switch",
307         .features       = (SUPPORTED_Pause | SUPPORTED_Asym_Pause),
308         .flags          = PHY_HAS_MAGICANEG,
309         .config_init    = kszphy_config_init,
310         .config_aneg    = ksz8873mll_config_aneg,
311         .read_status    = ksz8873mll_read_status,
312         .driver         = { .owner = THIS_MODULE, },
313 }, {
314         .phy_id         = PHY_ID_KSZ886X,
315         .phy_id_mask    = 0x00fffff0,
316         .name           = "Micrel KSZ886X Switch",
317         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
318         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
319         .config_init    = kszphy_config_init,
320         .config_aneg    = genphy_config_aneg,
321         .read_status    = genphy_read_status,
322         .driver         = { .owner = THIS_MODULE, },
323 } };
324
325 static int __init ksphy_init(void)
326 {
327         return phy_drivers_register(ksphy_driver,
328                 ARRAY_SIZE(ksphy_driver));
329 }
330
331 static void __exit ksphy_exit(void)
332 {
333         phy_drivers_unregister(ksphy_driver,
334                 ARRAY_SIZE(ksphy_driver));
335 }
336
337 module_init(ksphy_init);
338 module_exit(ksphy_exit);
339
340 MODULE_DESCRIPTION("Micrel PHY driver");
341 MODULE_AUTHOR("David J. Choi");
342 MODULE_LICENSE("GPL");
343
344 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
345         { PHY_ID_KSZ9021, 0x000ffffe },
346         { PHY_ID_KSZ9031, 0x00fffff0 },
347         { PHY_ID_KSZ8001, 0x00ffffff },
348         { PHY_ID_KS8737, 0x00fffff0 },
349         { PHY_ID_KSZ8021, 0x00ffffff },
350         { PHY_ID_KSZ8031, 0x00ffffff },
351         { PHY_ID_KSZ8041, 0x00fffff0 },
352         { PHY_ID_KSZ8051, 0x00fffff0 },
353         { PHY_ID_KSZ8061, 0x00fffff0 },
354         { PHY_ID_KSZ8081, 0x00fffff0 },
355         { PHY_ID_KSZ8873MLL, 0x00fffff0 },
356         { PHY_ID_KSZ886X, 0x00fffff0 },
357         { }
358 };
359
360 MODULE_DEVICE_TABLE(mdio, micrel_tbl);