drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c
Extension
.c
Size
9767 bytes
Lines
365
Domain
Driver Families
Bucket
drivers/media
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 netup_i2c_fifo_regs {
	union {
		__u8	data8;
		__le16	data16;
		__le32	data32;
	};
	__u8		padding[4];
	__le16		stat_ctrl;
} __packed __aligned(1);

struct netup_i2c_regs {
	__le16				clkdiv;
	__le16				twi_ctrl0_stat;
	__le16				twi_addr_ctrl1;
	__le16				length;
	__u8				padding1[8];
	struct netup_i2c_fifo_regs	tx_fifo;
	__u8				padding2[6];
	struct netup_i2c_fifo_regs	rx_fifo;
} __packed __aligned(1);

irqreturn_t netup_i2c_interrupt(struct netup_i2c *i2c)
{
	u16 reg, tmp;
	unsigned long flags;
	irqreturn_t iret = IRQ_HANDLED;

	spin_lock_irqsave(&i2c->lock, flags);
	reg = readw(&i2c->regs->twi_ctrl0_stat);
	writew(reg & ~TWI_IRQEN, &i2c->regs->twi_ctrl0_stat);
	dev_dbg(i2c->adap.dev.parent,
		"%s(): twi_ctrl0_state 0x%x\n", __func__, reg);
	if ((reg & TWI_IRQEN_COMPL) != 0 && (reg & TWI_IRQ_COMPL)) {
		dev_dbg(i2c->adap.dev.parent,
			"%s(): TWI_IRQEN_COMPL\n", __func__);
		i2c->state = STATE_DONE;
		goto irq_ok;
	}
	if ((reg & TWI_IRQEN_ANACK) != 0 && (reg & TWI_IRQ_ANACK)) {
		dev_dbg(i2c->adap.dev.parent,
			"%s(): TWI_IRQEN_ANACK\n", __func__);
		i2c->state = STATE_ERROR;
		goto irq_ok;
	}
	if ((reg & TWI_IRQEN_DNACK) != 0 && (reg & TWI_IRQ_DNACK)) {
		dev_dbg(i2c->adap.dev.parent,
			"%s(): TWI_IRQEN_DNACK\n", __func__);
		i2c->state = STATE_ERROR;
		goto irq_ok;
	}
	if ((reg & TWI_IRQ_RX) != 0) {
		tmp = readw(&i2c->regs->rx_fifo.stat_ctrl);
		writew(tmp & ~FIFO_IRQEN, &i2c->regs->rx_fifo.stat_ctrl);
		i2c->state = STATE_WANT_READ;
		dev_dbg(i2c->adap.dev.parent,
			"%s(): want read\n", __func__);
		goto irq_ok;
	}
	if ((reg & TWI_IRQ_TX) != 0) {
		tmp = readw(&i2c->regs->tx_fifo.stat_ctrl);
		writew(tmp & ~FIFO_IRQEN, &i2c->regs->tx_fifo.stat_ctrl);
		i2c->state = STATE_WANT_WRITE;
		dev_dbg(i2c->adap.dev.parent,
			"%s(): want write\n", __func__);
		goto irq_ok;
	}
	dev_warn(&i2c->adap.dev, "%s(): not mine interrupt\n", __func__);
	iret = IRQ_NONE;
irq_ok:
	spin_unlock_irqrestore(&i2c->lock, flags);
	if (iret == IRQ_HANDLED)
		wake_up(&i2c->wq);
	return iret;
}

static void netup_i2c_reset(struct netup_i2c *i2c)
{
	dev_dbg(i2c->adap.dev.parent, "%s()\n", __func__);
	i2c->state = STATE_DONE;
	writew(TWI_SOFT_RESET, &i2c->regs->twi_addr_ctrl1);
	writew(TWI_CLKDIV, &i2c->regs->clkdiv);
	writew(FIFO_RESET, &i2c->regs->tx_fifo.stat_ctrl);
	writew(FIFO_RESET, &i2c->regs->rx_fifo.stat_ctrl);
	writew(0x800, &i2c->regs->tx_fifo.stat_ctrl);
	writew(0x800, &i2c->regs->rx_fifo.stat_ctrl);
}

static void netup_i2c_fifo_tx(struct netup_i2c *i2c)
{
	u8 data;

Annotation

Implementation Notes