drivers/iio/chemical/mhz19b.c

Source file repositories/reference/linux-study-clean/drivers/iio/chemical/mhz19b.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/chemical/mhz19b.c
Extension
.c
Size
8022 bytes
Lines
334
Domain
Driver Families
Bucket
drivers/iio
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 mhz19b_state {
	struct serdev_device *serdev;

	/* Must wait until the 'buf' is filled with 9 bytes.*/
	struct completion buf_ready;

	u8 buf_idx;
	bool buf_overflow;

	/*
	 * Serdev receive buffer.
	 * When data is received from the MH-Z19B,
	 * the 'mhz19b_receive_buf' callback function is called and fills this buffer.
	 */
	u8 buf[MHZ19B_CMD_SIZE] __aligned(IIO_DMA_MINALIGN);
};

static u8 mhz19b_get_checksum(u8 *cmd_buf)
{
	u8 i, checksum = 0;

/*
 * +------+------+-----+------+------+------+------+------+-------+
 * | 0xFF | 0x01 | cmd | arg0 | arg1 | 0x00 | 0x00 | 0x00 | cksum |
 * +------+------+-----+------+------+------+------+------+-------+
 *	     i:1    2      3      4      5      6      7
 *
 *  Sum all cmd_buf elements from index 1 to 7.
 */
	for (i = 1; i < 8; i++)
		checksum += cmd_buf[i];

	return -checksum;
}

static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg)
{
	struct mhz19b_state *st = iio_priv(indio_dev);
	struct serdev_device *serdev = st->serdev;
	struct device *dev = &indio_dev->dev;
	int ret;

	/*
	 * cmd_buf[3,4] : arg0,1
	 * cmd_buf[8]	: checksum
	 */
	u8 cmd_buf[MHZ19B_CMD_SIZE] = {
		0xFF, 0x01, cmd,
	};

	switch (cmd) {
	case MHZ19B_ABC_LOGIC_CMD:
		cmd_buf[3] = arg ? 0xA0 : 0;
		break;
	case MHZ19B_SPAN_POINT_CMD:
		put_unaligned_be16(arg, &cmd_buf[3]);
		break;
	default:
		break;
	}
	cmd_buf[8] = mhz19b_get_checksum(cmd_buf);

	/* Write buf to uart ctrl synchronously */
	st->buf_idx = 0;
	st->buf_overflow = false;
	reinit_completion(&st->buf_ready);

	ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0);
	if (ret < 0)
		return ret;
	if (ret != MHZ19B_CMD_SIZE)
		return -EIO;

	switch (cmd) {
	case MHZ19B_READ_CO2_CMD:
		ret = wait_for_completion_interruptible_timeout(&st->buf_ready,
			MHZ19B_SERDEV_TIMEOUT);
		if (ret < 0)
			return ret;
		if (!ret)
			return -ETIMEDOUT;

		if (st->buf_overflow)
			return -EMSGSIZE;

		if (st->buf[8] != mhz19b_get_checksum(st->buf)) {
			dev_err(dev, "checksum err");
			return -EINVAL;
		}

Annotation

Implementation Notes