drivers/char/tpm/tpm_tis_spi_main.c

Source file repositories/reference/linux-study-clean/drivers/char/tpm/tpm_tis_spi_main.c

File Facts

System
Linux kernel
Corpus path
drivers/char/tpm/tpm_tis_spi_main.c
Extension
.c
Size
9413 bytes
Lines
363
Domain
Driver Families
Bucket
drivers/char
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 (out) {
			spi_xfer[2].tx_buf = &phy->iobuf[4];
			spi_xfer[2].rx_buf = NULL;
			memcpy(&phy->iobuf[4], out, transfer_len);
			out += transfer_len;
		}

		if (in) {
			spi_xfer[2].tx_buf = NULL;
			spi_xfer[2].rx_buf = &phy->iobuf[4];
		}

		spi_xfer[2].len = transfer_len;
		spi_message_add_tail(&spi_xfer[2], &m);

		reinit_completion(&phy->ready);

		ret = spi_sync(phy->spi_device, &m);
		if (ret < 0)
			return ret;

		if (in) {
			memcpy(in, &phy->iobuf[4], transfer_len);
			in += transfer_len;
		}

		len -= transfer_len;
	}

	return ret;
}

static int tpm_tis_spi_transfer_full(struct tpm_tis_data *data, u32 addr,
				     u16 len, u8 *in, const u8 *out)
{
	struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
	int ret = 0;
	struct spi_message m;
	struct spi_transfer spi_xfer;
	u8 transfer_len;

	spi_bus_lock(phy->spi_device->controller);

	while (len) {
		transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);

		phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1);
		phy->iobuf[1] = 0xd4;
		phy->iobuf[2] = addr >> 8;
		phy->iobuf[3] = addr;

		memset(&spi_xfer, 0, sizeof(spi_xfer));
		spi_xfer.tx_buf = phy->iobuf;
		spi_xfer.rx_buf = phy->iobuf;
		spi_xfer.len = 4;
		spi_xfer.cs_change = 1;

		spi_message_init(&m);
		spi_message_add_tail(&spi_xfer, &m);
		ret = spi_sync_locked(phy->spi_device, &m);
		if (ret < 0)
			goto exit;

		/* Flow control transfers are receive only */
		spi_xfer.tx_buf = NULL;
		ret = phy->flow_control(phy, &spi_xfer);
		if (ret < 0)
			goto exit;

		spi_xfer.cs_change = 0;
		spi_xfer.len = transfer_len;
		spi_xfer.delay.value = 5;
		spi_xfer.delay.unit = SPI_DELAY_UNIT_USECS;

		if (out) {
			spi_xfer.tx_buf = phy->iobuf;
			spi_xfer.rx_buf = NULL;
			memcpy(phy->iobuf, out, transfer_len);
			out += transfer_len;
		}

		spi_message_init(&m);
		spi_message_add_tail(&spi_xfer, &m);
		reinit_completion(&phy->ready);
		ret = spi_sync_locked(phy->spi_device, &m);
		if (ret < 0)
			goto exit;

		if (in) {
			memcpy(in, phy->iobuf, transfer_len);

Annotation

Implementation Notes