drivers/spi/spi-sun6i.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-sun6i.c
Extension
.c
Size
21265 bytes
Lines
820
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 sun6i_spi_cfg {
	unsigned long		fifo_depth;
	bool			has_clk_ctl;
	u32			mode_bits;
};

struct sun6i_spi {
	struct spi_controller	*host;
	void __iomem		*base_addr;
	dma_addr_t		dma_addr_rx;
	dma_addr_t		dma_addr_tx;
	struct clk		*hclk;
	struct clk		*mclk;
	struct reset_control	*rstc;

	struct completion	done;
	struct completion	dma_rx_done;

	const u8		*tx_buf;
	u8			*rx_buf;
	int			len;
	const struct sun6i_spi_cfg *cfg;
};

static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
{
	return readl(sspi->base_addr + reg);
}

static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
{
	writel(value, sspi->base_addr + reg);
}

static inline u32 sun6i_spi_get_rx_fifo_count(struct sun6i_spi *sspi)
{
	u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);

	return FIELD_GET(SUN6I_FIFO_STA_RF_CNT_MASK, reg);
}

static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
{
	u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);

	return FIELD_GET(SUN6I_FIFO_STA_TF_CNT_MASK, reg);
}

static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask)
{
	u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);

	reg &= ~mask;
	sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
}

static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi)
{
	u32 len;
	u8 byte;

	/* See how much data is available */
	len = sun6i_spi_get_rx_fifo_count(sspi);

	while (len--) {
		byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
		if (sspi->rx_buf)
			*sspi->rx_buf++ = byte;
	}
}

static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
{
	u32 cnt;
	int len;
	u8 byte;

	/* See how much data we can fit */
	cnt = sspi->cfg->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);

	len = min((int)cnt, sspi->len);

	while (len--) {
		byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
		writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
		sspi->len--;
	}
}

static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)

Annotation

Implementation Notes