1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2019 4 * Alex Marginean, NXP 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <miiphy.h> 10 #include <dm/device-internal.h> 11 #include <dm/uclass-internal.h> 12 13 void dm_mdio_probe_devices(void) 14 { 15 struct udevice *it; 16 struct uclass *uc; 17 18 uclass_get(UCLASS_MDIO, &uc); 19 uclass_foreach_dev(it, uc) { 20 device_probe(it); 21 } 22 } 23 24 static int dm_mdio_post_bind(struct udevice *dev) 25 { 26 /* 27 * MDIO command doesn't like spaces in names, don't allow them to keep 28 * it happy 29 */ 30 if (strchr(dev->name, ' ')) { 31 debug("\nError: MDIO device name \"%s\" has a space!\n", 32 dev->name); 33 return -EINVAL; 34 } 35 36 return 0; 37 } 38 39 /* 40 * Following read/write/reset functions are registered with legacy MII code. 41 * These are called for PHY operations by upper layers and we further call the 42 * DM MDIO driver functions. 43 */ 44 static int mdio_read(struct mii_dev *mii_bus, int addr, int devad, int reg) 45 { 46 struct udevice *dev = mii_bus->priv; 47 48 return mdio_get_ops(dev)->read(dev, addr, devad, reg); 49 } 50 51 static int mdio_write(struct mii_dev *mii_bus, int addr, int devad, int reg, 52 u16 val) 53 { 54 struct udevice *dev = mii_bus->priv; 55 56 return mdio_get_ops(dev)->write(dev, addr, devad, reg, val); 57 } 58 59 static int mdio_reset(struct mii_dev *mii_bus) 60 { 61 struct udevice *dev = mii_bus->priv; 62 63 if (mdio_get_ops(dev)->reset) 64 return mdio_get_ops(dev)->reset(dev); 65 else 66 return 0; 67 } 68 69 static int dm_mdio_post_probe(struct udevice *dev) 70 { 71 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); 72 73 pdata->mii_bus = mdio_alloc(); 74 pdata->mii_bus->read = mdio_read; 75 pdata->mii_bus->write = mdio_write; 76 pdata->mii_bus->reset = mdio_reset; 77 pdata->mii_bus->priv = dev; 78 strncpy(pdata->mii_bus->name, dev->name, MDIO_NAME_LEN); 79 80 return mdio_register(pdata->mii_bus); 81 } 82 83 static int dm_mdio_pre_remove(struct udevice *dev) 84 { 85 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); 86 struct mdio_ops *ops = mdio_get_ops(dev); 87 88 if (ops->reset) 89 ops->reset(dev); 90 mdio_unregister(pdata->mii_bus); 91 mdio_free(pdata->mii_bus); 92 93 return 0; 94 } 95 96 struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, 97 struct udevice *ethdev, 98 phy_interface_t interface) 99 { 100 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); 101 102 if (device_probe(dev)) 103 return 0; 104 105 return phy_connect(pdata->mii_bus, addr, ethdev, interface); 106 } 107 108 UCLASS_DRIVER(mdio) = { 109 .id = UCLASS_MDIO, 110 .name = "mdio", 111 .post_bind = dm_mdio_post_bind, 112 .post_probe = dm_mdio_post_probe, 113 .pre_remove = dm_mdio_pre_remove, 114 .per_device_auto_alloc_size = sizeof(struct mdio_perdev_priv), 115 }; 116