drivers/spi/spi-img-spfi.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-img-spfi.c
Extension
.c
Size
19863 bytes
Lines
761
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 img_spfi {
	struct device *dev;
	struct spi_controller *host;
	spinlock_t lock;

	void __iomem *regs;
	phys_addr_t phys;
	int irq;
	struct clk *spfi_clk;
	struct clk *sys_clk;

	struct dma_chan *rx_ch;
	struct dma_chan *tx_ch;
	bool tx_dma_busy;
	bool rx_dma_busy;
};

static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{
	return readl(spfi->regs + reg);
}

static inline void spfi_writel(struct img_spfi *spfi, u32 val, u32 reg)
{
	writel(val, spfi->regs + reg);
}

static inline void spfi_start(struct img_spfi *spfi)
{
	u32 val;

	val = spfi_readl(spfi, SPFI_CONTROL);
	val |= SPFI_CONTROL_SPFI_EN;
	spfi_writel(spfi, val, SPFI_CONTROL);
}

static inline void spfi_reset(struct img_spfi *spfi)
{
	spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL);
	spfi_writel(spfi, 0, SPFI_CONTROL);
}

static int spfi_wait_all_done(struct img_spfi *spfi)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(50);

	while (time_before(jiffies, timeout)) {
		u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);

		if (status & SPFI_INTERRUPT_ALLDONETRIG) {
			spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
				    SPFI_INTERRUPT_CLEAR);
			return 0;
		}
		cpu_relax();
	}

	dev_err(spfi->dev, "Timed out waiting for transaction to complete\n");
	spfi_reset(spfi);

	return -ETIMEDOUT;
}

static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
				     unsigned int max)
{
	unsigned int count = 0;
	u32 status;

	while (count < max / 4) {
		spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR);
		status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
		if (status & SPFI_INTERRUPT_SDFUL)
			break;
		spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA);
		count++;
	}

	return count * 4;
}

static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf,
				    unsigned int max)
{
	unsigned int count = 0;
	u32 status;

	while (count < max) {
		spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR);
		status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);

Annotation

Implementation Notes