drivers/spi/spi-ar934x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-ar934x.c
Extension
.c
Size
5944 bytes
Lines
234
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 ar934x_spi {
	struct spi_controller *ctlr;
	void __iomem *base;
	struct clk *clk;
	unsigned int clk_freq;
};

static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq)
{
	int div = DIV_ROUND_UP(sp->clk_freq, freq * 2) - 1;

	if (div < 0)
		return 0;
	else if (div > AR934X_SPI_CLK_MASK)
		return -EINVAL;
	else
		return div;
}

static int ar934x_spi_setup(struct spi_device *spi)
{
	struct ar934x_spi *sp = spi_controller_get_devdata(spi->controller);

	if ((spi->max_speed_hz == 0) ||
	    (spi->max_speed_hz > (sp->clk_freq / 2))) {
		spi->max_speed_hz = sp->clk_freq / 2;
	} else if (spi->max_speed_hz < (sp->clk_freq / 128)) {
		dev_err(&spi->dev, "spi clock is too low\n");
		return -EINVAL;
	}

	return 0;
}

static int ar934x_spi_transfer_one_message(struct spi_controller *ctlr,
					   struct spi_message *m)
{
	struct ar934x_spi *sp = spi_controller_get_devdata(ctlr);
	struct spi_transfer *t = NULL;
	struct spi_device *spi = m->spi;
	unsigned long trx_done, trx_cur;
	int stat = 0;
	u8 bpw, term = 0;
	int div, i;
	u32 reg;
	const u8 *tx_buf;
	u8 *buf;

	m->actual_length = 0;
	list_for_each_entry(t, &m->transfers, transfer_list) {
		if (t->bits_per_word >= 8 && t->bits_per_word < 32)
			bpw = t->bits_per_word >> 3;
		else
			bpw = 4;

		if (t->speed_hz)
			div = ar934x_spi_clk_div(sp, t->speed_hz);
		else
			div = ar934x_spi_clk_div(sp, spi->max_speed_hz);
		if (div < 0) {
			stat = -EIO;
			goto msg_done;
		}

		reg = ioread32(sp->base + AR934X_SPI_REG_CTRL);
		reg &= ~AR934X_SPI_CLK_MASK;
		reg |= div;
		iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL);
		iowrite32(0, sp->base + AR934X_SPI_DATAOUT);

		for (trx_done = 0; trx_done < t->len; trx_done += bpw) {
			trx_cur = t->len - trx_done;
			if (trx_cur > bpw)
				trx_cur = bpw;
			else if (list_is_last(&t->transfer_list, &m->transfers))
				term = 1;

			if (t->tx_buf) {
				tx_buf = t->tx_buf + trx_done;
				reg = tx_buf[0];
				for (i = 1; i < trx_cur; i++)
					reg = reg << 8 | tx_buf[i];
				iowrite32(reg, sp->base + AR934X_SPI_DATAOUT);
			}

			reg = AR934X_SPI_SHIFT_VAL(spi_get_chipselect(spi, 0), term,
						   trx_cur * 8);
			iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL);
			stat = readl_poll_timeout(
				sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg,

Annotation

Implementation Notes