allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / net / phy / fixed.c
blobbb966911a137a051593b1b4ff7f32cf2263cd65f
1 /*
2 * drivers/net/phy/fixed.c
4 * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode.
6 * Author: Vitaly Bordug
8 * Copyright (c) 2006 MontaVista Software, Inc.
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/unistd.h>
20 #include <linux/slab.h>
21 #include <linux/interrupt.h>
22 #include <linux/init.h>
23 #include <linux/delay.h>
24 #include <linux/netdevice.h>
25 #include <linux/etherdevice.h>
26 #include <linux/skbuff.h>
27 #include <linux/spinlock.h>
28 #include <linux/mm.h>
29 #include <linux/module.h>
30 #include <linux/mii.h>
31 #include <linux/ethtool.h>
32 #include <linux/phy.h>
34 #include <asm/io.h>
35 #include <asm/irq.h>
36 #include <asm/uaccess.h>
38 #define MII_REGS_NUM 7
41 The idea is to emulate normal phy behavior by responding with
42 pre-defined values to mii BMCR read, so that read_status hook could
43 take all the needed info.
46 struct fixed_phy_status {
47 u8 link;
48 u16 speed;
49 u8 duplex;
52 /*-----------------------------------------------------------------------------
53 * Private information hoder for mii_bus
54 *-----------------------------------------------------------------------------*/
55 struct fixed_info {
56 u16 *regs;
57 u8 regs_num;
58 struct fixed_phy_status phy_status;
59 struct phy_device *phydev; /* pointer to the container */
60 /* link & speed cb */
61 int(*link_update)(struct net_device*, struct fixed_phy_status*);
65 /*-----------------------------------------------------------------------------
66 * If something weird is required to be done with link/speed,
67 * network driver is able to assign a function to implement this.
68 * May be useful for PHY's that need to be software-driven.
69 *-----------------------------------------------------------------------------*/
70 int fixed_mdio_set_link_update(struct phy_device* phydev,
71 int(*link_update)(struct net_device*, struct fixed_phy_status*))
73 struct fixed_info *fixed;
75 if(link_update == NULL)
76 return -EINVAL;
78 if(phydev) {
79 if(phydev->bus) {
80 fixed = phydev->bus->priv;
81 fixed->link_update = link_update;
82 return 0;
85 return -EINVAL;
87 EXPORT_SYMBOL(fixed_mdio_set_link_update);
89 /*-----------------------------------------------------------------------------
90 * This is used for updating internal mii regs from the status
91 *-----------------------------------------------------------------------------*/
92 #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
93 static int fixed_mdio_update_regs(struct fixed_info *fixed)
95 u16 *regs = fixed->regs;
96 u16 bmsr = 0;
97 u16 bmcr = 0;
99 if(!regs) {
100 printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
101 return -EINVAL;
104 if(fixed->phy_status.link)
105 bmsr |= BMSR_LSTATUS;
107 if(fixed->phy_status.duplex) {
108 bmcr |= BMCR_FULLDPLX;
110 switch ( fixed->phy_status.speed ) {
111 case 100:
112 bmsr |= BMSR_100FULL;
113 bmcr |= BMCR_SPEED100;
114 break;
116 case 10:
117 bmsr |= BMSR_10FULL;
118 break;
120 } else {
121 switch ( fixed->phy_status.speed ) {
122 case 100:
123 bmsr |= BMSR_100HALF;
124 bmcr |= BMCR_SPEED100;
125 break;
127 case 10:
128 bmsr |= BMSR_100HALF;
129 break;
133 regs[MII_BMCR] = bmcr;
134 regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/
136 return 0;
139 static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
141 struct fixed_info *fixed = bus->priv;
143 /* if user has registered link update callback, use it */
144 if(fixed->phydev)
145 if(fixed->phydev->attached_dev) {
146 if(fixed->link_update) {
147 fixed->link_update(fixed->phydev->attached_dev,
148 &fixed->phy_status);
149 fixed_mdio_update_regs(fixed);
153 if ((unsigned int)location >= fixed->regs_num)
154 return -1;
155 return fixed->regs[location];
158 static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
160 /* do nothing for now*/
161 return 0;
164 static int fixed_mii_reset(struct mii_bus *bus)
166 /*nothing here - no way/need to reset it*/
167 return 0;
169 #endif
171 static int fixed_config_aneg(struct phy_device *phydev)
173 /* :TODO:03/13/2006 09:45:37 PM::
174 The full autoneg funcionality can be emulated,
175 but no need to have anything here for now
177 return 0;
180 /*-----------------------------------------------------------------------------
181 * the manual bind will do the magic - with phy_id_mask == 0
182 * match will never return true...
183 *-----------------------------------------------------------------------------*/
184 static struct phy_driver fixed_mdio_driver = {
185 .name = "Fixed PHY",
186 .features = PHY_BASIC_FEATURES,
187 .config_aneg = fixed_config_aneg,
188 .read_status = genphy_read_status,
189 .driver = { .owner = THIS_MODULE,},
192 /*-----------------------------------------------------------------------------
193 * This func is used to create all the necessary stuff, bind
194 * the fixed phy driver and register all it on the mdio_bus_type.
195 * speed is either 10 or 100, duplex is boolean.
196 * number is used to create multiple fixed PHYs, so that several devices can
197 * utilize them simultaneously.
198 *-----------------------------------------------------------------------------*/
199 #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
200 static int fixed_mdio_register_device(int number, int speed, int duplex)
202 struct mii_bus *new_bus;
203 struct fixed_info *fixed;
204 struct phy_device *phydev;
205 int err = 0;
207 struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL);
209 if (NULL == dev)
210 return -ENOMEM;
212 new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
214 if (NULL == new_bus) {
215 kfree(dev);
216 return -ENOMEM;
218 fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
220 if (NULL == fixed) {
221 kfree(dev);
222 kfree(new_bus);
223 return -ENOMEM;
226 fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL);
227 fixed->regs_num = MII_REGS_NUM;
228 fixed->phy_status.speed = speed;
229 fixed->phy_status.duplex = duplex;
230 fixed->phy_status.link = 1;
232 new_bus->name = "Fixed MII Bus",
233 new_bus->read = &fixed_mii_read,
234 new_bus->write = &fixed_mii_write,
235 new_bus->reset = &fixed_mii_reset,
237 /*set up workspace*/
238 fixed_mdio_update_regs(fixed);
239 new_bus->priv = fixed;
241 new_bus->dev = dev;
242 dev_set_drvdata(dev, new_bus);
244 /* create phy_device and register it on the mdio bus */
245 phydev = phy_device_create(new_bus, 0, 0);
248 Put the phydev pointer into the fixed pack so that bus read/write code could
249 be able to access for instance attached netdev. Well it doesn't have to do
250 so, only in case of utilizing user-specified link-update...
252 fixed->phydev = phydev;
254 if(NULL == phydev) {
255 err = -ENOMEM;
256 goto device_create_fail;
259 phydev->irq = PHY_IGNORE_INTERRUPT;
260 phydev->dev.bus = &mdio_bus_type;
262 if(number)
263 snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
264 "fixed_%d@%d:%d", number, speed, duplex);
265 else
266 snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
267 "fixed@%d:%d", speed, duplex);
268 phydev->bus = new_bus;
270 err = device_register(&phydev->dev);
271 if(err) {
272 printk(KERN_ERR "Phy %s failed to register\n",
273 phydev->dev.bus_id);
274 goto bus_register_fail;
278 the mdio bus has phy_id match... In order not to do it
279 artificially, we are binding the driver here by hand;
280 it will be the same for all the fixed phys anyway.
282 phydev->dev.driver = &fixed_mdio_driver.driver;
284 err = phydev->dev.driver->probe(&phydev->dev);
285 if(err < 0) {
286 printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
287 goto probe_fail;
290 err = device_bind_driver(&phydev->dev);
291 if (err)
292 goto probe_fail;
294 return 0;
296 probe_fail:
297 device_unregister(&phydev->dev);
298 bus_register_fail:
299 kfree(phydev);
300 device_create_fail:
301 kfree(dev);
302 kfree(new_bus);
303 kfree(fixed);
305 return err;
307 #endif
310 MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
311 MODULE_AUTHOR("Vitaly Bordug");
312 MODULE_LICENSE("GPL");
314 static int __init fixed_init(void)
316 #if 0
317 int ret;
318 int duplex = 0;
319 #endif
321 /* register on the bus... Not expected to be matched with anything there... */
322 phy_driver_register(&fixed_mdio_driver);
324 /* So let the fun begin...
325 We will create several mdio devices here, and will bound the upper
326 driver to them.
328 Then the external software can lookup the phy bus by searching
329 fixed@speed:duplex, e.g. fixed@100:1, to be connected to the
330 virtual 100M Fdx phy.
332 In case several virtual PHYs required, the bus_id will be in form
333 fixed_<num>@<speed>:<duplex>, which make it able even to define
334 driver-specific link control callback, if for instance PHY is completely
335 SW-driven.
339 #ifdef CONFIG_FIXED_MII_DUPLEX
340 #if 0
341 duplex = 1;
342 #endif
343 #endif
345 #ifdef CONFIG_FIXED_MII_100_FDX
346 fixed_mdio_register_device(0, 100, 1);
347 #endif
349 #ifdef CONFIG_FIXED_MII_10_FDX
350 fixed_mdio_register_device(0, 10, 1);
351 #endif
352 return 0;
355 static void __exit fixed_exit(void)
357 phy_driver_unregister(&fixed_mdio_driver);
358 /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */
361 module_init(fixed_init);
362 module_exit(fixed_exit);