summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/iio/accel/bmc150-accel.c86
1 files changed, 51 insertions, 35 deletions
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 46ac9659e2aa..db95237888ae 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -147,10 +147,24 @@ struct bmc150_accel_chip_info {
const struct bmc150_scale_info scale_table[4];
};
+struct bmc150_accel_interrupt {
+ const struct bmc150_accel_interrupt_info *info;
+ atomic_t users;
+};
+
+enum bmc150_accel_interrupt_id {
+ BMC150_ACCEL_INT_DATA_READY,
+ BMC150_ACCEL_INT_ANY_MOTION,
+ BMC150_ACCEL_INT_WATERMARK,
+ BMC150_ACCEL_INTERRUPTS,
+};
+
struct bmc150_accel_data {
struct i2c_client *client;
+ struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
+ atomic_t active_intr;
struct mutex mutex;
s16 buffer[8];
u8 bw_bits;
@@ -421,7 +435,7 @@ static const struct bmc150_accel_interrupt_info {
u8 map_bitmask;
u8 en_reg;
u8 en_bitmask;
-} bmc150_accel_interrupts[] = {
+} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
{ /* data ready interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
@@ -438,12 +452,30 @@ static const struct bmc150_accel_interrupt_info {
},
};
-static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
- const struct bmc150_accel_interrupt_info *info,
+static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
+ struct bmc150_accel_data *data)
+{
+ int i;
+
+ for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
+ data->interrupts[i].info = &bmc150_accel_interrupts[i];
+}
+
+static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
bool state)
{
+ struct bmc150_accel_interrupt *intr = &data->interrupts[i];
+ const struct bmc150_accel_interrupt_info *info = intr->info;
int ret;
+ if (state) {
+ if (atomic_inc_return(&intr->users) > 1)
+ return 0;
+ } else {
+ if (atomic_dec_return(&intr->users) > 0)
+ return 0;
+ }
+
/*
* We will expect the enable and disable to do operation in
* in reverse order. This will happen here anyway as our
@@ -493,6 +525,11 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
goto out_fix_power_state;
}
+ if (state)
+ atomic_inc(&data->active_intr);
+ else
+ atomic_dec(&data->active_intr);
+
return 0;
out_fix_power_state:
@@ -500,20 +537,6 @@ out_fix_power_state:
return ret;
}
-static int bmc150_accel_setup_any_motion_interrupt(
- struct bmc150_accel_data *data,
- bool status)
-{
- return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1],
- status);
-}
-
-static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
- bool status)
-{
- return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0],
- status);
-}
static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
{
@@ -753,13 +776,8 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
mutex_lock(&data->mutex);
- if (!state && data->motion_trigger_on) {
- data->ev_enable_state = 0;
- mutex_unlock(&data->mutex);
- return 0;
- }
-
- ret = bmc150_accel_setup_any_motion_interrupt(data, state);
+ ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION,
+ state);
if (ret < 0) {
mutex_unlock(&data->mutex);
return ret;
@@ -996,19 +1014,16 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
}
}
- if (!state && data->ev_enable_state && data->motion_trigger_on) {
- data->motion_trigger_on = false;
- mutex_unlock(&data->mutex);
- return 0;
- }
-
if (data->motion_trig == trig) {
ret = bmc150_accel_update_slope(data);
if (!ret)
- ret = bmc150_accel_setup_any_motion_interrupt(data,
- state);
+ ret = bmc150_accel_set_interrupt(data,
+ BMC150_ACCEL_INT_ANY_MOTION,
+ state);
} else {
- ret = bmc150_accel_setup_new_data_interrupt(data, state);
+ ret = bmc150_accel_set_interrupt(data,
+ BMC150_ACCEL_INT_DATA_READY,
+ state);
}
if (ret < 0) {
mutex_unlock(&data->mutex);
@@ -1206,6 +1221,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
return ret;
}
+ bmc150_accel_interrupts_setup(indio_dev, data);
+
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
@@ -1321,8 +1338,7 @@ static int bmc150_accel_resume(struct device *dev)
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
- if (data->dready_trigger_on || data->motion_trigger_on ||
- data->ev_enable_state)
+ if (atomic_read(&data->active_intr))
bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
mutex_unlock(&data->mutex);