return 0;
 }
 
-/*
- * Write value to the PHY for this device to the register at regnum,waiting
- * until the write is done before it returns.  All PHY configuration has to be
- * done through the TSEC1 MIIM regs.
- */
-static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
+static int xgmac_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,
+                               u16 value)
 {
        struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
        struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
-       uint16_t dev_addr;
+       bool endian = priv->is_little_endian;
+       u16 dev_addr = regnum & 0x1f;
        u32 mdio_ctl, mdio_stat;
        int ret;
+
+       mdio_stat = xgmac_read32(®s->mdio_stat, endian);
+       mdio_stat &= ~MDIO_STAT_ENC;
+       xgmac_write32(mdio_stat, ®s->mdio_stat, endian);
+
+       ret = xgmac_wait_until_free(&bus->dev, regs, endian);
+       if (ret)
+               return ret;
+
+       /* Set the port and dev addr */
+       mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
+       xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);
+
+       /* Write the value to the register */
+       xgmac_write32(MDIO_DATA(value), ®s->mdio_data, endian);
+
+       ret = xgmac_wait_until_done(&bus->dev, regs, endian);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int xgmac_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
+                               int regnum, u16 value)
+{
+       struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
+       struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
        bool endian = priv->is_little_endian;
+       u32 mdio_ctl, mdio_stat;
+       int ret;
 
        mdio_stat = xgmac_read32(®s->mdio_stat, endian);
-       if (regnum & MII_ADDR_C45) {
-               /* Clause 45 (ie 10G) */
-               dev_addr = (regnum >> 16) & 0x1f;
-               mdio_stat |= MDIO_STAT_ENC;
-       } else {
-               /* Clause 22 (ie 1G) */
-               dev_addr = regnum & 0x1f;
-               mdio_stat &= ~MDIO_STAT_ENC;
-       }
+       mdio_stat |= MDIO_STAT_ENC;
 
        xgmac_write32(mdio_stat, ®s->mdio_stat, endian);
 
        xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);
 
        /* Set the register address */
-       if (regnum & MII_ADDR_C45) {
-               xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian);
+       xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian);
 
-               ret = xgmac_wait_until_free(&bus->dev, regs, endian);
-               if (ret)
-                       return ret;
-       }
+       ret = xgmac_wait_until_free(&bus->dev, regs, endian);
+       if (ret)
+               return ret;
 
        /* Write the value to the register */
        xgmac_write32(MDIO_DATA(value), ®s->mdio_data, endian);
        return 0;
 }
 
-/*
- * Reads from register regnum in the PHY for device dev, returning the value.
+/* Reads from register regnum in the PHY for device dev, returning the value.
  * Clears miimcom first.  All PHY configuration has to be done through the
  * TSEC1 MIIM regs.
  */
-static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+static int xgmac_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
 {
        struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
        struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
+       bool endian = priv->is_little_endian;
+       u16 dev_addr = regnum & 0x1f;
        unsigned long flags;
-       uint16_t dev_addr;
        uint32_t mdio_stat;
        uint32_t mdio_ctl;
        int ret;
-       bool endian = priv->is_little_endian;
 
        mdio_stat = xgmac_read32(®s->mdio_stat, endian);
-       if (regnum & MII_ADDR_C45) {
-               dev_addr = (regnum >> 16) & 0x1f;
-               mdio_stat |= MDIO_STAT_ENC;
+       mdio_stat &= ~MDIO_STAT_ENC;
+       xgmac_write32(mdio_stat, ®s->mdio_stat, endian);
+
+       ret = xgmac_wait_until_free(&bus->dev, regs, endian);
+       if (ret)
+               return ret;
+
+       /* Set the Port and Device Addrs */
+       mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
+       xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);
+
+       if (priv->has_a009885)
+               /* Once the operation completes, i.e. MDIO_STAT_BSY clears, we
+                * must read back the data register within 16 MDC cycles.
+                */
+               local_irq_save(flags);
+
+       /* Initiate the read */
+       xgmac_write32(mdio_ctl | MDIO_CTL_READ, ®s->mdio_ctl, endian);
+
+       ret = xgmac_wait_until_done(&bus->dev, regs, endian);
+       if (ret)
+               goto irq_restore;
+
+       /* Return all Fs if nothing was there */
+       if ((xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) &&
+           !priv->has_a011043) {
+               dev_dbg(&bus->dev,
+                       "Error while reading PHY%d reg at %d.%d\n",
+                       phy_id, dev_addr, regnum);
+               ret = 0xffff;
        } else {
-               dev_addr = regnum & 0x1f;
-               mdio_stat &= ~MDIO_STAT_ENC;
+               ret = xgmac_read32(®s->mdio_data, endian) & 0xffff;
+               dev_dbg(&bus->dev, "read %04x\n", ret);
        }
 
+irq_restore:
+       if (priv->has_a009885)
+               local_irq_restore(flags);
+
+       return ret;
+}
+
+/* Reads from register regnum in the PHY for device dev, returning the value.
+ * Clears miimcom first.  All PHY configuration has to be done through the
+ * TSEC1 MIIM regs.
+ */
+static int xgmac_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,
+                              int regnum)
+{
+       struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;
+       struct tgec_mdio_controller __iomem *regs = priv->mdio_base;
+       bool endian = priv->is_little_endian;
+       u32 mdio_stat, mdio_ctl;
+       unsigned long flags;
+       int ret;
+
+       mdio_stat = xgmac_read32(®s->mdio_stat, endian);
+       mdio_stat |= MDIO_STAT_ENC;
+
        xgmac_write32(mdio_stat, ®s->mdio_stat, endian);
 
        ret = xgmac_wait_until_free(&bus->dev, regs, endian);
        xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);
 
        /* Set the register address */
-       if (regnum & MII_ADDR_C45) {
-               xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian);
+       xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian);
 
-               ret = xgmac_wait_until_free(&bus->dev, regs, endian);
-               if (ret)
-                       return ret;
-       }
+       ret = xgmac_wait_until_free(&bus->dev, regs, endian);
+       if (ret)
+               return ret;
 
        if (priv->has_a009885)
                /* Once the operation completes, i.e. MDIO_STAT_BSY clears, we
                return -ENOMEM;
 
        bus->name = "Freescale XGMAC MDIO Bus";
-       bus->read = xgmac_mdio_read;
-       bus->write = xgmac_mdio_write;
+       bus->read = xgmac_mdio_read_c22;
+       bus->write = xgmac_mdio_write_c22;
+       bus->read_c45 = xgmac_mdio_read_c45;
+       bus->write_c45 = xgmac_mdio_write_c45;
        bus->parent = &pdev->dev;
        bus->probe_capabilities = MDIOBUS_C22_C45;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res->start);