drivers/spi/spi-rb4xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-rb4xx.c
Extension
.c
Size
5379 bytes
Lines
207
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 rb4xx_spi {
	void __iomem *base;
	struct clk *clk;
};

static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg)
{
	return __raw_readl(rbspi->base + reg);
}

static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value)
{
	__raw_writel(value, rbspi->base + reg);
}

static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value)
{
	u32 regval;

	regval = spi_ioc;
	if (value & BIT(0))
		regval |= AR71XX_SPI_IOC_DO;

	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
}

static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
{
	int i;

	for (i = 7; i >= 0; i--)
		do_spi_clk(rbspi, spi_ioc, byte >> i);
}

/* The CS2 pin is used to clock in a second bit per clock cycle. */
static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc,
				   u8 value)
{
	u32 regval;

	regval = spi_ioc;
	if (value & BIT(1))
		regval |= AR71XX_SPI_IOC_DO;
	if (value & BIT(0))
		regval |= AR71XX_SPI_IOC_CS(2);

	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
}

/* Two bits at a time, msb first */
static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
{
	do_spi_clk_two(rbspi, spi_ioc, byte >> 6);
	do_spi_clk_two(rbspi, spi_ioc, byte >> 4);
	do_spi_clk_two(rbspi, spi_ioc, byte >> 2);
	do_spi_clk_two(rbspi, spi_ioc, byte >> 0);
}

static void rb4xx_set_cs(struct spi_device *spi, bool enable)
{
	struct rb4xx_spi *rbspi = spi_controller_get_devdata(spi->controller);

	/*
	 * Setting CS is done along with bitbanging the actual values,
	 * since it's all on the same hardware register. However the
	 * CPLD needs CS deselected after every command.
	 */
	if (enable)
		rb4xx_write(rbspi, AR71XX_SPI_REG_IOC,
			    AR71XX_SPI_IOC_CS(0) | AR71XX_SPI_IOC_CS(1));
}

static int rb4xx_transfer_one(struct spi_controller *host,
			      struct spi_device *spi, struct spi_transfer *t)
{
	struct rb4xx_spi *rbspi = spi_controller_get_devdata(host);
	int i;
	u32 spi_ioc;
	u8 *rx_buf;
	const u8 *tx_buf;

	/*
	 * Prime the SPI register with the SPI device selected. The m25p80 boot
	 * flash and CPLD share the CS0 pin. This works because the CPLD's
	 * command set was designed to almost not clash with that of the
	 * boot flash.
	 */
	if (spi_get_chipselect(spi, 0) == 2)

Annotation

Implementation Notes