drivers/mmc/host/mmc_spi.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/mmc_spi.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/mmc_spi.c
Extension
.c
Size
37734 bytes
Lines
1360
Domain
Driver Families
Bucket
drivers/mmc
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 scratch {
	u8			status[29];
	u8			data_token;
	__be16			crc_val;
};

struct mmc_spi_host {
	struct mmc_host		*mmc;
	struct spi_device	*spi;

	unsigned char		power_mode;
	u16			powerup_msecs;

	struct mmc_spi_platform_data	*pdata;

	/* for bulk data transfers */
	struct spi_transfer	token, t, crc, early_status;
	struct spi_message	m;

	/* for status readback */
	struct spi_transfer	status;
	struct spi_message	readback;

	/* buffer used for commands and for message "overhead" */
	struct scratch		*data;

	/* Specs say to write ones most of the time, even when the card
	 * has no need to read its input data; and many cards won't care.
	 * This is our source of those ones.
	 */
	void			*ones;
};


/****************************************************************************/

/*
 * MMC-over-SPI protocol glue, used by the MMC stack interface
 */

static inline int mmc_cs_off(struct mmc_spi_host *host)
{
	/* chipselect will always be inactive after setup() */
	return spi_setup(host->spi);
}

static int mmc_spi_readbytes(struct mmc_spi_host *host, unsigned int len)
{
	if (len > sizeof(*host->data)) {
		WARN_ON(1);
		return -EIO;
	}

	host->status.len = len;

	return spi_sync_locked(host->spi, &host->readback);
}

static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
			unsigned n, u8 byte)
{
	u8 *cp = host->data->status;
	unsigned long start = jiffies;

	do {
		int		status;
		unsigned	i;

		status = mmc_spi_readbytes(host, n);
		if (status < 0)
			return status;

		for (i = 0; i < n; i++) {
			if (cp[i] != byte)
				return cp[i];
		}

		/* If we need long timeouts, we may release the CPU */
		cond_resched();
	} while (time_is_after_jiffies(start + timeout));
	return -ETIMEDOUT;
}

static inline int
mmc_spi_wait_unbusy(struct mmc_spi_host *host, unsigned long timeout)
{
	return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
}

static int mmc_spi_readtoken(struct mmc_spi_host *host, unsigned long timeout)

Annotation

Implementation Notes