drivers/i2c/busses/i2c-sun6i-p2wi.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-sun6i-p2wi.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-sun6i-p2wi.c
Extension
.c
Size
8567 bytes
Lines
318
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 p2wi {
	struct i2c_adapter adapter;
	struct completion complete;
	unsigned int status;
	void __iomem *regs;
	struct clk *clk;
	struct reset_control *rstc;
	int target_addr;
};

static irqreturn_t p2wi_interrupt(int irq, void *dev_id)
{
	struct p2wi *p2wi = dev_id;
	unsigned long status;

	status = readl(p2wi->regs + P2WI_INTS);
	p2wi->status = status;

	/* Clear interrupts */
	status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR |
		   P2WI_INTS_TRANS_OVER);
	writel(status, p2wi->regs + P2WI_INTS);

	complete(&p2wi->complete);

	return IRQ_HANDLED;
}

static u32 p2wi_functionality(struct i2c_adapter *adap)
{
	return I2C_FUNC_SMBUS_BYTE_DATA;
}

static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
			   unsigned short flags, char read_write,
			   u8 command, int size, union i2c_smbus_data *data)
{
	struct p2wi *p2wi = i2c_get_adapdata(adap);
	unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1);

	if (p2wi->target_addr >= 0 && addr != p2wi->target_addr) {
		dev_err(&adap->dev, "invalid P2WI address\n");
		return -EINVAL;
	}

	if (!data)
		return -EINVAL;

	writel(command, p2wi->regs + P2WI_DADDR0);

	if (read_write == I2C_SMBUS_READ)
		dlen |= P2WI_DLEN_READ;
	else
		writel(data->byte, p2wi->regs + P2WI_DATA0);

	writel(dlen, p2wi->regs + P2WI_DLEN);

	if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) {
		dev_err(&adap->dev, "P2WI bus busy\n");
		return -EBUSY;
	}

	reinit_completion(&p2wi->complete);

	writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER,
	       p2wi->regs + P2WI_INTE);

	writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB,
	       p2wi->regs + P2WI_CTRL);

	wait_for_completion(&p2wi->complete);

	if (p2wi->status & P2WI_INTS_LOAD_BSY) {
		dev_err(&adap->dev, "P2WI bus busy\n");
		return -EBUSY;
	}

	if (p2wi->status & P2WI_INTS_TRANS_ERR) {
		dev_err(&adap->dev, "P2WI bus xfer error\n");
		return -ENXIO;
	}

	if (read_write == I2C_SMBUS_READ)
		data->byte = readl(p2wi->regs + P2WI_DATA0);

	return 0;
}

static const struct i2c_algorithm p2wi_algo = {
	.smbus_xfer = p2wi_smbus_xfer,

Annotation

Implementation Notes