iio: bmc150: refactor interrupt enabling

This patch combines the any motion and new data interrupts function
into a single, generic, interrupt enable function. On top of this, we
can later refactor triggers to make it easier to add new triggers.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
Octavian Purdila 2015-01-31 02:00:04 +02:00 committed by Jonathan Cameron
parent 802a3aef30
commit 8e22f477e1
1 changed files with 113 additions and 159 deletions

View File

@ -359,137 +359,6 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return 0; return 0;
} }
static int bmc150_accel_setup_any_motion_interrupt(
struct bmc150_accel_data *data,
bool status)
{
int ret;
/* Enable/Disable INT1 mapping */
ret = i2c_smbus_read_byte_data(data->client,
BMC150_ACCEL_REG_INT_MAP_0);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_map_0\n");
return ret;
}
if (status)
ret |= BMC150_ACCEL_INT_MAP_0_BIT_SLOPE;
else
ret &= ~BMC150_ACCEL_INT_MAP_0_BIT_SLOPE;
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_MAP_0,
ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_map_0\n");
return ret;
}
if (status) {
/*
* New data interrupt is always non-latched,
* which will have higher priority, so no need
* to set latched mode, we will be flooded anyway with INTR
*/
if (!data->dready_trigger_on) {
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
}
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_EN_0,
BMC150_ACCEL_INT_EN_BIT_SLP_X |
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
BMC150_ACCEL_INT_EN_BIT_SLP_Z);
} else
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_EN_0,
0);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_en_0\n");
return ret;
}
return 0;
}
static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
bool status)
{
int ret;
/* Enable/Disable INT1 mapping */
ret = i2c_smbus_read_byte_data(data->client,
BMC150_ACCEL_REG_INT_MAP_1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_map_1\n");
return ret;
}
if (status)
ret |= BMC150_ACCEL_INT_MAP_1_BIT_DATA;
else
ret &= ~BMC150_ACCEL_INT_MAP_1_BIT_DATA;
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_MAP_1,
ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_map_1\n");
return ret;
}
if (status) {
/*
* Set non latched mode interrupt and clear any latched
* interrupt
*/
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_NON_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_EN_1,
BMC150_ACCEL_INT_EN_BIT_DATA_EN);
} else {
/* Restore default interrupt mode */
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_EN_1,
0);
}
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
return ret;
}
return 0;
}
static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
int *val2) int *val2)
{ {
@ -547,6 +416,105 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
} }
#endif #endif
static const struct bmc150_accel_interrupt_info {
u8 map_reg;
u8 map_bitmask;
u8 en_reg;
u8 en_bitmask;
} bmc150_accel_interrupts[] = {
{ /* data ready interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
},
{ /* motion interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
.map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE,
.en_reg = BMC150_ACCEL_REG_INT_EN_0,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
BMC150_ACCEL_INT_EN_BIT_SLP_Z
},
};
static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
const struct bmc150_accel_interrupt_info *info,
bool state)
{
int ret;
/*
* We will expect the enable and disable to do operation in
* in reverse order. This will happen here anyway as our
* resume operation uses sync mode runtime pm calls, the
* suspend operation will be delayed by autosuspend delay
* So the disable operation will still happen in reverse of
* enable operation. When runtime pm is disabled the mode
* is always on so sequence doesn't matter
*/
ret = bmc150_accel_set_power_state(data, state);
if (ret < 0)
return ret;
/* map the interrupt to the appropriate pins */
ret = i2c_smbus_read_byte_data(data->client, info->map_reg);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_map\n");
goto out_fix_power_state;
}
if (state)
ret |= info->map_bitmask;
else
ret &= ~info->map_bitmask;
ret = i2c_smbus_write_byte_data(data->client, info->map_reg,
ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_map\n");
goto out_fix_power_state;
}
/* enable/disable the interrupt */
ret = i2c_smbus_read_byte_data(data->client, info->en_reg);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_en\n");
goto out_fix_power_state;
}
if (state)
ret |= info->en_bitmask;
else
ret &= ~info->en_bitmask;
ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_en\n");
goto out_fix_power_state;
}
return 0;
out_fix_power_state:
bmc150_accel_set_power_state(data, false);
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) static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
{ {
int ret, i; int ret, i;
@ -791,25 +759,8 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
return 0; return 0;
} }
/*
* We will expect the enable and disable to do operation in
* in reverse order. This will happen here anyway as our
* resume operation uses sync mode runtime pm calls, the
* suspend operation will be delayed by autosuspend delay
* So the disable operation will still happen in reverse of
* enable operation. When runtime pm is disabled the mode
* is always on so sequence doesn't matter
*/
ret = bmc150_accel_set_power_state(data, state);
if (ret < 0) {
mutex_unlock(&data->mutex);
return ret;
}
ret = bmc150_accel_setup_any_motion_interrupt(data, state); ret = bmc150_accel_setup_any_motion_interrupt(data, state);
if (ret < 0) { if (ret < 0) {
bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return ret; return ret;
} }
@ -1039,16 +990,6 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
return 0; return 0;
} }
/*
* Refer to comment in bmc150_accel_write_event_config for
* enable/disable operation order
*/
ret = bmc150_accel_set_power_state(data, state);
if (ret < 0) {
mutex_unlock(&data->mutex);
return ret;
}
if (data->motion_trig == trig) { if (data->motion_trig == trig) {
ret = bmc150_accel_update_slope(data); ret = bmc150_accel_update_slope(data);
if (!ret) if (!ret)
@ -1058,7 +999,6 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
ret = bmc150_accel_setup_new_data_interrupt(data, state); ret = bmc150_accel_setup_new_data_interrupt(data, state);
} }
if (ret < 0) { if (ret < 0) {
bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return ret; return ret;
} }
@ -1244,6 +1184,20 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (ret) if (ret)
return ret; return ret;
/*
* Set latched mode interrupt. While certain interrupts are
* non-latched regardless of this settings (e.g. new data) we
* want to use latch mode when we can to prevent interrupt
* flooding.
*/
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
return ret;
}
data->dready_trig = devm_iio_trigger_alloc(&client->dev, data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d", "%s-dev%d",
indio_dev->name, indio_dev->name,