Skip to content

Commit

Permalink
iio: mma8452: add freefall detection for Freescale's accelerometers
Browse files Browse the repository at this point in the history
This adds freefall event detection to the supported devices. It adds
the in_accel_x&y&z_mag_falling_en iio event attribute, which activates
freefall mode.

In freefall mode, the current acceleration magnitude (AND combination
of all axis values) is compared to the specified threshold.
If it falls under the threshold (in_accel_mag_falling_value),
the appropriate IIO event code is generated.

This is what the sysfs "events" directory for these devices looks
like after this change:

-rw-r--r--    4096 Oct 23 08:45 in_accel_mag_falling_period
-rw-r--r--    4096 Oct 23 08:45 in_accel_mag_falling_value
-rw-r--r--    4096 Oct 23 08:45 in_accel_mag_rising_period
-rw-r--r--    4096 Oct 23 08:45 in_accel_mag_rising_value
-r--r--r--    4096 Oct 23 08:45 in_accel_scale
-rw-r--r--    4096 Oct 23 08:45 in_accel_x&y&z_mag_falling_en
-rw-r--r--    4096 Oct 23 08:45 in_accel_x_mag_rising_en
-rw-r--r--    4096 Oct 23 08:45 in_accel_y_mag_rising_en
-rw-r--r--    4096 Oct 23 08:45 in_accel_z_mag_rising_en

Signed-off-by: Martin Kepplinger <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Jonathan Cameron <[email protected]>
  • Loading branch information
merge authored and jic23 committed Jan 23, 2016
1 parent 61be8fd commit 4b04266
Showing 1 changed file with 144 additions and 16 deletions.
160 changes: 144 additions & 16 deletions drivers/iio/accel/mma8452.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
*
* TODO: orientation / freefall events, autosleep
* TODO: orientation events, autosleep
*/

#include <linux/module.h>
Expand Down Expand Up @@ -416,6 +416,51 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
return ret;
}

/* returns >0 if in freefall mode, 0 if not or <0 if an error occured */
static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
{
int val;
const struct mma_chip_info *chip = data->chip_info;

val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
if (val < 0)
return val;

return !(val & MMA8452_FF_MT_CFG_OAE);
}

static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state)
{
int val;
const struct mma_chip_info *chip = data->chip_info;

if ((state && mma8452_freefall_mode_enabled(data)) ||
(!state && !(mma8452_freefall_mode_enabled(data))))
return 0;

val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
if (val < 0)
return val;

if (state) {
val |= BIT(idx_x + chip->ev_cfg_chan_shift);
val |= BIT(idx_y + chip->ev_cfg_chan_shift);
val |= BIT(idx_z + chip->ev_cfg_chan_shift);
val &= ~MMA8452_FF_MT_CFG_OAE;
} else {
val &= ~BIT(idx_x + chip->ev_cfg_chan_shift);
val &= ~BIT(idx_y + chip->ev_cfg_chan_shift);
val &= ~BIT(idx_z + chip->ev_cfg_chan_shift);
val |= MMA8452_FF_MT_CFG_OAE;
}

val = mma8452_change_config(data, chip->ev_cfg, val);
if (val)
return val;

return 0;
}

static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
int val, int val2)
{
Expand Down Expand Up @@ -609,12 +654,22 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
const struct mma_chip_info *chip = data->chip_info;
int ret;

ret = i2c_smbus_read_byte_data(data->client,
data->chip_info->ev_cfg);
if (ret < 0)
return ret;
switch (dir) {
case IIO_EV_DIR_FALLING:
return mma8452_freefall_mode_enabled(data);
case IIO_EV_DIR_RISING:
if (mma8452_freefall_mode_enabled(data))
return 0;

ret = i2c_smbus_read_byte_data(data->client,
data->chip_info->ev_cfg);
if (ret < 0)
return ret;

return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
default:
return -EINVAL;
}
}

