Release 4.7 drivers/net/phy/fixed_phy.c
/*
* Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
*
* Author: Vitaly Bordug <vbordug@ru.mvista.com>
* Anton Vorontsov <avorontsov@ru.mvista.com>
*
* Copyright (c) 2006-2007 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/idr.h>
#define MII_REGS_NUM 29
struct fixed_mdio_bus {
struct mii_bus *mii_bus;
struct list_head phys;
};
struct fixed_phy {
int addr;
u16 regs[MII_REGS_NUM];
struct phy_device *phydev;
struct fixed_phy_status status;
int (*link_update)(struct net_device *, struct fixed_phy_status *);
struct list_head node;
int link_gpio;
};
static struct platform_device *pdev;
static struct fixed_mdio_bus platform_fmb = {
.phys = LIST_HEAD_INIT(platform_fmb.phys),
};
static int fixed_phy_update_regs(struct fixed_phy *fp)
{
u16 bmsr = BMSR_ANEGCAPABLE;
u16 bmcr = 0;
u16 lpagb = 0;
u16 lpa = 0;
if (gpio_is_valid(fp->link_gpio))
fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
if (fp->status.duplex) {
switch (fp->status.speed) {
case 1000:
bmsr |= BMSR_ESTATEN;
break;
case 100:
bmsr |= BMSR_100FULL;
break;
case 10:
bmsr |= BMSR_10FULL;
break;
default:
break;
}
} else {
switch (fp->status.speed) {
case 1000:
bmsr |= BMSR_ESTATEN;
break;
case 100:
bmsr |= BMSR_100HALF;
break;
case 10:
bmsr |= BMSR_10HALF;
break;
default:
break;
}
}
if (fp->status.link) {
bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
if (fp->status.duplex) {
bmcr |= BMCR_FULLDPLX;
switch (fp->status.speed) {
case 1000:
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000FULL;
break;
case 100:
bmcr |= BMCR_SPEED100;
lpa |= LPA_100FULL;
break;
case 10:
lpa |= LPA_10FULL;
break;
default:
pr_warn("fixed phy: unknown speed\n");
return -EINVAL;
}
} else {
switch (fp->status.speed) {
case 1000:
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000HALF;
break;
case 100:
bmcr |= BMCR_SPEED100;
lpa |= LPA_100HALF;
break;
case 10:
lpa |= LPA_10HALF;
break;
default:
pr_warn("fixed phy: unknown speed\n");
return -EINVAL;
}
}
if (fp->status.pause)
lpa |= LPA_PAUSE_CAP;
if (fp->status.asym_pause)
lpa |= LPA_PAUSE_ASYM;
}
fp->regs[MII_PHYSID1] = 0;
fp->regs[MII_PHYSID2] = 0;
fp->regs[MII_BMSR] = bmsr;
fp->regs[MII_BMCR] = bmcr;
fp->regs[MII_LPA] = lpa;
fp->regs[MII_STAT1000] = lpagb;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 229 | 63.97% | 2 | 28.57% |
andrew lunn | andrew lunn | 111 | 31.01% | 2 | 28.57% |
stas sergeev | stas sergeev | 14 | 3.91% | 1 | 14.29% |
joe perches | joe perches | 2 | 0.56% | 1 | 14.29% |
thomas petazzoni | thomas petazzoni | 2 | 0.56% | 1 | 14.29% |
| Total | 358 | 100.00% | 7 | 100.00% |
static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
{
struct fixed_mdio_bus *fmb = bus->priv;
struct fixed_phy *fp;
if (reg_num >= MII_REGS_NUM)
return -1;
/* We do not support emulating Clause 45 over Clause 22 register reads
* return an error instead of bogus data.
*/
switch (reg_num) {
case MII_MMD_CTRL:
case MII_MMD_DATA:
return -1;
default:
break;
}
list_for_each_entry(fp, &fmb->phys, node) {
if (fp->addr == phy_addr) {
/* Issue callback if user registered it. */
if (fp->link_update) {
fp->link_update(fp->phydev->attached_dev,
&fp->status);
fixed_phy_update_regs(fp);
}
return fp->regs[reg_num];
}
}
return 0xFFFF;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 97 | 80.17% | 2 | 40.00% |
florian fainelli | florian fainelli | 19 | 15.70% | 1 | 20.00% |
thomas petazzoni | thomas petazzoni | 3 | 2.48% | 1 | 20.00% |
lennert buytenhek | lennert buytenhek | 2 | 1.65% | 1 | 20.00% |
| Total | 121 | 100.00% | 5 | 100.00% |
static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
u16 val)
{
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 22 | 95.65% | 2 | 66.67% |
thomas petazzoni | thomas petazzoni | 1 | 4.35% | 1 | 33.33% |
| Total | 23 | 100.00% | 3 | 100.00% |
/*
* If something weird is required to be done with link/speed,
* network driver is able to assign a function to implement this.
* May be useful for PHY's that need to be software-driven.
*/
int fixed_phy_set_link_update(struct phy_device *phydev,
int (*link_update)(struct net_device *,
struct fixed_phy_status *))
{
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp;
if (!phydev || !phydev->mdio.bus)
return -EINVAL;
list_for_each_entry(fp, &fmb->phys, node) {
if (fp->addr == phydev->mdio.addr) {
fp->link_update = link_update;
fp->phydev = phydev;
return 0;
}
}
return -ENOENT;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 91 | 93.81% | 3 | 60.00% |
andrew lunn | andrew lunn | 4 | 4.12% | 1 | 20.00% |
thomas petazzoni | thomas petazzoni | 2 | 2.06% | 1 | 20.00% |
| Total | 97 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
int fixed_phy_update_state(struct phy_device *phydev,
const struct fixed_phy_status *status,
const struct fixed_phy_status *changed)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp;
if (!phydev || phydev->mdio.bus != fmb->mii_bus)
return -EINVAL;
list_for_each_entry(fp, &fmb->phys, node) {
if (fp->addr == phydev->mdio.addr) {
#define _UPD(x) if (changed->x) \
fp->status.x = status->x
_UPD(link);
_UPD(speed);
_UPD(duplex);
_UPD(pause);
_UPD(asym_pause);
#undef _UPD
fixed_phy_update_regs(fp);
return 0;
}
}
return -ENOENT;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
stas sergeev | stas sergeev | 117 | 93.60% | 1 | 33.33% |
russell king | russell king | 4 | 3.20% | 1 | 33.33% |
andrew lunn | andrew lunn | 4 | 3.20% | 1 | 33.33% |
| Total | 125 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(fixed_phy_update_state);
int fixed_phy_add(unsigned int irq, int phy_addr,
struct fixed_phy_status *status,
int link_gpio)
{
int ret;
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp;
fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (!fp)
return -ENOMEM;
memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM);
if (irq != PHY_POLL)
fmb->mii_bus->irq[phy_addr] = irq;
fp->addr = phy_addr;
fp->status = *status;
fp->link_gpio = link_gpio;
if (gpio_is_valid(fp->link_gpio)) {
ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN,
"fixed-link-gpio-link");
if (ret)
goto err_regs;
}
ret = fixed_phy_update_regs(fp);
if (ret)
goto err_gpio;
list_add_tail(&fp->node, &fmb->phys);
return 0;
err_gpio:
if (gpio_is_valid(fp->link_gpio))
gpio_free(fp->link_gpio);
err_regs:
kfree(fp);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 132 | 64.71% | 3 | 42.86% |
andrew lunn | andrew lunn | 62 | 30.39% | 2 | 28.57% |
rabin vincent | rabin vincent | 6 | 2.94% | 1 | 14.29% |
thomas petazzoni | thomas petazzoni | 4 | 1.96% | 1 | 14.29% |
| Total | 204 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL_GPL(fixed_phy_add);
static DEFINE_IDA(phy_fixed_ida);
static void fixed_phy_del(int phy_addr)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp, *tmp;
list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
if (fp->addr == phy_addr) {
list_del(&fp->node);
if (gpio_is_valid(fp->link_gpio))
gpio_free(fp->link_gpio);
kfree(fp);
ida_simple_remove(&phy_fixed_ida, phy_addr);
return;
}
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
thomas petazzoni | thomas petazzoni | 60 | 70.59% | 1 | 25.00% |
andrew lunn | andrew lunn | 17 | 20.00% | 2 | 50.00% |
florian fainelli | florian fainelli | 8 | 9.41% | 1 | 25.00% |
| Total | 85 | 100.00% | 4 | 100.00% |
struct phy_device *fixed_phy_register(unsigned int irq,
struct fixed_phy_status *status,
int link_gpio,
struct device_node *np)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
struct phy_device *phy;
int phy_addr;
int ret;
if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED)
return ERR_PTR(-EPROBE_DEFER);
/* Get the next available PHY address, up to PHY_MAX_ADDR */
phy_addr = ida_simple_get(&phy_fixed_ida, 0, PHY_MAX_ADDR, GFP_KERNEL);
if (phy_addr < 0)
return ERR_PTR(phy_addr);
ret = fixed_phy_add(irq, phy_addr, status, link_gpio);
if (ret < 0) {
ida_simple_remove(&phy_fixed_ida, phy_addr);
return ERR_PTR(ret);
}
phy = get_phy_device(fmb->mii_bus, phy_addr, false);
if (IS_ERR(phy)) {
fixed_phy_del(phy_addr);
return ERR_PTR(-EINVAL);
}
/* propagate the fixed link values to struct phy_device */
phy->link = status->link;
if (status->link) {
phy->speed = status->speed;
phy->duplex = status->duplex;
phy->pause = status->pause;
phy->asym_pause = status->asym_pause;
}
of_node_get(np);
phy->mdio.dev.of_node = np;
phy->is_pseudo_fixed_link = true;
switch (status->speed) {
case SPEED_1000:
phy->supported = PHY_1000BT_FEATURES;
break;
case SPEED_100:
phy->supported = PHY_100BT_FEATURES;
break;
case SPEED_10:
default:
phy->supported = PHY_10BT_FEATURES;
}
ret = phy_device_register(phy);
if (ret) {
phy_device_free(phy);
of_node_put(np);
fixed_phy_del(phy_addr);
return ERR_PTR(ret);
}
return phy;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
thomas petazzoni | thomas petazzoni | 144 | 47.06% | 1 | 10.00% |
madalin bucur | madalin bucur | 49 | 16.01% | 1 | 10.00% |
andrew lunn | andrew lunn | 45 | 14.71% | 3 | 30.00% |
florian fainelli | florian fainelli | 30 | 9.80% | 2 | 20.00% |
rabin vincent | rabin vincent | 22 | 7.19% | 1 | 10.00% |
petri gynther | petri gynther | 15 | 4.90% | 1 | 10.00% |
sergei shtylyov | sergei shtylyov | 1 | 0.33% | 1 | 10.00% |
| Total | 306 | 100.00% | 10 | 100.00% |
EXPORT_SYMBOL_GPL(fixed_phy_register);
void fixed_phy_unregister(struct phy_device *phy)
{
phy_device_remove(phy);
fixed_phy_del(phy->mdio.addr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andrew lunn | andrew lunn | 24 | 100.00% | 1 | 100.00% |
| Total | 24 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(fixed_phy_unregister);
static int __init fixed_mdio_bus_init(void)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
int ret;
pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
goto err_pdev;
}
fmb->mii_bus = mdiobus_alloc();
if (fmb->mii_bus == NULL) {
ret = -ENOMEM;
goto err_mdiobus_reg;
}
snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
fmb->mii_bus->name = "Fixed MDIO Bus";
fmb->mii_bus->priv = fmb;
fmb->mii_bus->parent = &pdev->dev;
fmb->mii_bus->read = &fixed_mdio_read;
fmb->mii_bus->write = &fixed_mdio_write;
ret = mdiobus_register(fmb->mii_bus);
if (ret)
goto err_mdiobus_alloc;
return 0;
err_mdiobus_alloc:
mdiobus_free(fmb->mii_bus);
err_mdiobus_reg:
platform_device_unregister(pdev);
err_pdev:
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 106 | 60.57% | 3 | 30.00% |
lennert buytenhek | lennert buytenhek | 49 | 28.00% | 3 | 30.00% |
dan carpenter | dan carpenter | 7 | 4.00% | 1 | 10.00% |
jeff garzik | jeff garzik | 6 | 3.43% | 1 | 10.00% |
andy fleming | andy fleming | 6 | 3.43% | 1 | 10.00% |
florian fainelli | florian fainelli | 1 | 0.57% | 1 | 10.00% |
| Total | 175 | 100.00% | 10 | 100.00% |
module_init(fixed_mdio_bus_init);
static void __exit fixed_mdio_bus_exit(void)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp, *tmp;
mdiobus_unregister(fmb->mii_bus);
mdiobus_free(fmb->mii_bus);
platform_device_unregister(pdev);
list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
list_del(&fp->node);
kfree(fp);
}
ida_destroy(&phy_fixed_ida);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 56 | 74.67% | 3 | 50.00% |
lennert buytenhek | lennert buytenhek | 7 | 9.33% | 1 | 16.67% |
florian fainelli | florian fainelli | 6 | 8.00% | 1 | 16.67% |
adrian bunk | adrian bunk | 6 | 8.00% | 1 | 16.67% |
| Total | 75 | 100.00% | 6 | 100.00% |
module_exit(fixed_mdio_bus_exit);
MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
MODULE_AUTHOR("Vitaly Bordug");
MODULE_LICENSE("GPL");
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vitaly bordug | vitaly bordug | 872 | 49.18% | 3 | 9.38% |
andrew lunn | andrew lunn | 278 | 15.68% | 6 | 18.75% |
thomas petazzoni | thomas petazzoni | 220 | 12.41% | 2 | 6.25% |
stas sergeev | stas sergeev | 136 | 7.67% | 2 | 6.25% |
florian fainelli | florian fainelli | 73 | 4.12% | 4 | 12.50% |
lennert buytenhek | lennert buytenhek | 59 | 3.33% | 3 | 9.38% |
madalin bucur | madalin bucur | 49 | 2.76% | 1 | 3.12% |
rabin vincent | rabin vincent | 28 | 1.58% | 1 | 3.12% |
petri gynther | petri gynther | 15 | 0.85% | 1 | 3.12% |
dan carpenter | dan carpenter | 10 | 0.56% | 1 | 3.12% |
jeff garzik | jeff garzik | 6 | 0.34% | 1 | 3.12% |
andy fleming | andy fleming | 6 | 0.34% | 1 | 3.12% |
adrian bunk | adrian bunk | 6 | 0.34% | 1 | 3.12% |
mark salter | mark salter | 5 | 0.28% | 1 | 3.12% |
russell king | russell king | 4 | 0.23% | 1 | 3.12% |
tejun heo | tejun heo | 3 | 0.17% | 1 | 3.12% |
joe perches | joe perches | 2 | 0.11% | 1 | 3.12% |
sergei shtylyov | sergei shtylyov | 1 | 0.06% | 1 | 3.12% |
| Total | 1773 | 100.00% | 32 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.