From: Lothar Rubusch <l.rubusch@gmail.com>
To: lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org
Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org,
eraretuya@gmail.com, l.rubusch@gmail.com
Subject: [PATCH v4 08/14] iio: accel: adxl345: add freefall feature
Date: Thu, 13 Mar 2025 16:50:43 +0000 [thread overview]
Message-ID: <20250313165049.48305-9-l.rubusch@gmail.com> (raw)
In-Reply-To: <20250313165049.48305-1-l.rubusch@gmail.com>
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@gmail.com>
---
drivers/iio/accel/adxl345_core.c | 122 +++++++++++++++++++++++++++++++
1 file changed, 122 insertions(+)
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 9e33236c786a..1a2bf0c630c9 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -78,6 +78,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);
};
@@ -99,6 +100,14 @@ static struct iio_event_spec adxl345_events[] = {
BIT(IIO_EV_INFO_RESET_TIMEOUT) |
BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
},
+ {
+ /* free fall */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD),
+ },
};
#define ADXL345_CHANNEL(index, reg, axis) { \
@@ -379,6 +388,64 @@ 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;
+ const unsigned int freefall_mask = 0x02;
+ 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,
+ freefall_mask, 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)
@@ -491,6 +558,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;
}
@@ -514,6 +586,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;
}
@@ -528,6 +602,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) {
@@ -561,6 +636,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;
}
@@ -601,6 +692,18 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev,
break;
}
break;
+ case IIO_EV_TYPE_MAG:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_write(st->regmap, ADXL345_REG_THRESH_FF, val);
+ break;
+ case IIO_EV_INFO_PERIOD:
+ ret = adxl345_set_ff_time(st, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
default:
ret = -EINVAL;
break;
@@ -862,6 +965,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_OR_Y_OR_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)
@@ -968,6 +1082,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));
@@ -987,6 +1102,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;
@@ -1063,6 +1181,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)
--
2.39.5
next prev parent reply other threads:[~2025-03-13 16:51 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-13 16:50 [PATCH v4 00/14] iio: accel: adxl345: add interrupt based sensor events Lothar Rubusch
2025-03-13 16:50 ` [PATCH v4 01/14] iio: accel: adxl345: use regmap cache for INT mapping Lothar Rubusch
2025-03-16 11:06 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 02/14] iio: accel: adxl345: move INT enable to regmap cache Lothar Rubusch
2025-03-16 11:11 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 03/14] iio: accel: adxl345: cleanup regmap return values Lothar Rubusch
2025-03-16 11:12 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 04/14] iio: accel: adxl345: introduce adxl345_push_event function Lothar Rubusch
2025-03-16 11:14 ` Jonathan Cameron
2025-03-16 19:58 ` Andy Shevchenko
2025-03-17 10:55 ` Jonathan Cameron
2025-03-17 15:51 ` Andy Shevchenko
2025-03-18 9:44 ` Lothar Rubusch
2025-03-26 9:32 ` Andy Shevchenko
2025-03-28 15:30 ` Lothar Rubusch
2025-03-13 16:50 ` [PATCH v4 05/14] iio: accel: adxl345: add single tap feature Lothar Rubusch
2025-03-16 11:22 ` Jonathan Cameron
2025-03-18 10:32 ` Lothar Rubusch
2025-03-18 23:08 ` Lothar Rubusch
2025-03-31 12:36 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 06/14] iio: accel: adxl345: add double " Lothar Rubusch
2025-03-13 16:50 ` [PATCH v4 07/14] iio: accel: adxl345: set the tap suppress bit permanently Lothar Rubusch
2025-03-13 16:50 ` Lothar Rubusch [this message]
2025-03-13 16:50 ` [PATCH v4 09/14] iio: accel: adxl345: extend sample frequency adjustments Lothar Rubusch
2025-03-16 11:26 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 10/14] iio: accel: adxl345: add g-range configuration Lothar Rubusch
2025-03-16 11:28 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 11/14] iio: accel: adxl345: add activity event feature Lothar Rubusch
2025-03-16 11:32 ` Jonathan Cameron
2025-03-13 16:50 ` [PATCH v4 12/14] iio: accel: adxl345: add inactivity feature Lothar Rubusch
2025-03-13 16:50 ` [PATCH v4 13/14] iio: accel: adxl345: add coupling detection for activity/inactivity Lothar Rubusch
2025-03-13 16:50 ` [PATCH v4 14/14] docs: iio: add documentation for adxl345 driver Lothar Rubusch
2025-03-16 11:37 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250313165049.48305-9-l.rubusch@gmail.com \
--to=l.rubusch@gmail.com \
--cc=Michael.Hennerich@analog.com \
--cc=eraretuya@gmail.com \
--cc=jic23@kernel.org \
--cc=lars@metafoo.de \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.