Contributors: 2
Author Tokens Token Proportion Commits Commit Proportion
Waqar Hameed 3868 99.77% 1 50.00%
Ruiqi Gong 9 0.23% 1 50.00%
Total 3877 2


// SPDX-License-Identifier: GPL-2.0-only
/*
 * Driver for Murata IRS-D200 PIR sensor.
 *
 * Copyright (C) 2023 Axis Communications AB
 */

#include <asm/unaligned.h>
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>

#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/types.h>

#define IRS_DRV_NAME "irsd200"

/* Registers. */
#define IRS_REG_OP		0x00	/* Operation mode. */
#define IRS_REG_DATA_LO		0x02	/* Sensor data LSB. */
#define IRS_REG_DATA_HI		0x03	/* Sensor data MSB. */
#define IRS_REG_STATUS		0x04	/* Interrupt status. */
#define IRS_REG_COUNT		0x05	/* Count of exceeding threshold. */
#define IRS_REG_DATA_RATE	0x06	/* Output data rate. */
#define IRS_REG_FILTER		0x07	/* High-pass and low-pass filter. */
#define IRS_REG_INTR		0x09	/* Interrupt mode. */
#define IRS_REG_NR_COUNT	0x0a	/* Number of counts before interrupt. */
#define IRS_REG_THR_HI		0x0b	/* Upper threshold. */
#define IRS_REG_THR_LO		0x0c	/* Lower threshold. */
#define IRS_REG_TIMER_LO	0x0d	/* Timer setting LSB. */
#define IRS_REG_TIMER_HI	0x0e	/* Timer setting MSB. */

/* Interrupt status bits. */
#define IRS_INTR_DATA		0	/* Data update. */
#define IRS_INTR_TIMER		1	/* Timer expiration. */
#define IRS_INTR_COUNT_THR_AND	2	/* Count "AND" threshold. */
#define IRS_INTR_COUNT_THR_OR	3	/* Count "OR" threshold. */

/* Operation states. */
#define IRS_OP_ACTIVE		0x00
#define IRS_OP_SLEEP		0x01

/*
 * Quantization scale value for threshold. Used for conversion from/to register
 * value.
 */
#define IRS_THR_QUANT_SCALE	128

#define IRS_UPPER_COUNT(count)	FIELD_GET(GENMASK(7, 4), count)
#define IRS_LOWER_COUNT(count)	FIELD_GET(GENMASK(3, 0), count)

/* Index corresponds to the value of IRS_REG_DATA_RATE register. */
static const int irsd200_data_rates[] = {
	50,
	100,
};

/* Index corresponds to the (field) value of IRS_REG_FILTER register. */
static const unsigned int irsd200_lp_filter_freq[] = {
	10,
	7,
};

/*
 * Index corresponds to the (field) value of IRS_REG_FILTER register. Note that
 * this represents a fractional value (e.g the first value corresponds to 3 / 10
 * = 0.3 Hz).
 */
static const unsigned int irsd200_hp_filter_freq[][2] = {
	{ 3, 10 },
	{ 5, 10 },
};

/* Register fields. */
enum irsd200_regfield {
	/* Data interrupt. */
	IRS_REGF_INTR_DATA,
	/* Timer interrupt. */
	IRS_REGF_INTR_TIMER,
	/* AND count threshold interrupt. */
	IRS_REGF_INTR_COUNT_THR_AND,
	/* OR count threshold interrupt. */
	IRS_REGF_INTR_COUNT_THR_OR,

	/* Low-pass filter frequency. */
	IRS_REGF_LP_FILTER,
	/* High-pass filter frequency. */
	IRS_REGF_HP_FILTER,

	/* Sentinel value. */
	IRS_REGF_MAX
};

