drivers/spi/spi-sprd.c
Source file repositories/reference/linux-study-clean/drivers/spi/spi-sprd.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/spi/spi-sprd.c- Extension
.c- Size
- 27327 bytes
- Lines
- 1078
- Domain
- Driver Families
- Bucket
- drivers/spi
- 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/dmaengine.hlinux/dma-mapping.hlinux/dma/sprd-dma.hlinux/interrupt.hlinux/io.hlinux/iopoll.hlinux/kernel.hlinux/module.hlinux/of.hlinux/of_dma.hlinux/platform_device.hlinux/pm_runtime.hlinux/spi/spi.h
Detected Declarations
struct sprd_spi_dmastruct sprd_spienum sprd_spi_dma_channelfunction sprd_spi_transfer_max_timeoutfunction sprd_spi_wait_for_tx_endfunction sprd_spi_wait_for_rx_endfunction sprd_spi_tx_reqfunction sprd_spi_rx_reqfunction sprd_spi_enter_idlefunction sprd_spi_set_transfer_bitsfunction sprd_spi_set_tx_lengthfunction sprd_spi_set_rx_lengthfunction sprd_spi_chipselectfunction sprd_spi_write_only_receivefunction sprd_spi_write_bufs_u8function sprd_spi_write_bufs_u16function sprd_spi_write_bufs_u32function sprd_spi_read_bufs_u8function sprd_spi_read_bufs_u16function sprd_spi_read_bufs_u32function sprd_spi_txrx_bufsfunction sprd_spi_irq_enablefunction sprd_spi_irq_disablefunction sprd_spi_dma_enablefunction sprd_spi_dma_submitfunction sprd_spi_dma_rx_configfunction sprd_spi_dma_tx_configfunction sprd_spi_dma_requestfunction sprd_spi_dma_releasefunction sprd_spi_dma_txrx_bufsfunction sprd_spi_set_speedfunction sprd_spi_init_hwfunction sprd_spi_setup_transferfunction sprd_spi_transfer_onefunction sprd_spi_handle_irqfunction sprd_spi_irq_initfunction sprd_spi_clk_initfunction sprd_spi_can_dmafunction sprd_spi_dma_initfunction sprd_spi_probefunction sprd_spi_removefunction sprd_spi_runtime_suspendfunction sprd_spi_runtime_resume
Annotated Snippet
struct sprd_spi_dma {
bool enable;
struct dma_chan *dma_chan[SPRD_SPI_MAX];
enum dma_slave_buswidth width;
u32 fragmens_len;
u32 rx_len;
};
struct sprd_spi {
void __iomem *base;
phys_addr_t phy_base;
struct device *dev;
struct clk *clk;
int irq;
u32 src_clk;
u32 hw_mode;
u32 trans_len;
u32 trans_mode;
u32 word_delay;
u32 hw_speed_hz;
u32 len;
int status;
struct sprd_spi_dma dma;
struct completion xfer_completion;
const void *tx_buf;
void *rx_buf;
int (*read_bufs)(struct sprd_spi *ss, u32 len);
int (*write_bufs)(struct sprd_spi *ss, u32 len);
};
static u32 sprd_spi_transfer_max_timeout(struct sprd_spi *ss,
struct spi_transfer *t)
{
/*
* The time spent on transmission of the full FIFO data is the maximum
* SPI transmission time.
*/
u32 size = t->bits_per_word * SPRD_SPI_FIFO_SIZE;
u32 bit_time_us = DIV_ROUND_UP(USEC_PER_SEC, ss->hw_speed_hz);
u32 total_time_us = size * bit_time_us;
/*
* There is an interval between data and the data in our SPI hardware,
* so the total transmission time need add the interval time.
*/
u32 interval_cycle = SPRD_SPI_FIFO_SIZE * ss->word_delay;
u32 interval_time_us = DIV_ROUND_UP(interval_cycle * USEC_PER_SEC,
ss->src_clk);
return total_time_us + interval_time_us;
}
static int sprd_spi_wait_for_tx_end(struct sprd_spi *ss, struct spi_transfer *t)
{
u32 val, us;
int ret;
us = sprd_spi_transfer_max_timeout(ss, t);
ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val,
val & SPRD_SPI_TX_END_IRQ, 0, us);
if (ret) {
dev_err(ss->dev, "SPI error, spi send timeout!\n");
return ret;
}
ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_STS2, val,
!(val & SPRD_SPI_TX_BUSY), 0, us);
if (ret) {
dev_err(ss->dev, "SPI error, spi busy timeout!\n");
return ret;
}
writel_relaxed(SPRD_SPI_TX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR);
return 0;
}
static int sprd_spi_wait_for_rx_end(struct sprd_spi *ss, struct spi_transfer *t)
{
u32 val, us;
int ret;
us = sprd_spi_transfer_max_timeout(ss, t);
ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val,
val & SPRD_SPI_RX_END_IRQ, 0, us);
if (ret) {
dev_err(ss->dev, "SPI error, spi rx timeout!\n");
return ret;
}
writel_relaxed(SPRD_SPI_RX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR);
Annotation
- Immediate include surface: `linux/clk.h`, `linux/dmaengine.h`, `linux/dma-mapping.h`, `linux/dma/sprd-dma.h`, `linux/interrupt.h`, `linux/io.h`, `linux/iopoll.h`, `linux/kernel.h`.
- Detected declarations: `struct sprd_spi_dma`, `struct sprd_spi`, `enum sprd_spi_dma_channel`, `function sprd_spi_transfer_max_timeout`, `function sprd_spi_wait_for_tx_end`, `function sprd_spi_wait_for_rx_end`, `function sprd_spi_tx_req`, `function sprd_spi_rx_req`, `function sprd_spi_enter_idle`, `function sprd_spi_set_transfer_bits`.
- Atlas domain: Driver Families / drivers/spi.
- 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.