drivers/i2c/busses/i2c-amd-asf-plat.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-amd-asf-plat.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-amd-asf-plat.c
Extension
.c
Size
10507 bytes
Lines
371
Domain
Driver Families
Bucket
drivers/i2c
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 amd_asf_dev {
	struct i2c_adapter adap;
	void __iomem *eoi_base;
	struct i2c_client *target;
	struct delayed_work work_buf;
	struct sb800_mmio_cfg mmio_cfg;
	struct resource *port_addr;
};

static void amd_asf_process_target(struct work_struct *work)
{
	struct amd_asf_dev *dev = container_of(work, struct amd_asf_dev, work_buf.work);
	unsigned short piix4_smba = dev->port_addr->start;
	u8 data[ASF_BLOCK_MAX_BYTES];
	u8 bank, reg, cmd;
	u8 len = 0, idx, val;

	/* Read target status register */
	reg = inb_p(ASFSLVSTA);

	/* Check if no error bits are set in target status register */
	if (reg & ASF_ERROR_STATUS) {
		/* Set bank as full */
		cmd = 1;
		reg |= GENMASK(3, 2);
		outb_p(reg, ASFDATABNKSEL);
	} else {
		/* Read data bank */
		reg = inb_p(ASFDATABNKSEL);
		bank = (reg & BIT(3)) ? 1 : 0;

		/* Set read data bank */
		if (bank) {
			reg |= BIT(4);
			reg &= ~BIT(3);
		} else {
			reg &= ~BIT(4);
			reg &= ~BIT(2);
		}

		/* Read command register */
		outb_p(reg, ASFDATABNKSEL);
		cmd = inb_p(ASFINDEX);
		len = inb_p(ASFDATARWPTR);
		for (idx = 0; idx < len; idx++)
			data[idx] = inb_p(ASFINDEX);

		/* Clear data bank status */
		if (bank) {
			reg |= BIT(3);
			outb_p(reg, ASFDATABNKSEL);
		} else {
			reg |= BIT(2);
			outb_p(reg, ASFDATABNKSEL);
		}
	}

	outb_p(0, ASFSETDATARDPTR);
	if (cmd & BIT(0))
		return;

	/*
	 * Although i2c_slave_event() returns an appropriate error code, we
	 * don't check it here because we're operating in the workqueue context.
	 */
	i2c_slave_event(dev->target, I2C_SLAVE_WRITE_REQUESTED, &val);
	for (idx = 0; idx < len; idx++) {
		val = data[idx];
		i2c_slave_event(dev->target, I2C_SLAVE_WRITE_RECEIVED, &val);
	}
	i2c_slave_event(dev->target, I2C_SLAVE_STOP, &val);
}

static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit,
					 unsigned long offset, bool set)
{
	unsigned long reg;

	reg = inb_p(offset);
	__assign_bit(bit, &reg, set);
	outb_p(reg, offset);
}

static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set)
{
	unsigned long reg;

	reg = ioread32(dev->mmio_cfg.addr);
	__assign_bit(bit, &reg, set);
	iowrite32(reg, dev->mmio_cfg.addr);

Annotation

Implementation Notes