drivers/spi/spi-sunplus-sp7021.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-sunplus-sp7021.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-sunplus-sp7021.c
Extension
.c
Size
17041 bytes
Lines
563
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 sp7021_spi_ctlr {
	struct device *dev;
	struct spi_controller *ctlr;
	void __iomem *m_base;
	void __iomem *s_base;
	u32 xfer_conf;
	int mode;
	int m_irq;
	int s_irq;
	struct clk *spi_clk;
	struct reset_control *rstc;
	// data xfer lock
	struct mutex buf_lock;
	struct completion isr_done;
	struct completion target_isr;
	unsigned int  rx_cur_len;
	unsigned int  tx_cur_len;
	unsigned int  data_unit;
	const u8 *tx_buf;
	u8 *rx_buf;
};

static irqreturn_t sp7021_spi_target_irq(int irq, void *dev)
{
	struct sp7021_spi_ctlr *pspim = dev;
	unsigned int data_status;

	data_status = readl(pspim->s_base + SP7021_DATA_RDY_REG);
	data_status |= SP7021_SLAVE_CLR_INT;
	writel(data_status, pspim->s_base + SP7021_DATA_RDY_REG);
	complete(&pspim->target_isr);
	return IRQ_HANDLED;
}

static int sp7021_spi_target_abort(struct spi_controller *ctlr)
{
	struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);

	complete(&pspim->target_isr);
	complete(&pspim->isr_done);
	return 0;
}

static int sp7021_spi_target_tx(struct spi_device *spi, struct spi_transfer *xfer)
{
	struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller);
	u32 value;

	reinit_completion(&pspim->target_isr);
	value = SP7021_SLAVE_DMA_EN | SP7021_SLAVE_DMA_RW | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3);
	writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG);
	writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG);
	writel(xfer->tx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG);
	value = readl(pspim->s_base + SP7021_DATA_RDY_REG);
	value |= SP7021_SLAVE_DATA_RDY;
	writel(value, pspim->s_base + SP7021_DATA_RDY_REG);
	if (wait_for_completion_interruptible(&pspim->isr_done)) {
		dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__);
		return -EINTR;
	}
	return 0;
}

static int sp7021_spi_target_rx(struct spi_device *spi, struct spi_transfer *xfer)
{
	struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller);
	u32 value;

	reinit_completion(&pspim->isr_done);
	value = SP7021_SLAVE_DMA_EN | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3);
	writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG);
	writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG);
	writel(xfer->rx_dma, pspim->s_base + SP7021_SLAVE_DMA_ADDR_REG);
	if (wait_for_completion_interruptible(&pspim->isr_done)) {
		dev_err(&spi->dev, "%s() wait_for_completion err\n", __func__);
		return -EINTR;
	}
	writel(SP7021_SLAVE_SW_RST, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG);
	return 0;
}

static void sp7021_spi_host_rb(struct sp7021_spi_ctlr *pspim, unsigned int len)
{
	int i;

	for (i = 0; i < len; i++) {
		pspim->rx_buf[pspim->rx_cur_len] =
			readl(pspim->m_base + SP7021_FIFO_REG);
		pspim->rx_cur_len++;
	}

Annotation

Implementation Notes