drivers/i2c/busses/i2c-ls2x-v2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-ls2x-v2.c
Extension
.c
Size
16638 bytes
Lines
545
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 loongson2_i2c_msg {
	u8	*buf;
	u32	count;
	int	result;
	u8      addr;
	bool	stop;
};

/**
 * struct loongson2_i2c_priv - private data of the controller
 * @adapter: I2C adapter for this controller
 * @complete: completion of I2C message
 * @clk: hw i2c clock
 * @regmap: regmap of the I2C device
 * @parent_rate_MHz: I2C clock parent rate
 * @msg: I2C transfer information
 */
struct loongson2_i2c_priv {
	struct i2c_adapter		adapter;
	struct completion		complete;
	struct clk			*clk;
	struct regmap			*regmap;
	unsigned long			parent_rate_MHz;
	struct loongson2_i2c_msg	msg;
};

static void loongson2_i2c_disable_irq(struct loongson2_i2c_priv *priv)
{
	regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_INT_MASK, 0);
}

static void loongson2_i2c_read_msg(struct loongson2_i2c_priv *priv)
{
	struct loongson2_i2c_msg *msg = &priv->msg;
	u32 rbuf;

	regmap_read(priv->regmap, LOONGSON2_I2C_DR, &rbuf);
	*msg->buf++ = rbuf;
	msg->count--;
}

static void loongson2_i2c_write_msg(struct loongson2_i2c_priv *priv, u8 byte)
{
	regmap_write(priv->regmap, LOONGSON2_I2C_DR, byte);
}

static void loongson2_i2c_terminate_xfer(struct loongson2_i2c_priv *priv)
{
	struct loongson2_i2c_msg *msg = &priv->msg;

	loongson2_i2c_disable_irq(priv);
	regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
			   msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
	complete(&priv->complete);
}

static void loongson2_i2c_handle_write(struct loongson2_i2c_priv *priv)
{
	struct loongson2_i2c_msg *msg = &priv->msg;

	if (msg->count) {
		loongson2_i2c_write_msg(priv, *msg->buf++);
		if (!--msg->count)
			regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2,
					   LOONGSON2_I2C_CR2_ITBUFEN, 0);
	} else {
		loongson2_i2c_terminate_xfer(priv);
	}
}

static void loongson2_i2c_handle_rx_addr(struct loongson2_i2c_priv *priv)
{
	struct loongson2_i2c_msg *msg = &priv->msg;

	switch (msg->count) {
	case 0:
		loongson2_i2c_terminate_xfer(priv);
		break;
	case 1:
		/* Enable NACK and reset POS (Acknowledge position) */
		regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1,
				   LOONGSON2_I2C_CR1_ACK | LOONGSON2_I2C_CR1_POS, 0);
		/* Set STOP or RepSTART */
		regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
				   msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
		break;
	case 2:
		/* Enable NACK */
		regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK, 0);
		/* Set POS (NACK position) */

Annotation

Implementation Notes