drivers/net/mdio/mdio-airoha.c

Source file repositories/reference/linux-study-clean/drivers/net/mdio/mdio-airoha.c

File Facts

System
Linux kernel
Corpus path
drivers/net/mdio/mdio-airoha.c
Extension
.c
Size
7480 bytes
Lines
279
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct airoha_mdio_data {
	u32 base_addr;
	struct regmap *regmap;
	struct clk *clk;
	struct reset_control *reset;
};

static int airoha_mdio_wait_busy(struct airoha_mdio_data *priv)
{
	u32 busy;

	return regmap_read_poll_timeout(priv->regmap, priv->base_addr, busy,
					!(busy & AN7583_MII_BUSY),
					AN7583_MII_MDIO_DELAY_USEC,
					AN7583_MII_MDIO_RETRY_MSEC * USEC_PER_MSEC);
}

static void 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);
}

static int 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);
}

static int 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;
}

static int 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;

Annotation

Implementation Notes