net: phy: smsc: Cache interrupt mask
[linux-2.6-block.git] / drivers / net / phy / smsc.c
CommitLineData
a2443fd1 1// SPDX-License-Identifier: GPL-2.0+
c9e055ac
HVR
2/*
3 * drivers/net/phy/smsc.c
4 *
5 * Driver for SMSC PHYs
6 *
7 * Author: Herbert Valerio Riedel
8 *
9 * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
10 *
90b24cfb 11 * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net
4d9b1a02 12 *
c9e055ac
HVR
13 */
14
bedd8d78 15#include <linux/clk.h>
c9e055ac
HVR
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/mii.h>
19#include <linux/ethtool.h>
c6e970a0 20#include <linux/of.h>
c9e055ac
HVR
21#include <linux/phy.h>
22#include <linux/netdevice.h>
43c6759e 23#include <linux/smscphy.h>
c9e055ac 24
05b35e7e
AE
25/* Vendor-specific PHY Definitions */
26/* EDPD NLP / crossover time configuration */
27#define PHY_EDPD_CONFIG 16
28#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ 0x0001
29
30/* Control/Status Indication Register */
31#define SPECIAL_CTRL_STS 27
32#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ 0x8000
33#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ 0x4000
34#define SPECIAL_CTRL_STS_AMDIX_STATE_ 0x2000
35
030a8902
AL
36struct smsc_hw_stat {
37 const char *string;
38 u8 reg;
39 u8 bits;
40};
41
42static struct smsc_hw_stat smsc_hw_stats[] = {
43 { "phy_symbol_errors", 26, 16},
44};
45
0a9c453e 46struct smsc_phy_priv {
7e8b617e 47 u16 intmask;
0a9c453e 48 bool energy_enable;
bedd8d78 49 struct clk *refclk;
0a9c453e
TR
50};
51
824ef51f
IC
52static int smsc_phy_ack_interrupt(struct phy_device *phydev)
53{
54 int rc = phy_read(phydev, MII_LAN83C185_ISF);
55
56 return rc < 0 ? rc : 0;
57}
58
48c41b99 59static int smsc_phy_config_intr(struct phy_device *phydev)
c9e055ac 60{
73654945 61 struct smsc_phy_priv *priv = phydev->priv;
73654945
MF
62 int rc;
63
64 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
824ef51f
IC
65 rc = smsc_phy_ack_interrupt(phydev);
66 if (rc)
67 return rc;
68
7e8b617e 69 priv->intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6;
73654945 70 if (priv->energy_enable)
7e8b617e
LW
71 priv->intmask |= MII_LAN83C185_ISF_INT7;
72
73 rc = phy_write(phydev, MII_LAN83C185_IM, priv->intmask);
824ef51f 74 } else {
7e8b617e
LW
75 priv->intmask = 0;
76
77 rc = phy_write(phydev, MII_LAN83C185_IM, 0);
824ef51f
IC
78 if (rc)
79 return rc;
c9e055ac 80
824ef51f
IC
81 rc = smsc_phy_ack_interrupt(phydev);
82 }
c9e055ac
HVR
83
84 return rc < 0 ? rc : 0;
85}
86
36b25c26
IC
87static irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev)
88{
7e8b617e
LW
89 struct smsc_phy_priv *priv = phydev->priv;
90 int irq_status;
36b25c26
IC
91
92 irq_status = phy_read(phydev, MII_LAN83C185_ISF);
93 if (irq_status < 0) {
94 phy_error(phydev);
95 return IRQ_NONE;
96 }
97
7e8b617e 98 if (!(irq_status & priv->intmask))
36b25c26
IC
99 return IRQ_NONE;
100
101 phy_trigger_machine(phydev);
102
103 return IRQ_HANDLED;
104}
105
48c41b99 106static int smsc_phy_config_init(struct phy_device *phydev)
21009686 107{
0a9c453e 108 struct smsc_phy_priv *priv = phydev->priv;
436e3800
MF
109 int rc;
110
111 if (!priv->energy_enable)
112 return 0;
0a9c453e 113
436e3800 114 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
21009686
GGM
115
116 if (rc < 0)
117 return rc;
118
436e3800
MF
119 /* Enable energy detect mode for this SMSC Transceivers */
120 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
121 rc | MII_LAN83C185_EDPWRDOWN);
122 if (rc < 0)
123 return rc;
21009686
GGM
124
125 return smsc_phy_ack_interrupt(phydev);
126}
127
128static int smsc_phy_reset(struct phy_device *phydev)
c9e055ac 129{
6ded7cd6 130 int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
131 if (rc < 0)
132 return rc;
133
134 /* If the SMSC PHY is in power down mode, then set it
135 * in all capable mode before using it.
136 */
137 if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {
fc0f7e33 138 /* set "all capable" mode */
6ded7cd6 139 rc |= MII_LAN83C185_MODE_ALL;
140 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
6ded7cd6 141 }
fc0f7e33
MS
142
143 /* reset the phy */
144 return genphy_soft_reset(phydev);
c9e055ac
HVR
145}
146
4223dbff 147static int lan911x_config_init(struct phy_device *phydev)
b629820d 148{
b629820d
MV
149 return smsc_phy_ack_interrupt(phydev);
150}
151
05b35e7e
AE
152static int lan87xx_config_aneg(struct phy_device *phydev)
153{
154 int rc;
155 int val;
156
157 switch (phydev->mdix_ctrl) {
158 case ETH_TP_MDI:
159 val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;
160 break;
161 case ETH_TP_MDI_X:
162 val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
163 SPECIAL_CTRL_STS_AMDIX_STATE_;
164 break;
165 case ETH_TP_MDI_AUTO:
166 val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;
167 break;
168 default:
169 return genphy_config_aneg(phydev);
170 }
171
172 rc = phy_read(phydev, SPECIAL_CTRL_STS);
173 if (rc < 0)
174 return rc;
175
176 rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
177 SPECIAL_CTRL_STS_AMDIX_ENABLE_ |
178 SPECIAL_CTRL_STS_AMDIX_STATE_);
179 rc |= val;
180 phy_write(phydev, SPECIAL_CTRL_STS, rc);
181
182 phydev->mdix = phydev->mdix_ctrl;
183 return genphy_config_aneg(phydev);
184}
185
fdb5cc6a 186static int lan95xx_config_aneg_ext(struct phy_device *phydev)
05b35e7e
AE
187{
188 int rc;
189
fdb5cc6a
AE
190 if (phydev->phy_id != 0x0007c0f0) /* not (LAN9500A or LAN9505A) */
191 return lan87xx_config_aneg(phydev);
192
05b35e7e
AE
193 /* Extend Manual AutoMDIX timer */
194 rc = phy_read(phydev, PHY_EDPD_CONFIG);
195 if (rc < 0)
196 return rc;
197
198 rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_;
199 phy_write(phydev, PHY_EDPD_CONFIG, rc);
200 return lan87xx_config_aneg(phydev);
201}
202
4223dbff 203/*
776829de
IP
204 * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
205 * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
206 * unstable detection of plugging in Ethernet cable.
207 * This workaround disables Energy Detect Power-Down mode and waiting for
208 * response on link pulses to detect presence of plugged Ethernet cable.
209 * The Energy Detect Power-Down mode is enabled again in the end of procedure to
210 * save approximately 220 mW of power if cable is unplugged.
4223dbff
PT
211 */
212static int lan87xx_read_status(struct phy_device *phydev)
698244ac 213{
0a9c453e
TR
214 struct smsc_phy_priv *priv = phydev->priv;
215
4223dbff
PT
216 int err = genphy_read_status(phydev);
217
0a9c453e 218 if (!phydev->link && priv->energy_enable) {
4223dbff
PT
219 /* Disable EDPD to wake up PHY */
220 int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
221 if (rc < 0)
222 return rc;
223
224 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
225 rc & ~MII_LAN83C185_EDPWRDOWN);
226 if (rc < 0)
227 return rc;
228
6d61f483
DZ
229 /* Wait max 640 ms to detect energy and the timeout is not
230 * an actual error.
231 */
232 read_poll_timeout(phy_read, rc,
233 rc & MII_LAN83C185_ENERGYON || rc < 0,
234 10000, 640000, true, phydev,
235 MII_LAN83C185_CTRL_STATUS);
7ae7ad2f
DZ
236 if (rc < 0)
237 return rc;
4223dbff
PT
238
239 /* Re-enable EDPD */
240 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
241 if (rc < 0)
242 return rc;
243
244 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
245 rc | MII_LAN83C185_EDPWRDOWN);
246 if (rc < 0)
247 return rc;
248 }
249
250 return err;
698244ac 251}
c9e055ac 252
030a8902
AL
253static int smsc_get_sset_count(struct phy_device *phydev)
254{
255 return ARRAY_SIZE(smsc_hw_stats);
256}
257
258static void smsc_get_strings(struct phy_device *phydev, u8 *data)
259{
260 int i;
261
262 for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) {
2da55390 263 strncpy(data + i * ETH_GSTRING_LEN,
030a8902
AL
264 smsc_hw_stats[i].string, ETH_GSTRING_LEN);
265 }
266}
267
030a8902
AL
268static u64 smsc_get_stat(struct phy_device *phydev, int i)
269{
270 struct smsc_hw_stat stat = smsc_hw_stats[i];
271 int val;
272 u64 ret;
273
274 val = phy_read(phydev, stat.reg);
275 if (val < 0)
6c3442f5 276 ret = U64_MAX;
030a8902
AL
277 else
278 ret = val;
279
280 return ret;
281}
282
283static void smsc_get_stats(struct phy_device *phydev,
284 struct ethtool_stats *stats, u64 *data)
285{
286 int i;
287
288 for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)
289 data[i] = smsc_get_stat(phydev, i);
290}
291
bedd8d78
MF
292static void smsc_phy_remove(struct phy_device *phydev)
293{
294 struct smsc_phy_priv *priv = phydev->priv;
295
296 clk_disable_unprepare(priv->refclk);
297 clk_put(priv->refclk);
298}
299
0a9c453e
TR
300static int smsc_phy_probe(struct phy_device *phydev)
301{
302 struct device *dev = &phydev->mdio.dev;
303 struct device_node *of_node = dev->of_node;
304 struct smsc_phy_priv *priv;
bedd8d78 305 int ret;
0a9c453e
TR
306
307 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
308 if (!priv)
309 return -ENOMEM;
310
311 priv->energy_enable = true;
312
313 if (of_property_read_bool(of_node, "smsc,disable-energy-detect"))
314 priv->energy_enable = false;
315
316 phydev->priv = priv;
317
bedd8d78
MF
318 /* Make clk optional to keep DTB backward compatibility. */
319 priv->refclk = clk_get_optional(dev, NULL);
320 if (IS_ERR(priv->refclk))
a18caa97
MF
321 return dev_err_probe(dev, PTR_ERR(priv->refclk),
322 "Failed to request clock\n");
bedd8d78
MF
323
324 ret = clk_prepare_enable(priv->refclk);
325 if (ret)
326 return ret;
327
328 ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000);
37344718
ZC
329 if (ret) {
330 clk_disable_unprepare(priv->refclk);
bedd8d78 331 return ret;
37344718 332 }
bedd8d78 333
0a9c453e
TR
334 return 0;
335}
336
d5bf9071
CH
337static struct phy_driver smsc_phy_driver[] = {
338{
c9e055ac
HVR
339 .phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
340 .phy_id_mask = 0xfffffff0,
341 .name = "SMSC LAN83C185",
342
dcdecdcf 343 /* PHY_BASIC_FEATURES */
c9e055ac 344
0a9c453e
TR
345 .probe = smsc_phy_probe,
346
c9e055ac 347 /* basic functions */
48c41b99 348 .config_init = smsc_phy_config_init,
21009686 349 .soft_reset = smsc_phy_reset,
c9e055ac
HVR
350
351 /* IRQ related */
48c41b99 352 .config_intr = smsc_phy_config_intr,
36b25c26 353 .handle_interrupt = smsc_phy_handle_interrupt,
c9e055ac 354
c64d2a9a
SG
355 .suspend = genphy_suspend,
356 .resume = genphy_resume,
d5bf9071 357}, {
4d9b1a02
SG
358 .phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
359 .phy_id_mask = 0xfffffff0,
360 .name = "SMSC LAN8187",
361
dcdecdcf 362 /* PHY_BASIC_FEATURES */
4d9b1a02 363
0a9c453e
TR
364 .probe = smsc_phy_probe,
365
4d9b1a02 366 /* basic functions */
4d9b1a02 367 .config_init = smsc_phy_config_init,
21009686 368 .soft_reset = smsc_phy_reset,
4d9b1a02
SG
369
370 /* IRQ related */
4d9b1a02 371 .config_intr = smsc_phy_config_intr,
36b25c26 372 .handle_interrupt = smsc_phy_handle_interrupt,
4d9b1a02 373
030a8902
AL
374 /* Statistics */
375 .get_sset_count = smsc_get_sset_count,
376 .get_strings = smsc_get_strings,
377 .get_stats = smsc_get_stats,
378
c64d2a9a
SG
379 .suspend = genphy_suspend,
380 .resume = genphy_resume,
d5bf9071 381}, {
05b35e7e
AE
382 /* This covers internal PHY (phy_id: 0x0007C0C3) for
383 * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505)
384 */
4d9b1a02
SG
385 .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
386 .phy_id_mask = 0xfffffff0,
387 .name = "SMSC LAN8700",
388
dcdecdcf 389 /* PHY_BASIC_FEATURES */
4d9b1a02 390
0a9c453e
TR
391 .probe = smsc_phy_probe,
392
4d9b1a02 393 /* basic functions */
776829de 394 .read_status = lan87xx_read_status,
4d9b1a02 395 .config_init = smsc_phy_config_init,
21009686 396 .soft_reset = smsc_phy_reset,
05b35e7e 397 .config_aneg = lan87xx_config_aneg,
4d9b1a02
SG
398
399 /* IRQ related */
4d9b1a02 400 .config_intr = smsc_phy_config_intr,
36b25c26 401 .handle_interrupt = smsc_phy_handle_interrupt,
4d9b1a02 402
030a8902
AL
403 /* Statistics */
404 .get_sset_count = smsc_get_sset_count,
405 .get_strings = smsc_get_strings,
406 .get_stats = smsc_get_stats,
407
c64d2a9a
SG
408 .suspend = genphy_suspend,
409 .resume = genphy_resume,
d5bf9071 410}, {
fd9abb3d
SG
411 .phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
412 .phy_id_mask = 0xfffffff0,
413 .name = "SMSC LAN911x Internal PHY",
414
dcdecdcf 415 /* PHY_BASIC_FEATURES */
fd9abb3d 416
0a9c453e
TR
417 .probe = smsc_phy_probe,
418
fd9abb3d 419 /* basic functions */
698244ac 420 .config_init = lan911x_config_init,
fd9abb3d
SG
421
422 /* IRQ related */
fd9abb3d 423 .config_intr = smsc_phy_config_intr,
36b25c26 424 .handle_interrupt = smsc_phy_handle_interrupt,
fd9abb3d 425
c64d2a9a
SG
426 .suspend = genphy_suspend,
427 .resume = genphy_resume,
d5bf9071 428}, {
05b35e7e
AE
429 /* This covers internal PHY (phy_id: 0x0007C0F0) for
430 * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)
431 */
e072b639
SG
432 .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
433 .phy_id_mask = 0xfffffff0,
434 .name = "SMSC LAN8710/LAN8720",
435
dcdecdcf 436 /* PHY_BASIC_FEATURES */
e072b639 437
0a9c453e 438 .probe = smsc_phy_probe,
bedd8d78 439 .remove = smsc_phy_remove,
0a9c453e 440
e072b639 441 /* basic functions */
4223dbff 442 .read_status = lan87xx_read_status,
4257d583 443 .config_init = smsc_phy_config_init,
21009686 444 .soft_reset = smsc_phy_reset,
fdb5cc6a 445 .config_aneg = lan95xx_config_aneg_ext,
e072b639
SG
446
447 /* IRQ related */
e072b639 448 .config_intr = smsc_phy_config_intr,
36b25c26 449 .handle_interrupt = smsc_phy_handle_interrupt,
e072b639 450
030a8902
AL
451 /* Statistics */
452 .get_sset_count = smsc_get_sset_count,
453 .get_strings = smsc_get_strings,
454 .get_stats = smsc_get_stats,
455
26706d43
JH
456 .suspend = genphy_suspend,
457 .resume = genphy_resume,
458}, {
459 .phy_id = 0x0007c110,
460 .phy_id_mask = 0xfffffff0,
461 .name = "SMSC LAN8740",
462
dcdecdcf 463 /* PHY_BASIC_FEATURES */
76db2d46 464 .flags = PHY_RST_AFTER_CLK_EN,
26706d43 465
0a9c453e
TR
466 .probe = smsc_phy_probe,
467
26706d43 468 /* basic functions */
26706d43
JH
469 .read_status = lan87xx_read_status,
470 .config_init = smsc_phy_config_init,
471 .soft_reset = smsc_phy_reset,
472
473 /* IRQ related */
26706d43 474 .config_intr = smsc_phy_config_intr,
36b25c26 475 .handle_interrupt = smsc_phy_handle_interrupt,
26706d43 476
030a8902
AL
477 /* Statistics */
478 .get_sset_count = smsc_get_sset_count,
479 .get_strings = smsc_get_strings,
480 .get_stats = smsc_get_stats,
481
53ad2286
YO
482 .suspend = genphy_suspend,
483 .resume = genphy_resume,
484}, {
b2be0751
YO
485 .phy_id = 0x0007c130, /* 0x0007c130 and 0x0007c131 */
486 /* This mask (0xfffffff2) is to differentiate from
487 * LAN88xx (phy_id 0x0007c132)
488 * and allows future phy_id revisions.
489 */
53ad2286
YO
490 .phy_id_mask = 0xfffffff2,
491 .name = "Microchip LAN8742",
492
493 /* PHY_BASIC_FEATURES */
494 .flags = PHY_RST_AFTER_CLK_EN,
495
496 .probe = smsc_phy_probe,
497
498 /* basic functions */
499 .read_status = lan87xx_read_status,
500 .config_init = smsc_phy_config_init,
501 .soft_reset = smsc_phy_reset,
502
503 /* IRQ related */
504 .config_intr = smsc_phy_config_intr,
505 .handle_interrupt = smsc_phy_handle_interrupt,
506
507 /* Statistics */
508 .get_sset_count = smsc_get_sset_count,
509 .get_strings = smsc_get_strings,
510 .get_stats = smsc_get_stats,
511
e072b639
SG
512 .suspend = genphy_suspend,
513 .resume = genphy_resume,
d5bf9071 514} };
e072b639 515
50fd7150 516module_phy_driver(smsc_phy_driver);
c9e055ac
HVR
517
518MODULE_DESCRIPTION("SMSC PHY driver");
519MODULE_AUTHOR("Herbert Valerio Riedel");
520MODULE_LICENSE("GPL");
521
cf93c945 522static struct mdio_device_id __maybe_unused smsc_tbl[] = {
4e4f10f6
DW
523 { 0x0007c0a0, 0xfffffff0 },
524 { 0x0007c0b0, 0xfffffff0 },
525 { 0x0007c0c0, 0xfffffff0 },
526 { 0x0007c0d0, 0xfffffff0 },
527 { 0x0007c0f0, 0xfffffff0 },
26706d43 528 { 0x0007c110, 0xfffffff0 },
53ad2286 529 { 0x0007c130, 0xfffffff2 },
4e4f10f6
DW
530 { }
531};
532
533MODULE_DEVICE_TABLE(mdio, smsc_tbl);