drivers/net/ethernet/atheros/atl1c/atl1c_hw.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
Extension
.c
Size
23373 bytes
Lines
877
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

if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
			/* Enable OTP CLK */
			if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
				otp_ctrl_data |= OTP_CTRL_CLK_EN;
				AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
				AT_WRITE_FLUSH(hw);
				msleep(1);
			}
		}
		/* raise voltage temporally for l2cb */
		if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) {
			atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data);
			phy_data &= ~ANACTRL_HB_EN;
			atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data);
			atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
			phy_data |= VOLT_CTRL_SWLOWEST;
			atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
			udelay(20);
			raise_vol = true;
		}

		AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
		AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
		for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
			msleep(10);
			AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
			if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
				break;
		}
		if (i >= AT_TWSI_EEPROM_TIMEOUT)
			return -1;
	}
	/* Disable OTP_CLK */
	if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
		otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
		msleep(1);
	}
	if (raise_vol) {
		atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data);
		phy_data |= ANACTRL_HB_EN;
		atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data);
		atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
		phy_data &= ~VOLT_CTRL_SWLOWEST;
		atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
		udelay(20);
	}

	if (atl1c_read_current_addr(hw, hw->perm_mac_addr))
		return 0;

	return -1;
}

bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value)
{
	int i;
	bool ret = false;
	u32 otp_ctrl_data;
	u32 control;
	u32 data;

	if (offset & 3)
		return ret; /* address do not align */

	AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
	if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
		AT_WRITE_REG(hw, REG_OTP_CTRL,
				(otp_ctrl_data | OTP_CTRL_CLK_EN));

	AT_WRITE_REG(hw, REG_EEPROM_DATA_LO, 0);
	control = (offset & EEPROM_CTRL_ADDR_MASK) << EEPROM_CTRL_ADDR_SHIFT;
	AT_WRITE_REG(hw, REG_EEPROM_CTRL, control);

	for (i = 0; i < 10; i++) {
		udelay(100);
		AT_READ_REG(hw, REG_EEPROM_CTRL, &control);
		if (control & EEPROM_CTRL_RW)
			break;
	}
	if (control & EEPROM_CTRL_RW) {
		AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
		AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
		data = data & 0xFFFF;
		*p_value = swab32((data << 16) | (*p_value >> 16));
		ret = true;
	}
	if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);

Annotation

Implementation Notes