From: Lothar Rubusch <l.rubusch@gmail.com>
To: jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com,
andy@kernel.org, corbet@lwn.net, lucas.p.stankus@gmail.com,
lars@metafoo.de, Michael.Hennerich@analog.com,
l.rubusch@gmail.com
Cc: linux-iio@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v2 10/12] iio: accel: adxl313: add inactivity sensing
Date: Tue, 20 May 2025 22:50:05 +0000 [thread overview]
Message-ID: <20250520225007.10990-11-l.rubusch@gmail.com> (raw)
In-Reply-To: <20250520225007.10990-1-l.rubusch@gmail.com>
Extend the interrupt handler to process interrupts as inactivity events.
Add functions to set threshold and period registers for inactivity. Add
functions to enable / disable inactivity. Extend the fake iio channel to
deal with inactivity events on x, y and z combined with AND.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/iio/accel/adxl313.h | 2 +
drivers/iio/accel/adxl313_core.c | 138 +++++++++++++++++++++++++------
2 files changed, 114 insertions(+), 26 deletions(-)
diff --git a/drivers/iio/accel/adxl313.h b/drivers/iio/accel/adxl313.h
index 9c7aedf7da7a..1398ac54d19b 100644
--- a/drivers/iio/accel/adxl313.h
+++ b/drivers/iio/accel/adxl313.h
@@ -18,6 +18,8 @@
#define ADXL313_REG_SOFT_RESET 0x18
#define ADXL313_REG_OFS_AXIS(index) (0x1E + (index))
#define ADXL313_REG_THRESH_ACT 0x24
+#define ADXL313_REG_THRESH_INACT 0x25
+#define ADXL313_REG_TIME_INACT 0x26
#define ADXL313_REG_ACT_INACT_CTL 0x27
#define ADXL313_REG_BW_RATE 0x2C
#define ADXL313_REG_POWER_CTL 0x2D
diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c
index 2ad87e98525c..7356aacd8874 100644
--- a/drivers/iio/accel/adxl313_core.c
+++ b/drivers/iio/accel/adxl313_core.c
@@ -29,18 +29,22 @@
#define ADXL313_REG_XYZ_BASE ADXL313_REG_DATA_AXIS(0)
#define ADXL313_ACT_XYZ_EN GENMASK(6, 4)
+#define ADXL313_INACT_XYZ_EN GENMASK(2, 0)
/* activity/inactivity */
enum adxl313_activity_type {
ADXL313_ACTIVITY,
+ ADXL313_INACTIVITY,
};
static const unsigned int adxl313_act_int_reg[] = {
[ADXL313_ACTIVITY] = ADXL313_INT_ACTIVITY,
+ [ADXL313_INACTIVITY] = ADXL313_INT_INACTIVITY,
};
static const unsigned int adxl313_act_thresh_reg[] = {
[ADXL313_ACTIVITY] = ADXL313_REG_THRESH_ACT,
+ [ADXL313_INACTIVITY] = ADXL313_REG_THRESH_INACT,
};
static const struct regmap_range adxl312_readable_reg_range[] = {
@@ -255,6 +259,14 @@ static const struct iio_event_spec adxl313_fake_chan_events[] = {
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
},
+ {
+ /* inactivity */
+ .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),
+ },
};
enum adxl313_chans {
@@ -335,6 +347,15 @@ static int adxl313_read_freq_avail(struct iio_dev *indio_dev,
}
}
+static int adxl313_set_inact_time_s(struct adxl313_data *data,
+ unsigned int val_s)
+{
+ unsigned int max_boundary = 255;
+ unsigned int val = min(val_s, max_boundary);
+
+ return regmap_write(data->regmap, ADXL313_REG_TIME_INACT, val);
+}
+
static int adxl313_is_act_inact_en(struct adxl313_data *data,
enum adxl313_activity_type type)
{
@@ -350,7 +371,7 @@ static int adxl313_is_act_inact_en(struct adxl313_data *data,
if (type == ADXL313_ACTIVITY)
axis_en = FIELD_GET(ADXL313_ACT_XYZ_EN, axis_ctrl);
else
- return 0;
+ axis_en = FIELD_GET(ADXL313_INACT_XYZ_EN, axis_ctrl);
/* The axis are enabled, now check if specific interrupt is enabled */
ret = regmap_read(data->regmap, ADXL313_REG_INT_ENABLE, ®val);
@@ -366,13 +387,16 @@ static int adxl313_set_act_inact_en(struct adxl313_data *data,
enum adxl313_activity_type type,
bool cmd_en)
{
- unsigned int axis_ctrl = 0;
+ unsigned int axis_ctrl;
unsigned int threshold;
+ unsigned int inact_time_s;
bool en;
int ret;
if (type == ADXL313_ACTIVITY)
axis_ctrl = ADXL313_ACT_XYZ_EN;
+ else
+ axis_ctrl = ADXL313_INACT_XYZ_EN;
ret = regmap_update_bits(data->regmap,
ADXL313_REG_ACT_INACT_CTL,
@@ -385,10 +409,14 @@ static int adxl313_set_act_inact_en(struct adxl313_data *data,
if (ret)
return ret;
- if (type == ADXL313_ACTIVITY)
- en = cmd_en && threshold;
- else
- en = false;
+ en = cmd_en && threshold;
+ if (type == ADXL313_INACTIVITY) {
+ ret = regmap_read(data->regmap, ADXL313_REG_TIME_INACT, &inact_time_s);
+ if (ret)
+ return ret;
+
+ en = en && inact_time_s;
+ }
return regmap_update_bits(data->regmap, ADXL313_REG_INT_ENABLE,
adxl313_act_int_reg[type],
@@ -481,6 +509,8 @@ static int adxl313_read_event_config(struct iio_dev *indio_dev,
switch (dir) {
case IIO_EV_DIR_RISING:
return adxl313_is_act_inact_en(data, ADXL313_ACTIVITY);
+ case IIO_EV_DIR_FALLING:
+ return adxl313_is_act_inact_en(data, ADXL313_INACTIVITY);
default:
return -EINVAL;
}
@@ -500,6 +530,8 @@ static int adxl313_write_event_config(struct iio_dev *indio_dev,
switch (dir) {
case IIO_EV_DIR_RISING:
return adxl313_set_act_inact_en(data, ADXL313_ACTIVITY, state);
+ case IIO_EV_DIR_FALLING:
+ return adxl313_set_act_inact_en(data, ADXL313_INACTIVITY, state);
default:
return -EINVAL;
}
@@ -514,6 +546,8 @@ static int adxl313_read_event_value(struct iio_dev *indio_dev,
{
struct adxl313_data *data = iio_priv(indio_dev);
unsigned int act_threshold;
+ unsigned int inact_threshold;
+ unsigned int inact_time_s;
int ret;
/* Measurement stays enabled, reading from regmap cache */
@@ -521,19 +555,38 @@ static int adxl313_read_event_value(struct iio_dev *indio_dev,
if (type != IIO_EV_TYPE_MAG)
return -EINVAL;
- if (info != IIO_EV_INFO_VALUE)
- return -EINVAL;
-
- switch (dir) {
- case IIO_EV_DIR_RISING:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = regmap_read(data->regmap,
+ adxl313_act_thresh_reg[ADXL313_ACTIVITY],
+ &act_threshold);
+ if (ret)
+ return ret;
+ *val = act_threshold * 15625;
+ *val2 = MICRO;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_read(data->regmap,
+ adxl313_act_thresh_reg[ADXL313_INACTIVITY],
+ &inact_threshold);
+ if (ret)
+ return ret;
+ *val = inact_threshold * 15625;
+ *val2 = MICRO;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_PERIOD:
ret = regmap_read(data->regmap,
- adxl313_act_thresh_reg[ADXL313_ACTIVITY],
- &act_threshold);
+ ADXL313_REG_TIME_INACT,
+ &inact_time_s);
if (ret)
return ret;
- *val = act_threshold * 15625;
- *val2 = MICRO;
- return IIO_VAL_FRACTIONAL;
+ *val = inact_time_s;
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
@@ -557,16 +610,30 @@ static int adxl313_write_event_value(struct iio_dev *indio_dev,
if (type != IIO_EV_TYPE_MAG)
return -EINVAL;
- if (info != IIO_EV_INFO_VALUE)
- return -EINVAL;
-
- /* Scale factor 15.625 mg/LSB */
- regval = DIV_ROUND_CLOSEST(MICRO * val + val2, 15625);
- switch (dir) {
- case IIO_EV_DIR_RISING:
- ret = regmap_write(data->regmap,
- adxl313_act_thresh_reg[ADXL313_ACTIVITY],
- regval);
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ /* The scale factor is 15.625 mg/LSB */
+ regval = DIV_ROUND_CLOSEST(MICRO * val + val2, 15625);
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = regmap_write(data->regmap,
+ adxl313_act_thresh_reg[ADXL313_ACTIVITY],
+ regval);
+ if (ret)
+ return ret;
+ return adxl313_set_measure_en(data, true);
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_write(data->regmap,
+ adxl313_act_thresh_reg[ADXL313_INACTIVITY],
+ regval);
+ if (ret)
+ return ret;
+ return adxl313_set_measure_en(data, true);
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_PERIOD:
+ ret = adxl313_set_inact_time_s(data, val);
if (ret)
return ret;
return adxl313_set_measure_en(data, true);
@@ -722,6 +789,17 @@ static int adxl313_push_event(struct iio_dev *indio_dev, int int_stat)
return ret;
}
+ if (FIELD_GET(ADXL313_INT_INACTIVITY, 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(ADXL313_INT_WATERMARK, int_stat)) {
samples = adxl313_get_samples(data);
if (samples < 0)
@@ -891,6 +969,14 @@ int adxl313_core_probe(struct device *dev,
if (ret)
return ret;
+ ret = regmap_write(data->regmap, ADXL313_REG_TIME_INACT, 5);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, ADXL313_REG_THRESH_INACT, 0x4f);
+ if (ret)
+ return ret;
+
ret = regmap_write(data->regmap, ADXL313_REG_THRESH_ACT, 0x52);
if (ret)
return ret;
--
2.39.5
next prev parent reply other threads:[~2025-05-20 22:50 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-20 22:49 [PATCH v2 00/12] iio: accel: adxl313: add power-save on activity/inactivity Lothar Rubusch
2025-05-20 22:49 ` [PATCH v2 01/12] iio: accel: adxl313: add debug register Lothar Rubusch
2025-05-20 22:49 ` [PATCH v2 02/12] iio: accel: adxl313: introduce channel scan_index Lothar Rubusch
2025-05-20 22:49 ` [PATCH v2 03/12] iio: accel: adxl313: configure scan type for buffer Lothar Rubusch
2025-05-20 22:49 ` [PATCH v2 04/12] iio: accel: adxl313: make use of regmap cache Lothar Rubusch
2025-05-20 22:50 ` [PATCH v2 05/12] iio: accel: adxl313: add function to enable measurement Lothar Rubusch
2025-05-20 22:50 ` [PATCH v2 06/12] iio: accel: adxl313: prepare interrupt handling Lothar Rubusch
2025-05-20 22:50 ` [PATCH v2 07/12] iio: accel: adxl313: add basic " Lothar Rubusch
2025-05-21 10:10 ` Andy Shevchenko
2025-05-20 22:50 ` [PATCH v2 08/12] iio: accel: adxl313: add FIFO watermark Lothar Rubusch
2025-05-21 10:16 ` Andy Shevchenko
2025-05-20 22:50 ` [PATCH v2 09/12] iio: accel: adxl313: add activity sensing Lothar Rubusch
2025-05-21 9:21 ` Andy Shevchenko
2025-05-20 22:50 ` Lothar Rubusch [this message]
2025-05-20 22:50 ` [PATCH v2 11/12] iio: accel: adxl313: implement power-save on inactivity Lothar Rubusch
2025-05-20 22:50 ` [PATCH v2 12/12] docs: iio: add ADXL313 accelerometer Lothar Rubusch
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=20250520225007.10990-11-l.rubusch@gmail.com \
--to=l.rubusch@gmail.com \
--cc=Michael.Hennerich@analog.com \
--cc=andy@kernel.org \
--cc=corbet@lwn.net \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=lars@metafoo.de \
--cc=linux-doc@vger.kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lucas.p.stankus@gmail.com \
--cc=nuno.sa@analog.com \
/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.