Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d963215 authored by Octavian Purdila's avatar Octavian Purdila Committed by Jonathan Cameron
Browse files

iio: bmc150: introduce bmc150_accel_trigger



Add a separate structure for triggers and add the infrastructure to
support an arbitrary number of triggers. Each trigger is associated
with an interrupt and has an enabled/disabled state.

Signed-off-by: default avatarOctavian Purdila <octavian.purdila@intel.com>
Acked-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 3e825ec9
Loading
Loading
Loading
Loading
+125 −79
Original line number Original line Diff line number Diff line
@@ -152,6 +152,14 @@ struct bmc150_accel_interrupt {
	atomic_t users;
	atomic_t users;
};
};


struct bmc150_accel_trigger {
	struct bmc150_accel_data *data;
	struct iio_trigger *indio_trig;
	int (*setup)(struct bmc150_accel_trigger *t, bool state);
	int intr;
	bool enabled;
};

enum bmc150_accel_interrupt_id {
enum bmc150_accel_interrupt_id {
	BMC150_ACCEL_INT_DATA_READY,
	BMC150_ACCEL_INT_DATA_READY,
	BMC150_ACCEL_INT_ANY_MOTION,
	BMC150_ACCEL_INT_ANY_MOTION,
@@ -159,12 +167,17 @@ enum bmc150_accel_interrupt_id {
	BMC150_ACCEL_INTERRUPTS,
	BMC150_ACCEL_INTERRUPTS,
};
};


enum bmc150_accel_trigger_id {
	BMC150_ACCEL_TRIGGER_DATA_READY,
	BMC150_ACCEL_TRIGGER_ANY_MOTION,
	BMC150_ACCEL_TRIGGERS,
};

struct bmc150_accel_data {
struct bmc150_accel_data {
	struct i2c_client *client;
	struct i2c_client *client;
	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
	struct iio_trigger *dready_trig;
	struct iio_trigger *motion_trig;
	atomic_t active_intr;
	atomic_t active_intr;
	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
	struct mutex mutex;
	struct mutex mutex;
	s16 buffer[8];
	s16 buffer[8];
	u8 bw_bits;
	u8 bw_bits;
@@ -172,8 +185,6 @@ struct bmc150_accel_data {
	u32 slope_thres;
	u32 slope_thres;
	u32 range;
	u32 range;
	int ev_enable_state;
	int ev_enable_state;
	bool dready_trigger_on;
	bool motion_trigger_on;
	int64_t timestamp;
	int64_t timestamp;
	const struct bmc150_accel_chip_info *chip_info;
	const struct bmc150_accel_chip_info *chip_info;
};
};
@@ -314,6 +325,15 @@ static int bmc150_accel_update_slope(struct bmc150_accel_data *data)
	return ret;
	return ret;
}
}


static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t,
					 bool state)
{
	if (state)
		return bmc150_accel_update_slope(t->data);

	return 0;
}

static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
{
{
	int ret;
	int ret;
@@ -793,13 +813,16 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
				   struct iio_trigger *trig)
				   struct iio_trigger *trig)
{
{
	struct bmc150_accel_data *data = iio_priv(indio_dev);
	struct bmc150_accel_data *data = iio_priv(indio_dev);
	int i;


	if (data->dready_trig != trig && data->motion_trig != trig)
	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
		return -EINVAL;
		if (data->triggers[i].indio_trig == trig)

			return 0;
			return 0;
	}
	}


	return -EINVAL;
}

static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
		"7.810000 15.630000 31.250000 62.500000 125 250 500 1000");
		"7.810000 15.630000 31.250000 62.500000 125 250 500 1000");


@@ -969,12 +992,12 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)


static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
{
{
	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
	struct bmc150_accel_data *data = iio_priv(indio_dev);
	struct bmc150_accel_data *data = t->data;
	int ret;
	int ret;


	/* new data interrupts don't need ack */
	/* new data interrupts don't need ack */
	if (data->dready_trigger_on)
	if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY])
		return 0;
		return 0;


	mutex_lock(&data->mutex);
	mutex_lock(&data->mutex);
@@ -993,46 +1016,35 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
	return 0;
	return 0;
}
}


