drivers/i2c/busses/i2c-stm32f4.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-stm32f4.c
Extension
.c
Size
24269 bytes
Lines
869
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 stm32f4_i2c_msg {
	u8 addr;
	u32 count;
	u8 *buf;
	int result;
	bool stop;
};

/**
 * struct stm32f4_i2c_dev - private data of the controller
 * @adap: I2C adapter for this controller
 * @dev: device for this controller
 * @base: virtual memory area
 * @complete: completion of I2C message
 * @clk: hw i2c clock
 * @speed: I2C clock frequency of the controller. Standard or Fast are supported
 * @parent_rate: I2C clock parent rate in MHz
 * @msg: I2C transfer information
 */
struct stm32f4_i2c_dev {
	struct i2c_adapter adap;
	struct device *dev;
	void __iomem *base;
	struct completion complete;
	struct clk *clk;
	int speed;
	int parent_rate;
	struct stm32f4_i2c_msg msg;
};

static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
{
	writel_relaxed(readl_relaxed(reg) | mask, reg);
}

static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
{
	writel_relaxed(readl_relaxed(reg) & ~mask, reg);
}

static void stm32f4_i2c_disable_irq(struct stm32f4_i2c_dev *i2c_dev)
{
	void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;

	stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
}

static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
{
	u32 freq;
	u32 cr2 = 0;

	i2c_dev->parent_rate = clk_get_rate(i2c_dev->clk);
	freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);

	if (i2c_dev->speed == STM32_I2C_SPEED_STANDARD) {
		/*
		 * To reach 100 kHz, the parent clk frequency should be between
		 * a minimum value of 2 MHz and a maximum value of 46 MHz due
		 * to hardware limitation
		 */
		if (freq < STM32F4_I2C_MIN_STANDARD_FREQ ||
		    freq > STM32F4_I2C_MAX_FREQ)
			return dev_err_probe(i2c_dev->dev, -EINVAL,
					     "bad parent clk freq for standard mode\n");
	} else {
		/*
		 * To be as close as possible to 400 kHz, the parent clk
		 * frequency should be between a minimum value of 6 MHz and a
		 * maximum value of 46 MHz due to hardware limitation
		 */
		if (freq < STM32F4_I2C_MIN_FAST_FREQ ||
		    freq > STM32F4_I2C_MAX_FREQ)
			return dev_err_probe(i2c_dev->dev, -EINVAL,
					     "bad parent clk freq for fast mode\n");
	}

	cr2 |= STM32F4_I2C_CR2_FREQ(freq);
	writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);

	return 0;
}

static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
{
	u32 freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
	u32 trise;

	/*
	 * These bits must be programmed with the maximum SCL rise time given in

Annotation

Implementation Notes