drivers/spi/spi-sn-f-ospi.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-sn-f-ospi.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-sn-f-ospi.c
Extension
.c
Size
16917 bytes
Lines
674
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 f_ospi {
	void __iomem *base;
	struct device *dev;
	struct clk *clk;
	struct mutex mlock;
};

static u32 f_ospi_get_dummy_cycle(const struct spi_mem_op *op)
{
	if (!op->dummy.nbytes)
		return 0;

	return (op->dummy.nbytes * 8) / op->dummy.buswidth;
}

static void f_ospi_clear_irq(struct f_ospi *ospi)
{
	writel(OSPI_IRQ_CS_DEASSERT | OSPI_IRQ_CS_TRANS_COMP,
	       ospi->base + OSPI_IRQ);
}

static void f_ospi_enable_irq_status(struct f_ospi *ospi, u32 irq_bits)
{
	u32 val;

	val = readl(ospi->base + OSPI_IRQ_STAT_EN);
	val |= irq_bits;
	writel(val, ospi->base + OSPI_IRQ_STAT_EN);
}

static void f_ospi_disable_irq_status(struct f_ospi *ospi, u32 irq_bits)
{
	u32 val;

	val = readl(ospi->base + OSPI_IRQ_STAT_EN);
	val &= ~irq_bits;
	writel(val, ospi->base + OSPI_IRQ_STAT_EN);
}

static void f_ospi_disable_irq_output(struct f_ospi *ospi, u32 irq_bits)
{
	u32 val;

	val = readl(ospi->base + OSPI_IRQ_SIG_EN);
	val &= ~irq_bits;
	writel(val, ospi->base + OSPI_IRQ_SIG_EN);
}

static int f_ospi_prepare_config(struct f_ospi *ospi)
{
	u32 val, stat0, stat1;

	/* G4: Disable internal clock */
	val = readl(ospi->base + OSPI_CLK_CTL);
	val &= ~(OSPI_CLK_CTL_BOOT_INT_CLK_EN | OSPI_CLK_CTL_INT_CLK_EN);
	writel(val, ospi->base + OSPI_CLK_CTL);

	/* G5: Wait for stop */
	stat0 = OSPI_STAT_IS_AXI_WRITING | OSPI_STAT_IS_AXI_READING;
	stat1 = OSPI_STAT_IS_SPI_IDLE | OSPI_STAT_IS_SPI_INT_CLK_STOP;

	return readl_poll_timeout(ospi->base + OSPI_STAT,
				  val, (val & (stat0 | stat1)) == stat1,
				  0, OSPI_WAIT_MAX_MSEC);
}

static int f_ospi_unprepare_config(struct f_ospi *ospi)
{
	u32 val;

	/* G11: Enable internal clock */
	val = readl(ospi->base + OSPI_CLK_CTL);
	val |= OSPI_CLK_CTL_BOOT_INT_CLK_EN | OSPI_CLK_CTL_INT_CLK_EN;
	writel(val, ospi->base + OSPI_CLK_CTL);

	/* G12: Wait for clock to start */
	return readl_poll_timeout(ospi->base + OSPI_STAT,
				  val, !(val & OSPI_STAT_IS_SPI_INT_CLK_STOP),
				  0, OSPI_WAIT_MAX_MSEC);
}

static void f_ospi_config_clk(struct f_ospi *ospi, u32 device_hz)
{
	long rate_hz = clk_get_rate(ospi->clk);
	u32 div = DIV_ROUND_UP(rate_hz, device_hz);
	u32 div_reg;
	u32 val;

	if (rate_hz < device_hz) {
		dev_warn(ospi->dev, "Device frequency too large: %d\n",

Annotation

Implementation Notes