static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
static int bmc150_accel_trigger_set_state(struct iio_trigger *trig,
						   bool state)
						   bool state)
{
{
	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
	struct bmc150_accel_data *data = iio_priv(indio_dev);
	struct bmc150_accel_data *data = t->data;
	int ret;
	int ret;


	mutex_lock(&data->mutex);
	mutex_lock(&data->mutex);


	if (data->motion_trig == trig) {
	if (t->enabled == state) {
		if (data->motion_trigger_on == state) {
		mutex_unlock(&data->mutex);
		mutex_unlock(&data->mutex);
		return 0;
		return 0;
	}
	}
	} else {

		if (data->dready_trigger_on == state) {
	if (t->setup) {
		ret = t->setup(t, state);
		if (ret < 0) {
			mutex_unlock(&data->mutex);
			mutex_unlock(&data->mutex);
			return 0;
			return ret;
		}
		}
	}
	}


	if (data->motion_trig == trig) {
	ret = bmc150_accel_set_interrupt(data, t->intr, state);
		ret = bmc150_accel_update_slope(data);
		if (!ret)
			ret = bmc150_accel_set_interrupt(data,
						 BMC150_ACCEL_INT_ANY_MOTION,
							 state);
	} else {
		ret = bmc150_accel_set_interrupt(data,
						 BMC150_ACCEL_INT_DATA_READY,
						 state);
	}
	if (ret < 0) {
	if (ret < 0) {
		mutex_unlock(&data->mutex);
		mutex_unlock(&data->mutex);
		return ret;
		return ret;
	}
	}
	if (data->motion_trig == trig)

		data->motion_trigger_on = state;
	t->enabled = state;
	else
		data->dready_trigger_on = state;


	mutex_unlock(&data->mutex);
	mutex_unlock(&data->mutex);


@@ -1040,7 +1052,7 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
}
}


static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
	.set_trigger_state = bmc150_accel_data_rdy_trigger_set_state,
	.set_trigger_state = bmc150_accel_trigger_set_state,
	.try_reenable = bmc150_accel_trig_try_reen,
	.try_reenable = bmc150_accel_trig_try_reen,
	.owner = THIS_MODULE,
	.owner = THIS_MODULE,
};
};
@@ -1086,7 +1098,7 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
							dir),
							dir),
							data->timestamp);
							data->timestamp);
ack_intr_status:
ack_intr_status:
	if (!data->dready_trigger_on)
	if (!data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY].enabled)
		ret = i2c_smbus_write_byte_data(data->client,
		ret = i2c_smbus_write_byte_data(data->client,
					BMC150_ACCEL_REG_INT_RST_LATCH,
					BMC150_ACCEL_REG_INT_RST_LATCH,
					BMC150_ACCEL_INT_MODE_LATCH_INT |
					BMC150_ACCEL_INT_MODE_LATCH_INT |
@@ -1099,13 +1111,16 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
{
{
	struct iio_dev *indio_dev = private;
	struct iio_dev *indio_dev = private;
	struct bmc150_accel_data *data = iio_priv(indio_dev);
	struct bmc150_accel_data *data = iio_priv(indio_dev);
	int i;


	data->timestamp = iio_get_time_ns();
	data->timestamp = iio_get_time_ns();


	if (data->dready_trigger_on)
	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
		iio_trigger_poll(data->dready_trig);
		if (data->triggers[i].enabled) {
	else if (data->motion_trigger_on)
			iio_trigger_poll(data->triggers[i].indio_trig);
		iio_trigger_poll(data->motion_trig);
			break;
		}
	}


	if (data->ev_enable_state)
	if (data->ev_enable_state)
		return IRQ_WAKE_THREAD;
		return IRQ_WAKE_THREAD;
@@ -1153,6 +1168,70 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client,
	return ret;
	return ret;
}
}


static const struct {
	int intr;
	const char *name;
	int (*setup)(struct bmc150_accel_trigger *t, bool state);
} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = {
	{
		.intr = 0,
		.name = "%s-dev%d",
	},
	{
		.intr = 1,
		.name = "%s-any-motion-dev%d",
		.setup = bmc150_accel_any_motion_setup,
	},
};

static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
					     int from)
{
	int i;

	for (i = from; i >= 0; i++) {
		if (data->triggers[i].indio_trig) {
			iio_trigger_unregister(data->triggers[i].indio_trig);
			data->triggers[i].indio_trig = NULL;
		}
	}
}

