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
;
55 if (fp
->status
.duplex
) {
56 bmcr
|= BMCR_FULLDPLX
;
58 switch (fp
->status
.speed
) {
61 bmcr
|= BMCR_SPEED1000
;
62 lpagb
|= LPA_1000FULL
;
66 bmcr
|= BMCR_SPEED100
;
74 pr_warn("fixed phy: unknown speed\n");
78 switch (fp
->status
.speed
) {
81 bmcr
|= BMCR_SPEED1000
;
82 lpagb
|= LPA_1000HALF
;
86 bmcr
|= BMCR_SPEED100
;
94 pr_warn("fixed phy: unknown speed\n");
100 bmsr
|= BMSR_LSTATUS
| BMSR_ANEGCOMPLETE
;
102 if (fp
->status
.pause
)
103 lpa
|= LPA_PAUSE_CAP
;
105 if (fp
->status
.asym_pause
)
106 lpa
|= LPA_PAUSE_ASYM
;
108 fp
->regs
[MII_PHYSID1
] = 0;
109 fp
->regs
[MII_PHYSID2
] = 0;
111 fp
->regs
[MII_BMSR
] = bmsr
;
112 fp
->regs
[MII_BMCR
] = bmcr
;
113 fp
->regs
[MII_LPA
] = lpa
;
114 fp
->regs
[MII_STAT1000
] = lpagb
;
119 static int fixed_mdio_read(struct mii_bus
*bus
, int phy_addr
, int reg_num
)
121 struct fixed_mdio_bus
*fmb
= bus
->priv
;
122 struct fixed_phy
*fp
;
124 if (reg_num
>= MII_REGS_NUM
)
127 /* We do not support emulating Clause 45 over Clause 22 register reads
128 * return an error instead of bogus data.
138 list_for_each_entry(fp
, &fmb
->phys
, node
) {
139 if (fp
->addr
== phy_addr
) {
140 /* Issue callback if user registered it. */
141 if (fp
->link_update
) {
142 fp
->link_update(fp
->phydev
->attached_dev
,
144 fixed_phy_update_regs(fp
);
146 return fp
->regs
[reg_num
];
153 static int fixed_mdio_write(struct mii_bus
*bus
, int phy_addr
, int reg_num
,
160 * If something weird is required to be done with link/speed,
161 * network driver is able to assign a function to implement this.
162 * May be useful for PHY's that need to be software-driven.
164 int fixed_phy_set_link_update(struct phy_device
*phydev
,
165 int (*link_update
)(struct net_device
*,
166 struct fixed_phy_status
*))
168 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
169 struct fixed_phy
*fp
;
171 if (!phydev
|| !phydev
->bus
)
174 list_for_each_entry(fp
, &fmb
->phys
, node
) {
175 if (fp
->addr
== phydev
->addr
) {
176 fp
->link_update
= link_update
;
184 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update
);
186 int fixed_phy_update_state(struct phy_device
*phydev
,
187 const struct fixed_phy_status
*status
,
188 const struct fixed_phy_status
*changed
)
190 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
191 struct fixed_phy
*fp
;
193 if (!phydev
|| !phydev
->bus
)
196 list_for_each_entry(fp
, &fmb
->phys
, node
) {
197 if (fp
->addr
== phydev
->addr
) {
198 #define _UPD(x) if (changed->x) \
199 fp->status.x = status->x
206 fixed_phy_update_regs(fp
);
213 EXPORT_SYMBOL(fixed_phy_update_state
);
215 int fixed_phy_add(unsigned int irq
, int phy_addr
,
216 struct fixed_phy_status
*status
)
219 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
220 struct fixed_phy
*fp
;
222 fp
= kzalloc(sizeof(*fp
), GFP_KERNEL
);
226 memset(fp
->regs
, 0xFF, sizeof(fp
->regs
[0]) * MII_REGS_NUM
);
228 fmb
->irqs
[phy_addr
] = irq
;
231 fp
->status
= *status
;
233 ret
= fixed_phy_update_regs(fp
);
237 list_add_tail(&fp
->node
, &fmb
->phys
);
245 EXPORT_SYMBOL_GPL(fixed_phy_add
);
247 void fixed_phy_del(int phy_addr
)
249 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
250 struct fixed_phy
*fp
, *tmp
;
252 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
253 if (fp
->addr
== phy_addr
) {
260 EXPORT_SYMBOL_GPL(fixed_phy_del
);
262 static int phy_fixed_addr
;
263 static DEFINE_SPINLOCK(phy_fixed_addr_lock
);
265 struct phy_device
*fixed_phy_register(unsigned int irq
,
266 struct fixed_phy_status
*status
,
267 struct device_node
*np
)
269 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
270 struct phy_device
*phy
;
274 /* Get the next available PHY address, up to PHY_MAX_ADDR */
275 spin_lock(&phy_fixed_addr_lock
);
276 if (phy_fixed_addr
== PHY_MAX_ADDR
) {
277 spin_unlock(&phy_fixed_addr_lock
);
278 return ERR_PTR(-ENOSPC
);
280 phy_addr
= phy_fixed_addr
++;
281 spin_unlock(&phy_fixed_addr_lock
);
283 ret
= fixed_phy_add(PHY_POLL
, phy_addr
, status
);
287 phy
= get_phy_device(fmb
->mii_bus
, phy_addr
, false);
288 if (!phy
|| IS_ERR(phy
)) {
289 fixed_phy_del(phy_addr
);
290 return ERR_PTR(-EINVAL
);
294 phy
->dev
.of_node
= np
;
296 ret
= phy_device_register(phy
);
298 phy_device_free(phy
);
300 fixed_phy_del(phy_addr
);
306 EXPORT_SYMBOL_GPL(fixed_phy_register
);
308 static int __init
fixed_mdio_bus_init(void)
310 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
313 pdev
= platform_device_register_simple("Fixed MDIO bus", 0, NULL
, 0);
319 fmb
->mii_bus
= mdiobus_alloc();
320 if (fmb
->mii_bus
== NULL
) {
322 goto err_mdiobus_reg
;
325 snprintf(fmb
->mii_bus
->id
, MII_BUS_ID_SIZE
, "fixed-0");
326 fmb
->mii_bus
->name
= "Fixed MDIO Bus";
327 fmb
->mii_bus
->priv
= fmb
;
328 fmb
->mii_bus
->parent
= &pdev
->dev
;
329 fmb
->mii_bus
->read
= &fixed_mdio_read
;
330 fmb
->mii_bus
->write
= &fixed_mdio_write
;
331 fmb
->mii_bus
->irq
= fmb
->irqs
;
333 ret
= mdiobus_register(fmb
->mii_bus
);
335 goto err_mdiobus_alloc
;
340 mdiobus_free(fmb
->mii_bus
);
342 platform_device_unregister(pdev
);
346 module_init(fixed_mdio_bus_init
);
348 static void __exit
fixed_mdio_bus_exit(void)
350 struct fixed_mdio_bus
*fmb
= &platform_fmb
;
351 struct fixed_phy
*fp
, *tmp
;
353 mdiobus_unregister(fmb
->mii_bus
);
354 mdiobus_free(fmb
->mii_bus
);
355 platform_device_unregister(pdev
);
357 list_for_each_entry_safe(fp
, tmp
, &fmb
->phys
, node
) {
362 module_exit(fixed_mdio_bus_exit
);
364 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
365 MODULE_AUTHOR("Vitaly Bordug");
366 MODULE_LICENSE("GPL");