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>
23 #include <linux/slab.h>
26 #define MII_REGS_NUM 29
28 struct fixed_mdio_bus
{
29 int irqs
[PHY_MAX_ADDR
];
30 struct mii_bus
*mii_bus
;
31 struct list_head phys
;
36 u16 regs
[MII_REGS_NUM
];
37 struct phy_device
*phydev
;
38 struct fixed_phy_status status
;
39 int (*link_update
)(struct net_device
*, struct fixed_phy_status
*);
40 struct list_head node
;
43 static struct platform_device
*pdev
;
44 static struct fixed_mdio_bus platform_fmb
= {
45 .phys
= LIST_HEAD_INIT(platform_fmb
.phys
),
48 static int fixed_phy_update_regs(struct fixed_phy
*fp
)
50 u16 bmsr
= BMSR_ANEGCAPABLE
;
57 bmsr
|= BMSR_LSTATUS
| BMSR_ANEGCOMPLETE
;
59 if (fp
->status
.duplex
) {
60 bmcr
|= BMCR_FULLDPLX
;
62 switch (fp
->status
.speed
) {
65 bmcr
|= BMCR_SPEED1000
;
66 lpagb
|= LPA_1000FULL
;
70 bmcr
|= BMCR_SPEED100
;
78 pr_warn("fixed phy: unknown speed\n");
82 switch (fp
->status
.speed
) {
85 bmcr
|= BMCR_SPEED1000
;
86 lpagb
|= LPA_1000HALF
;
90 bmcr
|= BMCR_SPEED100
;
98 pr_warn("fixed phy: unknown speed\n");
103 if (fp
->status
.pause
)
104 lpa
|= LPA_PAUSE_CAP
;
106 if (fp
->status
.asym_pause
)
107 lpa
|= LPA_PAUSE_ASYM
;
110 fp
->regs
[MII_PHYSID1
] = 0;
111 fp
->regs
[MII_PHYSID2
] = 0;
113 fp
->regs
[MII_BMSR
] = bmsr
;
114 fp
->regs
[MII_BMCR
] = bmcr
;
115 fp
->regs
[MII_LPA
] = lpa
;
116 fp
->regs
[MII_STAT1000
] = lpagb
;
121 static int fixed_mdio_read(struct mii_bus
*bus
, int phy_addr
, int reg_num
)
123 struct fixed_mdio_bus
*fmb
= bus
->priv
;
124 struct fixed_phy
*fp
;
126 if (reg_num
>= MII_REGS_NUM
)
129 /* We do not support emulating Clause 45 over Clause 22 register reads
130 * return an error instead of bogus data.
140 list_for_each_entry(fp
, &fmb
->phys
, node
) {
141 if (fp
->addr
== phy_addr
) {
142 /* Issue callback if user registered it. */
143 if (fp
->link_update
) {
144 fp
->link_update(fp
->phydev
->attached_dev
,
146 fixed_phy_update_regs(fp
);
148 return fp
->regs
[reg_num
];
155 static int fixed_mdio_write(struct mii_bus
*bus
, int phy_addr
, int reg_num
,
162 * If something weird is required to be done with link/speed,
163 * network driver is able to assign a function to implement this.
164 * May be useful for PHY's that need to be software-driven.
166 int fixed_phy_set_link_update(struct phy_device
*phydev
,
167 int (*link_update
)(struct net_device
*,
168 struct fixed_phy_status
*))
170 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
171 struct fixed_phy
*fp
;
173 if (!phydev
|| !phydev
->bus
)
176 list_for_each_entry(fp
, &fmb
->phys
, node
) {
177 if (fp
->addr
== phydev
->addr
) {
178 fp
->link_update
= link_update
;
186 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update
);
188 int fixed_phy_update_state(struct phy_device
*phydev
,
189 const struct fixed_phy_status
*status
,
190 const struct fixed_phy_status
*changed
)
192 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
193 struct fixed_phy
*fp
;
195 if (!phydev
|| !phydev
->bus
)
198 list_for_each_entry(fp
, &fmb
->phys
, node
) {
199 if (fp
->addr
== phydev
->addr
) {
200 #define _UPD(x) if (changed->x) \
201 fp->status.x = status->x
208 fixed_phy_update_regs(fp
);
215 EXPORT_SYMBOL(fixed_phy_update_state
);
217 int fixed_phy_add(unsigned int irq
, int phy_addr
,
218 struct fixed_phy_status
*status
)
221 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
222 struct fixed_phy
*fp
;
224 fp
= kzalloc(sizeof(*fp
), GFP_KERNEL
);
228 memset(fp
->regs
, 0xFF, sizeof(fp
->regs
[0]) * MII_REGS_NUM
);
230 fmb
->irqs
[phy_addr
] = irq
;
233 fp
->status
= *status
;
235 ret
= fixed_phy_update_regs(fp
);
239 list_add_tail(&fp
->node
, &fmb
->phys
);
247 EXPORT_SYMBOL_GPL(fixed_phy_add
);
249 void fixed_phy_del(int phy_addr
)
251 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
252 struct fixed_phy
*fp
, *tmp
;
254 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
255 if (fp
->addr
== phy_addr
) {
262 EXPORT_SYMBOL_GPL(fixed_phy_del
);
264 static int phy_fixed_addr
;
265 static DEFINE_SPINLOCK(phy_fixed_addr_lock
);
267 struct phy_device
*fixed_phy_register(unsigned int irq
,
268 struct fixed_phy_status
*status
,
269 struct device_node
*np
)
271 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
272 struct phy_device
*phy
;
276 /* Get the next available PHY address, up to PHY_MAX_ADDR */
277 spin_lock(&phy_fixed_addr_lock
);
278 if (phy_fixed_addr
== PHY_MAX_ADDR
) {
279 spin_unlock(&phy_fixed_addr_lock
);
280 return ERR_PTR(-ENOSPC
);
282 phy_addr
= phy_fixed_addr
++;
283 spin_unlock(&phy_fixed_addr_lock
);
285 ret
= fixed_phy_add(PHY_POLL
, phy_addr
, status
);
289 phy
= get_phy_device(fmb
->mii_bus
, phy_addr
, false);
290 if (!phy
|| IS_ERR(phy
)) {
291 fixed_phy_del(phy_addr
);
292 return ERR_PTR(-EINVAL
);
296 phy
->dev
.of_node
= np
;
298 ret
= phy_device_register(phy
);
300 phy_device_free(phy
);
302 fixed_phy_del(phy_addr
);
308 EXPORT_SYMBOL_GPL(fixed_phy_register
);
310 static int __init
fixed_mdio_bus_init(void)
312 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
315 pdev
= platform_device_register_simple("Fixed MDIO bus", 0, NULL
, 0);
321 fmb
->mii_bus
= mdiobus_alloc();
322 if (fmb
->mii_bus
== NULL
) {
324 goto err_mdiobus_reg
;
327 snprintf(fmb
->mii_bus
->id
, MII_BUS_ID_SIZE
, "fixed-0");
328 fmb
->mii_bus
->name
= "Fixed MDIO Bus";
329 fmb
->mii_bus
->priv
= fmb
;
330 fmb
->mii_bus
->parent
= &pdev
->dev
;
331 fmb
->mii_bus
->read
= &fixed_mdio_read
;
332 fmb
->mii_bus
->write
= &fixed_mdio_write
;
333 fmb
->mii_bus
->irq
= fmb
->irqs
;
335 ret
= mdiobus_register(fmb
->mii_bus
);
337 goto err_mdiobus_alloc
;
342 mdiobus_free(fmb
->mii_bus
);
344 platform_device_unregister(pdev
);
348 module_init(fixed_mdio_bus_init
);
350 static void __exit
fixed_mdio_bus_exit(void)
352 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
353 struct fixed_phy
*fp
, *tmp
;
355 mdiobus_unregister(fmb
->mii_bus
);
356 mdiobus_free(fmb
->mii_bus
);
357 platform_device_unregister(pdev
);
359 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
364 module_exit(fixed_mdio_bus_exit
);
366 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
367 MODULE_AUTHOR("Vitaly Bordug");
368 MODULE_LICENSE("GPL");