static const struct reg_field irsd200_regfields[] = {
	[IRS_REGF_INTR_DATA] =
		REG_FIELD(IRS_REG_INTR, IRS_INTR_DATA, IRS_INTR_DATA),
	[IRS_REGF_INTR_TIMER] =
		REG_FIELD(IRS_REG_INTR, IRS_INTR_TIMER, IRS_INTR_TIMER),
	[IRS_REGF_INTR_COUNT_THR_AND] = REG_FIELD(
		IRS_REG_INTR, IRS_INTR_COUNT_THR_AND, IRS_INTR_COUNT_THR_AND),
	[IRS_REGF_INTR_COUNT_THR_OR] = REG_FIELD(
		IRS_REG_INTR, IRS_INTR_COUNT_THR_OR, IRS_INTR_COUNT_THR_OR),

	[IRS_REGF_LP_FILTER] = REG_FIELD(IRS_REG_FILTER, 1, 1),
	[IRS_REGF_HP_FILTER] = REG_FIELD(IRS_REG_FILTER, 0, 0),
};

static const struct regmap_config irsd200_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = IRS_REG_TIMER_HI,
};

struct irsd200_data {
	struct regmap *regmap;
	struct regmap_field *regfields[IRS_REGF_MAX];
	struct device *dev;
};

static int irsd200_setup(struct irsd200_data *data)
{
	unsigned int val;
	int ret;

	/* Disable all interrupt sources. */
	ret = regmap_write(data->regmap, IRS_REG_INTR, 0);
	if (ret) {
		dev_err(data->dev, "Could not set interrupt sources (%d)\n",
			ret);
		return ret;
	}

	/* Set operation to active. */
	ret = regmap_write(data->regmap, IRS_REG_OP, IRS_OP_ACTIVE);
	if (ret) {
		dev_err(data->dev, "Could not set operation mode (%d)\n", ret);
		return ret;
	}

	/* Clear threshold count. */
	ret = regmap_read(data->regmap, IRS_REG_COUNT, &val);
	if (ret) {
		dev_err(data->dev, "Could not clear threshold count (%d)\n",
			ret);
		return ret;
	}

	/* Clear status. */
	ret = regmap_write(data->regmap, IRS_REG_STATUS, 0x0f);
	if (ret) {
		dev_err(data->dev, "Could not clear status (%d)\n", ret);
		return ret;
	}

	return 0;
}

static int irsd200_read_threshold(struct irsd200_data *data,
				  enum iio_event_direction dir, int *val)
{
	unsigned int regval;
	unsigned int reg;
	int scale;
	int ret;

	/* Set quantization scale. */
	if (dir == IIO_EV_DIR_RISING) {
		scale = IRS_THR_QUANT_SCALE;
		reg = IRS_REG_THR_HI;
	} else if (dir == IIO_EV_DIR_FALLING) {
		scale = -IRS_THR_QUANT_SCALE;
		reg = IRS_REG_THR_LO;
	} else {
		return -EINVAL;
	}

	ret = regmap_read(data->regmap, reg, &regval);
	if (ret) {
		dev_err(data->dev, "Could not read threshold (%d)\n", ret);
		return ret;
	}

	*val = ((int)regval) * scale;

	return 0;
}

static int irsd200_write_threshold(struct irsd200_data *data,
				   enum iio_event_direction dir, int val)
{
	unsigned int regval;
	unsigned int reg;
	int scale;
	int ret;

	/* Set quantization scale. */
	if (dir == IIO_EV_DIR_RISING) {
		if (val < 0)
			return -ERANGE;

		scale = IRS_THR_QUANT_SCALE;
		reg = IRS_REG_THR_HI;
	} else if (dir == IIO_EV_DIR_FALLING) {
		if (val > 0)
			return -ERANGE;

		scale = -IRS_THR_QUANT_SCALE;
		reg = IRS_REG_THR_LO;
	} else {
		return -EINVAL;
	}

	regval = val / scale;

	if (regval >= BIT(8))
		return -ERANGE;

	ret = regmap_write(data->regmap, reg, regval);
	if (ret) {
		dev_err(data->dev, "Could not write threshold (%d)\n", ret);
		return ret;
	}

	return 0;
}

static int irsd200_read_data(struct irsd200_data *data, s16 *val)
{
	__le16 buf;
	int ret;

	ret = regmap_bulk_read(data->regmap, IRS_REG_DATA_LO, &buf,
			       sizeof(buf));
	if (ret) {
		dev_err(data->dev, "Could not bulk read data (%d)\n", ret);
		return ret;
	}

	*val = le16_to_cpu(buf);

	return 0;
}

