diff options
Diffstat (limited to 'drivers/net/fs_enet/mii-fec.c')
-rw-r--r-- | drivers/net/fs_enet/mii-fec.c | 143 |
1 files changed, 142 insertions, 1 deletions
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 53db696b948f..f91c38d0b57b 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c | |||
@@ -36,6 +36,10 @@ | |||
36 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | 38 | ||
39 | #ifdef CONFIG_PPC_CPM_NEW_BINDING | ||
40 | #include <asm/of_platform.h> | ||
41 | #endif | ||
42 | |||
39 | #include "fs_enet.h" | 43 | #include "fs_enet.h" |
40 | #include "fec.h" | 44 | #include "fec.h" |
41 | 45 | ||
@@ -47,6 +51,7 @@ | |||
47 | 51 | ||
48 | #define FEC_MII_LOOPS 10000 | 52 | #define FEC_MII_LOOPS 10000 |
49 | 53 | ||
54 | #ifndef CONFIG_PPC_CPM_NEW_BINDING | ||
50 | static int match_has_phy (struct device *dev, void* data) | 55 | static int match_has_phy (struct device *dev, void* data) |
51 | { | 56 | { |
52 | struct platform_device* pdev = container_of(dev, struct platform_device, dev); | 57 | struct platform_device* pdev = container_of(dev, struct platform_device, dev); |
@@ -90,6 +95,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info | |||
90 | 95 | ||
91 | return 0; | 96 | return 0; |
92 | } | 97 | } |
98 | #endif | ||
93 | 99 | ||
94 | static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) | 100 | static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) |
95 | { | 101 | { |
@@ -145,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) | |||
145 | return 0; | 151 | return 0; |
146 | } | 152 | } |
147 | 153 | ||
154 | #ifdef CONFIG_PPC_CPM_NEW_BINDING | ||
155 | static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) | ||
156 | { | ||
157 | const u32 *data; | ||
158 | int len, id, irq; | ||
159 | |||
160 | data = of_get_property(np, "reg", &len); | ||
161 | if (!data || len != 4) | ||
162 | return; | ||
163 | |||
164 | id = *data; | ||
165 | bus->phy_mask &= ~(1 << id); | ||
166 | |||
167 | irq = of_irq_to_resource(np, 0, NULL); | ||
168 | if (irq != NO_IRQ) | ||
169 | bus->irq[id] = irq; | ||
170 | } | ||
171 | |||
172 | static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, | ||
173 | const struct of_device_id *match) | ||
174 | { | ||
175 | struct device_node *np = NULL; | ||
176 | struct resource res; | ||
177 | struct mii_bus *new_bus; | ||
178 | struct fec_info *fec; | ||
179 | int ret = -ENOMEM, i; | ||
180 | |||
181 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | ||
182 | if (!new_bus) | ||
183 | goto out; | ||
184 | |||
185 | fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); | ||
186 | if (!fec) | ||
187 | goto out_mii; | ||
188 | |||
189 | new_bus->priv = fec; | ||
190 | new_bus->name = "FEC MII Bus"; | ||
191 | new_bus->read = &fs_enet_fec_mii_read; | ||
192 | new_bus->write = &fs_enet_fec_mii_write; | ||
193 | new_bus->reset = &fs_enet_fec_mii_reset; | ||
194 | |||
195 | ret = of_address_to_resource(ofdev->node, 0, &res); | ||
196 | if (ret) | ||
197 | return ret; | ||
198 | |||
199 | new_bus->id = res.start; | ||
200 | |||
201 | fec->fecp = ioremap(res.start, res.end - res.start + 1); | ||
202 | if (!fec->fecp) | ||
203 | goto out_fec; | ||
204 | |||
205 | fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1; | ||
206 | |||
207 | setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); | ||
208 | setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | | ||
209 | FEC_ECNTRL_ETHER_EN); | ||
210 | out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); | ||
211 | out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed); | ||
212 | |||
213 | new_bus->phy_mask = ~0; | ||
214 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
215 | if (!new_bus->irq) | ||
216 | goto out_unmap_regs; | ||
217 | |||
218 | for (i = 0; i < PHY_MAX_ADDR; i++) | ||
219 | new_bus->irq[i] = -1; | ||
220 | |||
221 | while ((np = of_get_next_child(ofdev->node, np))) | ||
222 | if (!strcmp(np->type, "ethernet-phy")) | ||
223 | add_phy(new_bus, np); | ||
224 | |||
225 | new_bus->dev = &ofdev->dev; | ||
226 | dev_set_drvdata(&ofdev->dev, new_bus); | ||
227 | |||
228 | ret = mdiobus_register(new_bus); | ||
229 | if (ret) | ||
230 | goto out_free_irqs; | ||
231 | |||
232 | return 0; | ||
233 | |||
234 | out_free_irqs: | ||
235 | dev_set_drvdata(&ofdev->dev, NULL); | ||
236 | kfree(new_bus->irq); | ||
237 | out_unmap_regs: | ||
238 | iounmap(fec->fecp); | ||
239 | out_fec: | ||
240 | kfree(fec); | ||
241 | out_mii: | ||
242 | kfree(new_bus); | ||
243 | out: | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | static int fs_enet_mdio_remove(struct of_device *ofdev) | ||
248 | { | ||
249 | struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); | ||
250 | struct fec_info *fec = bus->priv; | ||
251 | |||
252 | mdiobus_unregister(bus); | ||
253 | dev_set_drvdata(&ofdev->dev, NULL); | ||
254 | kfree(bus->irq); | ||
255 | iounmap(fec->fecp); | ||
256 | kfree(fec); | ||
257 | kfree(bus); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static struct of_device_id fs_enet_mdio_fec_match[] = { | ||
263 | { | ||
264 | .compatible = "fsl,pq1-fec-mdio", | ||
265 | }, | ||
266 | {}, | ||
267 | }; | ||
268 | |||
269 | static struct of_platform_driver fs_enet_fec_mdio_driver = { | ||
270 | .name = "fsl-fec-mdio", | ||
271 | .match_table = fs_enet_mdio_fec_match, | ||
272 | .probe = fs_enet_mdio_probe, | ||
273 | .remove = fs_enet_mdio_remove, | ||
274 | }; | ||
275 | |||
276 | static int fs_enet_mdio_fec_init(void) | ||
277 | { | ||
278 | return of_register_platform_driver(&fs_enet_fec_mdio_driver); | ||
279 | } | ||
280 | |||
281 | static void fs_enet_mdio_fec_exit(void) | ||
282 | { | ||
283 | of_unregister_platform_driver(&fs_enet_fec_mdio_driver); | ||
284 | } | ||
285 | |||
286 | module_init(fs_enet_mdio_fec_init); | ||
287 | module_exit(fs_enet_mdio_fec_exit); | ||
288 | #else | ||
148 | static int __devinit fs_enet_fec_mdio_probe(struct device *dev) | 289 | static int __devinit fs_enet_fec_mdio_probe(struct device *dev) |
149 | { | 290 | { |
150 | struct platform_device *pdev = to_platform_device(dev); | 291 | struct platform_device *pdev = to_platform_device(dev); |
@@ -235,4 +376,4 @@ void fs_enet_mdio_fec_exit(void) | |||
235 | { | 376 | { |
236 | driver_unregister(&fs_enet_fec_mdio_driver); | 377 | driver_unregister(&fs_enet_fec_mdio_driver); |
237 | } | 378 | } |
238 | 379 | #endif | |