to ensure the integrated PHY is used. The absence of this property indicates
   the muxers should be configured so that the external PHY is used.
 
+- reset-gpios: The GPIO phandle and specifier for the PHY reset signal.
+
 Example:
 
 ethernet-phy@0 {
 
 
 struct at803x_priv {
        bool phy_reset:1;
-       struct gpio_desc *gpiod_reset;
 };
 
 struct at803x_context {
 {
        struct device *dev = &phydev->mdio.dev;
        struct at803x_priv *priv;
-       struct gpio_desc *gpiod_reset;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       if (phydev->drv->phy_id != ATH8030_PHY_ID)
-               goto does_not_require_reset_workaround;
-
-       gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
-       if (IS_ERR(gpiod_reset))
-               return PTR_ERR(gpiod_reset);
-
-       priv->gpiod_reset = gpiod_reset;
-
-does_not_require_reset_workaround:
        phydev->priv = priv;
 
        return 0;
         * cannot recover from by software.
         */
        if (phydev->state == PHY_NOLINK) {
-               if (priv->gpiod_reset && !priv->phy_reset) {
+               if (phydev->mdio.reset && !priv->phy_reset) {
                        struct at803x_context context;
 
                        at803x_context_save(phydev, &context);
 
-                       gpiod_set_value(priv->gpiod_reset, 1);
+                       phy_device_reset(phydev, 1);
                        msleep(1);
-                       gpiod_set_value(priv->gpiod_reset, 0);
+                       phy_device_reset(phydev, 0);
                        msleep(1);
 
                        at803x_context_restore(phydev, &context);
 
 #include <linux/phy.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/gpio/consumer.h>
 
 #include <asm/irq.h>
 
 
 int mdiobus_register_device(struct mdio_device *mdiodev)
 {
+       struct gpio_desc *gpiod = NULL;
+
        if (mdiodev->bus->mdio_map[mdiodev->addr])
                return -EBUSY;
 
+       /* Deassert the optional reset signal */
+       if (mdiodev->dev.of_node)
+               gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode,
+                                              "reset-gpios", 0, GPIOD_OUT_LOW,
+                                              "PHY reset");
+       if (PTR_ERR(gpiod) == -ENOENT)
+               gpiod = NULL;
+       else if (IS_ERR(gpiod))
+               return PTR_ERR(gpiod);
+
+       mdiodev->reset = gpiod;
+
+       /* Assert the reset signal again */
+       mdio_device_reset(mdiodev, 1);
+
        mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;
 
        return 0;
                if (!mdiodev)
                        continue;
 
+               if (mdiodev->reset)
+                       gpiod_put(mdiodev->reset);
+
                mdiodev->device_remove(mdiodev);
                mdiodev->device_free(mdiodev);
        }
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 }
 EXPORT_SYMBOL(mdio_device_remove);
 
+void mdio_device_reset(struct mdio_device *mdiodev, int value)
+{
+       if (mdiodev->reset)
+               gpiod_set_value(mdiodev->reset, value);
+}
+EXPORT_SYMBOL(mdio_device_reset);
+
 /**
  * mdio_probe - probe an MDIO device
  * @dev: device to probe
        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
        int err = 0;
 
-       if (mdiodrv->probe)
+       if (mdiodrv->probe) {
+               /* Deassert the reset signal */
+               mdio_device_reset(mdiodev, 0);
+
                err = mdiodrv->probe(mdiodev);
+               if (err) {
+                       /* Assert the reset signal */
+                       mdio_device_reset(mdiodev, 1);
+               }
+       }
 
        return err;
 }
        struct device_driver *drv = mdiodev->dev.driver;
        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 
-       if (mdiodrv->remove)
+       if (mdiodrv->remove) {
                mdiodrv->remove(mdiodev);
 
+               /* Assert the reset signal */
+               mdio_device_reset(mdiodev, 1);
+       }
+
        return 0;
 }
 
 
        if (err)
                return err;
 
+       /* Deassert the reset signal */
+       phy_device_reset(phydev, 0);
+
        /* Run all of the fixups for this PHY */
        err = phy_scan_fixups(phydev);
        if (err) {
        return 0;
 
  out:
+       /* Assert the reset signal */
+       phy_device_reset(phydev, 1);
+
        mdiobus_unregister_device(&phydev->mdio);
        return err;
 }
 void phy_device_remove(struct phy_device *phydev)
 {
        device_del(&phydev->mdio.dev);
+
+       /* Assert the reset signal */
+       phy_device_reset(phydev, 1);
+
        mdiobus_unregister_device(&phydev->mdio);
 }
 EXPORT_SYMBOL(phy_device_remove);
 {
        int ret = 0;
 
+       /* Deassert the reset signal */
+       phy_device_reset(phydev, 0);
+
        if (!phydev->drv || !phydev->drv->config_init)
                return 0;
 
        put_device(&phydev->mdio.dev);
        if (ndev_owner != bus->owner)
                module_put(bus->owner);
+
+       /* Assert the reset signal */
+       phy_device_reset(phydev, 1);
 }
 EXPORT_SYMBOL(phy_detach);
 
        /* Set the state to READY by default */
        phydev->state = PHY_READY;
 
-       if (phydev->drv->probe)
+       if (phydev->drv->probe) {
+               /* Deassert the reset signal */
+               phy_device_reset(phydev, 0);
+
                err = phydev->drv->probe(phydev);
+               if (err) {
+                       /* Assert the reset signal */
+                       phy_device_reset(phydev, 1);
+               }
+       }
 
        mutex_unlock(&phydev->lock);
 
        phydev->state = PHY_DOWN;
        mutex_unlock(&phydev->lock);
 
-       if (phydev->drv && phydev->drv->remove)
+       if (phydev->drv && phydev->drv->remove) {
                phydev->drv->remove(phydev);
+
+               /* Assert the reset signal */
+               phy_device_reset(phydev, 1);
+       }
        phydev->drv = NULL;
 
        return 0;
 
 #include <uapi/linux/mdio.h>
 #include <linux/mod_devicetable.h>
 
+struct gpio_desc;
 struct mii_bus;
 
 /* Multiple levels of nesting are possible. However typically this is
        /* Bus address of the MDIO device (0-31) */
        int addr;
        int flags;
+       struct gpio_desc *reset;
 };
 #define to_mdio_device(d) container_of(d, struct mdio_device, dev)
 
 struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr);
 int mdio_device_register(struct mdio_device *mdiodev);
 void mdio_device_remove(struct mdio_device *mdiodev);
+void mdio_device_reset(struct mdio_device *mdiodev, int value);
 int mdio_driver_register(struct mdio_driver *drv);
 void mdio_driver_unregister(struct mdio_driver *drv);
 int mdio_device_bus_match(struct device *dev, struct device_driver *drv);
 
 int phy_stop_interrupts(struct phy_device *phydev);
 int phy_restart_aneg(struct phy_device *phydev);
 
+static inline void phy_device_reset(struct phy_device *phydev, int value)
+{
+       mdio_device_reset(&phydev->mdio, value);
+}
+
 #define phydev_err(_phydev, format, args...)   \
        dev_err(&_phydev->mdio.dev, format, ##args)