drivers/i2c/busses/i2c-ls2x.c
Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-ls2x.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/i2c/busses/i2c-ls2x.c- Extension
.c- Size
- 9682 bytes
- Lines
- 378
- 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.
- 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/bitfield.hlinux/bits.hlinux/completion.hlinux/device.hlinux/iopoll.hlinux/i2c.hlinux/init.hlinux/interrupt.hlinux/io.hlinux/kernel.hlinux/module.hlinux/pm_runtime.hlinux/platform_device.hlinux/property.hlinux/units.h
Detected Declarations
struct ls2x_i2c_privfunction ls2x_i2c_isrfunction ls2x_i2c_adjust_bus_speedfunction ls2x_i2c_initfunction ls2x_i2c_xfer_bytefunction ls2x_i2c_send_bytefunction ls2x_i2c_stopfunction ls2x_i2c_startfunction ls2x_i2c_rxfunction ls2x_i2c_txfunction ls2x_i2c_xfer_onefunction ls2x_i2c_xferfunction ls2x_i2c_funcfunction ls2x_i2c_probefunction ls2x_i2c_suspendfunction ls2x_i2c_resume
Annotated Snippet
struct ls2x_i2c_priv {
struct i2c_adapter adapter;
void __iomem *base;
struct i2c_timings i2c_t;
struct completion cmd_complete;
};
/*
* Interrupt service routine.
* This gets called whenever an I2C interrupt occurs.
*/
static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
{
struct ls2x_i2c_priv *priv = dev_id;
if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF))
return IRQ_NONE;
writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR);
complete(&priv->cmd_complete);
return IRQ_HANDLED;
}
/*
* The ls2x i2c controller supports standard mode and fast mode, so the
* maximum bus frequency is '400kHz'.
* The bus frequency is set to the empirical value of '33KHz' by default,
* but it can also be taken from ACPI or FDT for compatibility with more
* devices.
*/
static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
{
u16 val;
struct i2c_timings *t = &priv->i2c_t;
struct device *dev = priv->adapter.dev.parent;
u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
i2c_parse_fw_timings(dev, t, false);
if (acpi_speed || t->bus_freq_hz)
t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
else
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
/*
* According to the chip manual, we can only access the registers as bytes,
* otherwise the high bits will be truncated.
* So set the I2C frequency with a sequential writeb() instead of writew().
*/
val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1;
writeb(FIELD_GET(GENMASK(7, 0), val), priv->base + I2C_LS2X_PRER_LO);
writeb(FIELD_GET(GENMASK(15, 8), val), priv->base + I2C_LS2X_PRER_HI);
}
static void ls2x_i2c_init(struct ls2x_i2c_priv *priv)
{
/* Set i2c frequency setting mode and disable interrupts. */
writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK,
priv->base + I2C_LS2X_CTR);
ls2x_i2c_adjust_bus_speed(priv);
/* Set i2c normal operating mode and enable interrupts. */
writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK,
priv->base + I2C_LS2X_CTR);
}
static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap)
{
u8 rxdata;
unsigned long time_left;
writeb(txdata, priv->base + I2C_LS2X_CR);
time_left = wait_for_completion_timeout(&priv->cmd_complete,
priv->adapter.timeout);
if (!time_left)
return -ETIMEDOUT;
rxdata = readb(priv->base + I2C_LS2X_SR);
if (rxdatap)
*rxdatap = rxdata;
return 0;
}
static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata)
{
int ret;
u8 rxdata;
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/bits.h`, `linux/completion.h`, `linux/device.h`, `linux/iopoll.h`, `linux/i2c.h`, `linux/init.h`, `linux/interrupt.h`.
- Detected declarations: `struct ls2x_i2c_priv`, `function ls2x_i2c_isr`, `function ls2x_i2c_adjust_bus_speed`, `function ls2x_i2c_init`, `function ls2x_i2c_xfer_byte`, `function ls2x_i2c_send_byte`, `function ls2x_i2c_stop`, `function ls2x_i2c_start`, `function ls2x_i2c_rx`, `function ls2x_i2c_tx`.
- Atlas domain: Driver Families / drivers/i2c.
- Implementation status: source implementation candidate.
- 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.