drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c

Source file repositories/reference/linux-study-clean/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c
Extension
.c
Size
12499 bytes
Lines
442
Domain
Driver Families
Bucket
drivers/misc
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 pci1xxxx_otp_eeprom_device {
	struct auxiliary_device *pdev;
	void __iomem *reg_base;
	struct nvmem_config nvmem_config_eeprom;
	struct nvmem_device *nvmem_eeprom;
	struct nvmem_config nvmem_config_otp;
	struct nvmem_device *nvmem_otp;
};

static int set_sys_lock(struct pci1xxxx_otp_eeprom_device *priv)
{
	void __iomem *sys_lock = priv->reg_base +
				 MMAP_CFG_OFFSET(CFG_SYS_LOCK_OFFSET);
	u8 data;

	writel(CFG_SYS_LOCK_PF3, sys_lock);
	data = readl(sys_lock);
	if (data != CFG_SYS_LOCK_PF3)
		return -EPERM;

	return 0;
}

static void release_sys_lock(struct pci1xxxx_otp_eeprom_device *priv)
{
	void __iomem *sys_lock = priv->reg_base +
				 MMAP_CFG_OFFSET(CFG_SYS_LOCK_OFFSET);
	writel(0, sys_lock);
}

static bool is_eeprom_responsive(struct pci1xxxx_otp_eeprom_device *priv)
{
	void __iomem *rb = priv->reg_base;
	u32 regval;
	int ret;

	writel(EEPROM_CMD_EPC_TIMEOUT_BIT,
	       rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
	writel(EEPROM_CMD_EPC_BUSY_BIT,
	       rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));

	/* Wait for the EPC_BUSY bit to get cleared or timeout bit to get set*/
	ret = read_poll_timeout(readl, regval, !(regval & EEPROM_CMD_EPC_BUSY_BIT),
				STATUS_READ_DELAY_US, STATUS_READ_TIMEOUT_US,
				true, rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));

	/* Return failure if either of software or hardware timeouts happen */
	if (ret < 0 || (!ret && (regval & EEPROM_CMD_EPC_TIMEOUT_BIT)))
		return false;

	return true;
}

static int pci1xxxx_eeprom_read(void *priv_t, unsigned int off,
				void *buf_t, size_t count)
{
	struct pci1xxxx_otp_eeprom_device *priv = priv_t;
	void __iomem *rb = priv->reg_base;
	char *buf = buf_t;
	u32 regval;
	u32 byte;
	int ret;

	if (off >= priv->nvmem_config_eeprom.size)
		return -EFAULT;

	if ((off + count) > priv->nvmem_config_eeprom.size)
		count = priv->nvmem_config_eeprom.size - off;

	ret = set_sys_lock(priv);
	if (ret)
		return ret;

	for (byte = 0; byte < count; byte++) {
		writel(EEPROM_CMD_EPC_BUSY_BIT | (off + byte), rb +
		       MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));

		ret = read_poll_timeout(readl, regval,
					!(regval & EEPROM_CMD_EPC_BUSY_BIT),
					STATUS_READ_DELAY_US,
					STATUS_READ_TIMEOUT_US, true,
					rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
		if (ret < 0 || (!ret && (regval & EEPROM_CMD_EPC_TIMEOUT_BIT))) {
			ret = -EIO;
			goto error;
		}

		buf[byte] = readl(rb + MMAP_EEPROM_OFFSET(EEPROM_DATA_REG));
	}
error:

Annotation

Implementation Notes