diff options
author | Giuseppe CAVALLARO <peppe.cavallaro@st.com> | 2011-09-06 16:14:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-09-20 15:50:29 -0400 |
commit | 9c9b1f24f2aa31a3cea94939edc551f68ebadc89 (patch) | |
tree | 2735620455c67f98b977ed0c181e1927053cb9f5 /drivers/net/phy/icplus.c | |
parent | e3feb266c344394ce06bdecdfa05071118249c88 (diff) |
net/phy: add IC+ IP101A and support APS.
This patch adds the IC+ IP101A Single port 10/100 PHY
and supports the APS (i.e. power saving mode while link is down)
for both IP1001 and IP101A (where this mode is supported).
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/icplus.c')
-rw-r--r-- | drivers/net/phy/icplus.c | 79 |
1 files changed, 68 insertions, 11 deletions
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index d4cbc2922b23..6e344e59caf7 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c | |||
@@ -30,10 +30,17 @@ | |||
30 | #include <asm/irq.h> | 30 | #include <asm/irq.h> |
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | 32 | ||
33 | MODULE_DESCRIPTION("ICPlus IP175C/IC1001 PHY drivers"); | 33 | MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IC1001 PHY drivers"); |
34 | MODULE_AUTHOR("Michael Barkowski"); | 34 | MODULE_AUTHOR("Michael Barkowski"); |
35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
36 | 36 | ||
37 | /* IP101A/IP1001 */ | ||
38 | #define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ | ||
39 | #define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ | ||
40 | #define IP1001_PHASE_SEL_MASK 3 /* IP1001 RX/TXPHASE_SEL */ | ||
41 | #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ | ||
42 | #define IP101A_APS_ON 2 /* IP101A APS Mode bit */ | ||
43 | |||
37 | static int ip175c_config_init(struct phy_device *phydev) | 44 | static int ip175c_config_init(struct phy_device *phydev) |
38 | { | 45 | { |
39 | int err, i; | 46 | int err, i; |
@@ -89,27 +96,58 @@ static int ip175c_config_init(struct phy_device *phydev) | |||
89 | return 0; | 96 | return 0; |
90 | } | 97 | } |
91 | 98 | ||
92 | static int ip1001_config_init(struct phy_device *phydev) | 99 | static int ip1xx_reset(struct phy_device *phydev) |
93 | { | 100 | { |
94 | int err, value; | 101 | int err, bmcr; |
95 | 102 | ||
96 | /* Software Reset PHY */ | 103 | /* Software Reset PHY */ |
97 | value = phy_read(phydev, MII_BMCR); | 104 | bmcr = phy_read(phydev, MII_BMCR); |
98 | value |= BMCR_RESET; | 105 | bmcr |= BMCR_RESET; |
99 | err = phy_write(phydev, MII_BMCR, value); | 106 | err = phy_write(phydev, MII_BMCR, bmcr); |
100 | if (err < 0) | 107 | if (err < 0) |
101 | return err; | 108 | return err; |
102 | 109 | ||
103 | do { | 110 | do { |
104 | value = phy_read(phydev, MII_BMCR); | 111 | bmcr = phy_read(phydev, MII_BMCR); |
105 | } while (value & BMCR_RESET); | 112 | } while (bmcr & BMCR_RESET); |
113 | |||
114 | return err; | ||
115 | } | ||
116 | |||
117 | static int ip1001_config_init(struct phy_device *phydev) | ||
118 | { | ||
119 | int c; | ||
120 | |||
121 | c = ip1xx_reset(phydev); | ||
122 | if (c < 0) | ||
123 | return c; | ||
124 | |||
125 | /* Enable Auto Power Saving mode */ | ||
126 | c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2); | ||
127 | c |= IP1001_APS_ON; | ||
128 | if (c < 0) | ||
129 | return c; | ||
106 | 130 | ||
107 | /* Additional delay (2ns) used to adjust RX clock phase | 131 | /* Additional delay (2ns) used to adjust RX clock phase |
108 | * at GMII/ RGMII interface */ | 132 | * at GMII/ RGMII interface */ |
109 | value = phy_read(phydev, 16); | 133 | c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); |
110 | value |= 0x3; | 134 | c |= IP1001_PHASE_SEL_MASK; |
135 | |||
136 | return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); | ||
137 | } | ||
138 | |||
139 | static int ip101a_config_init(struct phy_device *phydev) | ||
140 | { | ||
141 | int c; | ||
111 | 142 | ||
112 | return phy_write(phydev, 16, value); | 143 | c = ip1xx_reset(phydev); |
144 | if (c < 0) | ||
145 | return c; | ||
146 | |||
147 | /* Enable Auto Power Saving mode */ | ||
148 | c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); | ||
149 | c |= IP101A_APS_ON; | ||
150 | return c; | ||
113 | } | 151 | } |
114 | 152 | ||
115 | static int ip175c_read_status(struct phy_device *phydev) | 153 | static int ip175c_read_status(struct phy_device *phydev) |
@@ -158,6 +196,20 @@ static struct phy_driver ip1001_driver = { | |||
158 | .driver = { .owner = THIS_MODULE,}, | 196 | .driver = { .owner = THIS_MODULE,}, |
159 | }; | 197 | }; |
160 | 198 | ||
199 | static struct phy_driver ip101a_driver = { | ||
200 | .phy_id = 0x02430c54, | ||
201 | .name = "ICPlus IP101A", | ||
202 | .phy_id_mask = 0x0ffffff0, | ||
203 | .features = PHY_BASIC_FEATURES | SUPPORTED_Pause | | ||
204 | SUPPORTED_Asym_Pause, | ||
205 | .config_init = &ip101a_config_init, | ||
206 | .config_aneg = &genphy_config_aneg, | ||
207 | .read_status = &genphy_read_status, | ||
208 | .suspend = genphy_suspend, | ||
209 | .resume = genphy_resume, | ||
210 | .driver = { .owner = THIS_MODULE,}, | ||
211 | }; | ||
212 | |||
161 | static int __init icplus_init(void) | 213 | static int __init icplus_init(void) |
162 | { | 214 | { |
163 | int ret = 0; | 215 | int ret = 0; |
@@ -166,12 +218,17 @@ static int __init icplus_init(void) | |||
166 | if (ret < 0) | 218 | if (ret < 0) |
167 | return -ENODEV; | 219 | return -ENODEV; |
168 | 220 | ||
221 | ret = phy_driver_register(&ip101a_driver); | ||
222 | if (ret < 0) | ||
223 | return -ENODEV; | ||
224 | |||
169 | return phy_driver_register(&ip175c_driver); | 225 | return phy_driver_register(&ip175c_driver); |
170 | } | 226 | } |
171 | 227 | ||
172 | static void __exit icplus_exit(void) | 228 | static void __exit icplus_exit(void) |
173 | { | 229 | { |
174 | phy_driver_unregister(&ip1001_driver); | 230 | phy_driver_unregister(&ip1001_driver); |
231 | phy_driver_unregister(&ip101a_driver); | ||
175 | phy_driver_unregister(&ip175c_driver); | 232 | phy_driver_unregister(&ip175c_driver); |
176 | } | 233 | } |
177 | 234 | ||