Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.17-rc5 221 lines 5.2 kB view raw
1/* 2 * drivers/net/gianfar_mii.c 3 * 4 * Gianfar Ethernet Driver -- MIIM bus implementation 5 * Provides Bus interface for MIIM regs 6 * 7 * Author: Andy Fleming 8 * Maintainer: Kumar Gala 9 * 10 * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. 11 * 12 * This program is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by the 14 * Free Software Foundation; either version 2 of the License, or (at your 15 * option) any later version. 16 * 17 */ 18 19#include <linux/config.h> 20#include <linux/kernel.h> 21#include <linux/sched.h> 22#include <linux/string.h> 23#include <linux/errno.h> 24#include <linux/unistd.h> 25#include <linux/slab.h> 26#include <linux/interrupt.h> 27#include <linux/init.h> 28#include <linux/delay.h> 29#include <linux/netdevice.h> 30#include <linux/etherdevice.h> 31#include <linux/skbuff.h> 32#include <linux/spinlock.h> 33#include <linux/mm.h> 34#include <linux/module.h> 35#include <linux/platform_device.h> 36#include <asm/ocp.h> 37#include <linux/crc32.h> 38#include <linux/mii.h> 39#include <linux/phy.h> 40 41#include <asm/io.h> 42#include <asm/irq.h> 43#include <asm/uaccess.h> 44 45#include "gianfar.h" 46#include "gianfar_mii.h" 47 48/* Write value to the PHY at mii_id at register regnum, 49 * on the bus, waiting until the write is done before returning. 50 * All PHY configuration is done through the TSEC1 MIIM regs */ 51int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) 52{ 53 struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; 54 55 /* Set the PHY address and the register address we want to write */ 56 gfar_write(&regs->miimadd, (mii_id << 8) | regnum); 57 58 /* Write out the value we want */ 59 gfar_write(&regs->miimcon, value); 60 61 /* Wait for the transaction to finish */ 62 while (gfar_read(&regs->miimind) & MIIMIND_BUSY) 63 cpu_relax(); 64 65 return 0; 66} 67 68/* Read the bus for PHY at addr mii_id, register regnum, and 69 * return the value. Clears miimcom first. All PHY 70 * configuration has to be done through the TSEC1 MIIM regs */ 71int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 72{ 73 struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; 74 u16 value; 75 76 /* Set the PHY address and the register address we want to read */ 77 gfar_write(&regs->miimadd, (mii_id << 8) | regnum); 78 79 /* Clear miimcom, and then initiate a read */ 80 gfar_write(&regs->miimcom, 0); 81 gfar_write(&regs->miimcom, MII_READ_COMMAND); 82 83 /* Wait for the transaction to finish */ 84 while (gfar_read(&regs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) 85 cpu_relax(); 86 87 /* Grab the value of the register from miimstat */ 88 value = gfar_read(&regs->miimstat); 89 90 return value; 91} 92 93 94/* Reset the MIIM registers, and wait for the bus to free */ 95int gfar_mdio_reset(struct mii_bus *bus) 96{ 97 struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; 98 unsigned int timeout = PHY_INIT_TIMEOUT; 99 100 spin_lock_bh(&bus->mdio_lock); 101 102 /* Reset the management interface */ 103 gfar_write(&regs->miimcfg, MIIMCFG_RESET); 104 105 /* Setup the MII Mgmt clock speed */ 106 gfar_write(&regs->miimcfg, MIIMCFG_INIT_VALUE); 107 108 /* Wait until the bus is free */ 109 while ((gfar_read(&regs->miimind) & MIIMIND_BUSY) && 110 timeout--) 111 cpu_relax(); 112 113 spin_unlock_bh(&bus->mdio_lock); 114 115 if(timeout <= 0) { 116 printk(KERN_ERR "%s: The MII Bus is stuck!\n", 117 bus->name); 118 return -EBUSY; 119 } 120 121 return 0; 122} 123 124 125int gfar_mdio_probe(struct device *dev) 126{ 127 struct platform_device *pdev = to_platform_device(dev); 128 struct gianfar_mdio_data *pdata; 129 struct gfar_mii __iomem *regs; 130 struct mii_bus *new_bus; 131 struct resource *r; 132 int err = 0; 133 134 if (NULL == dev) 135 return -EINVAL; 136 137 new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); 138 139 if (NULL == new_bus) 140 return -ENOMEM; 141 142 new_bus->name = "Gianfar MII Bus", 143 new_bus->read = &gfar_mdio_read, 144 new_bus->write = &gfar_mdio_write, 145 new_bus->reset = &gfar_mdio_reset, 146 new_bus->id = pdev->id; 147 148 pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; 149 150 if (NULL == pdata) { 151 printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); 152 return -ENODEV; 153 } 154 155 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 156 157 /* Set the PHY base address */ 158 regs = ioremap(r->start, sizeof (struct gfar_mii)); 159 160 if (NULL == regs) { 161 err = -ENOMEM; 162 goto reg_map_fail; 163 } 164 165 new_bus->priv = (void __force *)regs; 166 167 new_bus->irq = pdata->irq; 168 169 new_bus->dev = dev; 170 dev_set_drvdata(dev, new_bus); 171 172 err = mdiobus_register(new_bus); 173 174 if (0 != err) { 175 printk (KERN_ERR "%s: Cannot register as MDIO bus\n", 176 new_bus->name); 177 goto bus_register_fail; 178 } 179 180 return 0; 181 182bus_register_fail: 183 iounmap(regs); 184reg_map_fail: 185 kfree(new_bus); 186 187 return err; 188} 189 190 191int gfar_mdio_remove(struct device *dev) 192{ 193 struct mii_bus *bus = dev_get_drvdata(dev); 194 195 mdiobus_unregister(bus); 196 197 dev_set_drvdata(dev, NULL); 198 199 iounmap((void __iomem *)bus->priv); 200 bus->priv = NULL; 201 kfree(bus); 202 203 return 0; 204} 205 206static struct device_driver gianfar_mdio_driver = { 207 .name = "fsl-gianfar_mdio", 208 .bus = &platform_bus_type, 209 .probe = gfar_mdio_probe, 210 .remove = gfar_mdio_remove, 211}; 212 213int __init gfar_mdio_init(void) 214{ 215 return driver_register(&gianfar_mdio_driver); 216} 217 218void __exit gfar_mdio_exit(void) 219{ 220 driver_unregister(&gianfar_mdio_driver); 221}