Message ID | 20200810093257.65929-2-alexandru.tachici@analog.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iio: accel: adxl372: Add support for FIFO peak mode | expand |
On Mon, 10 Aug 2020 12:32:56 +0300 <alexandru.tachici@analog.com> wrote: > From: Stefan Popa <stefan.popa@analog.com> > > By default, if all three channels (x, y, z) are enabled, sample sets of > concurrent 3-axis data is stored in the FIFO. This patch adds the option > to configure the FIFO to store peak acceleration (x, y and z) of every > over-threshold event. When pushing to iio buffer we push only enabled > axis data. > > Currently the driver configures adxl372 to work in loop mode. > The inactivity and activity timings decide how fast the chip > will loop through the awake and waiting states and the > thresholds on x,y,z axis decide when activity or inactivity > will be detected. > > This patch adds standard events sysfs entries for the inactivity > and activity timings: thresh_falling_period/thresh_rising_period > and for the in_accel_x_thresh_falling/rising_value. > > Signed-off-by: Stefan Popa <stefan.popa@analog.com> > Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com> Hi Alexandru, This didn't go in remotely cleanly because of fuzz from moving the pollfunc attach / detach into the core which seems to have crossed with it. I think I have it correct, but please check and let me know if there are any problems. Pushed out as testing for the autobuilders to poke at it as well. thanks, Jonathan > --- > drivers/iio/accel/adxl372.c | 302 +++++++++++++++++++++++++++++++++++- > 1 file changed, 294 insertions(+), 8 deletions(-) > > diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c > index 67b8817995c0..4cad16e2f7b7 100644 > --- a/drivers/iio/accel/adxl372.c > +++ b/drivers/iio/accel/adxl372.c > @@ -5,6 +5,7 @@ > * Copyright 2018 Analog Devices Inc. > */ > > +#include <linux/bitfield.h> > #include <linux/bitops.h> > #include <linux/interrupt.h> > #include <linux/irq.h> > @@ -113,6 +114,11 @@ > #define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1) > #define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1) > > +/* ADXL372_STATUS_2 */ > +#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1) > +#define ADXL372_STATUS_2_ACT(x) (((x) >> 5) & 0x1) > +#define ADXL372_STATUS_2_AC2(x) (((x) >> 6) & 0x1) > + > /* ADXL372_INT1_MAP */ > #define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0) > #define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0) > @@ -131,8 +137,17 @@ > #define ADXL372_INT1_MAP_LOW_MSK BIT(7) > #define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7) > > +/* ADX372_THRESH */ > +#define ADXL372_THRESH_VAL_H_MSK GENMASK(10, 3) > +#define ADXL372_THRESH_VAL_H_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_H_MSK, x) > +#define ADXL372_THRESH_VAL_L_MSK GENMASK(2, 0) > +#define ADXL372_THRESH_VAL_L_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_L_MSK, x) > + > /* The ADXL372 includes a deep, 512 sample FIFO buffer */ > #define ADXL372_FIFO_SIZE 512 > +#define ADXL372_X_AXIS_EN(x) ((x) & BIT(0)) > +#define ADXL372_Y_AXIS_EN(x) ((x) & BIT(1)) > +#define ADXL372_Z_AXIS_EN(x) ((x) & BIT(2)) > > /* > * At +/- 200g with 12-bit resolution, scale is computed as: > @@ -222,6 +237,20 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { > { BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO }, > }; > > +static const struct iio_event_spec adxl372_events[] = { > + { > + .type = IIO_EV_TYPE_THRESH, > + .dir = IIO_EV_DIR_RISING, > + .mask_separate = BIT(IIO_EV_INFO_VALUE), > + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), > + }, { > + .type = IIO_EV_TYPE_THRESH, > + .dir = IIO_EV_DIR_FALLING, > + .mask_separate = BIT(IIO_EV_INFO_VALUE), > + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), > + }, > +}; > + > #define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \ > .type = IIO_ACCEL, \ > .address = reg, \ > @@ -238,6 +267,8 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { > .storagebits = 16, \ > .shift = 4, \ > }, \ > + .event_spec = adxl372_events, \ > + .num_event_specs = ARRAY_SIZE(adxl372_events) \ > } > > static const struct iio_chan_spec adxl372_channels[] = { > @@ -251,8 +282,10 @@ struct adxl372_state { > struct device *dev; > struct regmap *regmap; > struct iio_trigger *dready_trig; > + struct iio_trigger *peak_datardy_trig; > enum adxl372_fifo_mode fifo_mode; > enum adxl372_fifo_format fifo_format; > + unsigned int fifo_axis_mask; > enum adxl372_op_mode op_mode; > enum adxl372_act_proc_mode act_proc_mode; > enum adxl372_odr odr; > @@ -264,6 +297,8 @@ struct adxl372_state { > u8 int2_bitmask; > u16 watermark; > __be16 fifo_buf[ADXL372_FIFO_SIZE]; > + bool peak_fifo_mode_en; > + struct mutex threshold_m; /* lock for threshold */ > }; > > static const unsigned long adxl372_channel_masks[] = { > @@ -275,6 +310,45 @@ static const unsigned long adxl372_channel_masks[] = { > 0 > }; > > +static ssize_t adxl372_read_threshold_value(struct iio_dev *indio_dev, unsigned int addr, > + u16 *threshold) > +{ > + struct adxl372_state *st = iio_priv(indio_dev); > + __be16 raw_regval; > + u16 regval; > + int ret; > + > + ret = regmap_bulk_read(st->regmap, addr, &raw_regval, sizeof(raw_regval)); > + if (ret < 0) > + return ret; > + > + regval = be16_to_cpu(raw_regval); > + regval >>= 5; > + > + *threshold = regval; > + > + return 0; > +} > + > +static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned int addr, > + u16 threshold) > +{ > + struct adxl372_state *st = iio_priv(indio_dev); > + int ret; > + > + mutex_lock(&st->threshold_m); > + ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold)); > + if (ret < 0) > + return ret; > + > + ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5), > + ADXL372_THRESH_VAL_L_SEL(threshold) << 5); > + > + mutex_unlock(&st->threshold_m); > + > + return ret; > +} > + > static int adxl372_read_axis(struct adxl372_state *st, u8 addr) > { > __be16 regval; > @@ -522,6 +596,39 @@ static int adxl372_get_status(struct adxl372_state *st, > return ret; > } > > +static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample) > +{ > + __be16 axis_sample[3]; > + int i = 0; > + > + memset(axis_sample, 0, 3 * sizeof(__be16)); > + if (ADXL372_X_AXIS_EN(st->fifo_axis_mask)) > + axis_sample[i++] = sample[0]; > + if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask)) > + axis_sample[i++] = sample[1]; > + if (ADXL372_Z_AXIS_EN(st->fifo_axis_mask)) > + axis_sample[i++] = sample[2]; > + > + memcpy(sample, axis_sample, 3 * sizeof(__be16)); > +} > + > +static void adxl372_push_event(struct iio_dev *indio_dev, s64 timestamp, u8 status2) > +{ > + unsigned int ev_dir = IIO_EV_DIR_NONE; > + > + if (ADXL372_STATUS_2_ACT(status2)) > + ev_dir = IIO_EV_DIR_RISING; > + > + if (ADXL372_STATUS_2_INACT(status2)) > + ev_dir = IIO_EV_DIR_FALLING; > + > + if (ev_dir != IIO_EV_DIR_NONE) > + iio_push_event(indio_dev, > + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, > + IIO_EV_TYPE_THRESH, ev_dir), > + timestamp); > +} > + > static irqreturn_t adxl372_trigger_handler(int irq, void *p) > { > struct iio_poll_func *pf = p; > @@ -535,6 +642,8 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) > if (ret < 0) > goto err; > > + adxl372_push_event(indio_dev, iio_get_time_ns(indio_dev), status2); > + > if (st->fifo_mode != ADXL372_FIFO_BYPASSED && > ADXL372_STATUS_1_FIFO_FULL(status1)) { > /* > @@ -553,8 +662,12 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) > goto err; > > /* Each sample is 2 bytes */ > - for (i = 0; i < fifo_entries; i += st->fifo_set_size) > + for (i = 0; i < fifo_entries; i += st->fifo_set_size) { > + /* filter peak detection data */ > + if (st->peak_fifo_mode_en) > + adxl372_arrange_axis_data(st, &st->fifo_buf[i]); > iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); > + } > } > err: > iio_trigger_notify_done(indio_dev->trig); > @@ -722,6 +835,129 @@ static int adxl372_write_raw(struct iio_dev *indio_dev, > } > } > > +static int adxl372_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > + enum iio_event_type type, enum iio_event_direction dir, > + enum iio_event_info info, int *val, int *val2) > +{ > + struct adxl372_state *st = iio_priv(indio_dev); > + unsigned int addr; > + u16 raw_value; > + int ret; > + > + switch (info) { > + case IIO_EV_INFO_VALUE: > + switch (dir) { > + case IIO_EV_DIR_RISING: > + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; > + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); > + if (ret < 0) > + return ret; > + *val = raw_value * ADXL372_USCALE; > + *val2 = 1000000; > + return IIO_VAL_FRACTIONAL; > + case IIO_EV_DIR_FALLING: > + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; > + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); > + if (ret < 0) > + return ret; > + *val = raw_value * ADXL372_USCALE; > + *val2 = 1000000; > + return IIO_VAL_FRACTIONAL; > + default: > + return -EINVAL; > + } > + case IIO_EV_INFO_PERIOD: > + switch (dir) { > + case IIO_EV_DIR_RISING: > + *val = st->act_time_ms; > + *val2 = 1000; > + return IIO_VAL_FRACTIONAL; > + case IIO_EV_DIR_FALLING: > + *val = st->inact_time_ms; > + *val2 = 1000; > + return IIO_VAL_FRACTIONAL; > + default: > + return -EINVAL; > + } > + default: > + return -EINVAL; > + } > +} > + > +static int adxl372_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > + enum iio_event_type type, enum iio_event_direction dir, > + enum iio_event_info info, int val, int val2) > +{ > + struct adxl372_state *st = iio_priv(indio_dev); > + unsigned int val_ms; > + unsigned int addr; > + u16 raw_val; > + > + switch (info) { > + case IIO_EV_INFO_VALUE: > + raw_val = DIV_ROUND_UP(val * 1000000, ADXL372_USCALE); > + switch (dir) { > + case IIO_EV_DIR_RISING: > + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; > + return adxl372_write_threshold_value(indio_dev, addr, raw_val); > + case IIO_EV_DIR_FALLING: > + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; > + return adxl372_write_threshold_value(indio_dev, addr, raw_val); > + default: > + return -EINVAL; > + } > + case IIO_EV_INFO_PERIOD: > + val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000); > + switch (dir) { > + case IIO_EV_DIR_RISING: > + return adxl372_set_activity_time_ms(st, val_ms); > + case IIO_EV_DIR_FALLING: > + return adxl372_set_inactivity_time_ms(st, val_ms); > + default: > + return -EINVAL; > + } > + default: > + return -EINVAL; > + } > +} > + > +static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > + enum iio_event_type type, enum iio_event_direction dir) > +{ > + struct adxl372_state *st = iio_priv(indio_dev); > + > + switch (dir) { > + case IIO_EV_DIR_RISING: > + return FIELD_GET(ADXL372_INT1_MAP_ACT_MSK, st->int1_bitmask); > + case IIO_EV_DIR_FALLING: > + return FIELD_GET(ADXL372_INT1_MAP_INACT_MSK, st->int1_bitmask); > + default: > + return -EINVAL; > + } > +} > + > +static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > + enum iio_event_type type, enum iio_event_direction dir, > + int state) > +{ > + struct adxl372_state *st = iio_priv(indio_dev); > + > + switch (dir) { > + case IIO_EV_DIR_RISING: > + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK, > + ADXL372_INT1_MAP_ACT_MODE(state)); > + break; > + case IIO_EV_DIR_FALLING: > + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK, > + ADXL372_INT1_MAP_INACT_MODE(state)); > + break; > + default: > + return -EINVAL; > + } > + > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > +} > + > static ssize_t adxl372_show_filter_freq_avail(struct device *dev, > struct device_attribute *attr, > char *buf) > @@ -798,7 +1034,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > if (ret < 0) > return ret; > > - ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0); > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > + ret = adxl372_set_interrupts(st, st->int1_bitmask, 0); > if (ret < 0) > goto err; > > @@ -815,13 +1052,22 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > } > > st->fifo_format = adxl372_axis_lookup_table[i].fifo_format; > + st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits; > st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, > indio_dev->masklength); > + > + /* Configure the FIFO to store sets of impact event peak. */ > + if (st->peak_fifo_mode_en) { > + st->fifo_set_size = 3; > + st->fifo_format = ADXL372_XYZ_PEAK_FIFO; > + } > + > /* > * The 512 FIFO samples can be allotted in several ways, such as: > * 170 sample sets of concurrent 3-axis data > * 256 sample sets of concurrent 2-axis data (user selectable) > * 512 sample sets of single-axis data > + * 170 sets of impact event peak (x, y, z) > */ > if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE) > st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size); > @@ -831,7 +1077,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > ret = adxl372_configure_fifo(st); > if (ret < 0) { > st->fifo_mode = ADXL372_FIFO_BYPASSED; > - adxl372_set_interrupts(st, 0, 0); > + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; > + adxl372_set_interrupts(st, st->int1_bitmask, 0); > goto err; > } > > @@ -846,7 +1093,8 @@ static int adxl372_buffer_predisable(struct iio_dev *indio_dev) > { > struct adxl372_state *st = iio_priv(indio_dev); > > - adxl372_set_interrupts(st, 0, 0); > + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; > + adxl372_set_interrupts(st, st->int1_bitmask, 0); > st->fifo_mode = ADXL372_FIFO_BYPASSED; > adxl372_configure_fifo(st); > > @@ -863,12 +1111,11 @@ static int adxl372_dready_trig_set_state(struct iio_trigger *trig, > { > struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > struct adxl372_state *st = iio_priv(indio_dev); > - unsigned long int mask = 0; > > if (state) > - mask = ADXL372_INT1_MAP_FIFO_FULL_MSK; > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > - return adxl372_set_interrupts(st, mask, 0); > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > } > > static int adxl372_validate_trigger(struct iio_dev *indio_dev, > @@ -876,7 +1123,7 @@ static int adxl372_validate_trigger(struct iio_dev *indio_dev, > { > struct adxl372_state *st = iio_priv(indio_dev); > > - if (st->dready_trig != trig) > + if (st->dready_trig != trig && st->peak_datardy_trig != trig) > return -EINVAL; > > return 0; > @@ -887,6 +1134,25 @@ static const struct iio_trigger_ops adxl372_trigger_ops = { > .set_trigger_state = adxl372_dready_trig_set_state, > }; > > +static int adxl372_peak_dready_trig_set_state(struct iio_trigger *trig, > + bool state) > +{ > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > + struct adxl372_state *st = iio_priv(indio_dev); > + > + if (state) > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > + > + st->peak_fifo_mode_en = state; > + > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > +} > + > +static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = { > + .validate_device = &iio_trigger_validate_own_device, > + .set_trigger_state = adxl372_peak_dready_trig_set_state, > +}; > + > static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400"); > static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, > 0444, adxl372_show_filter_freq_avail, NULL, 0); > @@ -906,6 +1172,10 @@ static const struct iio_info adxl372_info = { > .attrs = &adxl372_attrs_group, > .read_raw = adxl372_read_raw, > .write_raw = adxl372_write_raw, > + .read_event_config = adxl372_read_event_config, > + .write_event_config = adxl372_write_event_config, > + .read_event_value = adxl372_read_event_value, > + .write_event_value = adxl372_write_event_value, > .debugfs_reg_access = &adxl372_reg_access, > .hwfifo_set_watermark = adxl372_set_watermark, > }; > @@ -934,6 +1204,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, > st->regmap = regmap; > st->irq = irq; > > + mutex_init(&st->threshold_m); > + > indio_dev->channels = adxl372_channels; > indio_dev->num_channels = ARRAY_SIZE(adxl372_channels); > indio_dev->available_scan_masks = adxl372_channel_masks; > @@ -965,13 +1237,27 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, > if (st->dready_trig == NULL) > return -ENOMEM; > > + st->peak_datardy_trig = devm_iio_trigger_alloc(dev, > + "%s-dev%d-peak", > + indio_dev->name, > + indio_dev->id); > + if (!st->peak_datardy_trig) > + return -ENOMEM; > + > st->dready_trig->ops = &adxl372_trigger_ops; > + st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; > st->dready_trig->dev.parent = dev; > + st->peak_datardy_trig->dev.parent = dev; > iio_trigger_set_drvdata(st->dready_trig, indio_dev); > + iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); > ret = devm_iio_trigger_register(dev, st->dready_trig); > if (ret < 0) > return ret; > > + ret = devm_iio_trigger_register(dev, st->peak_datardy_trig); > + if (ret < 0) > + return ret; > + > indio_dev->trig = iio_trigger_get(st->dready_trig); > > ret = devm_request_threaded_irq(dev, st->irq,
On Sat, 29 Aug 2020 18:43:50 +0100 Jonathan Cameron <jic23@kernel.org> wrote: > On Mon, 10 Aug 2020 12:32:56 +0300 > <alexandru.tachici@analog.com> wrote: > > > From: Stefan Popa <stefan.popa@analog.com> > > > > By default, if all three channels (x, y, z) are enabled, sample sets of > > concurrent 3-axis data is stored in the FIFO. This patch adds the option > > to configure the FIFO to store peak acceleration (x, y and z) of every > > over-threshold event. When pushing to iio buffer we push only enabled > > axis data. > > > > Currently the driver configures adxl372 to work in loop mode. > > The inactivity and activity timings decide how fast the chip > > will loop through the awake and waiting states and the > > thresholds on x,y,z axis decide when activity or inactivity > > will be detected. > > > > This patch adds standard events sysfs entries for the inactivity > > and activity timings: thresh_falling_period/thresh_rising_period > > and for the in_accel_x_thresh_falling/rising_value. > > > > Signed-off-by: Stefan Popa <stefan.popa@analog.com> > > Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com> > > Hi Alexandru, > > This didn't go in remotely cleanly because of fuzz from moving the > pollfunc attach / detach into the core which seems to have crossed with it. > > I think I have it correct, but please check and let me know if there > are any problems. > > Pushed out as testing for the autobuilders to poke at it as well. > > thanks, > > Jonathan > > > --- > > drivers/iio/accel/adxl372.c | 302 +++++++++++++++++++++++++++++++++++- > > 1 file changed, 294 insertions(+), 8 deletions(-) > > > > diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c > > index 67b8817995c0..4cad16e2f7b7 100644 > > --- a/drivers/iio/accel/adxl372.c > > +++ b/drivers/iio/accel/adxl372.c > > @@ -5,6 +5,7 @@ > > * Copyright 2018 Analog Devices Inc. > > */ > > > > +#include <linux/bitfield.h> > > #include <linux/bitops.h> > > #include <linux/interrupt.h> > > #include <linux/irq.h> > > @@ -113,6 +114,11 @@ > > #define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1) > > #define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1) > > > > +/* ADXL372_STATUS_2 */ > > +#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1) > > +#define ADXL372_STATUS_2_ACT(x) (((x) >> 5) & 0x1) > > +#define ADXL372_STATUS_2_AC2(x) (((x) >> 6) & 0x1) > > + > > /* ADXL372_INT1_MAP */ > > #define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0) > > #define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0) > > @@ -131,8 +137,17 @@ > > #define ADXL372_INT1_MAP_LOW_MSK BIT(7) > > #define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7) > > > > +/* ADX372_THRESH */ > > +#define ADXL372_THRESH_VAL_H_MSK GENMASK(10, 3) > > +#define ADXL372_THRESH_VAL_H_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_H_MSK, x) > > +#define ADXL372_THRESH_VAL_L_MSK GENMASK(2, 0) > > +#define ADXL372_THRESH_VAL_L_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_L_MSK, x) > > + > > /* The ADXL372 includes a deep, 512 sample FIFO buffer */ > > #define ADXL372_FIFO_SIZE 512 > > +#define ADXL372_X_AXIS_EN(x) ((x) & BIT(0)) > > +#define ADXL372_Y_AXIS_EN(x) ((x) & BIT(1)) > > +#define ADXL372_Z_AXIS_EN(x) ((x) & BIT(2)) > > > > /* > > * At +/- 200g with 12-bit resolution, scale is computed as: > > @@ -222,6 +237,20 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { > > { BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO }, > > }; > > > > +static const struct iio_event_spec adxl372_events[] = { > > + { > > + .type = IIO_EV_TYPE_THRESH, > > + .dir = IIO_EV_DIR_RISING, > > + .mask_separate = BIT(IIO_EV_INFO_VALUE), > > + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), > > + }, { > > + .type = IIO_EV_TYPE_THRESH, > > + .dir = IIO_EV_DIR_FALLING, > > + .mask_separate = BIT(IIO_EV_INFO_VALUE), > > + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), > > + }, > > +}; > > + > > #define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \ > > .type = IIO_ACCEL, \ > > .address = reg, \ > > @@ -238,6 +267,8 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { > > .storagebits = 16, \ > > .shift = 4, \ > > }, \ > > + .event_spec = adxl372_events, \ > > + .num_event_specs = ARRAY_SIZE(adxl372_events) \ > > } > > > > static const struct iio_chan_spec adxl372_channels[] = { > > @@ -251,8 +282,10 @@ struct adxl372_state { > > struct device *dev; > > struct regmap *regmap; > > struct iio_trigger *dready_trig; > > + struct iio_trigger *peak_datardy_trig; > > enum adxl372_fifo_mode fifo_mode; > > enum adxl372_fifo_format fifo_format; > > + unsigned int fifo_axis_mask; > > enum adxl372_op_mode op_mode; > > enum adxl372_act_proc_mode act_proc_mode; > > enum adxl372_odr odr; > > @@ -264,6 +297,8 @@ struct adxl372_state { > > u8 int2_bitmask; > > u16 watermark; > > __be16 fifo_buf[ADXL372_FIFO_SIZE]; > > + bool peak_fifo_mode_en; > > + struct mutex threshold_m; /* lock for threshold */ > > }; > > > > static const unsigned long adxl372_channel_masks[] = { > > @@ -275,6 +310,45 @@ static const unsigned long adxl372_channel_masks[] = { > > 0 > > }; > > > > +static ssize_t adxl372_read_threshold_value(struct iio_dev *indio_dev, unsigned int addr, > > + u16 *threshold) > > +{ > > + struct adxl372_state *st = iio_priv(indio_dev); > > + __be16 raw_regval; > > + u16 regval; > > + int ret; > > + > > + ret = regmap_bulk_read(st->regmap, addr, &raw_regval, sizeof(raw_regval)); > > + if (ret < 0) > > + return ret; > > + > > + regval = be16_to_cpu(raw_regval); > > + regval >>= 5; > > + > > + *threshold = regval; > > + > > + return 0; > > +} > > + > > +static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned int addr, > > + u16 threshold) > > +{ > > + struct adxl372_state *st = iio_priv(indio_dev); > > + int ret; > > + > > + mutex_lock(&st->threshold_m); > > + ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold)); > > + if (ret < 0) 0-day pointed this out. You are missing a lock here. I've fixed by using goto unlock; > > + return ret; > > + > > + ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5), > > + ADXL372_THRESH_VAL_L_SEL(threshold) << 5); > > + unlock: > > + mutex_unlock(&st->threshold_m); > > + > > + return ret; > > +} > > + > > static int adxl372_read_axis(struct adxl372_state *st, u8 addr) > > { > > __be16 regval; > > @@ -522,6 +596,39 @@ static int adxl372_get_status(struct adxl372_state *st, > > return ret; > > } > > > > +static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample) > > +{ > > + __be16 axis_sample[3]; > > + int i = 0; > > + > > + memset(axis_sample, 0, 3 * sizeof(__be16)); > > + if (ADXL372_X_AXIS_EN(st->fifo_axis_mask)) > > + axis_sample[i++] = sample[0]; > > + if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask)) > > + axis_sample[i++] = sample[1]; > > + if (ADXL372_Z_AXIS_EN(st->fifo_axis_mask)) > > + axis_sample[i++] = sample[2]; > > + > > + memcpy(sample, axis_sample, 3 * sizeof(__be16)); > > +} > > + > > +static void adxl372_push_event(struct iio_dev *indio_dev, s64 timestamp, u8 status2) > > +{ > > + unsigned int ev_dir = IIO_EV_DIR_NONE; > > + > > + if (ADXL372_STATUS_2_ACT(status2)) > > + ev_dir = IIO_EV_DIR_RISING; > > + > > + if (ADXL372_STATUS_2_INACT(status2)) > > + ev_dir = IIO_EV_DIR_FALLING; > > + > > + if (ev_dir != IIO_EV_DIR_NONE) > > + iio_push_event(indio_dev, > > + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, > > + IIO_EV_TYPE_THRESH, ev_dir), > > + timestamp); > > +} > > + > > static irqreturn_t adxl372_trigger_handler(int irq, void *p) > > { > > struct iio_poll_func *pf = p; > > @@ -535,6 +642,8 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) > > if (ret < 0) > > goto err; > > > > + adxl372_push_event(indio_dev, iio_get_time_ns(indio_dev), status2); > > + > > if (st->fifo_mode != ADXL372_FIFO_BYPASSED && > > ADXL372_STATUS_1_FIFO_FULL(status1)) { > > /* > > @@ -553,8 +662,12 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) > > goto err; > > > > /* Each sample is 2 bytes */ > > - for (i = 0; i < fifo_entries; i += st->fifo_set_size) > > + for (i = 0; i < fifo_entries; i += st->fifo_set_size) { > > + /* filter peak detection data */ > > + if (st->peak_fifo_mode_en) > > + adxl372_arrange_axis_data(st, &st->fifo_buf[i]); > > iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); > > + } > > } > > err: > > iio_trigger_notify_done(indio_dev->trig); > > @@ -722,6 +835,129 @@ static int adxl372_write_raw(struct iio_dev *indio_dev, > > } > > } > > > > +static int adxl372_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > + enum iio_event_type type, enum iio_event_direction dir, > > + enum iio_event_info info, int *val, int *val2) > > +{ > > + struct adxl372_state *st = iio_priv(indio_dev); > > + unsigned int addr; > > + u16 raw_value; > > + int ret; > > + > > + switch (info) { > > + case IIO_EV_INFO_VALUE: > > + switch (dir) { > > + case IIO_EV_DIR_RISING: > > + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; > > + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); > > + if (ret < 0) > > + return ret; > > + *val = raw_value * ADXL372_USCALE; > > + *val2 = 1000000; > > + return IIO_VAL_FRACTIONAL; > > + case IIO_EV_DIR_FALLING: > > + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; > > + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); > > + if (ret < 0) > > + return ret; > > + *val = raw_value * ADXL372_USCALE; > > + *val2 = 1000000; > > + return IIO_VAL_FRACTIONAL; > > + default: > > + return -EINVAL; > > + } > > + case IIO_EV_INFO_PERIOD: > > + switch (dir) { > > + case IIO_EV_DIR_RISING: > > + *val = st->act_time_ms; > > + *val2 = 1000; > > + return IIO_VAL_FRACTIONAL; > > + case IIO_EV_DIR_FALLING: > > + *val = st->inact_time_ms; > > + *val2 = 1000; > > + return IIO_VAL_FRACTIONAL; > > + default: > > + return -EINVAL; > > + } > > + default: > > + return -EINVAL; > > + } > > +} > > + > > +static int adxl372_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > + enum iio_event_type type, enum iio_event_direction dir, > > + enum iio_event_info info, int val, int val2) > > +{ > > + struct adxl372_state *st = iio_priv(indio_dev); > > + unsigned int val_ms; > > + unsigned int addr; > > + u16 raw_val; > > + > > + switch (info) { > > + case IIO_EV_INFO_VALUE: > > + raw_val = DIV_ROUND_UP(val * 1000000, ADXL372_USCALE); > > + switch (dir) { > > + case IIO_EV_DIR_RISING: > > + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; > > + return adxl372_write_threshold_value(indio_dev, addr, raw_val); > > + case IIO_EV_DIR_FALLING: > > + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; > > + return adxl372_write_threshold_value(indio_dev, addr, raw_val); > > + default: > > + return -EINVAL; > > + } > > + case IIO_EV_INFO_PERIOD: > > + val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000); > > + switch (dir) { > > + case IIO_EV_DIR_RISING: > > + return adxl372_set_activity_time_ms(st, val_ms); > > + case IIO_EV_DIR_FALLING: > > + return adxl372_set_inactivity_time_ms(st, val_ms); > > + default: > > + return -EINVAL; > > + } > > + default: > > + return -EINVAL; > > + } > > +} > > + > > +static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > + enum iio_event_type type, enum iio_event_direction dir) > > +{ > > + struct adxl372_state *st = iio_priv(indio_dev); > > + > > + switch (dir) { > > + case IIO_EV_DIR_RISING: > > + return FIELD_GET(ADXL372_INT1_MAP_ACT_MSK, st->int1_bitmask); > > + case IIO_EV_DIR_FALLING: > > + return FIELD_GET(ADXL372_INT1_MAP_INACT_MSK, st->int1_bitmask); > > + default: > > + return -EINVAL; > > + } > > +} > > + > > +static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > + enum iio_event_type type, enum iio_event_direction dir, > > + int state) > > +{ > > + struct adxl372_state *st = iio_priv(indio_dev); > > + > > + switch (dir) { > > + case IIO_EV_DIR_RISING: > > + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK, > > + ADXL372_INT1_MAP_ACT_MODE(state)); > > + break; > > + case IIO_EV_DIR_FALLING: > > + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK, > > + ADXL372_INT1_MAP_INACT_MODE(state)); > > + break; > > + default: > > + return -EINVAL; > > + } > > + > > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > > +} > > + > > static ssize_t adxl372_show_filter_freq_avail(struct device *dev, > > struct device_attribute *attr, > > char *buf) > > @@ -798,7 +1034,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > > if (ret < 0) > > return ret; > > > > - ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0); > > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > + ret = adxl372_set_interrupts(st, st->int1_bitmask, 0); > > if (ret < 0) > > goto err; > > > > @@ -815,13 +1052,22 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > > } > > > > st->fifo_format = adxl372_axis_lookup_table[i].fifo_format; > > + st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits; > > st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, > > indio_dev->masklength); > > + > > + /* Configure the FIFO to store sets of impact event peak. */ > > + if (st->peak_fifo_mode_en) { > > + st->fifo_set_size = 3; > > + st->fifo_format = ADXL372_XYZ_PEAK_FIFO; > > + } > > + > > /* > > * The 512 FIFO samples can be allotted in several ways, such as: > > * 170 sample sets of concurrent 3-axis data > > * 256 sample sets of concurrent 2-axis data (user selectable) > > * 512 sample sets of single-axis data > > + * 170 sets of impact event peak (x, y, z) > > */ > > if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE) > > st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size); > > @@ -831,7 +1077,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > > ret = adxl372_configure_fifo(st); > > if (ret < 0) { > > st->fifo_mode = ADXL372_FIFO_BYPASSED; > > - adxl372_set_interrupts(st, 0, 0); > > + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; > > + adxl372_set_interrupts(st, st->int1_bitmask, 0); > > goto err; > > } > > > > @@ -846,7 +1093,8 @@ static int adxl372_buffer_predisable(struct iio_dev *indio_dev) > > { > > struct adxl372_state *st = iio_priv(indio_dev); > > > > - adxl372_set_interrupts(st, 0, 0); > > + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; > > + adxl372_set_interrupts(st, st->int1_bitmask, 0); > > st->fifo_mode = ADXL372_FIFO_BYPASSED; > > adxl372_configure_fifo(st); > > > > @@ -863,12 +1111,11 @@ static int adxl372_dready_trig_set_state(struct iio_trigger *trig, > > { > > struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > > struct adxl372_state *st = iio_priv(indio_dev); > > - unsigned long int mask = 0; > > > > if (state) > > - mask = ADXL372_INT1_MAP_FIFO_FULL_MSK; > > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > > - return adxl372_set_interrupts(st, mask, 0); > > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > > } > > > > static int adxl372_validate_trigger(struct iio_dev *indio_dev, > > @@ -876,7 +1123,7 @@ static int adxl372_validate_trigger(struct iio_dev *indio_dev, > > { > > struct adxl372_state *st = iio_priv(indio_dev); > > > > - if (st->dready_trig != trig) > > + if (st->dready_trig != trig && st->peak_datardy_trig != trig) > > return -EINVAL; > > > > return 0; > > @@ -887,6 +1134,25 @@ static const struct iio_trigger_ops adxl372_trigger_ops = { > > .set_trigger_state = adxl372_dready_trig_set_state, > > }; > > > > +static int adxl372_peak_dready_trig_set_state(struct iio_trigger *trig, > > + bool state) > > +{ > > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > > + struct adxl372_state *st = iio_priv(indio_dev); > > + > > + if (state) > > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > + > > + st->peak_fifo_mode_en = state; > > + > > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > > +} > > + > > +static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = { > > + .validate_device = &iio_trigger_validate_own_device, > > + .set_trigger_state = adxl372_peak_dready_trig_set_state, > > +}; > > + > > static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400"); > > static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, > > 0444, adxl372_show_filter_freq_avail, NULL, 0); > > @@ -906,6 +1172,10 @@ static const struct iio_info adxl372_info = { > > .attrs = &adxl372_attrs_group, > > .read_raw = adxl372_read_raw, > > .write_raw = adxl372_write_raw, > > + .read_event_config = adxl372_read_event_config, > > + .write_event_config = adxl372_write_event_config, > > + .read_event_value = adxl372_read_event_value, > > + .write_event_value = adxl372_write_event_value, > > .debugfs_reg_access = &adxl372_reg_access, > > .hwfifo_set_watermark = adxl372_set_watermark, > > }; > > @@ -934,6 +1204,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, > > st->regmap = regmap; > > st->irq = irq; > > > > + mutex_init(&st->threshold_m); > > + > > indio_dev->channels = adxl372_channels; > > indio_dev->num_channels = ARRAY_SIZE(adxl372_channels); > > indio_dev->available_scan_masks = adxl372_channel_masks; > > @@ -965,13 +1237,27 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, > > if (st->dready_trig == NULL) > > return -ENOMEM; > > > > + st->peak_datardy_trig = devm_iio_trigger_alloc(dev, > > + "%s-dev%d-peak", > > + indio_dev->name, > > + indio_dev->id); > > + if (!st->peak_datardy_trig) > > + return -ENOMEM; > > + > > st->dready_trig->ops = &adxl372_trigger_ops; > > + st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; > > st->dready_trig->dev.parent = dev; > > + st->peak_datardy_trig->dev.parent = dev; > > iio_trigger_set_drvdata(st->dready_trig, indio_dev); > > + iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); > > ret = devm_iio_trigger_register(dev, st->dready_trig); > > if (ret < 0) > > return ret; > > > > + ret = devm_iio_trigger_register(dev, st->peak_datardy_trig); > > + if (ret < 0) > > + return ret; > > + > > indio_dev->trig = iio_trigger_get(st->dready_trig); > > > > ret = devm_request_threaded_irq(dev, st->irq, >
On Tue, 1 Sep 2020 19:40:03 +0100 Jonathan Cameron <jic23@kernel.org> wrote: > On Sat, 29 Aug 2020 18:43:50 +0100 > Jonathan Cameron <jic23@kernel.org> wrote: > > > On Mon, 10 Aug 2020 12:32:56 +0300 > > <alexandru.tachici@analog.com> wrote: > > > > > From: Stefan Popa <stefan.popa@analog.com> > > > > > > By default, if all three channels (x, y, z) are enabled, sample sets of > > > concurrent 3-axis data is stored in the FIFO. This patch adds the option > > > to configure the FIFO to store peak acceleration (x, y and z) of every > > > over-threshold event. When pushing to iio buffer we push only enabled > > > axis data. > > > > > > Currently the driver configures adxl372 to work in loop mode. > > > The inactivity and activity timings decide how fast the chip > > > will loop through the awake and waiting states and the > > > thresholds on x,y,z axis decide when activity or inactivity > > > will be detected. > > > > > > This patch adds standard events sysfs entries for the inactivity > > > and activity timings: thresh_falling_period/thresh_rising_period > > > and for the in_accel_x_thresh_falling/rising_value. > > > > > > Signed-off-by: Stefan Popa <stefan.popa@analog.com> > > > Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com> > > > > Hi Alexandru, > > > > This didn't go in remotely cleanly because of fuzz from moving the > > pollfunc attach / detach into the core which seems to have crossed with it. > > > > I think I have it correct, but please check and let me know if there > > are any problems. > > > > Pushed out as testing for the autobuilders to poke at it as well. > > > > thanks, > > > > Jonathan Round we go again, this time with a rather undocumented (at least I can't find any docs) with set_mask_bits. That only works with unsigned long types. It blows up on riscv builds as this 0-day report states. I think we are fine just making the two variables unsigned long and have done so, please check and get back to me if this is a problem. Pushed out as testing for the autobuilders to try it yet again and see what new issue they turn up. This one had me scratching my head for some time. > Subject: [iio:testing 75/96] include/linux/compiler_types.h:319:38: error: call to '__compiletime_assert_229' declared with attribute error: BUILD_BUG failed > > > tree: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git testing > head: 4b2f9499f323905a09734380d4b80800df1a5a50 > commit: da7a2605058e13d1e5a1bdacab6d89897086ab65 [75/96] iio: accel: adxl372: Add support for FIFO peak mode > config: riscv-randconfig-r011-20200901 (attached as .config) > compiler: riscv32-linux-gcc (GCC) 9.3.0 > reproduce (this is a W=1 build): > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > chmod +x ~/bin/make.cross > git checkout da7a2605058e13d1e5a1bdacab6d89897086ab65 > # save the attached .config to linux build tree > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=riscv > > If you fix the issue, kindly add following tag as appropriate > Reported-by: kernel test robot <lkp@intel.com> > > All errors (new ones prefixed by >>): > > In file included from <command-line>: > drivers/iio/accel/adxl372.c: In function 'adxl372_write_event_config': > >> include/linux/compiler_types.h:319:38: error: call to '__compiletime_assert_229' declared with attribute error: BUILD_BUG failed > 319 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) > | ^ > include/linux/compiler_types.h:300:4: note: in definition of macro '__compiletime_assert' > 300 | prefix ## suffix(); \ > | ^~~~~~ > include/linux/compiler_types.h:319:2: note: in expansion of macro '_compiletime_assert' > 319 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) > | ^~~~~~~~~~~~~~~~~~~ > include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert' > 39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) > | ^~~~~~~~~~~~~~~~~~ > include/linux/build_bug.h:59:21: note: in expansion of macro 'BUILD_BUG_ON_MSG' > 59 | #define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed") > | ^~~~~~~~~~~~~~~~ > arch/riscv/include/asm/cmpxchg.h:335:3: note: in expansion of macro 'BUILD_BUG' > 335 | BUILD_BUG(); \ > | ^~~~~~~~~ > arch/riscv/include/asm/cmpxchg.h:344:23: note: in expansion of macro '__cmpxchg' > 344 | (__typeof__(*(ptr))) __cmpxchg((ptr), \ > | ^~~~~~~~~ > include/linux/bitops.h:269:11: note: in expansion of macro 'cmpxchg' > 269 | } while (cmpxchg(ptr, old__, new__) != old__); \ > | ^~~~~~~ > drivers/iio/accel/adxl372.c:949:3: note: in expansion of macro 'set_mask_bits' > 949 | set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK, > | ^~~~~~~~~~~~~ > include/linux/compiler_types.h:319:38: error: call to '__compiletime_assert_231' declared with attribute error: BUILD_BUG failed > 319 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) > | ^ > include/linux/compiler_types.h:300:4: note: in definition of macro '__compiletime_assert' > 300 | prefix ## suffix(); \ > | ^~~~~~ > include/linux/compiler_types.h:319:2: note: in expansion of macro '_compiletime_assert' > 319 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) > | ^~~~~~~~~~~~~~~~~~~ > include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert' > 39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) > | ^~~~~~~~~~~~~~~~~~ > include/linux/build_bug.h:59:21: note: in expansion of macro 'BUILD_BUG_ON_MSG' > 59 | #define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed") > | ^~~~~~~~~~~~~~~~ > arch/riscv/include/asm/cmpxchg.h:335:3: note: in expansion of macro 'BUILD_BUG' > 335 | BUILD_BUG(); \ > | ^~~~~~~~~ > arch/riscv/include/asm/cmpxchg.h:344:23: note: in expansion of macro '__cmpxchg' > 344 | (__typeof__(*(ptr))) __cmpxchg((ptr), \ > | ^~~~~~~~~ > include/linux/bitops.h:269:11: note: in expansion of macro 'cmpxchg' > 269 | } while (cmpxchg(ptr, old__, new__) != old__); \ > | ^~~~~~~ > drivers/iio/accel/adxl372.c:953:3: note: in expansion of macro 'set_mask_bits' > 953 | set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK, > | ^~~~~~~~~~~~~ > > # https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/commit/?id=da7a2605058e13d1e5a1bdacab6d89897086ab65 > git remote add iio https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git > git fetch --no-tags iio testing > git checkout da7a2605058e13d1e5a1bdacab6d89897086ab65 > vim +/__compiletime_assert_229 +319 include/linux/compiler_types.h > > eb5c2d4b45e3d2d Will Deacon 2020-07-21 305 > eb5c2d4b45e3d2d Will Deacon 2020-07-21 306 #define _compiletime_assert(condition, msg, prefix, suffix) \ > eb5c2d4b45e3d2d Will Deacon 2020-07-21 307 __compiletime_assert(condition, msg, prefix, suffix) > eb5c2d4b45e3d2d Will Deacon 2020-07-21 308 > eb5c2d4b45e3d2d Will Deacon 2020-07-21 309 /** > eb5c2d4b45e3d2d Will Deacon 2020-07-21 310 * compiletime_assert - break build and emit msg if condition is false > eb5c2d4b45e3d2d Will Deacon 2020-07-21 311 * @condition: a compile-time constant condition to check > eb5c2d4b45e3d2d Will Deacon 2020-07-21 312 * @msg: a message to emit if condition is false > eb5c2d4b45e3d2d Will Deacon 2020-07-21 313 * > eb5c2d4b45e3d2d Will Deacon 2020-07-21 314 * In tradition of POSIX assert, this macro will break the build if the > eb5c2d4b45e3d2d Will Deacon 2020-07-21 315 * supplied condition is *false*, emitting the supplied error message if the > eb5c2d4b45e3d2d Will Deacon 2020-07-21 316 * compiler has support to do so. > eb5c2d4b45e3d2d Will Deacon 2020-07-21 317 */ > eb5c2d4b45e3d2d Will Deacon 2020-07-21 318 #define compiletime_assert(condition, msg) \ > eb5c2d4b45e3d2d Will Deacon 2020-07-21 @319 _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) > eb5c2d4b45e3d2d Will Deacon 2020-07-21 320 > > :::::: The code at line 319 was first introduced by commit > :::::: eb5c2d4b45e3d2d5d052ea6b8f1463976b1020d5 compiler.h: Move compiletime_assert() macros into compiler_types.h > > :::::: TO: Will Deacon <will@kernel.org> > :::::: CC: Will Deacon <will@kernel.org> > > --- > 0-DAY CI Kernel Test Service, Intel Corporation > https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org > > > > > --- > > > drivers/iio/accel/adxl372.c | 302 +++++++++++++++++++++++++++++++++++- > > > 1 file changed, 294 insertions(+), 8 deletions(-) > > > > > > diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c > > > index 67b8817995c0..4cad16e2f7b7 100644 > > > --- a/drivers/iio/accel/adxl372.c > > > +++ b/drivers/iio/accel/adxl372.c > > > @@ -5,6 +5,7 @@ > > > * Copyright 2018 Analog Devices Inc. > > > */ > > > > > > +#include <linux/bitfield.h> > > > #include <linux/bitops.h> > > > #include <linux/interrupt.h> > > > #include <linux/irq.h> > > > @@ -113,6 +114,11 @@ > > > #define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1) > > > #define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1) > > > > > > +/* ADXL372_STATUS_2 */ > > > +#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1) > > > +#define ADXL372_STATUS_2_ACT(x) (((x) >> 5) & 0x1) > > > +#define ADXL372_STATUS_2_AC2(x) (((x) >> 6) & 0x1) > > > + > > > /* ADXL372_INT1_MAP */ > > > #define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0) > > > #define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0) > > > @@ -131,8 +137,17 @@ > > > #define ADXL372_INT1_MAP_LOW_MSK BIT(7) > > > #define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7) > > > > > > +/* ADX372_THRESH */ > > > +#define ADXL372_THRESH_VAL_H_MSK GENMASK(10, 3) > > > +#define ADXL372_THRESH_VAL_H_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_H_MSK, x) > > > +#define ADXL372_THRESH_VAL_L_MSK GENMASK(2, 0) > > > +#define ADXL372_THRESH_VAL_L_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_L_MSK, x) > > > + > > > /* The ADXL372 includes a deep, 512 sample FIFO buffer */ > > > #define ADXL372_FIFO_SIZE 512 > > > +#define ADXL372_X_AXIS_EN(x) ((x) & BIT(0)) > > > +#define ADXL372_Y_AXIS_EN(x) ((x) & BIT(1)) > > > +#define ADXL372_Z_AXIS_EN(x) ((x) & BIT(2)) > > > > > > /* > > > * At +/- 200g with 12-bit resolution, scale is computed as: > > > @@ -222,6 +237,20 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { > > > { BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO }, > > > }; > > > > > > +static const struct iio_event_spec adxl372_events[] = { > > > + { > > > + .type = IIO_EV_TYPE_THRESH, > > > + .dir = IIO_EV_DIR_RISING, > > > + .mask_separate = BIT(IIO_EV_INFO_VALUE), > > > + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), > > > + }, { > > > + .type = IIO_EV_TYPE_THRESH, > > > + .dir = IIO_EV_DIR_FALLING, > > > + .mask_separate = BIT(IIO_EV_INFO_VALUE), > > > + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), > > > + }, > > > +}; > > > + > > > #define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \ > > > .type = IIO_ACCEL, \ > > > .address = reg, \ > > > @@ -238,6 +267,8 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { > > > .storagebits = 16, \ > > > .shift = 4, \ > > > }, \ > > > + .event_spec = adxl372_events, \ > > > + .num_event_specs = ARRAY_SIZE(adxl372_events) \ > > > } > > > > > > static const struct iio_chan_spec adxl372_channels[] = { > > > @@ -251,8 +282,10 @@ struct adxl372_state { > > > struct device *dev; > > > struct regmap *regmap; > > > struct iio_trigger *dready_trig; > > > + struct iio_trigger *peak_datardy_trig; > > > enum adxl372_fifo_mode fifo_mode; > > > enum adxl372_fifo_format fifo_format; > > > + unsigned int fifo_axis_mask; > > > enum adxl372_op_mode op_mode; > > > enum adxl372_act_proc_mode act_proc_mode; > > > enum adxl372_odr odr; > > > @@ -264,6 +297,8 @@ struct adxl372_state { > > > u8 int2_bitmask; > > > u16 watermark; > > > __be16 fifo_buf[ADXL372_FIFO_SIZE]; > > > + bool peak_fifo_mode_en; > > > + struct mutex threshold_m; /* lock for threshold */ > > > }; > > > > > > static const unsigned long adxl372_channel_masks[] = { > > > @@ -275,6 +310,45 @@ static const unsigned long adxl372_channel_masks[] = { > > > 0 > > > }; > > > > > > +static ssize_t adxl372_read_threshold_value(struct iio_dev *indio_dev, unsigned int addr, > > > + u16 *threshold) > > > +{ > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + __be16 raw_regval; > > > + u16 regval; > > > + int ret; > > > + > > > + ret = regmap_bulk_read(st->regmap, addr, &raw_regval, sizeof(raw_regval)); > > > + if (ret < 0) > > > + return ret; > > > + > > > + regval = be16_to_cpu(raw_regval); > > > + regval >>= 5; > > > + > > > + *threshold = regval; > > > + > > > + return 0; > > > +} > > > + > > > +static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned int addr, > > > + u16 threshold) > > > +{ > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + int ret; > > > + > > > + mutex_lock(&st->threshold_m); > > > + ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold)); > > > + if (ret < 0) > 0-day pointed this out. You are missing a lock here. I've fixed by using > goto unlock; > > > + return ret; > > > + > > > + ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5), > > > + ADXL372_THRESH_VAL_L_SEL(threshold) << 5); > > > + > unlock: > > > > + mutex_unlock(&st->threshold_m); > > > + > > > + return ret; > > > +} > > > + > > > static int adxl372_read_axis(struct adxl372_state *st, u8 addr) > > > { > > > __be16 regval; > > > @@ -522,6 +596,39 @@ static int adxl372_get_status(struct adxl372_state *st, > > > return ret; > > > } > > > > > > +static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample) > > > +{ > > > + __be16 axis_sample[3]; > > > + int i = 0; > > > + > > > + memset(axis_sample, 0, 3 * sizeof(__be16)); > > > + if (ADXL372_X_AXIS_EN(st->fifo_axis_mask)) > > > + axis_sample[i++] = sample[0]; > > > + if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask)) > > > + axis_sample[i++] = sample[1]; > > > + if (ADXL372_Z_AXIS_EN(st->fifo_axis_mask)) > > > + axis_sample[i++] = sample[2]; > > > + > > > + memcpy(sample, axis_sample, 3 * sizeof(__be16)); > > > +} > > > + > > > +static void adxl372_push_event(struct iio_dev *indio_dev, s64 timestamp, u8 status2) > > > +{ > > > + unsigned int ev_dir = IIO_EV_DIR_NONE; > > > + > > > + if (ADXL372_STATUS_2_ACT(status2)) > > > + ev_dir = IIO_EV_DIR_RISING; > > > + > > > + if (ADXL372_STATUS_2_INACT(status2)) > > > + ev_dir = IIO_EV_DIR_FALLING; > > > + > > > + if (ev_dir != IIO_EV_DIR_NONE) > > > + iio_push_event(indio_dev, > > > + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, > > > + IIO_EV_TYPE_THRESH, ev_dir), > > > + timestamp); > > > +} > > > + > > > static irqreturn_t adxl372_trigger_handler(int irq, void *p) > > > { > > > struct iio_poll_func *pf = p; > > > @@ -535,6 +642,8 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) > > > if (ret < 0) > > > goto err; > > > > > > + adxl372_push_event(indio_dev, iio_get_time_ns(indio_dev), status2); > > > + > > > if (st->fifo_mode != ADXL372_FIFO_BYPASSED && > > > ADXL372_STATUS_1_FIFO_FULL(status1)) { > > > /* > > > @@ -553,8 +662,12 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) > > > goto err; > > > > > > /* Each sample is 2 bytes */ > > > - for (i = 0; i < fifo_entries; i += st->fifo_set_size) > > > + for (i = 0; i < fifo_entries; i += st->fifo_set_size) { > > > + /* filter peak detection data */ > > > + if (st->peak_fifo_mode_en) > > > + adxl372_arrange_axis_data(st, &st->fifo_buf[i]); > > > iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); > > > + } > > > } > > > err: > > > iio_trigger_notify_done(indio_dev->trig); > > > @@ -722,6 +835,129 @@ static int adxl372_write_raw(struct iio_dev *indio_dev, > > > } > > > } > > > > > > +static int adxl372_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > > + enum iio_event_type type, enum iio_event_direction dir, > > > + enum iio_event_info info, int *val, int *val2) > > > +{ > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + unsigned int addr; > > > + u16 raw_value; > > > + int ret; > > > + > > > + switch (info) { > > > + case IIO_EV_INFO_VALUE: > > > + switch (dir) { > > > + case IIO_EV_DIR_RISING: > > > + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; > > > + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); > > > + if (ret < 0) > > > + return ret; > > > + *val = raw_value * ADXL372_USCALE; > > > + *val2 = 1000000; > > > + return IIO_VAL_FRACTIONAL; > > > + case IIO_EV_DIR_FALLING: > > > + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; > > > + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); > > > + if (ret < 0) > > > + return ret; > > > + *val = raw_value * ADXL372_USCALE; > > > + *val2 = 1000000; > > > + return IIO_VAL_FRACTIONAL; > > > + default: > > > + return -EINVAL; > > > + } > > > + case IIO_EV_INFO_PERIOD: > > > + switch (dir) { > > > + case IIO_EV_DIR_RISING: > > > + *val = st->act_time_ms; > > > + *val2 = 1000; > > > + return IIO_VAL_FRACTIONAL; > > > + case IIO_EV_DIR_FALLING: > > > + *val = st->inact_time_ms; > > > + *val2 = 1000; > > > + return IIO_VAL_FRACTIONAL; > > > + default: > > > + return -EINVAL; > > > + } > > > + default: > > > + return -EINVAL; > > > + } > > > +} > > > + > > > +static int adxl372_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > > + enum iio_event_type type, enum iio_event_direction dir, > > > + enum iio_event_info info, int val, int val2) > > > +{ > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + unsigned int val_ms; > > > + unsigned int addr; > > > + u16 raw_val; > > > + > > > + switch (info) { > > > + case IIO_EV_INFO_VALUE: > > > + raw_val = DIV_ROUND_UP(val * 1000000, ADXL372_USCALE); > > > + switch (dir) { > > > + case IIO_EV_DIR_RISING: > > > + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; > > > + return adxl372_write_threshold_value(indio_dev, addr, raw_val); > > > + case IIO_EV_DIR_FALLING: > > > + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; > > > + return adxl372_write_threshold_value(indio_dev, addr, raw_val); > > > + default: > > > + return -EINVAL; > > > + } > > > + case IIO_EV_INFO_PERIOD: > > > + val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000); > > > + switch (dir) { > > > + case IIO_EV_DIR_RISING: > > > + return adxl372_set_activity_time_ms(st, val_ms); > > > + case IIO_EV_DIR_FALLING: > > > + return adxl372_set_inactivity_time_ms(st, val_ms); > > > + default: > > > + return -EINVAL; > > > + } > > > + default: > > > + return -EINVAL; > > > + } > > > +} > > > + > > > +static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > > + enum iio_event_type type, enum iio_event_direction dir) > > > +{ > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + > > > + switch (dir) { > > > + case IIO_EV_DIR_RISING: > > > + return FIELD_GET(ADXL372_INT1_MAP_ACT_MSK, st->int1_bitmask); > > > + case IIO_EV_DIR_FALLING: > > > + return FIELD_GET(ADXL372_INT1_MAP_INACT_MSK, st->int1_bitmask); > > > + default: > > > + return -EINVAL; > > > + } > > > +} > > > + > > > +static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, > > > + enum iio_event_type type, enum iio_event_direction dir, > > > + int state) > > > +{ > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + > > > + switch (dir) { > > > + case IIO_EV_DIR_RISING: > > > + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK, > > > + ADXL372_INT1_MAP_ACT_MODE(state)); > > > + break; > > > + case IIO_EV_DIR_FALLING: > > > + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK, > > > + ADXL372_INT1_MAP_INACT_MODE(state)); > > > + break; > > > + default: > > > + return -EINVAL; > > > + } > > > + > > > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > > > +} > > > + > > > static ssize_t adxl372_show_filter_freq_avail(struct device *dev, > > > struct device_attribute *attr, > > > char *buf) > > > @@ -798,7 +1034,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > > > if (ret < 0) > > > return ret; > > > > > > - ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0); > > > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > + ret = adxl372_set_interrupts(st, st->int1_bitmask, 0); > > > if (ret < 0) > > > goto err; > > > > > > @@ -815,13 +1052,22 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > > > } > > > > > > st->fifo_format = adxl372_axis_lookup_table[i].fifo_format; > > > + st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits; > > > st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, > > > indio_dev->masklength); > > > + > > > + /* Configure the FIFO to store sets of impact event peak. */ > > > + if (st->peak_fifo_mode_en) { > > > + st->fifo_set_size = 3; > > > + st->fifo_format = ADXL372_XYZ_PEAK_FIFO; > > > + } > > > + > > > /* > > > * The 512 FIFO samples can be allotted in several ways, such as: > > > * 170 sample sets of concurrent 3-axis data > > > * 256 sample sets of concurrent 2-axis data (user selectable) > > > * 512 sample sets of single-axis data > > > + * 170 sets of impact event peak (x, y, z) > > > */ > > > if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE) > > > st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size); > > > @@ -831,7 +1077,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) > > > ret = adxl372_configure_fifo(st); > > > if (ret < 0) { > > > st->fifo_mode = ADXL372_FIFO_BYPASSED; > > > - adxl372_set_interrupts(st, 0, 0); > > > + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > + adxl372_set_interrupts(st, st->int1_bitmask, 0); > > > goto err; > > > } > > > > > > @@ -846,7 +1093,8 @@ static int adxl372_buffer_predisable(struct iio_dev *indio_dev) > > > { > > > struct adxl372_state *st = iio_priv(indio_dev); > > > > > > - adxl372_set_interrupts(st, 0, 0); > > > + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > + adxl372_set_interrupts(st, st->int1_bitmask, 0); > > > st->fifo_mode = ADXL372_FIFO_BYPASSED; > > > adxl372_configure_fifo(st); > > > > > > @@ -863,12 +1111,11 @@ static int adxl372_dready_trig_set_state(struct iio_trigger *trig, > > > { > > > struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > > > struct adxl372_state *st = iio_priv(indio_dev); > > > - unsigned long int mask = 0; > > > > > > if (state) > > > - mask = ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > > > > - return adxl372_set_interrupts(st, mask, 0); > > > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > > > } > > > > > > static int adxl372_validate_trigger(struct iio_dev *indio_dev, > > > @@ -876,7 +1123,7 @@ static int adxl372_validate_trigger(struct iio_dev *indio_dev, > > > { > > > struct adxl372_state *st = iio_priv(indio_dev); > > > > > > - if (st->dready_trig != trig) > > > + if (st->dready_trig != trig && st->peak_datardy_trig != trig) > > > return -EINVAL; > > > > > > return 0; > > > @@ -887,6 +1134,25 @@ static const struct iio_trigger_ops adxl372_trigger_ops = { > > > .set_trigger_state = adxl372_dready_trig_set_state, > > > }; > > > > > > +static int adxl372_peak_dready_trig_set_state(struct iio_trigger *trig, > > > + bool state) > > > +{ > > > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > > > + struct adxl372_state *st = iio_priv(indio_dev); > > > + > > > + if (state) > > > + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; > > > + > > > + st->peak_fifo_mode_en = state; > > > + > > > + return adxl372_set_interrupts(st, st->int1_bitmask, 0); > > > +} > > > + > > > +static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = { > > > + .validate_device = &iio_trigger_validate_own_device, > > > + .set_trigger_state = adxl372_peak_dready_trig_set_state, > > > +}; > > > + > > > static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400"); > > > static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, > > > 0444, adxl372_show_filter_freq_avail, NULL, 0); > > > @@ -906,6 +1172,10 @@ static const struct iio_info adxl372_info = { > > > .attrs = &adxl372_attrs_group, > > > .read_raw = adxl372_read_raw, > > > .write_raw = adxl372_write_raw, > > > + .read_event_config = adxl372_read_event_config, > > > + .write_event_config = adxl372_write_event_config, > > > + .read_event_value = adxl372_read_event_value, > > > + .write_event_value = adxl372_write_event_value, > > > .debugfs_reg_access = &adxl372_reg_access, > > > .hwfifo_set_watermark = adxl372_set_watermark, > > > }; > > > @@ -934,6 +1204,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, > > > st->regmap = regmap; > > > st->irq = irq; > > > > > > + mutex_init(&st->threshold_m); > > > + > > > indio_dev->channels = adxl372_channels; > > > indio_dev->num_channels = ARRAY_SIZE(adxl372_channels); > > > indio_dev->available_scan_masks = adxl372_channel_masks; > > > @@ -965,13 +1237,27 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, > > > if (st->dready_trig == NULL) > > > return -ENOMEM; > > > > > > + st->peak_datardy_trig = devm_iio_trigger_alloc(dev, > > > + "%s-dev%d-peak", > > > + indio_dev->name, > > > + indio_dev->id); > > > + if (!st->peak_datardy_trig) > > > + return -ENOMEM; > > > + > > > st->dready_trig->ops = &adxl372_trigger_ops; > > > + st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; > > > st->dready_trig->dev.parent = dev; > > > + st->peak_datardy_trig->dev.parent = dev; > > > iio_trigger_set_drvdata(st->dready_trig, indio_dev); > > > + iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); > > > ret = devm_iio_trigger_register(dev, st->dready_trig); > > > if (ret < 0) > > > return ret; > > > > > > + ret = devm_iio_trigger_register(dev, st->peak_datardy_trig); > > > + if (ret < 0) > > > + return ret; > > > + > > > indio_dev->trig = iio_trigger_get(st->dready_trig); > > > > > > ret = devm_request_threaded_irq(dev, st->irq, > > >
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 67b8817995c0..4cad16e2f7b7 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -5,6 +5,7 @@ * Copyright 2018 Analog Devices Inc. */ +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -113,6 +114,11 @@ #define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1) #define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1) +/* ADXL372_STATUS_2 */ +#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1) +#define ADXL372_STATUS_2_ACT(x) (((x) >> 5) & 0x1) +#define ADXL372_STATUS_2_AC2(x) (((x) >> 6) & 0x1) + /* ADXL372_INT1_MAP */ #define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0) #define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0) @@ -131,8 +137,17 @@ #define ADXL372_INT1_MAP_LOW_MSK BIT(7) #define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7) +/* ADX372_THRESH */ +#define ADXL372_THRESH_VAL_H_MSK GENMASK(10, 3) +#define ADXL372_THRESH_VAL_H_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_H_MSK, x) +#define ADXL372_THRESH_VAL_L_MSK GENMASK(2, 0) +#define ADXL372_THRESH_VAL_L_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_L_MSK, x) + /* The ADXL372 includes a deep, 512 sample FIFO buffer */ #define ADXL372_FIFO_SIZE 512 +#define ADXL372_X_AXIS_EN(x) ((x) & BIT(0)) +#define ADXL372_Y_AXIS_EN(x) ((x) & BIT(1)) +#define ADXL372_Z_AXIS_EN(x) ((x) & BIT(2)) /* * At +/- 200g with 12-bit resolution, scale is computed as: @@ -222,6 +237,20 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { { BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO }, }; +static const struct iio_event_spec adxl372_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE), + }, +}; + #define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .address = reg, \ @@ -238,6 +267,8 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = { .storagebits = 16, \ .shift = 4, \ }, \ + .event_spec = adxl372_events, \ + .num_event_specs = ARRAY_SIZE(adxl372_events) \ } static const struct iio_chan_spec adxl372_channels[] = { @@ -251,8 +282,10 @@ struct adxl372_state { struct device *dev; struct regmap *regmap; struct iio_trigger *dready_trig; + struct iio_trigger *peak_datardy_trig; enum adxl372_fifo_mode fifo_mode; enum adxl372_fifo_format fifo_format; + unsigned int fifo_axis_mask; enum adxl372_op_mode op_mode; enum adxl372_act_proc_mode act_proc_mode; enum adxl372_odr odr; @@ -264,6 +297,8 @@ struct adxl372_state { u8 int2_bitmask; u16 watermark; __be16 fifo_buf[ADXL372_FIFO_SIZE]; + bool peak_fifo_mode_en; + struct mutex threshold_m; /* lock for threshold */ }; static const unsigned long adxl372_channel_masks[] = { @@ -275,6 +310,45 @@ static const unsigned long adxl372_channel_masks[] = { 0 }; +static ssize_t adxl372_read_threshold_value(struct iio_dev *indio_dev, unsigned int addr, + u16 *threshold) +{ + struct adxl372_state *st = iio_priv(indio_dev); + __be16 raw_regval; + u16 regval; + int ret; + + ret = regmap_bulk_read(st->regmap, addr, &raw_regval, sizeof(raw_regval)); + if (ret < 0) + return ret; + + regval = be16_to_cpu(raw_regval); + regval >>= 5; + + *threshold = regval; + + return 0; +} + +static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned int addr, + u16 threshold) +{ + struct adxl372_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->threshold_m); + ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold)); + if (ret < 0) + return ret; + + ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5), + ADXL372_THRESH_VAL_L_SEL(threshold) << 5); + + mutex_unlock(&st->threshold_m); + + return ret; +} + static int adxl372_read_axis(struct adxl372_state *st, u8 addr) { __be16 regval; @@ -522,6 +596,39 @@ static int adxl372_get_status(struct adxl372_state *st, return ret; } +static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample) +{ + __be16 axis_sample[3]; + int i = 0; + + memset(axis_sample, 0, 3 * sizeof(__be16)); + if (ADXL372_X_AXIS_EN(st->fifo_axis_mask)) + axis_sample[i++] = sample[0]; + if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask)) + axis_sample[i++] = sample[1]; + if (ADXL372_Z_AXIS_EN(st->fifo_axis_mask)) + axis_sample[i++] = sample[2]; + + memcpy(sample, axis_sample, 3 * sizeof(__be16)); +} + +static void adxl372_push_event(struct iio_dev *indio_dev, s64 timestamp, u8 status2) +{ + unsigned int ev_dir = IIO_EV_DIR_NONE; + + if (ADXL372_STATUS_2_ACT(status2)) + ev_dir = IIO_EV_DIR_RISING; + + if (ADXL372_STATUS_2_INACT(status2)) + ev_dir = IIO_EV_DIR_FALLING; + + if (ev_dir != IIO_EV_DIR_NONE) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_THRESH, ev_dir), + timestamp); +} + static irqreturn_t adxl372_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -535,6 +642,8 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) if (ret < 0) goto err; + adxl372_push_event(indio_dev, iio_get_time_ns(indio_dev), status2); + if (st->fifo_mode != ADXL372_FIFO_BYPASSED && ADXL372_STATUS_1_FIFO_FULL(status1)) { /* @@ -553,8 +662,12 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p) goto err; /* Each sample is 2 bytes */ - for (i = 0; i < fifo_entries; i += st->fifo_set_size) + for (i = 0; i < fifo_entries; i += st->fifo_set_size) { + /* filter peak detection data */ + if (st->peak_fifo_mode_en) + adxl372_arrange_axis_data(st, &st->fifo_buf[i]); iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); + } } err: iio_trigger_notify_done(indio_dev->trig); @@ -722,6 +835,129 @@ static int adxl372_write_raw(struct iio_dev *indio_dev, } } +static int adxl372_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, + enum iio_event_type type, enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) +{ + struct adxl372_state *st = iio_priv(indio_dev); + unsigned int addr; + u16 raw_value; + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); + if (ret < 0) + return ret; + *val = raw_value * ADXL372_USCALE; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; + ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value); + if (ret < 0) + return ret; + *val = raw_value * ADXL372_USCALE; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = st->act_time_ms; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + *val = st->inact_time_ms; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl372_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, + enum iio_event_type type, enum iio_event_direction dir, + enum iio_event_info info, int val, int val2) +{ + struct adxl372_state *st = iio_priv(indio_dev); + unsigned int val_ms; + unsigned int addr; + u16 raw_val; + + switch (info) { + case IIO_EV_INFO_VALUE: + raw_val = DIV_ROUND_UP(val * 1000000, ADXL372_USCALE); + switch (dir) { + case IIO_EV_DIR_RISING: + addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index; + return adxl372_write_threshold_value(indio_dev, addr, raw_val); + case IIO_EV_DIR_FALLING: + addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index; + return adxl372_write_threshold_value(indio_dev, addr, raw_val); + default: + return -EINVAL; + } + case IIO_EV_INFO_PERIOD: + val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000); + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl372_set_activity_time_ms(st, val_ms); + case IIO_EV_DIR_FALLING: + return adxl372_set_inactivity_time_ms(st, val_ms); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, + enum iio_event_type type, enum iio_event_direction dir) +{ + struct adxl372_state *st = iio_priv(indio_dev); + + switch (dir) { + case IIO_EV_DIR_RISING: + return FIELD_GET(ADXL372_INT1_MAP_ACT_MSK, st->int1_bitmask); + case IIO_EV_DIR_FALLING: + return FIELD_GET(ADXL372_INT1_MAP_INACT_MSK, st->int1_bitmask); + default: + return -EINVAL; + } +} + +static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, + enum iio_event_type type, enum iio_event_direction dir, + int state) +{ + struct adxl372_state *st = iio_priv(indio_dev); + + switch (dir) { + case IIO_EV_DIR_RISING: + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK, + ADXL372_INT1_MAP_ACT_MODE(state)); + break; + case IIO_EV_DIR_FALLING: + set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK, + ADXL372_INT1_MAP_INACT_MODE(state)); + break; + default: + return -EINVAL; + } + + return adxl372_set_interrupts(st, st->int1_bitmask, 0); +} + static ssize_t adxl372_show_filter_freq_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -798,7 +1034,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) if (ret < 0) return ret; - ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0); + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; + ret = adxl372_set_interrupts(st, st->int1_bitmask, 0); if (ret < 0) goto err; @@ -815,13 +1052,22 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) } st->fifo_format = adxl372_axis_lookup_table[i].fifo_format; + st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits; st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); + + /* Configure the FIFO to store sets of impact event peak. */ + if (st->peak_fifo_mode_en) { + st->fifo_set_size = 3; + st->fifo_format = ADXL372_XYZ_PEAK_FIFO; + } + /* * The 512 FIFO samples can be allotted in several ways, such as: * 170 sample sets of concurrent 3-axis data * 256 sample sets of concurrent 2-axis data (user selectable) * 512 sample sets of single-axis data + * 170 sets of impact event peak (x, y, z) */ if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE) st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size); @@ -831,7 +1077,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) ret = adxl372_configure_fifo(st); if (ret < 0) { st->fifo_mode = ADXL372_FIFO_BYPASSED; - adxl372_set_interrupts(st, 0, 0); + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; + adxl372_set_interrupts(st, st->int1_bitmask, 0); goto err; } @@ -846,7 +1093,8 @@ static int adxl372_buffer_predisable(struct iio_dev *indio_dev) { struct adxl372_state *st = iio_priv(indio_dev); - adxl372_set_interrupts(st, 0, 0); + st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK; + adxl372_set_interrupts(st, st->int1_bitmask, 0); st->fifo_mode = ADXL372_FIFO_BYPASSED; adxl372_configure_fifo(st); @@ -863,12 +1111,11 @@ static int adxl372_dready_trig_set_state(struct iio_trigger *trig, { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct adxl372_state *st = iio_priv(indio_dev); - unsigned long int mask = 0; if (state) - mask = ADXL372_INT1_MAP_FIFO_FULL_MSK; + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; - return adxl372_set_interrupts(st, mask, 0); + return adxl372_set_interrupts(st, st->int1_bitmask, 0); } static int adxl372_validate_trigger(struct iio_dev *indio_dev, @@ -876,7 +1123,7 @@ static int adxl372_validate_trigger(struct iio_dev *indio_dev, { struct adxl372_state *st = iio_priv(indio_dev); - if (st->dready_trig != trig) + if (st->dready_trig != trig && st->peak_datardy_trig != trig) return -EINVAL; return 0; @@ -887,6 +1134,25 @@ static const struct iio_trigger_ops adxl372_trigger_ops = { .set_trigger_state = adxl372_dready_trig_set_state, }; +static int adxl372_peak_dready_trig_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct adxl372_state *st = iio_priv(indio_dev); + + if (state) + st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK; + + st->peak_fifo_mode_en = state; + + return adxl372_set_interrupts(st, st->int1_bitmask, 0); +} + +static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = { + .validate_device = &iio_trigger_validate_own_device, + .set_trigger_state = adxl372_peak_dready_trig_set_state, +}; + static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400"); static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, 0444, adxl372_show_filter_freq_avail, NULL, 0); @@ -906,6 +1172,10 @@ static const struct iio_info adxl372_info = { .attrs = &adxl372_attrs_group, .read_raw = adxl372_read_raw, .write_raw = adxl372_write_raw, + .read_event_config = adxl372_read_event_config, + .write_event_config = adxl372_write_event_config, + .read_event_value = adxl372_read_event_value, + .write_event_value = adxl372_write_event_value, .debugfs_reg_access = &adxl372_reg_access, .hwfifo_set_watermark = adxl372_set_watermark, }; @@ -934,6 +1204,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, st->regmap = regmap; st->irq = irq; + mutex_init(&st->threshold_m); + indio_dev->channels = adxl372_channels; indio_dev->num_channels = ARRAY_SIZE(adxl372_channels); indio_dev->available_scan_masks = adxl372_channel_masks; @@ -965,13 +1237,27 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, if (st->dready_trig == NULL) return -ENOMEM; + st->peak_datardy_trig = devm_iio_trigger_alloc(dev, + "%s-dev%d-peak", + indio_dev->name, + indio_dev->id); + if (!st->peak_datardy_trig) + return -ENOMEM; + st->dready_trig->ops = &adxl372_trigger_ops; + st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; st->dready_trig->dev.parent = dev; + st->peak_datardy_trig->dev.parent = dev; iio_trigger_set_drvdata(st->dready_trig, indio_dev); + iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); ret = devm_iio_trigger_register(dev, st->dready_trig); if (ret < 0) return ret; + ret = devm_iio_trigger_register(dev, st->peak_datardy_trig); + if (ret < 0) + return ret; + indio_dev->trig = iio_trigger_get(st->dready_trig); ret = devm_request_threaded_irq(dev, st->irq,