drivers/i2c/busses/i2c-mpc.c
Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-mpc.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/i2c/busses/i2c-mpc.c- Extension
.c- Size
- 24648 bytes
- Lines
- 955
- 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/kernel.hlinux/module.hlinux/sched/signal.hlinux/of.hlinux/of_address.hlinux/of_irq.hlinux/platform_device.hlinux/property.hlinux/slab.hlinux/clk.hlinux/io.hlinux/iopoll.hlinux/fsl_devices.hlinux/i2c.hlinux/interrupt.hlinux/delay.hasm/mpc52xx.hasm/mpc85xx.hsysdev/fsl_soc.h
Detected Declarations
struct mpc_i2cstruct mpc_i2c_dividerstruct mpc_i2c_dataenum mpc_i2c_actionfunction writeccrfunction mpc_i2c_fixupfunction i2c_mpc_wait_srfunction mpc_i2c_fixup_A004447function mpc_i2c_get_fdr_52xxfunction mpc_i2c_setup_52xxfunction mpc_i2c_setup_52xxfunction mpc_i2c_setup_512xfunction mpc_i2c_get_sec_cfg_8xxxfunction mpc_i2c_get_prescaler_8xxxfunction mpc_i2c_get_fdr_8xxxfunction mpc_i2c_setup_8xxxfunction mpc_i2c_setup_8xxxfunction mpc_i2c_do_actionfunction bytefunction mpc_i2c_do_intrfunction mpc_i2c_isrfunction mpc_i2c_wait_for_completionfunction mpc_i2c_execute_msgfunction mpc_xferfunction mpc_functionalityfunction fsl_i2c_bus_recoveryfunction fsl_i2c_probefunction fsl_i2c_removefunction mpc_i2c_suspendfunction mpc_i2c_resume
Annotated Snippet
struct mpc_i2c {
struct device *dev;
void __iomem *base;
u32 interrupt;
wait_queue_head_t waitq;
spinlock_t lock;
struct i2c_adapter adap;
int irq;
u32 real_clk;
u8 fdr, dfsrr;
u32 cntl_bits;
enum mpc_i2c_action action;
struct i2c_msg *msgs;
int num_msgs;
int curr_msg;
u32 byte_posn;
u32 block;
int rc;
int expect_rxack;
bool has_errata_A004447;
};
struct mpc_i2c_divider {
u16 divider;
u16 fdr; /* including dfsrr */
};
struct mpc_i2c_data {
void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock);
};
static inline void writeccr(struct mpc_i2c *i2c, u32 x)
{
writeb(x, i2c->base + MPC_I2C_CR);
}
/* Sometimes 9th clock pulse isn't generated, and target doesn't release
* the bus, because it wants to send ACK.
* Following sequence of enabling/disabling and sending start/stop generates
* the 9 pulses, each with a START then ending with STOP, so it's all OK.
*/
static void mpc_i2c_fixup(struct mpc_i2c *i2c)
{
int k;
unsigned long flags;
for (k = 9; k; k--) {
writeccr(i2c, 0);
writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */
writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */
readb(i2c->base + MPC_I2C_DR); /* init xfer */
udelay(15); /* let it hit the bus */
local_irq_save(flags); /* should not be delayed further */
writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */
readb(i2c->base + MPC_I2C_DR);
if (k != 1)
udelay(5);
local_irq_restore(flags);
}
writeccr(i2c, CCR_MEN); /* Initiate STOP */
readb(i2c->base + MPC_I2C_DR);
udelay(15); /* Let STOP propagate */
writeccr(i2c, 0);
}
static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask)
{
void __iomem *addr = i2c->base + MPC_I2C_SR;
u8 val;
return readb_poll_timeout(addr, val, val & mask, 0, 100);
}
/*
* Workaround for Erratum A004447. From the P2040CE Rev Q
*
* 1. Set up the frequency divider and sampling rate.
* 2. I2CCR - a0h
* 3. Poll for I2CSR[MBB] to get set.
* 4. If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to
* step 5. If MAL is not set, then go to step 13.
* 5. I2CCR - 00h
* 6. I2CCR - 22h
* 7. I2CCR - a2h
* 8. Poll for I2CSR[MBB] to get set.
* 9. Issue read to I2CDR.
* 10. Poll for I2CSR[MIF] to be set.
* 11. I2CCR - 82h
* 12. Workaround complete. Skip the next steps.
* 13. Issue read to I2CDR.
Annotation
- Immediate include surface: `linux/kernel.h`, `linux/module.h`, `linux/sched/signal.h`, `linux/of.h`, `linux/of_address.h`, `linux/of_irq.h`, `linux/platform_device.h`, `linux/property.h`.
- Detected declarations: `struct mpc_i2c`, `struct mpc_i2c_divider`, `struct mpc_i2c_data`, `enum mpc_i2c_action`, `function writeccr`, `function mpc_i2c_fixup`, `function i2c_mpc_wait_sr`, `function mpc_i2c_fixup_A004447`, `function mpc_i2c_get_fdr_52xx`, `function mpc_i2c_setup_52xx`.
- 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.