summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-01-07 11:57:51 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2014-01-07 11:57:51 +0100
commitc56fdbbc37cf676b42bbbf8d0efd0b78df4aed22 (patch)
tree6677350dc844c6fdb88c64401a1f965feb722557 /drivers
parent9d8c0841d2a893625c2eb5d7055cdf1615af5b8f (diff)
parent9bc898059000da9882f2f0561bfcff6d709e52ac (diff)
downloadbarebox-c56fdbbc37cf676b42bbbf8d0efd0b78df4aed22.tar.gz
barebox-c56fdbbc37cf676b42bbbf8d0efd0b78df4aed22.tar.xz
Merge branch 'for-next/miiphy'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/lxt.c31
-rw-r--r--drivers/net/phy/mdio_bus.c41
-rw-r--r--drivers/net/phy/phy.c108
5 files changed, 128 insertions, 58 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 83966f997f..7ebdaa0c01 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -13,6 +13,11 @@ config AT803X_PHY
---help---
Currently supports the AT8030, AT8031 and AT8035 PHYs.
+config LXT_PHY
+ bool "Driver for the Intel LXT PHYs"
+ ---help---
+ Currently supports the lxt971 PHY.
+
config MICREL_PHY
bool "Driver for Micrel PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 47e2b42331..451573ed83 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -1,4 +1,5 @@
obj-y += phy.o mdio_bus.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
+obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
new file mode 100644
index 0000000000..9e5ddbb426
--- /dev/null
+++ b/drivers/net/phy/lxt.c
@@ -0,0 +1,31 @@
+/*
+ * drivers/net/phy/lxt.c
+ *
+ * Driver for Intel LXT PHYs
+ *
+ * base on Andy Fleming's linux lxt.c driver
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <linux/phy.h>
+
+static struct phy_driver lxt97x_driver[] = {
+{
+ .phy_id = 0x001378e0,
+ .phy_id_mask = 0xfffffff0,
+ .drv.name = "LXT971",
+ .features = PHY_BASIC_FEATURES,
+} };
+
+static int lxt97x_phy_init(void)
+{
+ return phy_drivers_register(lxt97x_driver,
+ ARRAY_SIZE(lxt97x_driver));
+}
+fs_initcall(lxt97x_phy_init);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 87072be289..895ead0a5c 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -25,6 +25,30 @@
#include <linux/phy.h>
#include <linux/err.h>
+LIST_HEAD(mii_bus_list);
+
+int mdiobus_detect(struct device_d *dev)
+{
+ struct mii_bus *mii = to_mii_bus(dev);
+ int i, ret;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ struct phy_device *phydev;
+
+ phydev = mdiobus_scan(mii, i);
+ if (IS_ERR(phydev))
+ continue;
+ if (phydev->registered)
+ continue;
+ ret = phy_register_device(phydev);
+ if (ret)
+ dev_err(dev, "failed to register phy: %s\n", strerror(-ret));
+ dev_info(dev, "registered phy as /dev/%s\n", phydev->cdev.name);
+ }
+
+ return 0;
+}
+
/**
* mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
* @bus: target mii_bus
@@ -47,6 +71,7 @@ int mdiobus_register(struct mii_bus *bus)
bus->dev.id = DEVICE_ID_DYNAMIC;
strcpy(bus->dev.name, "miibus");
bus->dev.parent = bus->parent;
+ bus->dev.detect = mdiobus_detect;
err = register_device(&bus->dev);
if (err) {
@@ -57,6 +82,8 @@ int mdiobus_register(struct mii_bus *bus)
if (bus->reset)
bus->reset(bus);
+ list_add_tail(&bus->list, &mii_bus_list);
+
pr_info("%s: probed\n", dev_name(&bus->dev));
return 0;
}
@@ -71,6 +98,8 @@ void mdiobus_unregister(struct mii_bus *bus)
unregister_device(&bus->phy_map[i]->dev);
bus->phy_map[i] = NULL;
}
+
+ list_del(&bus->list);
}
EXPORT_SYMBOL(mdiobus_unregister);
@@ -153,8 +182,6 @@ static int mdio_bus_probe(struct device_d *_dev)
int ret;
- dev->attached_dev->phydev = dev;
-
if (drv->probe) {
ret = drv->probe(dev);
if (ret)
@@ -183,14 +210,6 @@ static int mdio_bus_probe(struct device_d *_dev)
dev->supported = drv->features;
dev->advertising = drv->features;
- ret = phy_init_hw(dev);
- if (ret)
- goto err;
-
- /* Sanitize settings based on PHY capabilities */
- if ((dev->supported & SUPPORTED_Autoneg) == 0)
- dev->autoneg = AUTONEG_DISABLE;
-
dev_add_param_int_ro(&dev->dev, "phy_addr", dev->addr, "%d");
dev_add_param_int_ro(&dev->dev, "phy_id", dev->phy_id, "0x%08x");
@@ -204,8 +223,6 @@ static int mdio_bus_probe(struct device_d *_dev)
return 0;
err:
- dev->attached_dev->phydev = NULL;
- dev->attached_dev = NULL;
return ret;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 2a33054589..6ca1bb2573 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -224,21 +224,40 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr)
return dev;
}
-static int phy_register_device(struct phy_device* dev)
+static void phy_config_aneg(struct phy_device *phydev)
+{
+ struct phy_driver *drv;
+
+ drv = to_phy_driver(phydev->dev.driver);
+ drv->config_aneg(phydev);
+}
+
+int phy_register_device(struct phy_device* dev)
{
int ret;
- dev->dev.parent = &dev->attached_dev->dev;
+ if (dev->registered)
+ return -EBUSY;
+
+ dev->dev.parent = &dev->bus->dev;
ret = register_device(&dev->dev);
if (ret)
return ret;
+ dev->registered = 1;
+
if (dev->dev.driver)
return 0;
dev->dev.driver = &genphy_driver.drv;
- return device_probe(&dev->dev);
+ ret = device_probe(&dev->dev);
+ if (ret) {
+ unregister_device(&dev->dev);
+ dev->registered = 0;
+ }
+
+ return ret;
}
/* Automatically gets and returns the PHY device */
@@ -246,66 +265,63 @@ int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
void (*adjust_link) (struct eth_device *edev),
u32 flags, phy_interface_t interface)
{
- struct phy_driver* drv;
struct phy_device* dev = NULL;
unsigned int i;
int ret = -EINVAL;
- if (!edev->phydev) {
- if (addr >= 0) {
- dev = mdiobus_scan(bus, addr);
- if (IS_ERR(dev)) {
- ret = -EIO;
- goto fail;
- }
-
- dev->attached_dev = edev;
- dev->interface = interface;
- dev->dev_flags = flags;
-
- ret = phy_register_device(dev);
- if (ret)
- goto fail;
- } else {
- for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
- /* skip masked out PHY addresses */
- if (bus->phy_mask & (1 << i))
- continue;
-
- dev = mdiobus_scan(bus, i);
- if (IS_ERR(dev) || dev->attached_dev)
- continue;
+ if (edev->phydev) {
+ phy_config_aneg(edev->phydev);
+ return 0;
+ }
- dev->attached_dev = edev;
- dev->interface = interface;
- dev->dev_flags = flags;
+ if (addr >= 0) {
+ dev = mdiobus_scan(bus, addr);
+ if (IS_ERR(dev)) {
+ ret = -EIO;
+ goto fail;
+ }
+ } else {
+ for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
+ /* skip masked out PHY addresses */
+ if (bus->phy_mask & (1 << i))
+ continue;
+
+ dev = mdiobus_scan(bus, i);
+ if (!IS_ERR(dev) && !dev->attached_dev)
+ break;
+ }
+ }
- ret = phy_register_device(dev);
- if (ret)
- goto fail;
+ if (dev->attached_dev)
+ return -EBUSY;
- break;
- }
- }
+ dev->interface = interface;
+ dev->dev_flags = flags;
- if (!edev->phydev) {
- ret = -EIO;
+ if (!dev->registered) {
+ ret = phy_register_device(dev);
+ if (ret)
goto fail;
- }
}
- dev = edev->phydev;
- drv = to_phy_driver(dev->dev.driver);
+ edev->phydev = dev;
+ dev->attached_dev = edev;
- drv->config_aneg(dev);
+ ret = phy_init_hw(dev);
+ if (ret)
+ goto fail;
+
+ /* Sanitize settings based on PHY capabilities */
+ if ((dev->supported & SUPPORTED_Autoneg) == 0)
+ dev->autoneg = AUTONEG_DISABLE;
+
+ phy_config_aneg(edev->phydev);
dev->adjust_link = adjust_link;
return 0;
fail:
- if (!IS_ERR(dev))
- dev->attached_dev = NULL;
puts("Unable to find a PHY (unknown ID?)\n");
return ret;
}
@@ -757,7 +773,7 @@ int phy_driver_register(struct phy_driver *phydrv)
return register_driver(&phydrv->drv);
}
-
+
int phy_drivers_register(struct phy_driver *new_driver, int n)
{
int i, ret = 0;