static int irsd200_read_data_rate(struct irsd200_data *data, int *val)
{
	unsigned int regval;
	int ret;

	ret = regmap_read(data->regmap, IRS_REG_DATA_RATE, &regval);
	if (ret) {
		dev_err(data->dev, "Could not read data rate (%d)\n", ret);
		return ret;
	}

	if (regval >= ARRAY_SIZE(irsd200_data_rates))
		return -ERANGE;

	*val = irsd200_data_rates[regval];

	return 0;
}

static int irsd200_write_data_rate(struct irsd200_data *data, int val)
{
	size_t idx;
	int ret;

	for (idx = 0; idx < ARRAY_SIZE(irsd200_data_rates); ++idx) {
		if (irsd200_data_rates[idx] == val)
			break;
	}

	if (idx == ARRAY_SIZE(irsd200_data_rates))
		return -ERANGE;

	ret = regmap_write(data->regmap, IRS_REG_DATA_RATE, idx);
	if (ret) {
		dev_err(data->dev, "Could not write data rate (%d)\n", ret);
		return ret;
	}

	/*
	 * Data sheet says the device needs 3 seconds of settling time. The
	 * device operates normally during this period though. This is more of a
	 * "guarantee" than trying to prevent other user space reads/writes.
	 */
	ssleep(3);

	return 0;
}

static int irsd200_read_timer(struct irsd200_data *data, int *val, int *val2)
{
	__le16 buf;
	int ret;

	ret = regmap_bulk_read(data->regmap, IRS_REG_TIMER_LO, &buf,
			       sizeof(buf));
	if (ret) {
		dev_err(data->dev, "Could not bulk read timer (%d)\n", ret);
		return ret;
	}

	ret = irsd200_read_data_rate(data, val2);
	if (ret)
		return ret;

	*val = le16_to_cpu(buf);

	return 0;
}

static int irsd200_write_timer(struct irsd200_data *data, int val, int val2)
{
	unsigned int regval;
	int data_rate;
	__le16 buf;
	int ret;

	if (val < 0 || val2 < 0)
		return -ERANGE;

	ret = irsd200_read_data_rate(data, &data_rate);
	if (ret)
		return ret;

	/* Quantize from seconds. */
	regval = val * data_rate + (val2 * data_rate) / 1000000;

	/* Value is 10 bits. */
	if (regval >= BIT(10))
		return -ERANGE;

	buf = cpu_to_le16((u16)regval);

	ret = regmap_bulk_write(data->regmap, IRS_REG_TIMER_LO, &buf,
				sizeof(buf));
	if (ret) {
		dev_err(data->dev, "Could not bulk write timer (%d)\n", ret);
		return ret;
	}

	return 0;
}

static int irsd200_read_nr_count(struct irsd200_data *data, int *val)
{
	unsigned int regval;
	int ret;

	ret = regmap_read(data->regmap, IRS_REG_NR_COUNT, &regval);
	if (ret) {
		dev_err(data->dev, "Could not read nr count (%d)\n", ret);
		return ret;
	}

	*val = regval;

	return 0;
}

static int irsd200_write_nr_count(struct irsd200_data *data, int val)
{
	unsigned int regval;
	int ret;

	/* A value of zero means that IRS_REG_STATUS is never set. */
	if (val <= 0 || val >= 8)
		return -ERANGE;

	regval = val;

	if (regval >= 2) {
		/*
		 * According to the data sheet, timer must be also set in this
		 * case (i.e. be non-zero). Check and enforce that.
		 */
		ret = irsd200_read_timer(data, &val, &val);
		if (ret)
			return ret;

		if (val == 0) {
			dev_err(data->dev,
				"Timer must be non-zero when nr count is %u\n",
				regval);
			return -EPERM;
		}
	}

	ret = regmap_write(data->regmap, IRS_REG_NR_COUNT, regval);
	if (ret) {
		dev_err(data->dev, "Could not write nr count (%d)\n", ret);
		return ret;
	}

	return 0;
}

static int irsd200_read_lp_filter(struct irsd200_data *data, int *val)
{
	unsigned int regval;
	int ret;

	ret = regmap_field_read(data->regfields[IRS_REGF_LP_FILTER], &regval);
	if (ret) {
		dev_err(data->dev, "Could not read lp filter frequency (%d)\n",
			ret);
		return ret;
	}

	*val = irsd200_lp_filter_freq[regval];

	return 0;
}

