diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/fsl_pq_mdio.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/fsl_pq_mdio.c')
-rw-r--r-- | drivers/net/fsl_pq_mdio.c | 99 |
1 files changed, 79 insertions, 20 deletions
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index efbf67689eca..3acac5f930c8 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c | |||
@@ -3,8 +3,9 @@ | |||
3 | * Provides Bus interface for MIIM regs | 3 | * Provides Bus interface for MIIM regs |
4 | * | 4 | * |
5 | * Author: Andy Fleming <afleming@freescale.com> | 5 | * Author: Andy Fleming <afleming@freescale.com> |
6 | * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> | ||
6 | * | 7 | * |
7 | * Copyright (c) 2002-2004,2008 Freescale Semiconductor, Inc. | 8 | * Copyright 2002-2004, 2008-2009 Freescale Semiconductor, Inc. |
8 | * | 9 | * |
9 | * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips) | 10 | * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips) |
10 | * | 11 | * |
@@ -45,6 +46,11 @@ | |||
45 | #include "gianfar.h" | 46 | #include "gianfar.h" |
46 | #include "fsl_pq_mdio.h" | 47 | #include "fsl_pq_mdio.h" |
47 | 48 | ||
49 | struct fsl_pq_mdio_priv { | ||
50 | void __iomem *map; | ||
51 | struct fsl_pq_mdio __iomem *regs; | ||
52 | }; | ||
53 | |||
48 | /* | 54 | /* |
49 | * Write value to the PHY at mii_id at register regnum, | 55 | * Write value to the PHY at mii_id at register regnum, |
50 | * on the bus attached to the local interface, which may be different from the | 56 | * on the bus attached to the local interface, which may be different from the |
@@ -102,13 +108,20 @@ int fsl_pq_local_mdio_read(struct fsl_pq_mdio __iomem *regs, | |||
102 | return value; | 108 | return value; |
103 | } | 109 | } |
104 | 110 | ||
111 | static struct fsl_pq_mdio __iomem *fsl_pq_mdio_get_regs(struct mii_bus *bus) | ||
112 | { | ||
113 | struct fsl_pq_mdio_priv *priv = bus->priv; | ||
114 | |||
115 | return priv->regs; | ||
116 | } | ||
117 | |||
105 | /* | 118 | /* |
106 | * Write value to the PHY at mii_id at register regnum, | 119 | * Write value to the PHY at mii_id at register regnum, |
107 | * on the bus, waiting until the write is done before returning. | 120 | * on the bus, waiting until the write is done before returning. |
108 | */ | 121 | */ |
109 | int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | 122 | int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) |
110 | { | 123 | { |
111 | struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv; | 124 | struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); |
112 | 125 | ||
113 | /* Write to the local MII regs */ | 126 | /* Write to the local MII regs */ |
114 | return(fsl_pq_local_mdio_write(regs, mii_id, regnum, value)); | 127 | return(fsl_pq_local_mdio_write(regs, mii_id, regnum, value)); |
@@ -120,7 +133,7 @@ int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | |||
120 | */ | 133 | */ |
121 | int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | 134 | int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) |
122 | { | 135 | { |
123 | struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv; | 136 | struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); |
124 | 137 | ||
125 | /* Read the local MII regs */ | 138 | /* Read the local MII regs */ |
126 | return(fsl_pq_local_mdio_read(regs, mii_id, regnum)); | 139 | return(fsl_pq_local_mdio_read(regs, mii_id, regnum)); |
@@ -129,7 +142,7 @@ int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | |||
129 | /* Reset the MIIM registers, and wait for the bus to free */ | 142 | /* Reset the MIIM registers, and wait for the bus to free */ |
130 | static int fsl_pq_mdio_reset(struct mii_bus *bus) | 143 | static int fsl_pq_mdio_reset(struct mii_bus *bus) |
131 | { | 144 | { |
132 | struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv; | 145 | struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); |
133 | int timeout = PHY_INIT_TIMEOUT; | 146 | int timeout = PHY_INIT_TIMEOUT; |
134 | 147 | ||
135 | mutex_lock(&bus->mdio_lock); | 148 | mutex_lock(&bus->mdio_lock); |
@@ -189,7 +202,7 @@ static int fsl_pq_mdio_find_free(struct mii_bus *new_bus) | |||
189 | 202 | ||
190 | 203 | ||
191 | #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) | 204 | #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) |
192 | static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs) | 205 | static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np) |
193 | { | 206 | { |
194 | struct gfar __iomem *enet_regs; | 207 | struct gfar __iomem *enet_regs; |
195 | 208 | ||
@@ -198,10 +211,16 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs) | |||
198 | * Also, we have to cast back to struct gfar because of | 211 | * Also, we have to cast back to struct gfar because of |
199 | * definition weirdness done in gianfar.h. | 212 | * definition weirdness done in gianfar.h. |
200 | */ | 213 | */ |
201 | enet_regs = (struct gfar __iomem *) | 214 | if(of_device_is_compatible(np, "fsl,gianfar-mdio") || |
202 | ((char __iomem *)regs - offsetof(struct gfar, gfar_mii_regs)); | 215 | of_device_is_compatible(np, "fsl,gianfar-tbi") || |
203 | 216 | of_device_is_compatible(np, "gianfar")) { | |
204 | return &enet_regs->tbipa; | 217 | enet_regs = (struct gfar __iomem *)regs; |
218 | return &enet_regs->tbipa; | ||
219 | } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") || | ||
220 | of_device_is_compatible(np, "fsl,etsec2-tbi")) { | ||
221 | return of_iomap(np, 1); | ||
222 | } else | ||
223 | return NULL; | ||
205 | } | 224 | } |
206 | #endif | 225 | #endif |
207 | 226 | ||
@@ -250,33 +269,58 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, | |||
250 | { | 269 | { |
251 | struct device_node *np = ofdev->node; | 270 | struct device_node *np = ofdev->node; |
252 | struct device_node *tbi; | 271 | struct device_node *tbi; |
253 | struct fsl_pq_mdio __iomem *regs; | 272 | struct fsl_pq_mdio_priv *priv; |
273 | struct fsl_pq_mdio __iomem *regs = NULL; | ||
274 | void __iomem *map; | ||
254 | u32 __iomem *tbipa; | 275 | u32 __iomem *tbipa; |
255 | struct mii_bus *new_bus; | 276 | struct mii_bus *new_bus; |
256 | int tbiaddr = -1; | 277 | int tbiaddr = -1; |
257 | u64 addr, size; | 278 | const u32 *addrp; |
279 | u64 addr = 0, size = 0; | ||
258 | int err = 0; | 280 | int err = 0; |
259 | 281 | ||
282 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
283 | if (!priv) | ||
284 | return -ENOMEM; | ||
285 | |||
260 | new_bus = mdiobus_alloc(); | 286 | new_bus = mdiobus_alloc(); |
261 | if (NULL == new_bus) | 287 | if (NULL == new_bus) |
262 | return -ENOMEM; | 288 | goto err_free_priv; |
263 | 289 | ||
264 | new_bus->name = "Freescale PowerQUICC MII Bus", | 290 | new_bus->name = "Freescale PowerQUICC MII Bus", |
265 | new_bus->read = &fsl_pq_mdio_read, | 291 | new_bus->read = &fsl_pq_mdio_read, |
266 | new_bus->write = &fsl_pq_mdio_write, | 292 | new_bus->write = &fsl_pq_mdio_write, |
267 | new_bus->reset = &fsl_pq_mdio_reset, | 293 | new_bus->reset = &fsl_pq_mdio_reset, |
294 | new_bus->priv = priv; | ||
268 | fsl_pq_mdio_bus_name(new_bus->id, np); | 295 | fsl_pq_mdio_bus_name(new_bus->id, np); |
269 | 296 | ||
297 | addrp = of_get_address(np, 0, &size, NULL); | ||
298 | if (!addrp) { | ||
299 | err = -EINVAL; | ||
300 | goto err_free_bus; | ||
301 | } | ||
302 | |||
270 | /* Set the PHY base address */ | 303 | /* Set the PHY base address */ |
271 | addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); | 304 | addr = of_translate_address(np, addrp); |
272 | regs = ioremap(addr, size); | 305 | if (addr == OF_BAD_ADDR) { |
306 | err = -EINVAL; | ||
307 | goto err_free_bus; | ||
308 | } | ||
273 | 309 | ||
274 | if (NULL == regs) { | 310 | map = ioremap(addr, size); |
311 | if (!map) { | ||
275 | err = -ENOMEM; | 312 | err = -ENOMEM; |
276 | goto err_free_bus; | 313 | goto err_free_bus; |
277 | } | 314 | } |
315 | priv->map = map; | ||
278 | 316 | ||
279 | new_bus->priv = (void __force *)regs; | 317 | if (of_device_is_compatible(np, "fsl,gianfar-mdio") || |
318 | of_device_is_compatible(np, "fsl,gianfar-tbi") || | ||
319 | of_device_is_compatible(np, "fsl,ucc-mdio") || | ||
320 | of_device_is_compatible(np, "ucc_geth_phy")) | ||
321 | map -= offsetof(struct fsl_pq_mdio, miimcfg); | ||
322 | regs = map; | ||
323 | priv->regs = regs; | ||
280 | 324 | ||
281 | new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); | 325 | new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); |
282 | 326 | ||
@@ -290,9 +334,15 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, | |||
290 | 334 | ||
291 | if (of_device_is_compatible(np, "fsl,gianfar-mdio") || | 335 | if (of_device_is_compatible(np, "fsl,gianfar-mdio") || |
292 | of_device_is_compatible(np, "fsl,gianfar-tbi") || | 336 | of_device_is_compatible(np, "fsl,gianfar-tbi") || |
337 | of_device_is_compatible(np, "fsl,etsec2-mdio") || | ||
338 | of_device_is_compatible(np, "fsl,etsec2-tbi") || | ||
293 | of_device_is_compatible(np, "gianfar")) { | 339 | of_device_is_compatible(np, "gianfar")) { |
294 | #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) | 340 | #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) |
295 | tbipa = get_gfar_tbipa(regs); | 341 | tbipa = get_gfar_tbipa(regs, np); |
342 | if (!tbipa) { | ||
343 | err = -EINVAL; | ||
344 | goto err_free_irqs; | ||
345 | } | ||
296 | #else | 346 | #else |
297 | err = -ENODEV; | 347 | err = -ENODEV; |
298 | goto err_free_irqs; | 348 | goto err_free_irqs; |
@@ -363,10 +413,11 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, | |||
363 | err_free_irqs: | 413 | err_free_irqs: |
364 | kfree(new_bus->irq); | 414 | kfree(new_bus->irq); |
365 | err_unmap_regs: | 415 | err_unmap_regs: |
366 | iounmap(regs); | 416 | iounmap(priv->map); |
367 | err_free_bus: | 417 | err_free_bus: |
368 | kfree(new_bus); | 418 | kfree(new_bus); |
369 | 419 | err_free_priv: | |
420 | kfree(priv); | ||
370 | return err; | 421 | return err; |
371 | } | 422 | } |
372 | 423 | ||
@@ -375,14 +426,16 @@ static int fsl_pq_mdio_remove(struct of_device *ofdev) | |||
375 | { | 426 | { |
376 | struct device *device = &ofdev->dev; | 427 | struct device *device = &ofdev->dev; |
377 | struct mii_bus *bus = dev_get_drvdata(device); | 428 | struct mii_bus *bus = dev_get_drvdata(device); |
429 | struct fsl_pq_mdio_priv *priv = bus->priv; | ||
378 | 430 | ||
379 | mdiobus_unregister(bus); | 431 | mdiobus_unregister(bus); |
380 | 432 | ||
381 | dev_set_drvdata(device, NULL); | 433 | dev_set_drvdata(device, NULL); |
382 | 434 | ||
383 | iounmap((void __iomem *)bus->priv); | 435 | iounmap(priv->map); |
384 | bus->priv = NULL; | 436 | bus->priv = NULL; |
385 | mdiobus_free(bus); | 437 | mdiobus_free(bus); |
438 | kfree(priv); | ||
386 | 439 | ||
387 | return 0; | 440 | return 0; |
388 | } | 441 | } |
@@ -405,6 +458,12 @@ static struct of_device_id fsl_pq_mdio_match[] = { | |||
405 | { | 458 | { |
406 | .compatible = "fsl,gianfar-mdio", | 459 | .compatible = "fsl,gianfar-mdio", |
407 | }, | 460 | }, |
461 | { | ||
462 | .compatible = "fsl,etsec2-tbi", | ||
463 | }, | ||
464 | { | ||
465 | .compatible = "fsl,etsec2-mdio", | ||
466 | }, | ||
408 | {}, | 467 | {}, |
409 | }; | 468 | }; |
410 | MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match); | 469 | MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match); |