static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
				       struct bmc150_accel_data *data)
{
	int i, ret;

	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
		struct bmc150_accel_trigger *t = &data->triggers[i];

		t->indio_trig = devm_iio_trigger_alloc(&data->client->dev,
					       bmc150_accel_triggers[i].name,
						       indio_dev->name,
						       indio_dev->id);
		if (!t->indio_trig) {
			ret = -ENOMEM;
			break;
		}

		t->indio_trig->dev.parent = &data->client->dev;
		t->indio_trig->ops = &bmc150_accel_trigger_ops;
		t->intr = bmc150_accel_triggers[i].intr;
		t->data = data;
		t->setup = bmc150_accel_triggers[i].setup;
		iio_trigger_set_drvdata(t->indio_trig, t);

		ret = iio_trigger_register(t->indio_trig);
		if (ret)
			break;
	}

	if (ret)
		bmc150_accel_unregister_triggers(data, i - 1);

	return ret;
}

static int bmc150_accel_probe(struct i2c_client *client,
static int bmc150_accel_probe(struct i2c_client *client,
			      const struct i2c_device_id *id)
			      const struct i2c_device_id *id)
{
{
@@ -1223,36 +1302,10 @@ static int bmc150_accel_probe(struct i2c_client *client,


		bmc150_accel_interrupts_setup(indio_dev, data);
		bmc150_accel_interrupts_setup(indio_dev, data);


		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
		ret = bmc150_accel_triggers_setup(indio_dev, data);
							   "%s-dev%d",
							   indio_dev->name,
							   indio_dev->id);
		if (!data->dready_trig)
			return -ENOMEM;

		data->motion_trig = devm_iio_trigger_alloc(&client->dev,
							  "%s-any-motion-dev%d",
							  indio_dev->name,
							  indio_dev->id);
		if (!data->motion_trig)
			return -ENOMEM;

		data->dready_trig->dev.parent = &client->dev;
		data->dready_trig->ops = &bmc150_accel_trigger_ops;
		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
		ret = iio_trigger_register(data->dready_trig);
		if (ret)
		if (ret)
			return ret;
			return ret;


		data->motion_trig->dev.parent = &client->dev;
		data->motion_trig->ops = &bmc150_accel_trigger_ops;
		iio_trigger_set_drvdata(data->motion_trig, indio_dev);
		ret = iio_trigger_register(data->motion_trig);
		if (ret) {
			data->motion_trig = NULL;
			goto err_trigger_unregister;
		}

		ret = iio_triggered_buffer_setup(indio_dev,
		ret = iio_triggered_buffer_setup(indio_dev,
						 &iio_pollfunc_store_time,
						 &iio_pollfunc_store_time,
						 bmc150_accel_trigger_handler,
						 bmc150_accel_trigger_handler,
@@ -1284,13 +1337,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
err_iio_unregister:
err_iio_unregister:
	iio_device_unregister(indio_dev);
	iio_device_unregister(indio_dev);
err_buffer_cleanup:
err_buffer_cleanup:
	if (data->dready_trig)
	if (indio_dev->pollfunc)
		iio_triggered_buffer_cleanup(indio_dev);
		iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister:
err_trigger_unregister:
	if (data->dready_trig)
	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
		iio_trigger_unregister(data->dready_trig);
	if (data->motion_trig)
		iio_trigger_unregister(data->motion_trig);


	return ret;
	return ret;
}
}
@@ -1306,11 +1356,7 @@ static int bmc150_accel_remove(struct i2c_client *client)


	iio_device_unregister(indio_dev);
	iio_device_unregister(indio_dev);


	if (data->dready_trig) {
	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
		iio_triggered_buffer_cleanup(indio_dev);
		iio_trigger_unregister(data->dready_trig);
		iio_trigger_unregister(data->motion_trig);
	}


	mutex_lock(&data->mutex);
	mutex_lock(&data->mutex);
	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);