drivers/spi/spi-qcom-qspi.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-qcom-qspi.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-qcom-qspi.c
Extension
.c
Size
24969 bytes
Lines
976
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct qspi_cmd_desc {
	u32 data_address;
	u32 next_descriptor;
	u32 direction:1;
	u32 multi_io_mode:3;
	u32 reserved1:4;
	u32 fragment:1;
	u32 reserved2:7;
	u32 length:16;
};

struct qspi_xfer {
	union {
		const void *tx_buf;
		void *rx_buf;
	};
	unsigned int rem_bytes;
	unsigned int buswidth;
	enum qspi_dir dir;
	bool is_last;
};

enum qspi_clocks {
	QSPI_CLK_CORE,
	QSPI_CLK_IFACE,
	QSPI_NUM_CLKS
};

/*
 * Number of entries in sgt returned from spi framework that-
 * will be supported. Can be modified as required.
 * In practice, given max_dma_len is 64KB, the number of
 * entries is not expected to exceed 1.
 */
#define QSPI_MAX_SG 5

struct qcom_qspi {
	void __iomem *base;
	struct device *dev;
	struct clk_bulk_data *clks;
	struct qspi_xfer xfer;
	struct dma_pool *dma_cmd_pool;
	dma_addr_t dma_cmd_desc[QSPI_MAX_SG];
	void *virt_cmd_desc[QSPI_MAX_SG];
	unsigned int n_cmd_desc;
	struct icc_path *icc_path_cpu_to_qspi;
	struct icc_path *icc_path_mem;
	unsigned long last_speed;
	/* Lock to protect data accessed by IRQs */
	spinlock_t lock;
};

static u32 qspi_buswidth_to_iomode(struct qcom_qspi *ctrl,
				   unsigned int buswidth)
{
	switch (buswidth) {
	case 1:
		return SDR_1BIT;
	case 2:
		return SDR_2BIT;
	case 4:
		return SDR_4BIT;
	default:
		dev_warn_once(ctrl->dev,
				"Unexpected bus width: %u\n", buswidth);
		return SDR_1BIT;
	}
}

static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl)
{
	u32 pio_xfer_cfg;
	u32 iomode;
	const struct qspi_xfer *xfer;

	xfer = &ctrl->xfer;
	pio_xfer_cfg = readl(ctrl->base + PIO_XFER_CFG);
	pio_xfer_cfg &= ~TRANSFER_DIRECTION;
	pio_xfer_cfg |= xfer->dir;
	if (xfer->is_last)
		pio_xfer_cfg &= ~TRANSFER_FRAGMENT;
	else
		pio_xfer_cfg |= TRANSFER_FRAGMENT;
	pio_xfer_cfg &= ~MULTI_IO_MODE_MSK;
	iomode = qspi_buswidth_to_iomode(ctrl, xfer->buswidth);
	pio_xfer_cfg |= iomode << MULTI_IO_MODE_SHFT;

	writel(pio_xfer_cfg, ctrl->base + PIO_XFER_CFG);
}

Annotation

Implementation Notes