drivers/iio/chemical/pms7003.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/chemical/pms7003.c
Extension
.c
Size
8845 bytes
Lines
353
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 pms7003_frame {
	u8 data[PMS7003_MAX_DATA_LENGTH];
	u16 expected_length;
	u16 length;
};

struct pms7003_state {
	struct serdev_device *serdev;
	struct pms7003_frame frame;
	struct completion frame_ready;
	struct mutex lock; /* must be held whenever state gets touched */
	/* Used to construct scan to push to the IIO buffer */
	struct {
		u16 data[3]; /* PM1, PM2P5, PM10 */
		aligned_s64 ts;
	} scan;
};

static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
{
	int ret;

	ret = serdev_device_write(state->serdev, pms7003_cmd_tbl[cmd],
				  PMS7003_CMD_LENGTH, PMS7003_TIMEOUT);
	if (ret < PMS7003_CMD_LENGTH)
		return ret < 0 ? ret : -EIO;

	ret = wait_for_completion_interruptible_timeout(&state->frame_ready,
							PMS7003_TIMEOUT);
	if (!ret)
		ret = -ETIMEDOUT;

	return ret < 0 ? ret : 0;
}

static u16 pms7003_get_pm(const u8 *data)
{
	return clamp_val(get_unaligned_be16(data),
			 PMS7003_PM_MIN, PMS7003_PM_MAX);
}

static irqreturn_t pms7003_trigger_handler(int irq, void *p)
{
	struct iio_poll_func *pf = p;
	struct iio_dev *indio_dev = pf->indio_dev;
	struct pms7003_state *state = iio_priv(indio_dev);
	struct pms7003_frame *frame = &state->frame;
	int ret;

	mutex_lock(&state->lock);
	ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
	if (ret) {
		mutex_unlock(&state->lock);
		goto err;
	}

	state->scan.data[PM1] =
		pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
	state->scan.data[PM2P5] =
		pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
	state->scan.data[PM10] =
		pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
	mutex_unlock(&state->lock);

	iio_push_to_buffers_with_ts(indio_dev, &state->scan, sizeof(state->scan),
				    iio_get_time_ns(indio_dev));
err:
	iio_trigger_notify_done(indio_dev->trig);

	return IRQ_HANDLED;
}

static int pms7003_read_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *chan,
			    int *val, int *val2, long mask)
{
	struct pms7003_state *state = iio_priv(indio_dev);
	struct pms7003_frame *frame = &state->frame;
	int ret;

	switch (mask) {
	case IIO_CHAN_INFO_PROCESSED:
		switch (chan->type) {
		case IIO_MASSCONCENTRATION:
			mutex_lock(&state->lock);
			ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
			if (ret) {
				mutex_unlock(&state->lock);
				return ret;
			}

Annotation

Implementation Notes