drivers/spi/spi-atcspi200.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-atcspi200.c
Extension
.c
Size
17890 bytes
Lines
659
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 atcspi_dev {
	struct spi_controller	*host;
	struct mutex		mutex_lock;
	struct completion	dma_completion;
	struct device		*dev;
	struct regmap		*regmap;
	struct clk		*clk;
	dma_addr_t		dma_addr;
	unsigned int		clk_rate;
	unsigned int		sclk_rate;
	unsigned int		txfifo_size;
	unsigned int		rxfifo_size;
	bool			data_merge;
	bool			use_dma;
};

static int atcspi_wait_fifo_ready(struct atcspi_dev *spi,
				  enum spi_mem_data_dir dir)
{
	unsigned int val;
	unsigned int mask;
	int ret;

	mask = (dir == SPI_MEM_DATA_OUT) ? ATCSPI_TX_FULL : ATCSPI_RX_EMPTY;
	ret = regmap_read_poll_timeout(spi->regmap,
				       ATCSPI_STATUS,
				       val,
				       !(val & mask),
				       0,
				       ATCSPI_RDY_TIMEOUT_US);
	if (ret)
		dev_info(spi->dev, "Timed out waiting for FIFO ready\n");

	return ret;
}

static int atcspi_xfer_data_poll(struct atcspi_dev *spi,
				 const struct spi_mem_op *op)
{
	void *rx_buf = op->data.buf.in;
	const void *tx_buf = op->data.buf.out;
	unsigned int val;
	int trans_bytes = op->data.nbytes;
	int num_byte;
	int ret = 0;

	num_byte = spi->data_merge ? 4 : 1;
	while (trans_bytes) {
		if (op->data.dir == SPI_MEM_DATA_OUT) {
			ret = atcspi_wait_fifo_ready(spi, SPI_MEM_DATA_OUT);
			if (ret)
				return ret;

			if (spi->data_merge)
				val = *(unsigned int *)tx_buf;
			else
				val = *(unsigned char *)tx_buf;
			regmap_write(spi->regmap, ATCSPI_DATA, val);
			tx_buf = (unsigned char *)tx_buf + num_byte;
		} else {
			ret = atcspi_wait_fifo_ready(spi, SPI_MEM_DATA_IN);
			if (ret)
				return ret;

			regmap_read(spi->regmap, ATCSPI_DATA, &val);
			if (spi->data_merge)
				*(unsigned int *)rx_buf = val;
			else
				*(unsigned char *)rx_buf = (unsigned char)val;
			rx_buf = (unsigned char *)rx_buf + num_byte;
		}
		trans_bytes -= num_byte;
	}

	return ret;
}

static void atcspi_set_trans_ctl(struct atcspi_dev *spi,
				 const struct spi_mem_op *op)
{
	unsigned int tc = 0;

	if (op->cmd.nbytes)
		tc |= TRANS_CMD_EN;
	if (op->addr.nbytes)
		tc |= TRANS_ADDR_EN;
	if (op->addr.buswidth > 1)
		tc |= TRANS_ADDR_FMT;
	if (op->data.nbytes) {
		unsigned int width_code;

Annotation

Implementation Notes