drivers/i2c/busses/i2c-synquacer.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-synquacer.c
Extension
.c
Size
17618 bytes
Lines
645
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 synquacer_i2c {
	struct completion	completion;

	struct i2c_msg		*msg;
	u32			msg_num;
	u32			msg_idx;
	u32			msg_ptr;

	int			irq;
	struct device		*dev;
	void __iomem		*base;
	u32			pclkrate;
	u32			speed_khz;
	u32			timeout_ms;
	enum i2c_state		state;
	struct i2c_adapter	adapter;
};

static inline int is_lastmsg(struct synquacer_i2c *i2c)
{
	return i2c->msg_idx >= (i2c->msg_num - 1);
}

static inline int is_msglast(struct synquacer_i2c *i2c)
{
	return i2c->msg_ptr == (i2c->msg->len - 1);
}

static inline int is_msgend(struct synquacer_i2c *i2c)
{
	return i2c->msg_ptr >= i2c->msg->len;
}

static inline unsigned long calc_timeout_ms(struct synquacer_i2c *i2c,
					    struct i2c_msg *msgs,
					    int num)
{
	unsigned long bit_count = 0;
	int i;

	for (i = 0; i < num; i++, msgs++)
		bit_count += msgs->len;

	return DIV_ROUND_UP((bit_count * 9 + num * 10) * 3, 200) + 10;
}

static void synquacer_i2c_stop(struct synquacer_i2c *i2c, int ret)
{
	/*
	 * clear IRQ (INT=0, BER=0)
	 * set Stop Condition (MSS=0)
	 * Interrupt Disable
	 */
	writeb(0, i2c->base + SYNQUACER_I2C_REG_BCR);

	i2c->state = STATE_IDLE;

	i2c->msg_ptr = 0;
	i2c->msg = NULL;
	i2c->msg_idx++;
	i2c->msg_num = 0;
	if (ret)
		i2c->msg_idx = ret;

	complete(&i2c->completion);
}

static void synquacer_i2c_hw_init(struct synquacer_i2c *i2c)
{
	unsigned char ccr_cs, csr_cs;
	u32 rt = i2c->pclkrate;

	/* Set own Address */
	writeb(0, i2c->base + SYNQUACER_I2C_REG_ADR);

	/* Set PCLK frequency */
	writeb(SYNQUACER_I2C_BUS_CLK_FR(i2c->pclkrate),
	       i2c->base + SYNQUACER_I2C_REG_FSR);

	switch (i2c->speed_khz) {
	case SYNQUACER_I2C_SPEED_FM:
		if (i2c->pclkrate <= SYNQUACER_I2C_CLK_RATE_18M) {
			ccr_cs = SYNQUACER_I2C_CCR_CS_FAST_MAX_18M(rt);
			csr_cs = SYNQUACER_I2C_CSR_CS_FAST_MAX_18M(rt);
		} else {
			ccr_cs = SYNQUACER_I2C_CCR_CS_FAST_MIN_18M(rt);
			csr_cs = SYNQUACER_I2C_CSR_CS_FAST_MIN_18M(rt);
		}

		/* Set Clock and enable, Set fast mode */

Annotation

Implementation Notes