static int irsd200_write_lp_filter(struct irsd200_data *data, int val)
{
	size_t idx;
	int ret;

	for (idx = 0; idx < ARRAY_SIZE(irsd200_lp_filter_freq); ++idx) {
		if (irsd200_lp_filter_freq[idx] == val)
			break;
	}

	if (idx == ARRAY_SIZE(irsd200_lp_filter_freq))
		return -ERANGE;

	ret = regmap_field_write(data->regfields[IRS_REGF_LP_FILTER], idx);
	if (ret) {
		dev_err(data->dev, "Could not write lp filter frequency (%d)\n",
			ret);
		return ret;
	}

	return 0;
}

static int irsd200_read_hp_filter(struct irsd200_data *data, int *val,
				  int *val2)
{
	unsigned int regval;
	int ret;

	ret = regmap_field_read(data->regfields[IRS_REGF_HP_FILTER], &regval);
	if (ret) {
		dev_err(data->dev, "Could not read hp filter frequency (%d)\n",
			ret);
		return ret;
	}

	*val = irsd200_hp_filter_freq[regval][0];
	*val2 = irsd200_hp_filter_freq[regval][1];

	return 0;
}

static int irsd200_write_hp_filter(struct irsd200_data *data, int val, int val2)
{
	size_t idx;
	int ret;

	/* Truncate fractional part to one digit. */
	val2 /= 100000;

	for (idx = 0; idx < ARRAY_SIZE(irsd200_hp_filter_freq); ++idx) {
		if (irsd200_hp_filter_freq[idx][0] == val2)
			break;
	}

	if (idx == ARRAY_SIZE(irsd200_hp_filter_freq) || val != 0)
		return -ERANGE;

	ret = regmap_field_write(data->regfields[IRS_REGF_HP_FILTER], idx);
	if (ret) {
		dev_err(data->dev, "Could not write hp filter frequency (%d)\n",
			ret);
		return ret;
	}

	return 0;
}

static int irsd200_read_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *chan, int *val,
			    int *val2, long mask)
{
	struct irsd200_data *data = iio_priv(indio_dev);
	int ret;
	s16 buf;

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
		ret = irsd200_read_data(data, &buf);
		if (ret)
			return ret;

		*val = buf;
		return IIO_VAL_INT;
	case IIO_CHAN_INFO_SAMP_FREQ:
		ret = irsd200_read_data_rate(data, val);
		if (ret)
			return ret;

		return IIO_VAL_INT;
	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
		ret = irsd200_read_lp_filter(data, val);
		if (ret)
			return ret;

		return IIO_VAL_INT;
	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
		ret = irsd200_read_hp_filter(data, val, val2);
		if (ret)
			return ret;

		return IIO_VAL_FRACTIONAL;
	default:
		return -EINVAL;
	}
}

static int irsd200_read_avail(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *chan,
			      const int **vals, int *type, int *length,
			      long mask)
{
	switch (mask) {
	case IIO_CHAN_INFO_SAMP_FREQ:
		*vals = irsd200_data_rates;
		*type = IIO_VAL_INT;
		*length = ARRAY_SIZE(irsd200_data_rates);
		return IIO_AVAIL_LIST;
	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
		*vals = irsd200_lp_filter_freq;
		*type = IIO_VAL_INT;
		*length = ARRAY_SIZE(irsd200_lp_filter_freq);
		return IIO_AVAIL_LIST;
	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
		*vals = (int *)irsd200_hp_filter_freq;
		*type = IIO_VAL_FRACTIONAL;
		*length = 2 * ARRAY_SIZE(irsd200_hp_filter_freq);
		return IIO_AVAIL_LIST;
	default:
		return -EINVAL;
	}
}

static int irsd200_write_raw(struct iio_dev *indio_dev,
			     struct iio_chan_spec const *chan, int val,
			     int val2, long mask)
{
	struct irsd200_data *data = iio_priv(indio_dev);

	switch (mask) {
	case IIO_CHAN_INFO_SAMP_FREQ:
		return irsd200_write_data_rate(data, val);
	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
		return irsd200_write_lp_filter(data, val);
	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
		return irsd200_write_hp_filter(data, val, val2);
	default:
		return -EINVAL;
	}
}

