Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[firefly-linux-kernel-4.4.55.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 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 : ksz9021 1000/100/10 phy from Micrel
16  *              ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/phy.h>
22 #include <linux/micrel_phy.h>
23
24 /* Operation Mode Strap Override */
25 #define MII_KSZPHY_OMSO                         0x16
26 #define KSZPHY_OMSO_B_CAST_OFF                  (1 << 9)
27 #define KSZPHY_OMSO_RMII_OVERRIDE               (1 << 1)
28 #define KSZPHY_OMSO_MII_OVERRIDE                (1 << 0)
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 #define KSZ8051_RMII_50MHZ_CLK                  (1 << 7)
50
51 static int kszphy_ack_interrupt(struct phy_device *phydev)
52 {
53         /* bit[7..0] int status, which is a read and clear register. */
54         int rc;
55
56         rc = phy_read(phydev, MII_KSZPHY_INTCS);
57
58         return (rc < 0) ? rc : 0;
59 }
60
61 static int kszphy_set_interrupt(struct phy_device *phydev)
62 {
63         int temp;
64         temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
65                 KSZPHY_INTCS_ALL : 0;
66         return phy_write(phydev, MII_KSZPHY_INTCS, temp);
67 }
68
69 static int kszphy_config_intr(struct phy_device *phydev)
70 {
71         int temp, rc;
72
73         /* set the interrupt pin active low */
74         temp = phy_read(phydev, MII_KSZPHY_CTRL);
75         temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
76         phy_write(phydev, MII_KSZPHY_CTRL, temp);
77         rc = kszphy_set_interrupt(phydev);
78         return rc < 0 ? rc : 0;
79 }
80
81 static int ksz9021_config_intr(struct phy_device *phydev)
82 {
83         int temp, rc;
84
85         /* set the interrupt pin active low */
86         temp = phy_read(phydev, MII_KSZPHY_CTRL);
87         temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
88         phy_write(phydev, MII_KSZPHY_CTRL, temp);
89         rc = kszphy_set_interrupt(phydev);
90         return rc < 0 ? rc : 0;
91 }
92
93 static int ks8737_config_intr(struct phy_device *phydev)
94 {
95         int temp, rc;
96
97         /* set the interrupt pin active low */
98         temp = phy_read(phydev, MII_KSZPHY_CTRL);
99         temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
100         phy_write(phydev, MII_KSZPHY_CTRL, temp);
101         rc = kszphy_set_interrupt(phydev);
102         return rc < 0 ? rc : 0;
103 }
104
105 static int kszphy_config_init(struct phy_device *phydev)
106 {
107         return 0;
108 }
109
110 static int ksz8021_config_init(struct phy_device *phydev)
111 {
112         const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
113         phy_write(phydev, MII_KSZPHY_OMSO, val);
114         return 0;
115 }
116
117 static int ks8051_config_init(struct phy_device *phydev)
118 {
119         int regval;
120
121         if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
122                 regval = phy_read(phydev, MII_KSZPHY_CTRL);
123                 regval |= KSZ8051_RMII_50MHZ_CLK;
124                 phy_write(phydev, MII_KSZPHY_CTRL, regval);
125         }
126
127         return 0;
128 }
129
130 #define KSZ8873MLL_GLOBAL_CONTROL_4     0x06
131 #define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX      (1 << 6)
132 #define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED       (1 << 4)
133 int ksz8873mll_read_status(struct phy_device *phydev)
134 {
135         int regval;
136
137         /* dummy read */
138         regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
139
140         regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
141
142         if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX)
143                 phydev->duplex = DUPLEX_HALF;
144         else
145                 phydev->duplex = DUPLEX_FULL;
146
147         if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED)
148                 phydev->speed = SPEED_10;
149         else
150                 phydev->speed = SPEED_100;
151
152         phydev->link = 1;
153         phydev->pause = phydev->asym_pause = 0;
154
155         return 0;
156 }
157
158 static int ksz8873mll_config_aneg(struct phy_device *phydev)
159 {
160         return 0;
161 }
162
163 static struct phy_driver ksphy_driver[] = {
164 {
165         .phy_id         = PHY_ID_KS8737,
166         .phy_id_mask    = 0x00fffff0,
167         .name           = "Micrel KS8737",
168         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
169         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
170         .config_init    = kszphy_config_init,
171         .config_aneg    = genphy_config_aneg,
172         .read_status    = genphy_read_status,
173         .ack_interrupt  = kszphy_ack_interrupt,
174         .config_intr    = ks8737_config_intr,
175         .driver         = { .owner = THIS_MODULE,},
176 }, {
177         .phy_id         = PHY_ID_KSZ8021,
178         .phy_id_mask    = 0x00ffffff,
179         .name           = "Micrel KSZ8021",
180         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
181                            SUPPORTED_Asym_Pause),
182         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
183         .config_init    = ksz8021_config_init,
184         .config_aneg    = genphy_config_aneg,
185         .read_status    = genphy_read_status,
186         .ack_interrupt  = kszphy_ack_interrupt,
187         .config_intr    = kszphy_config_intr,
188         .driver         = { .owner = THIS_MODULE,},
189 }, {
190         .phy_id         = PHY_ID_KSZ8041,
191         .phy_id_mask    = 0x00fffff0,
192         .name           = "Micrel KSZ8041",
193         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
194                                 | SUPPORTED_Asym_Pause),
195         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
196         .config_init    = kszphy_config_init,
197         .config_aneg    = genphy_config_aneg,
198         .read_status    = genphy_read_status,
199         .ack_interrupt  = kszphy_ack_interrupt,
200         .config_intr    = kszphy_config_intr,
201         .driver         = { .owner = THIS_MODULE,},
202 }, {
203         .phy_id         = PHY_ID_KSZ8051,
204         .phy_id_mask    = 0x00fffff0,
205         .name           = "Micrel KSZ8051",
206         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
207                                 | SUPPORTED_Asym_Pause),
208         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
209         .config_init    = ks8051_config_init,
210         .config_aneg    = genphy_config_aneg,
211         .read_status    = genphy_read_status,
212         .ack_interrupt  = kszphy_ack_interrupt,
213         .config_intr    = kszphy_config_intr,
214         .driver         = { .owner = THIS_MODULE,},
215 }, {
216         .phy_id         = PHY_ID_KSZ8001,
217         .name           = "Micrel KSZ8001 or KS8721",
218         .phy_id_mask    = 0x00ffffff,
219         .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
220         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
221         .config_init    = kszphy_config_init,
222         .config_aneg    = genphy_config_aneg,
223         .read_status    = genphy_read_status,
224         .ack_interrupt  = kszphy_ack_interrupt,
225         .config_intr    = kszphy_config_intr,
226         .driver         = { .owner = THIS_MODULE,},
227 }, {
228         .phy_id         = PHY_ID_KSZ9021,
229         .phy_id_mask    = 0x000ffffe,
230         .name           = "Micrel KSZ9021 Gigabit PHY",
231         .features       = (PHY_GBIT_FEATURES | SUPPORTED_Pause
232                                 | SUPPORTED_Asym_Pause),
233         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
234         .config_init    = kszphy_config_init,
235         .config_aneg    = genphy_config_aneg,
236         .read_status    = genphy_read_status,
237         .ack_interrupt  = kszphy_ack_interrupt,
238         .config_intr    = ksz9021_config_intr,
239         .driver         = { .owner = THIS_MODULE, },
240 }, {
241         .phy_id         = PHY_ID_KSZ8873MLL,
242         .phy_id_mask    = 0x00fffff0,
243         .name           = "Micrel KSZ8873MLL Switch",
244         .features       = (SUPPORTED_Pause | SUPPORTED_Asym_Pause),
245         .flags          = PHY_HAS_MAGICANEG,
246         .config_init    = kszphy_config_init,
247         .config_aneg    = ksz8873mll_config_aneg,
248         .read_status    = ksz8873mll_read_status,
249         .driver         = { .owner = THIS_MODULE, },
250 } };
251
252 static int __init ksphy_init(void)
253 {
254         return phy_drivers_register(ksphy_driver,
255                 ARRAY_SIZE(ksphy_driver));
256 }
257
258 static void __exit ksphy_exit(void)
259 {
260         phy_drivers_unregister(ksphy_driver,
261                 ARRAY_SIZE(ksphy_driver));
262 }
263
264 module_init(ksphy_init);
265 module_exit(ksphy_exit);
266
267 MODULE_DESCRIPTION("Micrel PHY driver");
268 MODULE_AUTHOR("David J. Choi");
269 MODULE_LICENSE("GPL");
270
271 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
272         { PHY_ID_KSZ9021, 0x000ffffe },
273         { PHY_ID_KSZ8001, 0x00ffffff },
274         { PHY_ID_KS8737, 0x00fffff0 },
275         { PHY_ID_KSZ8021, 0x00ffffff },
276         { PHY_ID_KSZ8041, 0x00fffff0 },
277         { PHY_ID_KSZ8051, 0x00fffff0 },
278         { PHY_ID_KSZ8873MLL, 0x00fffff0 },
279         { }
280 };
281
282 MODULE_DEVICE_TABLE(mdio, micrel_tbl);