drivers/spi/spi-rockchip.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-rockchip.c
Extension
.c
Size
27543 bytes
Lines
1045
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 rockchip_spi {
	struct device *dev;

	struct clk *spiclk;
	struct clk *apb_pclk;

	void __iomem *regs;
	dma_addr_t dma_addr_rx;
	dma_addr_t dma_addr_tx;

	const void *tx;
	void *rx;
	unsigned int tx_left;
	unsigned int rx_left;

	atomic_t state;

	/*depth of the FIFO buffer */
	u32 fifo_len;
	/* frequency of spiclk */
	u32 freq;

	u8 n_bytes;
	u8 rsd;

	bool target_abort;
	bool cs_inactive; /* spi target transmission stop when cs inactive */
	bool cs_high_supported; /* native CS supports active-high polarity */

	struct spi_transfer *xfer; /* Store xfer temporarily */
};

static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
{
	writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}

static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool target_mode)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(5);

	do {
		if (target_mode) {
			if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_TARGET_TX_BUSY) &&
			    !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)))
				return;
		} else {
			if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
				return;
		}
	} while (!time_after(jiffies, timeout));

	dev_warn(rs->dev, "spi controller is in busy state!\n");
}

static u32 get_fifo_len(struct rockchip_spi *rs)
{
	u32 ver;

	ver = readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION);

	switch (ver) {
	case ROCKCHIP_SPI_VER2_TYPE1:
	case ROCKCHIP_SPI_VER2_TYPE2:
		return 64;
	default:
		return 32;
	}
}

static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{
	struct spi_controller *ctlr = spi->controller;
	struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
	bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable;
	bool cs_actual;

	/*
	 * SPI subsystem tries to avoid no-op calls that would break the PM
	 * refcount below. It can't however for the first time it is used.
	 * To detect this case we read it here and bail out early for no-ops.
	 */
	if (spi_get_csgpiod(spi, 0))
		cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & 1);
	else
		cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) &
			       BIT(spi_get_chipselect(spi, 0)));
	if (unlikely(cs_actual == cs_asserted))
		return;

Annotation

Implementation Notes