drivers/net/mdio/mdio-mscc-miim.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/mdio/mdio-mscc-miim.c
Extension
.c
Size
9508 bytes
Lines
392
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 mscc_miim_info {
	unsigned int phy_reset_offset;
	unsigned int phy_reset_bits;
};

struct mscc_miim_dev {
	struct regmap *regs;
	int mii_status_offset;
	bool ignore_read_errors;
	struct regmap *phy_regs;
	const struct mscc_miim_info *info;
	struct clk *clk;
	u32 bus_freq;
};

/* When high resolution timers aren't built-in: we can't use usleep_range() as
 * we would sleep way too long. Use udelay() instead.
 */
#define mscc_readx_poll_timeout(op, addr, val, cond, delay_us, timeout_us)\
({									  \
	if (!IS_ENABLED(CONFIG_HIGH_RES_TIMERS))			  \
		readx_poll_timeout_atomic(op, addr, val, cond, delay_us,  \
					  timeout_us);			  \
	readx_poll_timeout(op, addr, val, cond, delay_us, timeout_us);	  \
})

static int mscc_miim_status(struct mii_bus *bus)
{
	struct mscc_miim_dev *miim = bus->priv;
	int val, ret;

	ret = regmap_read(miim->regs,
			  MSCC_MIIM_REG_STATUS + miim->mii_status_offset, &val);
	if (ret < 0) {
		WARN_ONCE(1, "mscc miim status read error %d\n", ret);
		return ret;
	}

	return val;
}

static int mscc_miim_wait_ready(struct mii_bus *bus)
{
	u32 val;

	return mscc_readx_poll_timeout(mscc_miim_status, bus, val,
				       !(val & MSCC_MIIM_STATUS_STAT_BUSY), 50,
				       10000);
}

static int mscc_miim_wait_pending(struct mii_bus *bus)
{
	u32 val;

	return mscc_readx_poll_timeout(mscc_miim_status, bus, val,
				       !(val & MSCC_MIIM_STATUS_STAT_PENDING),
				       50, 10000);
}

static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum)
{
	struct mscc_miim_dev *miim = bus->priv;
	u32 val;
	int ret;

	ret = mscc_miim_wait_pending(bus);
	if (ret)
		goto out;

	ret = regmap_write(miim->regs,
			   MSCC_MIIM_REG_CMD + miim->mii_status_offset,
			   MSCC_MIIM_CMD_VLD |
			   (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
			   (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
			   MSCC_MIIM_CMD_OPR_READ);

	if (ret < 0) {
		WARN_ONCE(1, "mscc miim write cmd reg error %d\n", ret);
		goto out;
	}

	ret = mscc_miim_wait_ready(bus);
	if (ret)
		goto out;

	ret = regmap_read(miim->regs,
			  MSCC_MIIM_REG_DATA + miim->mii_status_offset, &val);
	if (ret < 0) {
		WARN_ONCE(1, "mscc miim read data reg error %d\n", ret);
		goto out;

Annotation

Implementation Notes