staticvoid airoha_mdio_reset(struct airoha_mdio_data *priv)
{ /* There seems to be Hardware bug where AN7583_MII_RWDATA * is not wiped in the context of unconnected PHY and the * previous read value is returned. * * Example: (only one PHY on the BUS at 0x1f) * - read at 0x1f report at 0x2 0x7500 * - read at 0x0 report 0x7500 on every address * * To workaround this, we reset the Mdio BUS at every read * to have consistent values on read operation.
*/
reset_control_assert(priv->reset);
reset_control_deassert(priv->reset);
}
staticint airoha_mdio_read(struct mii_bus *bus, int addr, int regnum)
{ struct airoha_mdio_data *priv = bus->priv;
u32 val; int ret;
airoha_mdio_reset(priv);
val = AN7583_MII_BUSY | AN7583_MII_ST_CL22 |
AN7583_MII_CMD_CL22_READ;
val |= FIELD_PREP(AN7583_MII_PHY_ADDR, addr);
val |= FIELD_PREP(AN7583_MII_CL22_REG_ADDR, regnum);
ret = regmap_write(priv->regmap, priv->base_addr, val); if (ret) return ret;
ret = airoha_mdio_wait_busy(priv); if (ret) return ret;
ret = regmap_read(priv->regmap, priv->base_addr, &val); if (ret) return ret;
return FIELD_GET(AN7583_MII_RWDATA, val);
}
staticint airoha_mdio_write(struct mii_bus *bus, int addr, int regnum,
u16 value)
{ struct airoha_mdio_data *priv = bus->priv;
u32 val; int ret;
val = AN7583_MII_BUSY | AN7583_MII_ST_CL22 |
AN7583_MII_CMD_CL22_WRITE;
val |= FIELD_PREP(AN7583_MII_PHY_ADDR, addr);
val |= FIELD_PREP(AN7583_MII_CL22_REG_ADDR, regnum);
val |= FIELD_PREP(AN7583_MII_RWDATA, value);
ret = regmap_write(priv->regmap, priv->base_addr, val); if (ret) return ret;
ret = airoha_mdio_wait_busy(priv);
return ret;
}
staticint airoha_mdio_cl45_read(struct mii_bus *bus, int addr, int devnum, int regnum)
{ struct airoha_mdio_data *priv = bus->priv;
u32 val; int ret;
airoha_mdio_reset(priv);
val = AN7583_MII_BUSY | AN7583_MII_ST_CL45 |
AN7583_MII_CMD_CL45_ADDR;
val |= FIELD_PREP(AN7583_MII_PHY_ADDR, addr);
val |= FIELD_PREP(AN7583_MII_CL45_DEV_ADDR, devnum);
val |= FIELD_PREP(AN7583_MII_CL45_REG_ADDR, regnum);
ret = regmap_write(priv->regmap, priv->base_addr, val); if (ret) return ret;
ret = airoha_mdio_wait_busy(priv); if (ret) return ret;
val = AN7583_MII_BUSY | AN7583_MII_ST_CL45 |
AN7583_MII_CMD_CL45_READ;
val |= FIELD_PREP(AN7583_MII_PHY_ADDR, addr);
val |= FIELD_PREP(AN7583_MII_CL45_DEV_ADDR, devnum);
ret = regmap_write(priv->regmap, priv->base_addr, val); if (ret) return ret;
ret = airoha_mdio_wait_busy(priv); if (ret) return ret;
ret = regmap_read(priv->regmap, priv->base_addr, &val); if (ret) return ret;
return FIELD_GET(AN7583_MII_RWDATA, val);
}
staticint airoha_mdio_cl45_write(struct mii_bus *bus, int addr, int devnum, int regnum, u16 value)
{ struct airoha_mdio_data *priv = bus->priv;
u32 val; int ret;
val = AN7583_MII_BUSY | AN7583_MII_ST_CL45 |
AN7583_MII_CMD_CL45_ADDR;
val |= FIELD_PREP(AN7583_MII_PHY_ADDR, addr);
val |= FIELD_PREP(AN7583_MII_CL45_DEV_ADDR, devnum);
val |= FIELD_PREP(AN7583_MII_CL45_REG_ADDR, regnum);
ret = regmap_write(priv->regmap, priv->base_addr, val); if (ret) return ret;
ret = airoha_mdio_wait_busy(priv); if (ret) return ret;
val = AN7583_MII_BUSY | AN7583_MII_ST_CL45 |
AN7583_MII_CMD_CL45_WRITE;
val |= FIELD_PREP(AN7583_MII_PHY_ADDR, addr);
val |= FIELD_PREP(AN7583_MII_CL45_DEV_ADDR, devnum);
val |= FIELD_PREP(AN7583_MII_RWDATA, value);
ret = regmap_write(priv->regmap, priv->base_addr, val); if (ret) return ret;
/* Check if a custom frequency is defined in DT or default to 2.5 MHz */ if (of_property_read_u32(dev->of_node, "clock-frequency", &freq))
freq = 2500000;
ret = clk_set_rate(priv->clk, freq); if (ret) return ret;
ret = devm_of_mdiobus_register(dev, bus, dev->of_node); if (ret) {
reset_control_assert(priv->reset); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.