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>
22 #include <linux/err.h>
24 #define MII_REGS_NUM 29
26 struct fixed_mdio_bus
{
27 int irqs
[PHY_MAX_ADDR
];
28 struct mii_bus
*mii_bus
;
29 struct list_head phys
;
34 u16 regs
[MII_REGS_NUM
];
35 struct phy_device
*phydev
;
36 struct fixed_phy_status status
;
37 int (*link_update
)(struct net_device
*, struct fixed_phy_status
*);
38 struct list_head node
;
41 static struct platform_device
*pdev
;
42 static struct fixed_mdio_bus platform_fmb
= {
43 .phys
= LIST_HEAD_INIT(platform_fmb
.phys
),
46 static int fixed_phy_update_regs(struct fixed_phy
*fp
)
48 u16 bmsr
= BMSR_ANEGCAPABLE
;
53 if (fp
->status
.duplex
) {
54 bmcr
|= BMCR_FULLDPLX
;
56 switch (fp
->status
.speed
) {
59 bmcr
|= BMCR_SPEED1000
;
60 lpagb
|= LPA_1000FULL
;
64 bmcr
|= BMCR_SPEED100
;
72 printk(KERN_WARNING
"fixed phy: unknown speed\n");
76 switch (fp
->status
.speed
) {
79 bmcr
|= BMCR_SPEED1000
;
80 lpagb
|= LPA_1000HALF
;
84 bmcr
|= BMCR_SPEED100
;
92 printk(KERN_WARNING
"fixed phy: unknown speed\n");
98 bmsr
|= BMSR_LSTATUS
| BMSR_ANEGCOMPLETE
;
100 if (fp
->status
.pause
)
101 lpa
|= LPA_PAUSE_CAP
;
103 if (fp
->status
.asym_pause
)
104 lpa
|= LPA_PAUSE_ASYM
;
106 fp
->regs
[MII_PHYSID1
] = fp
->id
>> 16;
107 fp
->regs
[MII_PHYSID2
] = fp
->id
;
109 fp
->regs
[MII_BMSR
] = bmsr
;
110 fp
->regs
[MII_BMCR
] = bmcr
;
111 fp
->regs
[MII_LPA
] = lpa
;
112 fp
->regs
[MII_STAT1000
] = lpagb
;
117 static int fixed_mdio_read(struct mii_bus
*bus
, int phy_id
, int reg_num
)
119 struct fixed_mdio_bus
*fmb
= bus
->priv
;
120 struct fixed_phy
*fp
;
122 if (reg_num
>= MII_REGS_NUM
)
125 list_for_each_entry(fp
, &fmb
->phys
, node
) {
126 if (fp
->id
== phy_id
) {
127 /* Issue callback if user registered it. */
128 if (fp
->link_update
) {
129 fp
->link_update(fp
->phydev
->attached_dev
,
131 fixed_phy_update_regs(fp
);
133 return fp
->regs
[reg_num
];
140 static int fixed_mdio_write(struct mii_bus
*bus
, int phy_id
, int reg_num
,
147 * If something weird is required to be done with link/speed,
148 * network driver is able to assign a function to implement this.
149 * May be useful for PHY's that need to be software-driven.
151 int fixed_phy_set_link_update(struct phy_device
*phydev
,
152 int (*link_update
)(struct net_device
*,
153 struct fixed_phy_status
*))
155 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
156 struct fixed_phy
*fp
;
158 if (!link_update
|| !phydev
|| !phydev
->bus
)
161 list_for_each_entry(fp
, &fmb
->phys
, node
) {
162 if (fp
->id
== phydev
->phy_id
) {
163 fp
->link_update
= link_update
;
171 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update
);
173 int fixed_phy_add(unsigned int irq
, int phy_id
,
174 struct fixed_phy_status
*status
)
177 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
178 struct fixed_phy
*fp
;
180 fp
= kzalloc(sizeof(*fp
), GFP_KERNEL
);
184 memset(fp
->regs
, 0xFF, sizeof(fp
->regs
[0]) * MII_REGS_NUM
);
186 fmb
->irqs
[phy_id
] = irq
;
189 fp
->status
= *status
;
191 ret
= fixed_phy_update_regs(fp
);
195 list_add_tail(&fp
->node
, &fmb
->phys
);
203 EXPORT_SYMBOL_GPL(fixed_phy_add
);
205 static int __init
fixed_mdio_bus_init(void)
207 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
210 pdev
= platform_device_register_simple("Fixed MDIO bus", 0, NULL
, 0);
216 fmb
->mii_bus
= mdiobus_alloc();
217 if (fmb
->mii_bus
== NULL
) {
219 goto err_mdiobus_reg
;
222 snprintf(fmb
->mii_bus
->id
, MII_BUS_ID_SIZE
, "0");
223 fmb
->mii_bus
->name
= "Fixed MDIO Bus";
224 fmb
->mii_bus
->priv
= fmb
;
225 fmb
->mii_bus
->parent
= &pdev
->dev
;
226 fmb
->mii_bus
->read
= &fixed_mdio_read
;
227 fmb
->mii_bus
->write
= &fixed_mdio_write
;
228 fmb
->mii_bus
->irq
= fmb
->irqs
;
230 ret
= mdiobus_register(fmb
->mii_bus
);
232 goto err_mdiobus_alloc
;
237 mdiobus_free(fmb
->mii_bus
);
239 platform_device_unregister(pdev
);
243 module_init(fixed_mdio_bus_init
);
245 static void __exit
fixed_mdio_bus_exit(void)
247 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
248 struct fixed_phy
*fp
, *tmp
;
250 mdiobus_unregister(fmb
->mii_bus
);
251 mdiobus_free(fmb
->mii_bus
);
252 platform_device_unregister(pdev
);
254 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
259 module_exit(fixed_mdio_bus_exit
);
261 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
262 MODULE_AUTHOR("Vitaly Bordug");
263 MODULE_LICENSE("GPL");