From c3452b50c3aaa0db2bb0bc68039fed4d40bedbc0 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Mon, 3 Jun 2019 19:10:30 +0300 Subject: net: introduce MDIO DM class for MDIO devices Adds UCLASS_MDIO DM class supporting MDIO buses that are probed as stand-alone devices. Useful in particular for systems that support DM_ETH and have a stand-alone MDIO hardware block shared by multiple Ethernet interfaces. Signed-off-by: Alex Marginean Reviewed-by: Bin Meng Acked-by: Joe Hershberger --- net/mdio-uclass.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 net/mdio-uclass.c (limited to 'net/mdio-uclass.c') diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c new file mode 100644 index 0000000000..36a404ff44 --- /dev/null +++ b/net/mdio-uclass.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 + * Alex Marginean, NXP + */ + +#include +#include +#include +#include +#include + +void dm_mdio_probe_devices(void) +{ + struct udevice *it; + struct uclass *uc; + + uclass_get(UCLASS_MDIO, &uc); + uclass_foreach_dev(it, uc) { + device_probe(it); + } +} + +static int dm_mdio_post_bind(struct udevice *dev) +{ + /* + * MDIO command doesn't like spaces in names, don't allow them to keep + * it happy + */ + if (strchr(dev->name, ' ')) { + debug("\nError: MDIO device name \"%s\" has a space!\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +/* + * Following read/write/reset functions are registered with legacy MII code. + * These are called for PHY operations by upper layers and we further call the + * DM MDIO driver functions. + */ +static int mdio_read(struct mii_dev *mii_bus, int addr, int devad, int reg) +{ + struct udevice *dev = mii_bus->priv; + + return mdio_get_ops(dev)->read(dev, addr, devad, reg); +} + +static int mdio_write(struct mii_dev *mii_bus, int addr, int devad, int reg, + u16 val) +{ + struct udevice *dev = mii_bus->priv; + + return mdio_get_ops(dev)->write(dev, addr, devad, reg, val); +} + +static int mdio_reset(struct mii_dev *mii_bus) +{ + struct udevice *dev = mii_bus->priv; + + if (mdio_get_ops(dev)->reset) + return mdio_get_ops(dev)->reset(dev); + else + return 0; +} + +static int dm_mdio_post_probe(struct udevice *dev) +{ + struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); + + pdata->mii_bus = mdio_alloc(); + pdata->mii_bus->read = mdio_read; + pdata->mii_bus->write = mdio_write; + pdata->mii_bus->reset = mdio_reset; + pdata->mii_bus->priv = dev; + strncpy(pdata->mii_bus->name, dev->name, MDIO_NAME_LEN); + + return mdio_register(pdata->mii_bus); +} + +static int dm_mdio_pre_remove(struct udevice *dev) +{ + struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); + struct mdio_ops *ops = mdio_get_ops(dev); + + if (ops->reset) + ops->reset(dev); + mdio_unregister(pdata->mii_bus); + mdio_free(pdata->mii_bus); + + return 0; +} + +struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, + struct udevice *ethdev, + phy_interface_t interface) +{ + struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); + + if (device_probe(dev)) + return 0; + + return phy_connect(pdata->mii_bus, addr, ethdev, interface); +} + +UCLASS_DRIVER(mdio) = { + .id = UCLASS_MDIO, + .name = "mdio", + .post_bind = dm_mdio_post_bind, + .post_probe = dm_mdio_post_probe, + .pre_remove = dm_mdio_pre_remove, + .per_device_auto_alloc_size = sizeof(struct mdio_perdev_priv), +}; -- cgit v1.2.3