drivers/spi/spi-pxa2xx-dma.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-pxa2xx-dma.c
Extension
.c
Size
5817 bytes
Lines
226
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

if (error) {
			/* In case we got an error we disable the SSP now */
			pxa_ssp_disable(drv_data->ssp);
			msg->status = -EIO;
		}

		spi_finalize_current_transfer(drv_data->controller);
	}
}

static void pxa2xx_spi_dma_callback(void *data)
{
	pxa2xx_spi_dma_transfer_complete(data, false);
}

static struct dma_async_tx_descriptor *
pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
			   enum dma_transfer_direction dir,
			   struct spi_transfer *xfer)
{
	enum dma_slave_buswidth width;
	struct dma_slave_config cfg;
	struct dma_chan *chan;
	struct sg_table *sgt;
	int ret;

	switch (drv_data->n_bytes) {
	case 1:
		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
		break;
	case 2:
		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
		break;
	default:
		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
		break;
	}

	memset(&cfg, 0, sizeof(cfg));
	cfg.direction = dir;

	if (dir == DMA_MEM_TO_DEV) {
		cfg.dst_addr = drv_data->ssp->phys_base + SSDR;
		cfg.dst_addr_width = width;
		cfg.dst_maxburst = drv_data->controller_info->dma_burst_size;

		sgt = &xfer->tx_sg;
		chan = drv_data->controller->dma_tx;
	} else {
		cfg.src_addr = drv_data->ssp->phys_base + SSDR;
		cfg.src_addr_width = width;
		cfg.src_maxburst = drv_data->controller_info->dma_burst_size;

		sgt = &xfer->rx_sg;
		chan = drv_data->controller->dma_rx;
	}

	ret = dmaengine_slave_config(chan, &cfg);
	if (ret) {
		dev_warn(drv_data->ssp->dev, "DMA slave config failed\n");
		return NULL;
	}

	return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir,
				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
}

irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
	u32 status;

	status = read_SSSR_bits(drv_data, drv_data->mask_sr);
	if (status & SSSR_ROR) {
		dev_err(drv_data->ssp->dev, "FIFO overrun\n");

		dmaengine_terminate_async(drv_data->controller->dma_rx);
		dmaengine_terminate_async(drv_data->controller->dma_tx);

		pxa2xx_spi_dma_transfer_complete(drv_data, true);
		return IRQ_HANDLED;
	}

	return IRQ_NONE;
}

int pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
			   struct spi_transfer *xfer)
{
	struct dma_async_tx_descriptor *tx_desc, *rx_desc;
	int err;

Annotation

Implementation Notes