static int mma8452_write_event_config(struct iio_dev *indio_dev,
Expand All @@ -627,19 +682,35 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
const struct mma_chip_info *chip = data->chip_info;
int val;

val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
if (val < 0)
return val;
switch (dir) {
case IIO_EV_DIR_FALLING:
return mma8452_set_freefall_mode(data, state);
case IIO_EV_DIR_RISING:
val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
if (val < 0)
return val;

if (state) {
if (mma8452_freefall_mode_enabled(data)) {
val &= ~BIT(idx_x + chip->ev_cfg_chan_shift);
val &= ~BIT(idx_y + chip->ev_cfg_chan_shift);
val &= ~BIT(idx_z + chip->ev_cfg_chan_shift);
val |= MMA8452_FF_MT_CFG_OAE;
}
val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
} else {
if (mma8452_freefall_mode_enabled(data))
return 0;

if (state)
val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
else
val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
}

val |= chip->ev_cfg_ele;
val |= MMA8452_FF_MT_CFG_OAE;
val |= chip->ev_cfg_ele;

return mma8452_change_config(data, chip->ev_cfg, val);
return mma8452_change_config(data, chip->ev_cfg, val);
default:
return -EINVAL;
}
}

static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
Expand All @@ -652,6 +723,16 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
if (src < 0)
return;

if (mma8452_freefall_mode_enabled(data)) {
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_AND_Y_AND_Z,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_FALLING),
ts);
return;
}

if (src & data->chip_info->ev_src_xe)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
Expand Down Expand Up @@ -745,6 +826,27 @@ static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
return 0;
}

static const struct iio_event_spec mma8452_freefall_event[] = {
{
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD) |
BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
},
};

static const struct iio_event_spec mma8652_freefall_event[] = {
{
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD)
},
};

static const struct iio_event_spec mma8452_transient_event[] = {
{
.type = IIO_EV_TYPE_MAG,
Expand Down Expand Up @@ -781,6 +883,24 @@ static struct attribute_group mma8452_event_attribute_group = {
.attrs = mma8452_event_attributes,
};

#define MMA8452_FREEFALL_CHANNEL(modifier) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = modifier, \
.scan_index = -1, \
.event_spec = mma8452_freefall_event, \
.num_event_specs = ARRAY_SIZE(mma8452_freefall_event), \
}

#define MMA8652_FREEFALL_CHANNEL(modifier) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = modifier, \
.scan_index = -1, \
.event_spec = mma8652_freefall_event, \
.num_event_specs = ARRAY_SIZE(mma8652_freefall_event), \
}

#define MMA8452_CHANNEL(axis, idx, bits) { \
.type = IIO_ACCEL, \
.modified = 1, \
Expand Down Expand Up @@ -827,27 +947,31 @@ static const struct iio_chan_spec mma8452_channels[] = {
MMA8452_CHANNEL(Y, idx_y, 12),
MMA8452_CHANNEL(Z, idx_z, 12),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
};

static const struct iio_chan_spec mma8453_channels[] = {
MMA8452_CHANNEL(X, idx_x, 10),
MMA8452_CHANNEL(Y, idx_y, 10),
MMA8452_CHANNEL(Z, idx_z, 10),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
};

static const struct iio_chan_spec mma8652_channels[] = {
MMA8652_CHANNEL(X, idx_x, 12),
MMA8652_CHANNEL(Y, idx_y, 12),
MMA8652_CHANNEL(Z, idx_z, 12),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
};

static const struct iio_chan_spec mma8653_channels[] = {
MMA8652_CHANNEL(X, idx_x, 10),
MMA8652_CHANNEL(Y, idx_y, 10),
MMA8652_CHANNEL(Z, idx_z, 10),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
};

enum {
Expand Down Expand Up @@ -1190,6 +1314,10 @@ static int mma8452_probe(struct i2c_client *client,
if (ret < 0)
goto buffer_cleanup;

ret = mma8452_set_freefall_mode(data, false);
if (ret)
return ret;

return 0;

buffer_cleanup:
Expand Down

0 comments on commit 4b04266

Please sign in to comment.