drivers/i2c/busses/i2c-bcm-iproc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-bcm-iproc.c
Extension
.c
Size
35755 bytes
Lines
1253
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 bcm_iproc_i2c_dev {
	struct device *device;
	enum bcm_iproc_i2c_type type;
	int irq;

	void __iomem *base;
	void __iomem *idm_base;

	u32 ape_addr_mask;

	/* lock for indirect access through IDM */
	spinlock_t idm_lock;

	struct i2c_adapter adapter;
	unsigned int bus_speed;

	struct completion done;
	int xfer_is_done;

	struct i2c_msg *msg;

	struct i2c_client *slave;

	/* bytes that have been transferred */
	unsigned int tx_bytes;
	/* bytes that have been read */
	unsigned int rx_bytes;
	unsigned int thld_bytes;

	bool slave_rx_only;
	bool rx_start_rcvd;
	bool slave_read_complete;
	u32 tx_underrun;
	u32 slave_int_mask;
	struct tasklet_struct slave_rx_tasklet;
};

/* tasklet to process slave rx data */
static void slave_rx_tasklet_fn(unsigned long);

/*
 * Can be expanded in the future if more interrupt status bits are utilized
 */
#define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT)\
		| BIT(IS_M_RX_THLD_SHIFT))

#define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\
		| BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\
		| BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\
		| BIT(IS_S_RX_THLD_SHIFT))

static inline u32 iproc_i2c_rd_reg(struct bcm_iproc_i2c_dev *iproc_i2c,
				   u32 offset)
{
	u32 val;
	unsigned long flags;

	if (iproc_i2c->idm_base) {
		spin_lock_irqsave(&iproc_i2c->idm_lock, flags);
		writel(iproc_i2c->ape_addr_mask,
		       iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET);
		val = readl(iproc_i2c->base + offset);
		spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags);
	} else {
		val = readl(iproc_i2c->base + offset);
	}

	return val;
}

static inline void iproc_i2c_wr_reg(struct bcm_iproc_i2c_dev *iproc_i2c,
				    u32 offset, u32 val)
{
	unsigned long flags;

	if (iproc_i2c->idm_base) {
		spin_lock_irqsave(&iproc_i2c->idm_lock, flags);
		writel(iproc_i2c->ape_addr_mask,
		       iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET);
		writel(val, iproc_i2c->base + offset);
		spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags);
	} else {
		writel(val, iproc_i2c->base + offset);
	}
}

static void bcm_iproc_i2c_slave_init(struct bcm_iproc_i2c_dev *iproc_i2c,
				     bool need_reset)
{
	u32 val;

Annotation

Implementation Notes