static int irsd200_read_event(struct iio_dev *indio_dev,
			      const struct iio_chan_spec *chan,
			      enum iio_event_type type,
			      enum iio_event_direction dir,
			      enum iio_event_info info, int *val, int *val2)
{
	struct irsd200_data *data = iio_priv(indio_dev);
	int ret;

	switch (info) {
	case IIO_EV_INFO_VALUE:
		ret = irsd200_read_threshold(data, dir, val);
		if (ret)
			return ret;

		return IIO_VAL_INT;
	case IIO_EV_INFO_RUNNING_PERIOD:
		ret = irsd200_read_timer(data, val, val2);
		if (ret)
			return ret;

		return IIO_VAL_FRACTIONAL;
	case IIO_EV_INFO_RUNNING_COUNT:
		ret = irsd200_read_nr_count(data, val);
		if (ret)
			return ret;

		return IIO_VAL_INT;
	default:
		return -EINVAL;
	}
}

static int irsd200_write_event(struct iio_dev *indio_dev,
			       const struct iio_chan_spec *chan,
			       enum iio_event_type type,
			       enum iio_event_direction dir,
			       enum iio_event_info info, int val, int val2)
{
	struct irsd200_data *data = iio_priv(indio_dev);

	switch (info) {
	case IIO_EV_INFO_VALUE:
		return irsd200_write_threshold(data, dir, val);
	case IIO_EV_INFO_RUNNING_PERIOD:
		return irsd200_write_timer(data, val, val2);
	case IIO_EV_INFO_RUNNING_COUNT:
		return irsd200_write_nr_count(data, val);
	default:
		return -EINVAL;
	}
}

static int irsd200_read_event_config(struct iio_dev *indio_dev,
				     const struct iio_chan_spec *chan,
				     enum iio_event_type type,
				     enum iio_event_direction dir)
{
	struct irsd200_data *data = iio_priv(indio_dev);
	unsigned int val;
	int ret;

	switch (type) {
	case IIO_EV_TYPE_THRESH:
		ret = regmap_field_read(
			data->regfields[IRS_REGF_INTR_COUNT_THR_OR], &val);
		if (ret)
			return ret;

		return val;
	default:
		return -EINVAL;
	}
}

static int irsd200_write_event_config(struct iio_dev *indio_dev,
				      const struct iio_chan_spec *chan,
				      enum iio_event_type type,
				      enum iio_event_direction dir, int state)
{
	struct irsd200_data *data = iio_priv(indio_dev);
	unsigned int tmp;
	int ret;

	switch (type) {
	case IIO_EV_TYPE_THRESH:
		/* Clear the count register (by reading from it). */
		ret = regmap_read(data->regmap, IRS_REG_COUNT, &tmp);
		if (ret)
			return ret;

		return regmap_field_write(
			data->regfields[IRS_REGF_INTR_COUNT_THR_OR], !!state);
	default:
		return -EINVAL;
	}
}

