drivers/i2c/busses/i2c-k1.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-k1.c
Extension
.c
Size
22139 bytes
Lines
792
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 spacemit_i2c_dev {
	struct device *dev;
	struct i2c_adapter adapt;

	/* hardware resources */
	void __iomem *base;
	int irq;
	u32 clock_freq;

	struct i2c_msg *msgs;
	u32 msg_num;

	/* index of the current message being processed */
	u32 msg_idx;
	u8 *msg_buf;
	/* the number of unprocessed bytes remaining in the current message  */
	u32 unprocessed;

	enum spacemit_i2c_state state;
	bool read;
	bool use_pio;
	struct completion complete;
	u32 status;
};

static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
{
	u32 val;

	val = readl(i2c->base + SPACEMIT_ICR);
	val |= SPACEMIT_CR_IUE;
	writel(val, i2c->base + SPACEMIT_ICR);
}

static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
{
	u32 val;

	val = readl(i2c->base + SPACEMIT_ICR);
	val &= ~SPACEMIT_CR_IUE;
	writel(val, i2c->base + SPACEMIT_ICR);
}

static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
{
	writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
	udelay(5);
	writel(0, i2c->base + SPACEMIT_ICR);
}

static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
{
	dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status);

	/* Arbitration Loss Detected */
	if (i2c->status & SPACEMIT_SR_ALD) {
		spacemit_i2c_reset(i2c);
		return -EAGAIN;
	}

	/* Bus Error No ACK/NAK */
	if (i2c->status & SPACEMIT_SR_BED)
		spacemit_i2c_reset(i2c);

	return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;
}

static inline void spacemit_i2c_delay(struct spacemit_i2c_dev *i2c, unsigned int us)
{
	if (i2c->use_pio)
		udelay(us);
	else
		fsleep(us);
}

static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
{
	u32 status;
	u8 clk_cnt;

	/* if bus is locked, reset unit. 0: locked */
	status = readl(i2c->base + SPACEMIT_IBMR);
	if ((status & SPACEMIT_BMR_SDA) && (status & SPACEMIT_BMR_SCL))
		return;

	spacemit_i2c_reset(i2c);

	spacemit_i2c_delay(i2c, 10);

	for (clk_cnt = 0; clk_cnt < SPACEMIT_BUS_RESET_CLK_CNT_MAX; clk_cnt++) {

Annotation

Implementation Notes