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
= container_of(bus
, struct fixed_mdio_bus
,
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 snprintf(fmb
->mii_bus
.id
, MII_BUS_ID_SIZE
, "0");
217 fmb
->mii_bus
.name
= "Fixed MDIO Bus";
218 fmb
->mii_bus
.dev
= &pdev
->dev
;
219 fmb
->mii_bus
.read
= &fixed_mdio_read
;
220 fmb
->mii_bus
.write
= &fixed_mdio_write
;
221 fmb
->mii_bus
.irq
= fmb
->irqs
;
223 ret
= mdiobus_register(&fmb
->mii_bus
);
225 goto err_mdiobus_reg
;
230 platform_device_unregister(pdev
);
234 module_init(fixed_mdio_bus_init
);
236 static void __exit
fixed_mdio_bus_exit(void)
238 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
239 struct fixed_phy
*fp
, *tmp
;
241 mdiobus_unregister(&fmb
->mii_bus
);
242 platform_device_unregister(pdev
);
244 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
249 module_exit(fixed_mdio_bus_exit
);
251 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
252 MODULE_AUTHOR("Vitaly Bordug");
253 MODULE_LICENSE("GPL");