drivers/spi/spi-ch341.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-ch341.c
Extension
.c
Size
6369 bytes
Lines
255
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 ch341_spi_dev {
	struct spi_controller *ctrl;
	struct usb_device *udev;
	unsigned int write_pipe;
	unsigned int read_pipe;
	int rx_len;
	void *rx_buf;
	u8 *tx_buf;
	struct urb *rx_urb;
	struct spi_device *spidev;
};

static void ch341_set_cs(struct spi_device *spi, bool is_high)
{
	struct ch341_spi_dev *ch341 =
		spi_controller_get_devdata(spi->controller);
	int err;

	memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
	ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM;
	ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | (is_high ? 0x36 : 0x37);

	if (is_high) {
		ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | 0x3f;
		ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END;
	} else {
		ch341->tx_buf[2] = CH341A_CMD_UIO_STM_END;
	}

	err = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf,
			   (is_high ? 4 : 3), NULL, CH341_DEFAULT_TIMEOUT);
	if (err)
		dev_err(&spi->dev,
			"error sending USB message for setting CS (%d)\n", err);
}

static int ch341_transfer_one(struct spi_controller *host,
			      struct spi_device *spi,
			      struct spi_transfer *trans)
{
	struct ch341_spi_dev *ch341 =
		spi_controller_get_devdata(spi->controller);
	int len;
	int ret;

	len = min(CH341_PACKET_LENGTH, trans->len + 1);

	memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);

	ch341->tx_buf[0] = CH341A_CMD_SPI_STREAM;

	memcpy(ch341->tx_buf + 1, trans->tx_buf, len - 1);

	ret = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, len,
			   NULL, CH341_DEFAULT_TIMEOUT);
	if (ret)
		return ret;

	return usb_bulk_msg(ch341->udev, ch341->read_pipe, trans->rx_buf,
			    len - 1, NULL, CH341_DEFAULT_TIMEOUT);
}

static void ch341_recv(struct urb *urb)
{
	struct ch341_spi_dev *ch341 = urb->context;
	struct usb_device *udev = ch341->udev;

	switch (urb->status) {
	case 0:
		/* success */
		break;
	case -ENOENT:
	case -ECONNRESET:
	case -EPIPE:
	case -ESHUTDOWN:
		dev_dbg(&udev->dev, "rx urb terminated with status: %d\n",
			urb->status);
		return;
	default:
		dev_dbg(&udev->dev, "rx urb error: %d\n", urb->status);
		break;
	}
}

static int ch341_config_stream(struct ch341_spi_dev *ch341)
{
	memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
	ch341->tx_buf[0] = CH341A_CMD_I2C_STREAM;
	ch341->tx_buf[1] = CH341A_CMD_I2C_STM_SET | CH341A_STM_I2C_100K;
	ch341->tx_buf[2] = CH341A_CMD_I2C_STM_END;

Annotation

Implementation Notes