drivers/spi/spi-falcon.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-falcon.c
Extension
.c
Size
10383 bytes
Lines
429
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 falcon_sflash {
	u32 sfcmd; /* for caching of opcode, direction, ... */
	struct spi_controller *host;
};

static int
falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
		   unsigned long flags)
{
	struct device *dev = &spi->dev;
	struct falcon_sflash *priv = spi_controller_get_devdata(spi->controller);
	const u8 *txp = t->tx_buf;
	u8 *rxp = t->rx_buf;
	unsigned int bytelen = ((8 * t->len + 7) / 8);
	unsigned int len, alen, dumlen;
	u32 val;
	enum {
		state_init,
		state_command_prepare,
		state_write,
		state_read,
		state_disable_cs,
		state_end
	} state = state_init;

	do {
		switch (state) {
		case state_init: /* detect phase of upper layer sequence */
		{
			/* initial write ? */
			if (flags & FALCON_SPI_XFER_BEGIN) {
				if (!txp) {
					dev_err(dev,
						"BEGIN without tx data!\n");
					return -ENODATA;
				}
				/*
				 * Prepare the parts of the sfcmd register,
				 * which should not change during a sequence!
				 * Only exception are the length fields,
				 * especially alen and dumlen.
				 */

				priv->sfcmd = ((spi_get_chipselect(spi, 0)
						<< SFCMD_CS_OFFSET)
					       & SFCMD_CS_MASK);
				priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
				priv->sfcmd |= *txp;
				txp++;
				bytelen--;
				if (bytelen) {
					/*
					 * more data:
					 * maybe address and/or dummy
					 */
					state = state_command_prepare;
					break;
				} else {
					dev_dbg(dev, "write cmd %02X\n",
						priv->sfcmd & SFCMD_OPC_MASK);
				}
			}
			/* continued write ? */
			if (txp && bytelen) {
				state = state_write;
				break;
			}
			/* read data? */
			if (rxp && bytelen) {
				state = state_read;
				break;
			}
			/* end of sequence? */
			if (flags & FALCON_SPI_XFER_END)
				state = state_disable_cs;
			else
				state = state_end;
			break;
		}
		/* collect tx data for address and dummy phase */
		case state_command_prepare:
		{
			/* txp is valid, already checked */
			val = 0;
			alen = 0;
			dumlen = 0;
			while (bytelen > 0) {
				if (alen < 3) {
					val = (val << 8) | (*txp++);
					alen++;

Annotation

Implementation Notes