drivers/i2c/busses/i2c-meson.c
Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-meson.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/i2c/busses/i2c-meson.c- Extension
.c- Size
- 14746 bytes
- Lines
- 580
- 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/bitfield.hlinux/clk.hlinux/completion.hlinux/i2c.hlinux/interrupt.hlinux/io.hlinux/iopoll.hlinux/kernel.hlinux/module.hlinux/of.hlinux/platform_device.hlinux/types.h
Detected Declarations
struct meson_i2cstruct meson_i2c_datafunction meson_i2c_set_maskfunction meson_i2c_reset_tokensfunction meson_i2c_add_tokenfunction meson_gxbb_axg_i2c_set_clk_divfunction meson6_i2c_set_clk_divfunction meson_i2c_get_datafunction meson_i2c_put_datafunction meson_i2c_prepare_xferfunction meson_i2c_transfer_completefunction meson_i2c_irqfunction meson_i2c_do_startfunction meson_i2c_xfer_msgfunction meson_i2c_xfer_messagesfunction meson_i2c_xferfunction meson_i2c_xfer_atomicfunction meson_i2c_funcfunction meson_i2c_probefunction meson_i2c_remove
Annotated Snippet
struct meson_i2c {
struct i2c_adapter adap;
struct device *dev;
void __iomem *regs;
struct clk *clk;
struct i2c_msg *msg;
int state;
bool last;
int count;
int pos;
int error;
spinlock_t lock;
struct completion done;
u32 tokens[2];
int num_tokens;
const struct meson_i2c_data *data;
};
struct meson_i2c_data {
void (*set_clk_div)(struct meson_i2c *i2c, unsigned int freq);
};
static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask,
u32 val)
{
u32 data;
data = readl(i2c->regs + reg);
data &= ~mask;
data |= val & mask;
writel(data, i2c->regs + reg);
}
static void meson_i2c_reset_tokens(struct meson_i2c *i2c)
{
i2c->tokens[0] = 0;
i2c->tokens[1] = 0;
i2c->num_tokens = 0;
}
static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
{
if (i2c->num_tokens < 8)
i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4);
else
i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4);
i2c->num_tokens++;
}
static void meson_gxbb_axg_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
{
unsigned long clk_rate = clk_get_rate(i2c->clk);
unsigned int div_h, div_l;
/* According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum LOW period is 1.3uS, and
* minimum HIGH is least 0.6us.
* For 400000 freq, the period is 2.5us. To keep within the specs, give 40% of period to
* HIGH and 60% to LOW. This means HIGH at 1.0us and LOW 1.5us.
* The same applies for Fast-mode plus, where LOW is 0.5us and HIGH is 0.26us.
* Duty = H/(H + L) = 2/5
*/
if (freq <= I2C_MAX_STANDARD_MODE_FREQ) {
div_h = DIV_ROUND_UP(clk_rate, freq);
div_l = DIV_ROUND_UP(div_h, 4);
div_h = DIV_ROUND_UP(div_h, 2) - FILTER_DELAY;
} else {
div_h = DIV_ROUND_UP(clk_rate * 2, freq * 5) - FILTER_DELAY;
div_l = DIV_ROUND_UP(clk_rate * 3, freq * 5 * 2);
}
/* clock divider has 12 bits */
if (div_h > GENMASK(11, 0)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div_h = GENMASK(11, 0);
}
if (div_l > GENMASK(11, 0)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div_l = GENMASK(11, 0);
}
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
FIELD_PREP(REG_CTRL_CLKDIV_MASK, div_h & GENMASK(9, 0)));
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div_h >> 10));
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/clk.h`, `linux/completion.h`, `linux/i2c.h`, `linux/interrupt.h`, `linux/io.h`, `linux/iopoll.h`, `linux/kernel.h`.
- Detected declarations: `struct meson_i2c`, `struct meson_i2c_data`, `function meson_i2c_set_mask`, `function meson_i2c_reset_tokens`, `function meson_i2c_add_token`, `function meson_gxbb_axg_i2c_set_clk_div`, `function meson6_i2c_set_clk_div`, `function meson_i2c_get_data`, `function meson_i2c_put_data`, `function meson_i2c_prepare_xfer`.
- 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.