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