drivers/spi/spi-spacemit-k1.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-spacemit-k1.c
Extension
.c
Size
22078 bytes
Lines
790
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 k1_spi_driver_data {
	struct spi_controller *host;
	void __iomem *base;
	phys_addr_t base_addr;
	unsigned long bus_rate;
	struct clk *clk;
	unsigned long rate;
	int irq;

	/* Current transfer information; not valid if message is null */
	u32 bytes;			/* Bytes used for bits_per_word */
	unsigned int rx_resid;		/* RX bytes left in transfer */
	unsigned int tx_resid;		/* TX bytes left in transfer */
	struct spi_transfer *transfer;	/* Current transfer */

	bool dma_enabled;
};

/* Set our registers to a known initial state */
static void
k1_spi_register_reset(struct k1_spi_driver_data *drv_data, bool initial)
{
	u32 val = 0;

	writel(0, drv_data->base + SSP_TOP_CTRL);

	if (initial) {
		/*
		 * The TX and RX FIFO thresholds are the same no matter
		 * what the speed or bits per word, so we can just set
		 * them once.  The thresholds are one more than the values
		 * in the register.
		 */
		val = FIELD_PREP(FIFO_RFT_MASK, K1_SPI_THRESH - 1);
		val |= FIELD_PREP(FIFO_TFT_MASK, K1_SPI_THRESH - 1);
	}
	writel(val, drv_data->base + SSP_FIFO_CTRL);

	writel(0, drv_data->base + SSP_INT_EN);
	writel(0, drv_data->base + SSP_TIMEOUT);

	/* Clear any pending interrupt conditions */
	writel(~0, drv_data->base + SSP_STATUS);
}

/*
 * The client can call the setup function multiple times, and each call
 * can specify a different SPI mode (and transfer speed).  Each transfer
 * can specify its own speed though, and the core code ensures each
 * transfer's speed is set to something nonzero and supported by both
 * the controller and the device.  We just set the speed for each transfer.
 */
static int k1_spi_setup(struct spi_device *spi)
{
	struct k1_spi_driver_data *drv_data;
	u32 val;

	drv_data = spi_controller_get_devdata(spi->controller);

	/*
	 * Configure the message format for this device.  We only
	 * support Motorola SPI format in master mode.
	 */
	val = FIELD_PREP(TOP_FRF_MASK, TOP_FRF_MOTOROLA);

	/* Translate the mode into the value used to program the hardware. */
	if (spi->mode & SPI_CPHA)
		val |= TOP_SPH;		/* 1/2 cycle */
	if (spi->mode & SPI_CPOL)
		val |= TOP_SPO;		/* active low */
	if (spi->mode & SPI_LOOP)
		val |= TOP_LBM;		/* enable loopback */
	writel(val, drv_data->base + SSP_TOP_CTRL);

	return 0;
}

static void k1_spi_cleanup(struct spi_device *spi)
{
	struct k1_spi_driver_data *drv_data;

	drv_data = spi_controller_get_devdata(spi->controller);
	k1_spi_register_reset(drv_data, false);
}

static bool k1_spi_can_dma(struct spi_controller *host, struct spi_device *spi,
			   struct spi_transfer *transfer)
{
	struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
	u32 burst_size;

Annotation

Implementation Notes