diff options
author | Michael Barkowski <michael.barkowski@freescale.com> | 2007-05-11 19:24:51 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-07-08 22:16:38 -0400 |
commit | 0cefeebaf3da39d768bffcf62460fe2088e824ef (patch) | |
tree | 231a039f1b1032898bfae4c3b9c82181e14f893f /drivers/net/phy/icplus.c | |
parent | 146bd683cc160d728f1f62a6ddade8451801a8c3 (diff) |
phylib: add the ICPlus IP175C PHY driver
The ICPlus IP175C sports a 100Mbit/s 4-port switch in addition
to a dedicated 100Mbit/s WAN port.
Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/phy/icplus.c')
-rw-r--r-- | drivers/net/phy/icplus.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c new file mode 100644 index 000000000000..af3f1f2a9f87 --- /dev/null +++ b/drivers/net/phy/icplus.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Driver for ICPlus PHYs | ||
3 | * | ||
4 | * Copyright (c) 2007 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/unistd.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/etherdevice.h> | ||
22 | #include <linux/skbuff.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/mii.h> | ||
27 | #include <linux/ethtool.h> | ||
28 | #include <linux/phy.h> | ||
29 | |||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | MODULE_DESCRIPTION("ICPlus IP175C PHY driver"); | ||
35 | MODULE_AUTHOR("Michael Barkowski"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | static int ip175c_config_init(struct phy_device *phydev) | ||
39 | { | ||
40 | int err, i; | ||
41 | static int full_reset_performed = 0; | ||
42 | |||
43 | if (full_reset_performed == 0) { | ||
44 | |||
45 | /* master reset */ | ||
46 | err = phydev->bus->write(phydev->bus, 30, 0, 0x175c); | ||
47 | if (err < 0) | ||
48 | return err; | ||
49 | |||
50 | /* ensure no bus delays overlap reset period */ | ||
51 | err = phydev->bus->read(phydev->bus, 30, 0); | ||
52 | |||
53 | /* data sheet specifies reset period is 2 msec */ | ||
54 | mdelay(2); | ||
55 | |||
56 | /* enable IP175C mode */ | ||
57 | err = phydev->bus->write(phydev->bus, 29, 31, 0x175c); | ||
58 | if (err < 0) | ||
59 | return err; | ||
60 | |||
61 | /* Set MII0 speed and duplex (in PHY mode) */ | ||
62 | err = phydev->bus->write(phydev->bus, 29, 22, 0x420); | ||
63 | if (err < 0) | ||
64 | return err; | ||
65 | |||
66 | /* reset switch ports */ | ||
67 | for (i = 0; i < 5; i++) { | ||
68 | err = phydev->bus->write(phydev->bus, i, | ||
69 | MII_BMCR, BMCR_RESET); | ||
70 | if (err < 0) | ||
71 | return err; | ||
72 | } | ||
73 | |||
74 | for (i = 0; i < 5; i++) | ||
75 | err = phydev->bus->read(phydev->bus, i, MII_BMCR); | ||
76 | |||
77 | mdelay(2); | ||
78 | |||
79 | full_reset_performed = 1; | ||
80 | } | ||
81 | |||
82 | if (phydev->addr != 4) { | ||
83 | phydev->state = PHY_RUNNING; | ||
84 | phydev->speed = SPEED_100; | ||
85 | phydev->duplex = DUPLEX_FULL; | ||
86 | phydev->link = 1; | ||
87 | netif_carrier_on(phydev->attached_dev); | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int ip175c_read_status(struct phy_device *phydev) | ||
94 | { | ||
95 | if (phydev->addr == 4) /* WAN port */ | ||
96 | genphy_read_status(phydev); | ||
97 | else | ||
98 | /* Don't need to read status for switch ports */ | ||
99 | phydev->irq = PHY_IGNORE_INTERRUPT; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int ip175c_config_aneg(struct phy_device *phydev) | ||
105 | { | ||
106 | if (phydev->addr == 4) /* WAN port */ | ||
107 | genphy_config_aneg(phydev); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static struct phy_driver ip175c_driver = { | ||
113 | .phy_id = 0x02430d80, | ||
114 | .name = "ICPlus IP175C", | ||
115 | .phy_id_mask = 0x0ffffff0, | ||
116 | .features = PHY_BASIC_FEATURES, | ||
117 | .config_init = &ip175c_config_init, | ||
118 | .config_aneg = &ip175c_config_aneg, | ||
119 | .read_status = &ip175c_read_status, | ||
120 | .driver = { .owner = THIS_MODULE,}, | ||
121 | }; | ||
122 | |||
123 | static int __init ip175c_init(void) | ||
124 | { | ||
125 | return phy_driver_register(&ip175c_driver); | ||
126 | } | ||
127 | |||
128 | static void __exit ip175c_exit(void) | ||
129 | { | ||
130 | phy_driver_unregister(&ip175c_driver); | ||
131 | } | ||
132 | |||
133 | module_init(ip175c_init); | ||
134 | module_exit(ip175c_exit); | ||