drivers/i2c/busses/i2c-uniphier-f.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-uniphier-f.c
Extension
.c
Size
17892 bytes
Lines
622
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 uniphier_fi2c_priv {
	struct completion comp;
	struct i2c_adapter adap;
	void __iomem *membase;
	struct clk *clk;
	unsigned int len;
	u8 *buf;
	u32 enabled_irqs;
	int error;
	unsigned int flags;
	unsigned int busy_cnt;
	unsigned int clk_cycle;
	spinlock_t lock;	/* IRQ synchronization */
};

static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
				      bool first)
{
	int fifo_space = UNIPHIER_FI2C_FIFO_SIZE;

	/*
	 * TX-FIFO stores target address in it for the first access.
	 * Decrement the counter.
	 */
	if (first)
		fifo_space--;

	while (priv->len) {
		if (fifo_space-- <= 0)
			break;

		writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX);
		priv->len--;
	}
}

static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv)
{
	int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ?
						1 : UNIPHIER_FI2C_FIFO_SIZE;

	while (priv->len) {
		if (fifo_left-- <= 0)
			break;

		*priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX);
		priv->len--;
	}
}

static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
{
	writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
}

static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv,
				     u32 mask)
{
	writel(mask, priv->membase + UNIPHIER_FI2C_IC);
}

static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
{
	priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP;
	uniphier_fi2c_set_irqs(priv);
	writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO,
	       priv->membase + UNIPHIER_FI2C_CR);
}

static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
{
	struct uniphier_fi2c_priv *priv = dev_id;
	u32 irq_status;

	spin_lock(&priv->lock);

	irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
	irq_status &= priv->enabled_irqs;

	if (irq_status & UNIPHIER_FI2C_INT_STOP)
		goto complete;

	if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) {
		priv->error = -EAGAIN;
		goto complete;
	}

	if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) {
		priv->error = -ENXIO;
		if (priv->flags & UNIPHIER_FI2C_RD) {

Annotation

Implementation Notes