static irqreturn_t irsd200_irq_thread(int irq, void *dev_id)
{
	struct iio_dev *indio_dev = dev_id;
	struct irsd200_data *data = iio_priv(indio_dev);
	enum iio_event_direction dir;
	unsigned int lower_count;
	unsigned int upper_count;
	unsigned int status = 0;
	unsigned int source = 0;
	unsigned int clear = 0;
	unsigned int count = 0;
	int ret;

	ret = regmap_read(data->regmap, IRS_REG_INTR, &source);
	if (ret) {
		dev_err(data->dev, "Could not read interrupt source (%d)\n",
			ret);
		return IRQ_HANDLED;
	}

	ret = regmap_read(data->regmap, IRS_REG_STATUS, &status);
	if (ret) {
		dev_err(data->dev, "Could not acknowledge interrupt (%d)\n",
			ret);
		return IRQ_HANDLED;
	}

	if (status & BIT(IRS_INTR_DATA) && iio_buffer_enabled(indio_dev)) {
		iio_trigger_poll_nested(indio_dev->trig);
		clear |= BIT(IRS_INTR_DATA);
	}

	if (status & BIT(IRS_INTR_COUNT_THR_OR) &&
	    source & BIT(IRS_INTR_COUNT_THR_OR)) {
		/*
		 * The register value resets to zero after reading. We therefore
		 * need to read once and manually extract the lower and upper
		 * count register fields.
		 */
		ret = regmap_read(data->regmap, IRS_REG_COUNT, &count);
		if (ret)
			dev_err(data->dev, "Could not read count (%d)\n", ret);

		upper_count = IRS_UPPER_COUNT(count);
		lower_count = IRS_LOWER_COUNT(count);

		/*
		 * We only check the OR mode to be able to push events for
		 * rising and falling thresholds. AND mode is covered when both
		 * upper and lower count is non-zero, and is signaled with
		 * IIO_EV_DIR_EITHER.
		 */
		if (upper_count && !lower_count)
			dir = IIO_EV_DIR_RISING;
		else if (!upper_count && lower_count)
			dir = IIO_EV_DIR_FALLING;
		else
			dir = IIO_EV_DIR_EITHER;

		iio_push_event(indio_dev,
			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
						    IIO_EV_TYPE_THRESH, dir),
			       iio_get_time_ns(indio_dev));

		/*
		 * The OR mode will always trigger when the AND mode does, but
		 * not vice versa. However, it seems like the AND bit needs to
		 * be cleared if data capture _and_ threshold count interrupts
		 * are desirable, even though it hasn't explicitly been selected
		 * (with IRS_REG_INTR). Either way, it doesn't hurt...
		 */
		clear |= BIT(IRS_INTR_COUNT_THR_OR) |
			 BIT(IRS_INTR_COUNT_THR_AND);
	}

	if (!clear)
		return IRQ_NONE;

	ret = regmap_write(data->regmap, IRS_REG_STATUS, clear);
	if (ret)
		dev_err(data->dev,
			"Could not clear interrupt status (%d)\n", ret);

	return IRQ_HANDLED;
}

static irqreturn_t irsd200_trigger_handler(int irq, void *pollf)
{
	struct iio_dev *indio_dev = ((struct iio_poll_func *)pollf)->indio_dev;
	struct irsd200_data *data = iio_priv(indio_dev);
	s64 buf[2] = {};
	int ret;

	ret = irsd200_read_data(data, (s16 *)buf);
	if (ret)
		goto end;

	iio_push_to_buffers_with_timestamp(indio_dev, buf,
					   iio_get_time_ns(indio_dev));

end:
	iio_trigger_notify_done(indio_dev->trig);

	return IRQ_HANDLED;
}

static int irsd200_set_trigger_state(struct iio_trigger *trig, bool state)
{
	struct irsd200_data *data = iio_trigger_get_drvdata(trig);
	int ret;

	ret = regmap_field_write(data->regfields[IRS_REGF_INTR_DATA], state);
	if (ret) {
		dev_err(data->dev, "Could not %s data interrupt source (%d)\n",
			state ? "enable" : "disable", ret);
	}

	return ret;
}

static const struct iio_info irsd200_info = {
	.read_raw = irsd200_read_raw,
	.read_avail = irsd200_read_avail,
	.write_raw = irsd200_write_raw,
	.read_event_value = irsd200_read_event,
	.write_event_value = irsd200_write_event,
	.read_event_config = irsd200_read_event_config,
	.write_event_config = irsd200_write_event_config,
};

static const struct iio_trigger_ops irsd200_trigger_ops = {
	.set_trigger_state = irsd200_set_trigger_state,
	.validate_device = iio_trigger_validate_own_device,
};

static const struct iio_event_spec irsd200_event_spec[] = {
	{
		.type = IIO_EV_TYPE_THRESH,
		.dir = IIO_EV_DIR_RISING,
		.mask_separate = BIT(IIO_EV_INFO_VALUE),
	},
	{
		.type = IIO_EV_TYPE_THRESH,
		.dir = IIO_EV_DIR_FALLING,
		.mask_separate = BIT(IIO_EV_INFO_VALUE),
	},
	{
		.type = IIO_EV_TYPE_THRESH,
		.dir = IIO_EV_DIR_EITHER,
		.mask_separate =
			BIT(IIO_EV_INFO_RUNNING_PERIOD) |
			BIT(IIO_EV_INFO_RUNNING_COUNT) |
			BIT(IIO_EV_INFO_ENABLE),
	},
};

