drivers/i2c/busses/i2c-aspeed.c
Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-aspeed.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/i2c/busses/i2c-aspeed.c- Extension
.c- Size
- 33620 bytes
- Lines
- 1116
- 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.
- 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.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/clk.hlinux/completion.hlinux/err.hlinux/errno.hlinux/i2c.hlinux/init.hlinux/interrupt.hlinux/io.hlinux/irq.hlinux/kernel.hlinux/module.hlinux/of_address.hlinux/of_irq.hlinux/of_platform.hlinux/platform_device.hlinux/reset.hlinux/slab.h
Detected Declarations
struct aspeed_i2c_busenum aspeed_i2c_master_stateenum aspeed_i2c_slave_statefunction aspeed_i2c_do_stopfunction aspeed_i2c_recover_busfunction aspeed_i2c_slave_irqfunction aspeed_i2c_do_startfunction aspeed_i2c_next_msg_or_stopfunction aspeed_i2c_is_irq_errorfunction aspeed_i2c_master_irqfunction aspeed_i2c_bus_irqfunction aspeed_i2c_master_xferfunction aspeed_i2c_functionalityfunction __aspeed_i2c_reg_slavefunction aspeed_i2c_reg_slavefunction aspeed_i2c_unreg_slavefunction aspeed_i2c_get_clk_reg_valfunction aspeed_i2c_24xx_get_clk_reg_valfunction aspeed_i2c_25xx_get_clk_reg_valfunction aspeed_i2c_init_clkfunction aspeed_i2c_initfunction aspeed_i2c_resetfunction aspeed_i2c_probe_busfunction aspeed_i2c_remove_bus
Annotated Snippet
struct aspeed_i2c_bus {
struct i2c_adapter adap;
struct device *dev;
void __iomem *base;
struct reset_control *rst;
/* Synchronizes I/O mem access to base. */
spinlock_t lock;
struct completion cmd_complete;
u32 (*get_clk_reg_val)(struct device *dev,
u32 divisor);
unsigned long parent_clk_frequency;
u32 bus_frequency;
/* Transaction state. */
enum aspeed_i2c_master_state master_state;
struct i2c_msg *msgs;
size_t buf_index;
size_t msgs_index;
size_t msgs_count;
bool send_stop;
int cmd_err;
/* Protected only by i2c_lock_bus */
int master_xfer_result;
/* Multi-master */
bool multi_master;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
struct i2c_client *slave;
enum aspeed_i2c_slave_state slave_state;
#endif /* CONFIG_I2C_SLAVE */
};
static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
/* precondition: bus.lock has been acquired. */
static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus)
{
bus->master_state = ASPEED_I2C_MASTER_STOP;
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
}
static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
{
unsigned long time_left, flags;
int ret = 0;
u32 command;
spin_lock_irqsave(&bus->lock, flags);
command = readl(bus->base + ASPEED_I2C_CMD_REG);
if (command & ASPEED_I2CD_SDA_LINE_STS) {
/* Bus is idle: no recovery needed. */
if (command & ASPEED_I2CD_SCL_LINE_STS)
goto out;
dev_dbg(bus->dev, "SCL hung (state %x), attempting recovery\n",
command);
reinit_completion(&bus->cmd_complete);
aspeed_i2c_do_stop(bus);
spin_unlock_irqrestore(&bus->lock, flags);
time_left = wait_for_completion_timeout(
&bus->cmd_complete, bus->adap.timeout);
spin_lock_irqsave(&bus->lock, flags);
if (time_left == 0)
goto reset_out;
else if (bus->cmd_err)
goto reset_out;
/* Recovery failed. */
else if (!(readl(bus->base + ASPEED_I2C_CMD_REG) &
ASPEED_I2CD_SCL_LINE_STS))
goto reset_out;
/* Bus error. */
} else {
dev_dbg(bus->dev, "SDA hung (state %x), attempting recovery\n",
command);
reinit_completion(&bus->cmd_complete);
/* Writes 1 to 8 SCL clock cycles until SDA is released. */
writel(ASPEED_I2CD_BUS_RECOVER_CMD,
bus->base + ASPEED_I2C_CMD_REG);
spin_unlock_irqrestore(&bus->lock, flags);
time_left = wait_for_completion_timeout(
&bus->cmd_complete, bus->adap.timeout);
spin_lock_irqsave(&bus->lock, flags);
if (time_left == 0)
goto reset_out;
else if (bus->cmd_err)
goto reset_out;
Annotation
- Immediate include surface: `linux/clk.h`, `linux/completion.h`, `linux/err.h`, `linux/errno.h`, `linux/i2c.h`, `linux/init.h`, `linux/interrupt.h`, `linux/io.h`.
- Detected declarations: `struct aspeed_i2c_bus`, `enum aspeed_i2c_master_state`, `enum aspeed_i2c_slave_state`, `function aspeed_i2c_do_stop`, `function aspeed_i2c_recover_bus`, `function aspeed_i2c_slave_irq`, `function aspeed_i2c_do_start`, `function aspeed_i2c_next_msg_or_stop`, `function aspeed_i2c_is_irq_error`, `function aspeed_i2c_master_irq`.
- Atlas domain: Driver Families / drivers/i2c.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.