drivers/i2c/busses/i2c-xlp9xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-xlp9xx.c
Extension
.c
Size
15675 bytes
Lines
594
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 xlp9xx_i2c_dev {
	struct device *dev;
	struct i2c_adapter adapter;
	struct completion msg_complete;
	struct i2c_smbus_alert_setup alert_data;
	struct i2c_client *ara;
	int irq;
	bool msg_read;
	bool len_recv;
	bool client_pec;
	u32 __iomem *base;
	u32 msg_buf_remaining;
	u32 msg_len;
	u32 ip_clk_hz;
	u32 clk_hz;
	u32 msg_err;
	u8 *msg_buf;
};

static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv,
					unsigned long reg, u32 val)
{
	writel(val, priv->base + reg);
}

static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv,
				      unsigned long reg)
{
	return readl(priv->base + reg);
}

static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
{
	u32 inten;

	inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask;
	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
}

static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
{
	u32 inten;

	inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask;
	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
}

static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv)
{
	u32 thres;

	if (priv->len_recv)
		/* interrupt after the first read to examine
		 * the length byte before proceeding further
		 */
		thres = 1;
	else if (priv->msg_buf_remaining > XLP9XX_I2C_FIFO_SIZE)
		thres = XLP9XX_I2C_FIFO_SIZE;
	else
		thres = priv->msg_buf_remaining;

	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
			     thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT);
}

static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
{
	u32 len, i;
	u8 *buf = priv->msg_buf;

	len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
	for (i = 0; i < len; i++)
		xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]);
	priv->msg_buf_remaining -= len;
	priv->msg_buf += len;
}

static void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv)
{
	u32 val, len;

	/*
	 * Update receive length. Re-read len to get the latest value,
	 * and then add 4 to have a minimum value that can be safely
	 * written. This is to account for the byte read above, the
	 * transfer in progress and any delays in the register I/O
	 */
	val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
	len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
				  XLP9XX_I2C_FIFO_WCNT_MASK;

Annotation

Implementation Notes