static const struct iio_chan_spec irsd200_channels[] = {
	{
		.type = IIO_PROXIMITY,
		.info_mask_separate =
			BIT(IIO_CHAN_INFO_RAW) |
			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY),
		.info_mask_separate_available =
			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY),
		.event_spec = irsd200_event_spec,
		.num_event_specs = ARRAY_SIZE(irsd200_event_spec),
		.scan_type = {
			.sign = 's',
			.realbits = 16,
			.storagebits = 16,
			.endianness = IIO_CPU,
		},
	},
};

static int irsd200_probe(struct i2c_client *client)
{
	struct iio_trigger *trigger;
	struct irsd200_data *data;
	struct iio_dev *indio_dev;
	size_t i;
	int ret;

	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
	if (!indio_dev)
		return dev_err_probe(&client->dev, -ENOMEM,
				     "Could not allocate iio device\n");

	data = iio_priv(indio_dev);
	data->dev = &client->dev;

	data->regmap = devm_regmap_init_i2c(client, &irsd200_regmap_config);
	if (IS_ERR(data->regmap))
		return dev_err_probe(data->dev, PTR_ERR(data->regmap),
				     "Could not initialize regmap\n");

	for (i = 0; i < IRS_REGF_MAX; ++i) {
		data->regfields[i] = devm_regmap_field_alloc(
			data->dev, data->regmap, irsd200_regfields[i]);
		if (IS_ERR(data->regfields[i]))
			return dev_err_probe(
				data->dev, PTR_ERR(data->regfields[i]),
				"Could not allocate register field %zu\n", i);
	}

	ret = devm_regulator_get_enable(data->dev, "vdd");
	if (ret)
		return dev_err_probe(
			data->dev, ret,
			"Could not get and enable regulator (%d)\n", ret);

	ret = irsd200_setup(data);
	if (ret)
		return ret;

	indio_dev->info = &irsd200_info;
	indio_dev->name = IRS_DRV_NAME;
	indio_dev->channels = irsd200_channels;
	indio_dev->num_channels = ARRAY_SIZE(irsd200_channels);
	indio_dev->modes = INDIO_DIRECT_MODE;

	if (!client->irq)
		return dev_err_probe(data->dev, -ENXIO, "No irq available\n");

	ret = devm_iio_triggered_buffer_setup(data->dev, indio_dev, NULL,
					      irsd200_trigger_handler, NULL);
	if (ret)
		return dev_err_probe(
			data->dev, ret,
			"Could not setup iio triggered buffer (%d)\n", ret);

	ret = devm_request_threaded_irq(data->dev, client->irq, NULL,
					irsd200_irq_thread,
					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
					NULL, indio_dev);
	if (ret)
		return dev_err_probe(data->dev, ret,
				     "Could not request irq (%d)\n", ret);

	trigger = devm_iio_trigger_alloc(data->dev, "%s-dev%d", indio_dev->name,
					 iio_device_id(indio_dev));
	if (!trigger)
		return dev_err_probe(data->dev, -ENOMEM,
				     "Could not allocate iio trigger\n");

	trigger->ops = &irsd200_trigger_ops;
	iio_trigger_set_drvdata(trigger, data);

	ret = devm_iio_trigger_register(data->dev, trigger);
	if (ret)
		return dev_err_probe(data->dev, ret,
				     "Could not register iio trigger (%d)\n",
				     ret);

	ret = devm_iio_device_register(data->dev, indio_dev);
	if (ret)
		return dev_err_probe(data->dev, ret,
				     "Could not register iio device (%d)\n",
				     ret);

	return 0;
}

static const struct of_device_id irsd200_of_match[] = {
	{
		.compatible = "murata,irsd200",
	},
	{}
};
MODULE_DEVICE_TABLE(of, irsd200_of_match);

static struct i2c_driver irsd200_driver = {
	.driver = {
		.name = IRS_DRV_NAME,
		.of_match_table = irsd200_of_match,
	},
	.probe = irsd200_probe,
};
module_i2c_driver(irsd200_driver);

MODULE_AUTHOR("Waqar Hameed <waqar.hameed@axis.com>");
MODULE_DESCRIPTION("Murata IRS-D200 PIR sensor driver");
MODULE_LICENSE("GPL");