[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250427133710.48693777@jic23-huawei>
Date: Sun, 27 Apr 2025 13:37:10 +0100
From: Jonathan Cameron <jic23@...nel.org>
To: Lothar Rubusch <l.rubusch@...il.com>
Cc: lars@...afoo.de, Michael.Hennerich@...log.com,
linux-iio@...r.kernel.org, linux-kernel@...r.kernel.org,
eraretuya@...il.com
Subject: Re: [PATCH v7 05/11] iio: accel: adxl345: add freefall feature
On Mon, 21 Apr 2025 22:06:35 +0000
Lothar Rubusch <l.rubusch@...il.com> wrote:
> Add the freefall detection of the sensor together with a threshold and
> time parameter. A freefall event is detected if the measuring signal
> falls below the threshold.
>
> Introduce a freefall threshold stored in regmap cache, and a freefall
> time, having the scaled time value stored as a member variable in the
> state instance.
>
> Signed-off-by: Lothar Rubusch <l.rubusch@...il.com>
I tweaked as follows to make change in patch 9 simpler.
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 8fcb8ade049b..1f4fc512e05f 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -123,13 +123,15 @@ enum adxl345_chans {
chan_x, chan_y, chan_z,
};
-/* free fall */
-static const struct iio_event_spec adxl345_freefall_event_spec = {
- .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) |
+static const struct iio_event_spec adxl345_all_event_spec[] = {
+ /* free fall */
+ {
+ .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_chan_spec adxl345_channels[] = {
@@ -141,8 +143,8 @@ static const struct iio_chan_spec adxl345_channels[] = {
.modified = 1,
.channel2 = IIO_MOD_X_AND_Y_AND_Z,
.scan_index = -1, /* Fake channel */
- .event_spec = &adxl345_freefall_event_spec,
- .num_event_specs = 1,
+ .event_spec = adxl345_all_event_spec,
+ .num_event_specs = ARRAY_SIZE(adxl345_all_event_spec),
},
};
> ---
> drivers/iio/accel/adxl345_core.c | 134 +++++++++++++++++++++++++++++++
> 1 file changed, 134 insertions(+)
>
> diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
> index c464c87033fb..f42c861100cd 100644
> --- a/drivers/iio/accel/adxl345_core.c
> +++ b/drivers/iio/accel/adxl345_core.c
> @@ -75,6 +75,7 @@ struct adxl345_state {
> u32 tap_duration_us;
> u32 tap_latent_us;
> u32 tap_window_us;
> + u32 ff_time_ms;
>
> __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN);
> };
> @@ -122,10 +123,27 @@ enum adxl345_chans {
> chan_x, chan_y, chan_z,
> };
>
> +/* free fall */
> +static const struct iio_event_spec adxl345_freefall_event_spec = {
> + .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_chan_spec adxl345_channels[] = {
> ADXL345_CHANNEL(0, chan_x, X),
> ADXL345_CHANNEL(1, chan_y, Y),
> ADXL345_CHANNEL(2, chan_z, Z),
> + {
> + .type = IIO_ACCEL,
> + .modified = 1,
> + .channel2 = IIO_MOD_X_AND_Y_AND_Z,
> + .scan_index = -1, /* Fake channel */
> + .event_spec = &adxl345_freefall_event_spec,
> + .num_event_specs = 1,
> + },
> };
>
> static const unsigned long adxl345_scan_masks[] = {
> @@ -383,6 +401,63 @@ static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int,
> return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us);
> }
>
> +/* freefall */
> +
> +static int adxl345_is_ff_en(struct adxl345_state *st, bool *en)
> +{
> + int ret;
> + unsigned int regval;
> +
> + ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val);
> + if (ret)
> + return ret;
> +
> + *en = FIELD_GET(ADXL345_INT_FREE_FALL, regval) > 0;
> +
> + return 0;
> +}
> +
> +static int adxl345_set_ff_en(struct adxl345_state *st, bool cmd_en)
> +{
> + unsigned int regval, ff_threshold;
> + bool en;
> + int ret;
> +
> + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_FF, &ff_threshold);
> + if (ret)
> + return ret;
> +
> + en = cmd_en && ff_threshold > 0 && st->ff_time_ms > 0;
> +
> + regval = en ? ADXL345_INT_FREE_FALL : 0x00;
> +
> + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE,
> + ADXL345_INT_FREE_FALL, regval);
> +}
> +
> +static int adxl345_set_ff_time(struct adxl345_state *st, u32 val_int,
> + u32 val_fract_us)
> +{
> + unsigned int regval;
> + int val_ms;
> +
> + /*
> + * max value is 255 * 5000 us = 1.275000 seconds
> + *
> + * Note: the scaling is similar to the scaling in the ADXL380
> + */
> + if (1000000 * val_int + val_fract_us > 1275000)
> + return -EINVAL;
> +
> + val_ms = val_int * 1000 + DIV_ROUND_UP(val_fract_us, 1000);
> + st->ff_time_ms = val_ms;
> +
> + regval = DIV_ROUND_CLOSEST(val_ms, 5);
> +
> + /* Values between 100ms and 350ms (0x14 to 0x46) are recommended. */
> + return regmap_write(st->regmap, ADXL345_REG_TIME_FF, min(regval, 0xff));
> +}
> +
> static int adxl345_read_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan,
> int *val, int *val2, long mask)
> @@ -495,6 +570,11 @@ static int adxl345_read_event_config(struct iio_dev *indio_dev,
> default:
> return -EINVAL;
> }
> + case IIO_EV_TYPE_MAG:
> + ret = adxl345_is_ff_en(st, &int_en);
> + if (ret)
> + return ret;
> + return int_en;
> default:
> return -EINVAL;
> }
> @@ -518,6 +598,8 @@ static int adxl345_write_event_config(struct iio_dev *indio_dev,
> default:
> return -EINVAL;
> }
> + case IIO_EV_TYPE_MAG:
> + return adxl345_set_ff_en(st, state);
> default:
> return -EINVAL;
> }
> @@ -532,6 +614,7 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
> {
> struct adxl345_state *st = iio_priv(indio_dev);
> unsigned int tap_threshold;
> + unsigned int ff_threshold;
> int ret;
>
> switch (type) {
> @@ -565,6 +648,22 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
> default:
> return -EINVAL;
> }
> + case IIO_EV_TYPE_MAG:
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_FF,
> + &ff_threshold);
> + if (ret)
> + return ret;
> + *val = ff_threshold;
> + return IIO_VAL_INT;
> + case IIO_EV_INFO_PERIOD:
> + *val = st->ff_time_ms;
> + *val2 = 1000;
> + return IIO_VAL_FRACTIONAL;
> + default:
> + return -EINVAL;
> + }
> default:
> return -EINVAL;
> }
> @@ -612,6 +711,22 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev,
> return -EINVAL;
> }
> break;
> + case IIO_EV_TYPE_MAG:
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_FF, val);
> + if (ret)
> + return ret;
> + break;
> + case IIO_EV_INFO_PERIOD:
> + ret = adxl345_set_ff_time(st, val, val2);
> + if (ret)
> + return ret;
> + break;
> + default:
> + return -EINVAL;
> + }
> + break;
> default:
> return -EINVAL;
> }
> @@ -865,6 +980,17 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat,
> return ret;
> }
>
> + if (FIELD_GET(ADXL345_INT_FREE_FALL, int_stat)) {
> + ret = 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);
> + if (ret)
> + return ret;
> + }
> +
> if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) {
> samples = adxl345_get_samples(st);
> if (samples < 0)
> @@ -973,6 +1099,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
> ADXL345_DATA_FORMAT_FULL_RES |
> ADXL345_DATA_FORMAT_SELF_TEST);
> unsigned int tap_threshold;
> + unsigned int ff_threshold;
> int ret;
>
> indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
> @@ -992,6 +1119,9 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
> st->tap_window_us = 64; /* 64 [0x40] -> .080 */
> st->tap_latent_us = 16; /* 16 [0x10] -> .020 */
>
> + ff_threshold = 8; /* 8 [0x08] */
> + st->ff_time_ms = 32; /* 32 [0x20] -> 0.16 */
> +
> indio_dev->name = st->info->name;
> indio_dev->info = &adxl345_info;
> indio_dev->modes = INDIO_DIRECT_MODE;
> @@ -1068,6 +1198,10 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
> if (ret)
> return ret;
>
> + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_FF, ff_threshold);
> + if (ret)
> + return ret;
> +
> /* FIFO_STREAM mode is going to be activated later */
> ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops);
> if (ret)
Powered by blists - more mailing lists