drivers/i2c/busses/i2c-rzv2m.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-rzv2m.c
Extension
.c
Size
12500 bytes
Lines
540
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 rzv2m_i2c_priv {
	void __iomem *base;
	struct i2c_adapter adap;
	struct clk *clk;
	int bus_mode;
	struct completion msg_tia_done;
	u32 iicb0wl;
	u32 iicb0wh;
};

enum bcr_index {
	RZV2M_I2C_100K = 0,
	RZV2M_I2C_400K,
};

struct bitrate_config {
	unsigned int percent_low;
	unsigned int min_hold_time_ns;
};

static const struct bitrate_config bitrate_configs[] = {
	[RZV2M_I2C_100K] = { 47, 3450 },
	[RZV2M_I2C_400K] = { 52, 900 },
};

static inline void bit_setl(void __iomem *addr, u32 val)
{
	writel(readl(addr) | val, addr);
}

static inline void bit_clrl(void __iomem *addr, u32 val)
{
	writel(readl(addr) & ~val, addr);
}

static irqreturn_t rzv2m_i2c_tia_irq_handler(int this_irq, void *dev_id)
{
	struct rzv2m_i2c_priv *priv = dev_id;

	complete(&priv->msg_tia_done);

	return IRQ_HANDLED;
}

/* Calculate IICB0WL and IICB0WH */
static int rzv2m_i2c_clock_calculate(struct device *dev,
				     struct rzv2m_i2c_priv *priv)
{
	const struct bitrate_config *config;
	unsigned int hold_time_ns;
	unsigned int total_pclks;
	unsigned int trf_pclks;
	unsigned long pclk_hz;
	struct i2c_timings t;
	u32 trf_ns;

	i2c_parse_fw_timings(dev, &t, true);

	pclk_hz = clk_get_rate(priv->clk);
	total_pclks = pclk_hz / t.bus_freq_hz;

	trf_ns = t.scl_rise_ns + t.scl_fall_ns;
	trf_pclks = mul_u64_u32_div(pclk_hz, trf_ns, NSEC_PER_SEC);

	/* Config setting */
	switch (t.bus_freq_hz) {
	case I2C_MAX_FAST_MODE_FREQ:
		priv->bus_mode = RZV2M_I2C_400K;
		break;
	case I2C_MAX_STANDARD_MODE_FREQ:
		priv->bus_mode = RZV2M_I2C_100K;
		break;
	default:
		dev_err(dev, "transfer speed is invalid\n");
		return -EINVAL;
	}
	config = &bitrate_configs[priv->bus_mode];

	/* IICB0WL = (percent_low / Transfer clock) x PCLK */
	priv->iicb0wl = total_pclks * config->percent_low / 100;
	if (priv->iicb0wl > (BIT(10) - 1))
		return -EINVAL;

	/* IICB0WH = ((percent_high / Transfer clock) x PCLK) - (tR + tF) */
	priv->iicb0wh = total_pclks - priv->iicb0wl - trf_pclks;
	if (priv->iicb0wh > (BIT(10) - 1))
		return -EINVAL;

	/*
	 * Data hold time must be less than 0.9us in fast mode and

Annotation

Implementation Notes