drivers/spi/spi-kspi2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-kspi2.c
Extension
.c
Size
10877 bytes
Lines
432
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 kspi2 {
	struct keba_spi_auxdev *auxdev;
	void __iomem *base;
	struct spi_controller *host;

	u32 base_speed_hz; /* SPI base clock frequency in HZ */
	u8 control_shadow;

	struct spi_device **device;
	int device_size;
};

static int kspi2_inuse_lock(struct kspi2 *kspi)
{
	u8 sts;
	int ret;

	/*
	 * The SPI controller has an IN_USE bit for locking access to the
	 * controller. This enables the use of the SPI controller by other none
	 * Linux processors.
	 *
	 * If the SPI controller is free, then the first read returns
	 * IN_USE == 0. After that the SPI controller is locked and further
	 * reads of IN_USE return 1.
	 *
	 * The SPI controller is unlocked by writing 1 into IN_USE.
	 *
	 * The IN_USE bit acts as a hardware semaphore for the SPI controller.
	 * Poll for semaphore, but sleep while polling to free the CPU.
	 */
	ret = readb_poll_timeout(kspi->base + KSPI2_STATUS_REG,
				 sts, (sts & KSPI2_STATUS_IN_USE) == 0,
				 KSPI2_INUSE_SLEEP_US, KSPI2_INUSE_TIMEOUT_US);
	if (ret != 0)
		dev_warn(&kspi->auxdev->auxdev.dev, "%s err!\n", __func__);

	return ret;
}

static void kspi2_inuse_unlock(struct kspi2 *kspi)
{
	/* unlock the controller by writing 1 into IN_USE */
	iowrite8(KSPI2_STATUS_IN_USE, kspi->base + KSPI2_STATUS_REG);
}

static int kspi2_prepare_hardware(struct spi_controller *host)
{
	struct kspi2 *kspi = spi_controller_get_devdata(host);

	/* lock hardware semaphore before actual use of controller */
	return kspi2_inuse_lock(kspi);
}

static int kspi2_unprepare_hardware(struct spi_controller *host)
{
	struct kspi2 *kspi = spi_controller_get_devdata(host);

	/* unlock hardware semaphore after actual use of controller */
	kspi2_inuse_unlock(kspi);

	return 0;
}

static u8 kspi2_calc_minimal_divider(struct kspi2 *kspi, u32 max_speed_hz)
{
	u8 div;

	/*
	 * Divider values 2, 4, 8, 16, ..., 65536 are possible. They are coded
	 * as 0, 1, 2, 3, ..., 15 in the CONTROL_CLK_DIV bit.
	 */
	for (div = 0; div < KSPI2_CONTROL_CLK_DIV_MAX; div++) {
		if ((kspi->base_speed_hz >> (div + 1)) <= max_speed_hz)
			return div;
	}

	/* return divider for slowest clock if loop fails to find one */
	return KSPI2_CONTROL_CLK_DIV_MAX;
}

static void kspi2_write_control_reg(struct kspi2 *kspi, u8 val, u8 mask)
{
	/* write control register only when necessary to improve performance */
	if (val != (kspi->control_shadow & mask)) {
		kspi->control_shadow = (kspi->control_shadow & ~mask) | val;
		iowrite8(kspi->control_shadow, kspi->base + KSPI2_CONTROL_REG);
	}
}

Annotation

Implementation Notes