2 * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
4 * Author: Vitaly Bordug <vbordug@ru.mvista.com>
5 * Anton Vorontsov <avorontsov@ru.mvista.com>
7 * Copyright (c) 2006-2007 MontaVista Software, Inc.
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/list.h>
19 #include <linux/mii.h>
20 #include <linux/phy.h>
21 #include <linux/phy_fixed.h>
23 #define MII_REGS_NUM 29
25 struct fixed_mdio_bus
{
26 int irqs
[PHY_MAX_ADDR
];
27 struct mii_bus
*mii_bus
;
28 struct list_head phys
;
33 u16 regs
[MII_REGS_NUM
];
34 struct phy_device
*phydev
;
35 struct fixed_phy_status status
;
36 int (*link_update
)(struct net_device
*, struct fixed_phy_status
*);
37 struct list_head node
;
40 static struct platform_device
*pdev
;
41 static struct fixed_mdio_bus platform_fmb
= {
42 .phys
= LIST_HEAD_INIT(platform_fmb
.phys
),
45 static int fixed_phy_update_regs(struct fixed_phy
*fp
)
47 u16 bmsr
= BMSR_ANEGCAPABLE
;
52 if (fp
->status
.duplex
) {
53 bmcr
|= BMCR_FULLDPLX
;
55 switch (fp
->status
.speed
) {
58 bmcr
|= BMCR_SPEED1000
;
59 lpagb
|= LPA_1000FULL
;
63 bmcr
|= BMCR_SPEED100
;
71 printk(KERN_WARNING
"fixed phy: unknown speed\n");
75 switch (fp
->status
.speed
) {
78 bmcr
|= BMCR_SPEED1000
;
79 lpagb
|= LPA_1000HALF
;
83 bmcr
|= BMCR_SPEED100
;
91 printk(KERN_WARNING
"fixed phy: unknown speed\n");
97 bmsr
|= BMSR_LSTATUS
| BMSR_ANEGCOMPLETE
;
100 lpa
|= LPA_PAUSE_CAP
;
102 if (fp
->status
.asym_pause
)
103 lpa
|= LPA_PAUSE_ASYM
;
105 fp
->regs
[MII_PHYSID1
] = fp
->id
>> 16;
106 fp
->regs
[MII_PHYSID2
] = fp
->id
;
108 fp
->regs
[MII_BMSR
] = bmsr
;
109 fp
->regs
[MII_BMCR
] = bmcr
;
110 fp
->regs
[MII_LPA
] = lpa
;
111 fp
->regs
[MII_STAT1000
] = lpagb
;
116 static int fixed_mdio_read(struct mii_bus
*bus
, int phy_id
, int reg_num
)
118 struct fixed_mdio_bus
*fmb
= bus
->priv
;
119 struct fixed_phy
*fp
;
121 if (reg_num
>= MII_REGS_NUM
)
124 list_for_each_entry(fp
, &fmb
->phys
, node
) {
125 if (fp
->id
== phy_id
) {
126 /* Issue callback if user registered it. */
127 if (fp
->link_update
) {
128 fp
->link_update(fp
->phydev
->attached_dev
,
130 fixed_phy_update_regs(fp
);
132 return fp
->regs
[reg_num
];
139 static int fixed_mdio_write(struct mii_bus
*bus
, int phy_id
, int reg_num
,
146 * If something weird is required to be done with link/speed,
147 * network driver is able to assign a function to implement this.
148 * May be useful for PHY's that need to be software-driven.
150 int fixed_phy_set_link_update(struct phy_device
*phydev
,
151 int (*link_update
)(struct net_device
*,
152 struct fixed_phy_status
*))
154 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
155 struct fixed_phy
*fp
;
157 if (!link_update
|| !phydev
|| !phydev
->bus
)
160 list_for_each_entry(fp
, &fmb
->phys
, node
) {
161 if (fp
->id
== phydev
->phy_id
) {
162 fp
->link_update
= link_update
;
170 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update
);
172 int fixed_phy_add(unsigned int irq
, int phy_id
,
173 struct fixed_phy_status
*status
)
176 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
177 struct fixed_phy
*fp
;
179 fp
= kzalloc(sizeof(*fp
), GFP_KERNEL
);
183 memset(fp
->regs
, 0xFF, sizeof(fp
->regs
[0]) * MII_REGS_NUM
);
185 fmb
->irqs
[phy_id
] = irq
;
188 fp
->status
= *status
;
190 ret
= fixed_phy_update_regs(fp
);
194 list_add_tail(&fp
->node
, &fmb
->phys
);
202 EXPORT_SYMBOL_GPL(fixed_phy_add
);
204 static int __init
fixed_mdio_bus_init(void)
206 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
209 pdev
= platform_device_register_simple("Fixed MDIO bus", 0, NULL
, 0);
215 fmb
->mii_bus
= mdiobus_alloc();
216 if (fmb
->mii_bus
== NULL
) {
218 goto err_mdiobus_reg
;
221 snprintf(fmb
->mii_bus
->id
, MII_BUS_ID_SIZE
, "0");
222 fmb
->mii_bus
->name
= "Fixed MDIO Bus";
223 fmb
->mii_bus
->priv
= fmb
;
224 fmb
->mii_bus
->parent
= &pdev
->dev
;
225 fmb
->mii_bus
->read
= &fixed_mdio_read
;
226 fmb
->mii_bus
->write
= &fixed_mdio_write
;
227 fmb
->mii_bus
->irq
= fmb
->irqs
;
229 ret
= mdiobus_register(fmb
->mii_bus
);
231 goto err_mdiobus_alloc
;
236 mdiobus_free(fmb
->mii_bus
);
238 platform_device_unregister(pdev
);
242 module_init(fixed_mdio_bus_init
);
244 static void __exit
fixed_mdio_bus_exit(void)
246 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
247 struct fixed_phy
*fp
, *tmp
;
249 mdiobus_unregister(fmb
->mii_bus
);
250 mdiobus_free(fmb
->mii_bus
);
251 platform_device_unregister(pdev
);
253 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
258 module_exit(fixed_mdio_bus_exit
);
260 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
261 MODULE_AUTHOR("Vitaly Bordug");
262 MODULE_LICENSE("GPL");