drivers/spi/spi-geni-qcom.c
Source file repositories/reference/linux-study-clean/drivers/spi/spi-geni-qcom.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/spi/spi-geni-qcom.c- Extension
.c- Size
- 34496 bytes
- Lines
- 1242
- 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.
- 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.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
trace/events/qcom_geni_spi.hlinux/clk.hlinux/dmaengine.hlinux/dma-mapping.hlinux/dma/qcom-gpi-dma.hlinux/interrupt.hlinux/io.hlinux/log2.hlinux/module.hlinux/platform_device.hlinux/pm_opp.hlinux/pm_runtime.hlinux/property.hlinux/soc/qcom/geni-se.hlinux/spi/spi.hlinux/spinlock.h
Detected Declarations
struct spi_geni_masterfunction spi_slv_setupfunction get_spi_clk_cfgfunction handle_se_timeoutfunction handle_gpi_timeoutfunction spi_geni_handle_errfunction spi_geni_is_abort_still_pendingfunction spi_setup_word_lenfunction geni_spi_set_clock_and_bwfunction setup_fifo_paramsfunction spi_gsi_callback_resultfunction setup_gsi_xferfunction get_xfer_len_in_wordsfunction geni_can_dmafunction spi_geni_prepare_messagefunction spi_geni_release_dma_chanfunction spi_geni_grab_gpi_chanfunction spi_geni_initfunction geni_byte_per_fifo_wordfunction geni_spi_handle_txfunction geni_spi_handle_rxfunction setup_se_xferfunction spi_geni_transfer_onefunction geni_spi_isrfunction spi_geni_target_abortfunction spi_geni_probefunction spi_geni_runtime_suspendfunction spi_geni_runtime_resumefunction spi_geni_suspendfunction spi_geni_resume
Annotated Snippet
struct spi_geni_master {
struct geni_se se;
struct device *dev;
u32 tx_fifo_depth;
u32 fifo_width_bits;
u32 tx_wm;
u32 last_mode;
u8 last_cs;
unsigned long cur_speed_hz;
unsigned long cur_sclk_hz;
unsigned int cur_bits_per_word;
unsigned int tx_rem_bytes;
unsigned int rx_rem_bytes;
const struct spi_transfer *cur_xfer;
struct completion cs_done;
struct completion cancel_done;
struct completion abort_done;
struct completion tx_reset_done;
struct completion rx_reset_done;
unsigned int oversampling;
spinlock_t lock;
int irq;
bool cs_flag;
bool abort_failed;
struct dma_chan *tx;
struct dma_chan *rx;
int cur_xfer_mode;
};
static void spi_slv_setup(struct spi_geni_master *mas)
{
struct geni_se *se = &mas->se;
writel(SPI_SLAVE_EN, se->base + SE_SPI_SLAVE_EN);
writel(GENI_IO_MUX_0_EN, se->base + GENI_OUTPUT_CTRL);
writel(START_TRIGGER, se->base + SE_GENI_CFG_SEQ_START);
dev_dbg(mas->dev, "spi slave setup done\n");
}
static int get_spi_clk_cfg(unsigned int speed_hz,
struct spi_geni_master *mas,
unsigned int *clk_idx,
unsigned int *clk_div)
{
unsigned long sclk_freq;
unsigned int actual_hz;
int ret;
ret = geni_se_clk_freq_match(&mas->se,
speed_hz * mas->oversampling,
clk_idx, &sclk_freq, false);
if (ret) {
dev_err(mas->dev, "Failed(%d) to find src clk for %dHz\n",
ret, speed_hz);
return ret;
}
*clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz);
actual_hz = sclk_freq / (mas->oversampling * *clk_div);
dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz,
actual_hz, sclk_freq, *clk_idx, *clk_div);
ret = dev_pm_opp_set_rate(mas->dev, sclk_freq);
if (ret)
dev_err(mas->dev, "dev_pm_opp_set_rate failed %d\n", ret);
else
mas->cur_sclk_hz = sclk_freq;
return ret;
}
static void handle_se_timeout(struct spi_controller *spi)
{
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
unsigned long time_left;
struct geni_se *se = &mas->se;
const struct spi_transfer *xfer;
spin_lock_irq(&mas->lock);
if (mas->cur_xfer_mode == GENI_SE_FIFO)
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
xfer = mas->cur_xfer;
mas->cur_xfer = NULL;
/* The controller doesn't support the Cancel commnand in target mode */
if (!spi->target) {
reinit_completion(&mas->cancel_done);
geni_se_cancel_m_cmd(se);
Annotation
- Immediate include surface: `trace/events/qcom_geni_spi.h`, `linux/clk.h`, `linux/dmaengine.h`, `linux/dma-mapping.h`, `linux/dma/qcom-gpi-dma.h`, `linux/interrupt.h`, `linux/io.h`, `linux/log2.h`.
- Detected declarations: `struct spi_geni_master`, `function spi_slv_setup`, `function get_spi_clk_cfg`, `function handle_se_timeout`, `function handle_gpi_timeout`, `function spi_geni_handle_err`, `function spi_geni_is_abort_still_pending`, `function spi_setup_word_len`, `function geni_spi_set_clock_and_bw`, `function setup_fifo_params`.
- Atlas domain: Driver Families / drivers/spi.
- 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.