drivers/spi/spi-xlp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-xlp.c
Extension
.c
Size
11229 bytes
Lines
448
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 xlp_spi_priv {
	struct device		dev;		/* device structure */
	void __iomem		*base;		/* spi registers base address */
	const u8		*tx_buf;	/* tx data buffer */
	u8			*rx_buf;	/* rx data buffer */
	int			tx_len;		/* tx xfer length */
	int			rx_len;		/* rx xfer length */
	int			txerrors;	/* TXFIFO underflow count */
	int			rxerrors;	/* RXFIFO overflow count */
	int			cs;		/* target device chip select */
	u32			spi_clk;	/* spi clock frequency */
	bool			cmd_cont;	/* cs active */
	struct completion	done;		/* completion notification */
};

static inline u32 xlp_spi_reg_read(struct xlp_spi_priv *priv,
				int cs, int regoff)
{
	return readl(priv->base + regoff + cs * SPI_CS_OFFSET);
}

static inline void xlp_spi_reg_write(struct xlp_spi_priv *priv, int cs,
				int regoff, u32 val)
{
	writel(val, priv->base + regoff + cs * SPI_CS_OFFSET);
}

static inline void xlp_spi_sysctl_write(struct xlp_spi_priv *priv,
				int regoff, u32 val)
{
	writel(val, priv->base + regoff);
}

/*
 * Setup global SPI_SYSCTRL register for all SPI channels.
 */
static void xlp_spi_sysctl_setup(struct xlp_spi_priv *xspi)
{
	int cs;

	for (cs = 0; cs < XLP_SPI_MAX_CS; cs++)
		xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL,
				XLP_SPI_SYS_RESET << cs);
	xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL, XLP_SPI_SYS_PMEN);
}

static int xlp_spi_setup(struct spi_device *spi)
{
	struct xlp_spi_priv *xspi;
	u32 fdiv, cfg;
	int cs;

	xspi = spi_controller_get_devdata(spi->controller);
	cs = spi_get_chipselect(spi, 0);
	/*
	 * The value of fdiv must be between 4 and 65535.
	 */
	fdiv = DIV_ROUND_UP(xspi->spi_clk, spi->max_speed_hz);
	if (fdiv > XLP_SPI_FDIV_MAX)
		fdiv = XLP_SPI_FDIV_MAX;
	else if (fdiv < XLP_SPI_FDIV_MIN)
		fdiv = XLP_SPI_FDIV_MIN;

	xlp_spi_reg_write(xspi, cs, XLP_SPI_FDIV, fdiv);
	xlp_spi_reg_write(xspi, cs, XLP_SPI_FIFO_THRESH, XLP_SPI_TXRXTH);
	cfg = xlp_spi_reg_read(xspi, cs, XLP_SPI_CONFIG);
	if (spi->mode & SPI_CPHA)
		cfg |= XLP_SPI_CPHA;
	else
		cfg &= ~XLP_SPI_CPHA;
	if (spi->mode & SPI_CPOL)
		cfg |= XLP_SPI_CPOL;
	else
		cfg &= ~XLP_SPI_CPOL;
	if (!(spi->mode & SPI_CS_HIGH))
		cfg |= XLP_SPI_CS_POL;
	else
		cfg &= ~XLP_SPI_CS_POL;
	if (spi->mode & SPI_LSB_FIRST)
		cfg |= XLP_SPI_CS_LSBFE;
	else
		cfg &= ~XLP_SPI_CS_LSBFE;

	cfg |= XLP_SPI_TXMOSI_EN | XLP_SPI_RXMISO_EN;
	if (fdiv == 4)
		cfg |= XLP_SPI_RXCAP_EN;
	xlp_spi_reg_write(xspi, cs, XLP_SPI_CONFIG, cfg);

	return 0;
}

Annotation

Implementation Notes