drivers/i2c/busses/i2c-at91-master.c
Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-at91-master.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/i2c/busses/i2c-at91-master.c- Extension
.c- Size
- 27990 bytes
- Lines
- 922
- 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.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/clk.hlinux/completion.hlinux/dma-mapping.hlinux/dmaengine.hlinux/err.hlinux/gpio/consumer.hlinux/i2c.hlinux/interrupt.hlinux/io.hlinux/of.hlinux/pinctrl/consumer.hlinux/platform_device.hlinux/pm_runtime.hlinux/string_choices.hi2c-at91.h
Detected Declarations
function Copyrightfunction at91_calc_twi_clockfunction at91_twi_dma_cleanupfunction at91_twi_write_next_bytefunction at91_twi_write_data_dma_callbackfunction at91_twi_write_data_dmafunction at91_twi_read_next_bytefunction at91_twi_read_data_dma_callbackfunction at91_twi_read_data_dmafunction atmel_twi_interruptfunction Registerfunction at91_do_twi_transferfunction at91_twi_xferfunction at91_twi_funcfunction at91_twi_configure_dmafunction at91_init_twi_recovery_gpiofunction at91_twi_recover_bus_cmdfunction at91_init_twi_recovery_infofunction at91_twi_probe_master
Annotated Snippet
if (hold > AT91_TWI_CWGR_HOLD_MAX) {
dev_warn(dev->dev,
"HOLD field set to its maximum value (%d instead of %d)\n",
AT91_TWI_CWGR_HOLD_MAX, hold);
hold = AT91_TWI_CWGR_HOLD_MAX;
}
}
if (pdata->has_adv_dig_filtr) {
/*
* filter width = 0 to AT91_TWI_FILTR_THRES_MAX
* peripheral clocks
*/
filter_width = DIV_ROUND_UP(t->digital_filter_width_ns
* (clk_get_rate(dev->clk) / 1000), 1000000);
if (filter_width > AT91_TWI_FILTR_THRES_MAX) {
dev_warn(dev->dev,
"Filter threshold set to its maximum value (%d instead of %d)\n",
AT91_TWI_FILTR_THRES_MAX, filter_width);
filter_width = AT91_TWI_FILTR_THRES_MAX;
}
}
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
| AT91_TWI_CWGR_HOLD(hold);
dev->filter_width = filter_width;
dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns), filter_width %d (%d ns)\n",
cdiv, ckdiv, hold, t->sda_hold_ns, filter_width,
t->digital_filter_width_ns);
}
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
{
struct at91_twi_dma *dma = &dev->dma;
at91_twi_irq_save(dev);
if (dma->xfer_in_progress) {
if (dma->direction == DMA_FROM_DEVICE)
dmaengine_terminate_sync(dma->chan_rx);
else
dmaengine_terminate_sync(dma->chan_tx);
dma->xfer_in_progress = false;
}
if (dma->buf_mapped) {
dma_unmap_single(dev->dev, sg_dma_address(&dma->sg[0]),
dev->buf_len, dma->direction);
dma->buf_mapped = false;
}
at91_twi_irq_restore(dev);
}
static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
{
if (!dev->buf_len)
return;
/* 8bit write works with and without FIFO */
writeb_relaxed(*dev->buf, dev->base + AT91_TWI_THR);
/* send stop when last byte has been written */
if (--dev->buf_len == 0) {
if (!dev->use_alt_cmd)
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_TXRDY);
}
dev_dbg(dev->dev, "wrote 0x%x, to go %zu\n", *dev->buf, dev->buf_len);
++dev->buf;
}
static void at91_twi_write_data_dma_callback(void *data)
{
struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]),
dev->buf_len, DMA_TO_DEVICE);
/*
* When this callback is called, THR/TX FIFO is likely not to be empty
* yet. So we have to wait for TXCOMP or NACK bits to be set into the
* Status Register to be sure that the STOP bit has been sent and the
* transfer is completed. The NACK interrupt has already been enabled,
* we just have to enable TXCOMP one.
*/
at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
Annotation
- Immediate include surface: `linux/clk.h`, `linux/completion.h`, `linux/dma-mapping.h`, `linux/dmaengine.h`, `linux/err.h`, `linux/gpio/consumer.h`, `linux/i2c.h`, `linux/interrupt.h`.
- Detected declarations: `function Copyright`, `function at91_calc_twi_clock`, `function at91_twi_dma_cleanup`, `function at91_twi_write_next_byte`, `function at91_twi_write_data_dma_callback`, `function at91_twi_write_data_dma`, `function at91_twi_read_next_byte`, `function at91_twi_read_data_dma_callback`, `function at91_twi_read_data_dma`, `function atmel_twi_interrupt`.
- 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.