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:
parent
802a3aef30
commit
8e22f477e1
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue