Inactivity and free-fall events are essentially the same type of sensor
events. Therefore, inactivity detection (normally set for periods between 1
and 255 seconds) can be extended for shorter durations to support free-fall
detection.
For periods shorter than 1 second, the driver automatically configures the
threshold and duration using the free-fall register. For periods longer
than 1 second, it uses the inactivity threshold and duration using the
inactivity registers.
When using the free-fall register, the link bit is not set, which means
auto-sleep cannot be enabled if activity detection is also active.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/iio/accel/adxl345_core.c | 158 +++++++++++++++++++++----------
1 file changed, 109 insertions(+), 49 deletions(-)
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index c5a3dac5f938..f1f92635bc21 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -40,12 +40,15 @@
#define ADXL345_REG_INACT_AXIS_MSK GENMASK(2, 0)
#define ADXL345_REG_ACT_ACDC_MSK BIT(7)
#define ADXL345_REG_INACT_ACDC_MSK BIT(3)
+#define ADXL345_REG_NO_ACDC_MSK 0x00
#define ADXL345_POWER_CTL_INACT_MSK (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL345_POWER_CTL_LINK)
#define ADXL345_TAP_Z_EN BIT(0)
#define ADXL345_TAP_Y_EN BIT(1)
#define ADXL345_TAP_X_EN BIT(2)
+#define ADXL345_ACT_INACT_NO_AXIS_EN 0x00
+
#define ADXL345_INACT_Z_EN BIT(0)
#define ADXL345_INACT_Y_EN BIT(1)
#define ADXL345_INACT_X_EN BIT(2)
@@ -86,6 +89,7 @@ enum adxl345_activity_type {
ADXL345_INACTIVITY,
ADXL345_ACTIVITY_AC,
ADXL345_INACTIVITY_AC,
+ ADXL345_INACTIVITY_FF,
};
static const unsigned int adxl345_act_int_reg[] = {
@@ -93,6 +97,7 @@ static const unsigned int adxl345_act_int_reg[] = {
[ADXL345_INACTIVITY] = ADXL345_INT_INACTIVITY,
[ADXL345_ACTIVITY_AC] = ADXL345_INT_ACTIVITY,
[ADXL345_INACTIVITY_AC] = ADXL345_INT_INACTIVITY,
+ [ADXL345_INACTIVITY_FF] = ADXL345_INT_FREE_FALL,
};
static const unsigned int adxl345_act_thresh_reg[] = {
@@ -100,6 +105,7 @@ static const unsigned int adxl345_act_thresh_reg[] = {
[ADXL345_INACTIVITY] = ADXL345_REG_THRESH_INACT,
[ADXL345_ACTIVITY_AC] = ADXL345_REG_THRESH_ACT,
[ADXL345_INACTIVITY_AC] = ADXL345_REG_THRESH_INACT,
+ [ADXL345_INACTIVITY_FF] = ADXL345_REG_THRESH_FF,
};
static const unsigned int adxl345_act_acdc_msk[] = {
@@ -107,6 +113,7 @@ static const unsigned int adxl345_act_acdc_msk[] = {
[ADXL345_INACTIVITY] = ADXL345_REG_INACT_ACDC_MSK,
[ADXL345_ACTIVITY_AC] = ADXL345_REG_ACT_ACDC_MSK,
[ADXL345_INACTIVITY_AC] = ADXL345_REG_INACT_ACDC_MSK,
+ [ADXL345_INACTIVITY_FF] = ADXL345_REG_NO_ACDC_MSK,
};
enum adxl345_odr {
@@ -189,6 +196,9 @@ struct adxl345_state {
u8 watermark;
u8 fifo_mode;
+ u8 inact_threshold;
+ u32 inact_time_ms;
+
u32 tap_duration_us;
u32 tap_latent_us;
u32 tap_window_us;
@@ -333,10 +343,29 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en)
/* activity / inactivity */
+static int adxl345_set_inact_threshold(struct adxl345_state *st,
+ unsigned int threshold)
+{
+ int ret;
+
+ st->inact_threshold = min(U8_MAX, threshold);
+
+ ret = regmap_write(st->regmap,
+ adxl345_act_thresh_reg[ADXL345_INACTIVITY],
+ st->inact_threshold);
+ if (ret)
+ return ret;
+
+ return regmap_write(st->regmap,
+ adxl345_act_thresh_reg[ADXL345_INACTIVITY_FF],
+ st->inact_threshold);
+}
+
/**
* adxl345_set_inact_time - Configure inactivity time explicitly or by ODR.
* @st: The sensor state instance.
- * @val_s: A desired time value, between 0 and 255.
+ * @val_int: The inactivity time, integer part.
+ * @val_fract: The inactivity time, fractional part when val_int is 0.
*
* Inactivity time can be configured between 1 and 255 seconds. If a user sets
* val_s to 0, a default inactivity time is calculated automatically (since 0 is
@@ -357,16 +386,18 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en)
*
* Return: 0 or error value.
*/
-static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s)
+static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int,
+ u32 val_fract)
{
int max_boundary = U8_MAX;
int min_boundary = 10;
- unsigned int val = min(val_s, U8_MAX);
+ unsigned int val;
enum adxl345_odr odr;
unsigned int regval;
int ret;
- if (val == 0) {
+ if (val_int == 0 && val_fract == 0) {
+ /* Generated inactivity time based on ODR */
ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
if (ret)
return ret;
@@ -374,9 +405,31 @@ static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s)
odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
min_boundary, max_boundary);
+ st->inact_time_ms = MILLI * val;
+
+ /* Inactivity time in s */
+ return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
+ } else if (val_int == 0 && val_fract > 0) {
+ /* time < 1s, free-fall */
+
+ /*
+ * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
+ *
+ * Recommended values between 100ms and 350ms (0x14 to 0x46)
+ */
+ st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
+
+ return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
+ DIV_ROUND_CLOSEST(val_fract, 5));
+ } else if (val_int > 0) {
+ /* Time >= 1s, inactivity */
+ st->inact_time_ms = MILLI * val_int;
+
+ return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
}
- return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
+ /* Do not support negative or wrong input. */
+ return -EINVAL;
}
/**
@@ -399,6 +452,9 @@ static int adxl345_is_act_inact_ac(struct adxl345_state *st,
bool coupling;
int ret;
+ if (type == ADXL345_INACTIVITY_FF)
+ return true;
+
ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val);
if (ret)
return ret;
@@ -511,6 +567,9 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st,
if (!en)
return false;
break;
+ case ADXL345_INACTIVITY_FF:
+ en = true;
+ break;
default:
return -EINVAL;
}
@@ -542,15 +601,20 @@ static int adxl345_set_act_inact_linkbit(struct adxl345_state *st,
if (act_ac_en < 0)
return act_ac_en;
- inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY);
- if (inact_en < 0)
- return inact_en;
+ if (type == ADXL345_INACTIVITY_FF) {
+ inact_en = false;
+ } else {
+ inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY);
+ if (inact_en < 0)
+ return inact_en;
- inact_ac_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC);
- if (inact_ac_en < 0)
- return inact_ac_en;
+ inact_ac_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC);
+ if (inact_ac_en < 0)
+ return inact_ac_en;
+
+ inact_en = inact_en || inact_ac_en;
+ }
- inact_en = inact_en || inact_ac_en;
act_en = act_en || act_ac_en;
return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL,
@@ -569,11 +633,15 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st,
if (cmd_en) {
/* When turning on, check if threshold is valid */
- ret = regmap_read(st->regmap,
- adxl345_act_thresh_reg[type],
- &threshold);
- if (ret)
- return ret;
+ if (type == ADXL345_ACTIVITY || type == ADXL345_ACTIVITY_AC) {
+ ret = regmap_read(st->regmap,
+ adxl345_act_thresh_reg[type],
+ &threshold);
+ if (ret)
+ return ret;
+ } else {
+ threshold = st->inact_threshold;
+ }
if (!threshold) /* Just ignore the command if threshold is 0 */
return 0;
@@ -618,6 +686,9 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st,
axis_ctrl = ADXL345_INACT_X_EN | ADXL345_INACT_Y_EN |
ADXL345_INACT_Z_EN;
break;
+ case ADXL345_INACTIVITY_FF:
+ axis_ctrl = ADXL345_ACT_INACT_NO_AXIS_EN;
+ break;
default:
return -EINVAL;
}
@@ -884,7 +955,7 @@ static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr)
return ret;
/* update inactivity time by ODR */
- return adxl345_set_inact_time(st, 0);
+ return adxl345_set_inact_time(st, 0, 0);
}
static int adxl345_find_range(struct adxl345_state *st, int val, int val2,
@@ -921,12 +992,6 @@ static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range)
if (ret)
return ret;
- ret = regmap_read(st->regmap,
- adxl345_act_thresh_reg[ADXL345_INACTIVITY],
- &inact_threshold);
- if (ret)
- return ret;
-
ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
ADXL345_DATA_FORMAT_RANGE,
FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range));
@@ -937,6 +1002,7 @@ static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range)
/ adxl345_range_factor_tbl[range];
act_threshold = min(U8_MAX, max(1, act_threshold));
+ inact_threshold = st->inact_threshold;
inact_threshold = inact_threshold * adxl345_range_factor_tbl[range_old]
/ adxl345_range_factor_tbl[range];
inact_threshold = min(U8_MAX, max(1, inact_threshold));
@@ -946,8 +1012,7 @@ static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range)
if (ret)
return ret;
- return regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_INACTIVITY],
- inact_threshold);
+ return adxl345_set_inact_threshold(st, inact_threshold);
}
static int adxl345_read_avail(struct iio_dev *indio_dev,
@@ -1192,7 +1257,6 @@ static int adxl345_read_mag_value(struct adxl345_state *st,
int *val, int *val2)
{
unsigned int threshold;
- unsigned int period;
int ret;
switch (info) {
@@ -1208,25 +1272,16 @@ static int adxl345_read_mag_value(struct adxl345_state *st,
*val2 = MICRO;
return IIO_VAL_FRACTIONAL;
case IIO_EV_DIR_FALLING:
- ret = regmap_read(st->regmap,
- adxl345_act_thresh_reg[type_inact],
- &threshold);
- if (ret)
- return ret;
- *val = 62500 * threshold;
+ *val = 62500 * st->inact_threshold;
*val2 = MICRO;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_EV_INFO_PERIOD:
- ret = regmap_read(st->regmap,
- ADXL345_REG_TIME_INACT,
- &period);
- if (ret)
- return ret;
- *val = period;
- return IIO_VAL_INT;
+ *val = st->inact_time_ms;
+ *val2 = MILLI;
+ return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
@@ -1249,14 +1304,12 @@ static int adxl345_write_mag_value(struct adxl345_state *st,
adxl345_act_thresh_reg[type_act],
val);
case IIO_EV_DIR_FALLING:
- return regmap_write(st->regmap,
- adxl345_act_thresh_reg[type_inact],
- val);
+ return adxl345_set_inact_threshold(st, val);
default:
return -EINVAL;
}
case IIO_EV_INFO_PERIOD:
- return adxl345_set_inact_time(st, val);
+ return adxl345_set_inact_time(st, val, val2);
default:
return -EINVAL;
}
@@ -1669,6 +1722,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)
@@ -1907,15 +1971,11 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
if (ret)
return ret;
- ret = regmap_write(st->regmap, ADXL345_REG_TIME_INACT, 0x37);
- if (ret)
- return ret;
-
ret = regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6);
if (ret)
return ret;
- ret = regmap_write(st->regmap, ADXL345_REG_THRESH_INACT, 4);
+ ret = adxl345_set_inact_threshold(st, 4);
if (ret)
return ret;
--
2.39.5
On Sun, Jun 22, 2025 at 03:50:09PM +0000, Lothar Rubusch wrote:
> Inactivity and free-fall events are essentially the same type of sensor
> events. Therefore, inactivity detection (normally set for periods between 1
> and 255 seconds) can be extended for shorter durations to support free-fall
> detection.
>
> For periods shorter than 1 second, the driver automatically configures the
> threshold and duration using the free-fall register. For periods longer
> than 1 second, it uses the inactivity threshold and duration using the
> inactivity registers.
>
> When using the free-fall register, the link bit is not set, which means
> auto-sleep cannot be enabled if activity detection is also active.
...
> -static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s)
> +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int,
> + u32 val_fract)
> {
> int max_boundary = U8_MAX;
> int min_boundary = 10;
> - unsigned int val = min(val_s, U8_MAX);
> + unsigned int val;
You see, I even suggested splitting this assignment to begin with.
The change will be clearer with that done.
> enum adxl345_odr odr;
> unsigned int regval;
> int ret;
>
> - if (val == 0) {
> + if (val_int == 0 && val_fract == 0) {
> + /* Generated inactivity time based on ODR */
> ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
> if (ret)
> return ret;
> odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
> val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
> min_boundary, max_boundary);
> + st->inact_time_ms = MILLI * val;
> +
> + /* Inactivity time in s */
> + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> + } else if (val_int == 0 && val_fract > 0) {
val_fract check is not needed here.
> + /* time < 1s, free-fall */
> +
> + /*
> + * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
> + *
> + * Recommended values between 100ms and 350ms (0x14 to 0x46)
> + */
> + st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
> +
> + return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
> + DIV_ROUND_CLOSEST(val_fract, 5));
> + } else if (val_int > 0) {
if now is redundant here, right?
> + /* Time >= 1s, inactivity */
> + st->inact_time_ms = MILLI * val_int;
> +
> + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
> }
>
> - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> + /* Do not support negative or wrong input. */
> + return -EINVAL;
> }
--
With Best Regards,
Andy Shevchenko
Hi Andy,
This is a tricky one, I'll give some examples why (I think) the code
is needed as is.
On Mon, Jun 23, 2025 at 12:17 PM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Sun, Jun 22, 2025 at 03:50:09PM +0000, Lothar Rubusch wrote:
> > Inactivity and free-fall events are essentially the same type of sensor
> > events. Therefore, inactivity detection (normally set for periods between 1
> > and 255 seconds) can be extended for shorter durations to support free-fall
> > detection.
> >
> > For periods shorter than 1 second, the driver automatically configures the
> > threshold and duration using the free-fall register. For periods longer
> > than 1 second, it uses the inactivity threshold and duration using the
> > inactivity registers.
> >
> > When using the free-fall register, the link bit is not set, which means
> > auto-sleep cannot be enabled if activity detection is also active.
>
> ...
>
> > -static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s)
> > +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int,
> > + u32 val_fract)
> > {
> > int max_boundary = U8_MAX;
> > int min_boundary = 10;
> > - unsigned int val = min(val_s, U8_MAX);
> > + unsigned int val;
>
> You see, I even suggested splitting this assignment to begin with.
> The change will be clearer with that done.
>
> > enum adxl345_odr odr;
> > unsigned int regval;
> > int ret;
> >
> > - if (val == 0) {
> > + if (val_int == 0 && val_fract == 0) {
The case for 0sec, 0.0 or setting "0" and fract will consequently be
"0". 0 is an invalid input for this period and sensor, so it will
default to an optimized period based on given ODR.
> > + /* Generated inactivity time based on ODR */
> > ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
> > if (ret)
> > return ret;
>
> > odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
> > val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
> > min_boundary, max_boundary);
> > + st->inact_time_ms = MILLI * val;
> > +
> > + /* Inactivity time in s */
> > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > + } else if (val_int == 0 && val_fract > 0) {
>
> val_fract check is not needed here.
>
Case for e.g. 0.123, numbers under 1s. This goes into the free-fall register.
> > + /* time < 1s, free-fall */
> > +
> > + /*
> > + * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
> > + *
> > + * Recommended values between 100ms and 350ms (0x14 to 0x46)
> > + */
> > + st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
> > +
> > + return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
> > + DIV_ROUND_CLOSEST(val_fract, 5));
> > + } else if (val_int > 0) {
>
> if now is redundant here, right?
>
So, this will be 1s through 255s. Periods above 1sec. This goes into
the inactivity register.
> > + /* Time >= 1s, inactivity */
> > + st->inact_time_ms = MILLI * val_int;
> > +
> > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
> > }
> >
> > - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > + /* Do not support negative or wrong input. */
> > + return -EINVAL;
> > }
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
On Mon, Jun 23, 2025 at 11:21:01PM +0200, Lothar Rubusch wrote:
> On Mon, Jun 23, 2025 at 12:17 PM Andy Shevchenko
> <andriy.shevchenko@intel.com> wrote:
> > On Sun, Jun 22, 2025 at 03:50:09PM +0000, Lothar Rubusch wrote:
...
> > > -static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s)
> > > +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int,
> > > + u32 val_fract)
> > > {
> > > int max_boundary = U8_MAX;
> > > int min_boundary = 10;
> > > - unsigned int val = min(val_s, U8_MAX);
> > > + unsigned int val;
> >
> > You see, I even suggested splitting this assignment to begin with.
> > The change will be clearer with that done.
> >
> > > enum adxl345_odr odr;
> > > unsigned int regval;
> > > int ret;
> > >
> > > - if (val == 0) {
> > > + if (val_int == 0 && val_fract == 0) {
>
> The case for 0sec, 0.0 or setting "0" and fract will consequently be
> "0". 0 is an invalid input for this period and sensor, so it will
> default to an optimized period based on given ODR.
>
> > > + /* Generated inactivity time based on ODR */
> > > ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
> > > if (ret)
> > > return ret;
> >
> > > odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
> > > val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
> > > min_boundary, max_boundary);
> > > + st->inact_time_ms = MILLI * val;
> > > +
> > > + /* Inactivity time in s */
> > > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > > + } else if (val_int == 0 && val_fract > 0) {
> >
> > val_fract check is not needed here.
>
> Case for e.g. 0.123, numbers under 1s. This goes into the free-fall register.
0.0 is already checked above, and since the val_fract is unsigned this is check
is redundant.
> > > + /* time < 1s, free-fall */
> > > +
> > > + /*
> > > + * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
> > > + *
> > > + * Recommended values between 100ms and 350ms (0x14 to 0x46)
> > > + */
> > > + st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
> > > +
> > > + return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
> > > + DIV_ROUND_CLOSEST(val_fract, 5));
> > > + } else if (val_int > 0) {
> >
> > if now is redundant here, right?
>
> So, this will be 1s through 255s. Periods above 1sec. This goes into
> the inactivity register.
See above,
> > > + /* Time >= 1s, inactivity */
> > > + st->inact_time_ms = MILLI * val_int;
> > > +
> > > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
> > > }
> > >
> > > - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > > + /* Do not support negative or wrong input. */
> > > + return -EINVAL;
> > > }
--
With Best Regards,
Andy Shevchenko
On Tue, Jun 24, 2025 at 9:38 AM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:
>
> On Mon, Jun 23, 2025 at 11:21:01PM +0200, Lothar Rubusch wrote:
> > On Mon, Jun 23, 2025 at 12:17 PM Andy Shevchenko
> > <andriy.shevchenko@intel.com> wrote:
> > > On Sun, Jun 22, 2025 at 03:50:09PM +0000, Lothar Rubusch wrote:
>
> ...
>
> > > > -static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s)
> > > > +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int,
> > > > + u32 val_fract)
> > > > {
> > > > int max_boundary = U8_MAX;
> > > > int min_boundary = 10;
> > > > - unsigned int val = min(val_s, U8_MAX);
> > > > + unsigned int val;
> > >
> > > You see, I even suggested splitting this assignment to begin with.
> > > The change will be clearer with that done.
> > >
> > > > enum adxl345_odr odr;
> > > > unsigned int regval;
> > > > int ret;
> > > >
> > > > - if (val == 0) {
> > > > + if (val_int == 0 && val_fract == 0) {
> >
> > The case for 0sec, 0.0 or setting "0" and fract will consequently be
> > "0". 0 is an invalid input for this period and sensor, so it will
> > default to an optimized period based on given ODR.
> >
> > > > + /* Generated inactivity time based on ODR */
> > > > ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
> > > > if (ret)
> > > > return ret;
> > >
> > > > odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
> > > > val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
> > > > min_boundary, max_boundary);
> > > > + st->inact_time_ms = MILLI * val;
> > > > +
> > > > + /* Inactivity time in s */
> > > > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > > > + } else if (val_int == 0 && val_fract > 0) {
> > >
> > > val_fract check is not needed here.
> >
> > Case for e.g. 0.123, numbers under 1s. This goes into the free-fall register.
>
> 0.0 is already checked above, and since the val_fract is unsigned this is check
> is redundant.
>
> > > > + /* time < 1s, free-fall */
> > > > +
> > > > + /*
> > > > + * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
> > > > + *
> > > > + * Recommended values between 100ms and 350ms (0x14 to 0x46)
> > > > + */
> > > > + st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
> > > > +
> > > > + return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
> > > > + DIV_ROUND_CLOSEST(val_fract, 5));
> > > > + } else if (val_int > 0) {
> > >
> > > if now is redundant here, right?
> >
> > So, this will be 1s through 255s. Periods above 1sec. This goes into
> > the inactivity register.
>
> See above,
>
I agree, that checking for val_fract is actually done as a sub case of
val_int, and only if val_int was 0. So, would the following make it
clearer?
if (val_int == 0) {
if (val_fract == 0) {
// 0 provided, default values
} else {
// >0s, e.g. 0.123s, use free-fall register
} else {
// 1s - 255s, use inactivity register
}
Actually - I did not touch that - I saw some places where I'm already
using nested if/else in the third level. I guess, by the style advice
according to switch/case, this also applies to if/else, right?
If yes, when the according parts go into another round, I might give
it a try to separate as well using helper functions.
Best,
L
> > > > + /* Time >= 1s, inactivity */
> > > > + st->inact_time_ms = MILLI * val_int;
> > > > +
> > > > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
> > > > }
> > > >
> > > > - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > > > + /* Do not support negative or wrong input. */
> > > > + return -EINVAL;
> > > > }
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
On Tue, Jun 24, 2025 at 10:18:35AM +0200, Lothar Rubusch wrote:
> On Tue, Jun 24, 2025 at 9:38 AM Andy Shevchenko
> <andriy.shevchenko@intel.com> wrote:
> > On Mon, Jun 23, 2025 at 11:21:01PM +0200, Lothar Rubusch wrote:
> > > On Mon, Jun 23, 2025 at 12:17 PM Andy Shevchenko
> > > <andriy.shevchenko@intel.com> wrote:
> > > > On Sun, Jun 22, 2025 at 03:50:09PM +0000, Lothar Rubusch wrote:
...
> > > > > - if (val == 0) {
> > > > > + if (val_int == 0 && val_fract == 0) {
> > >
> > > The case for 0sec, 0.0 or setting "0" and fract will consequently be
> > > "0". 0 is an invalid input for this period and sensor, so it will
> > > default to an optimized period based on given ODR.
> > >
> > > > > + /* Generated inactivity time based on ODR */
> > > > > ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
> > > > > if (ret)
> > > > > return ret;
> > > >
> > > > > odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
> > > > > val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
> > > > > min_boundary, max_boundary);
> > > > > + st->inact_time_ms = MILLI * val;
> > > > > +
> > > > > + /* Inactivity time in s */
> > > > > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
> > > > > + } else if (val_int == 0 && val_fract > 0) {
> > > >
> > > > val_fract check is not needed here.
> > >
> > > Case for e.g. 0.123, numbers under 1s. This goes into the free-fall register.
> >
> > 0.0 is already checked above, and since the val_fract is unsigned this is check
> > is redundant.
> >
> > > > > + /* time < 1s, free-fall */
> > > > > +
> > > > > + /*
> > > > > + * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
> > > > > + *
> > > > > + * Recommended values between 100ms and 350ms (0x14 to 0x46)
> > > > > + */
> > > > > + st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
> > > > > +
> > > > > + return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
> > > > > + DIV_ROUND_CLOSEST(val_fract, 5));
> > > > > + } else if (val_int > 0) {
> > > >
> > > > if now is redundant here, right?
> > >
> > > So, this will be 1s through 255s. Periods above 1sec. This goes into
> > > the inactivity register.
> >
> > See above,
> >
>
> I agree, that checking for val_fract is actually done as a sub case of
> val_int, and only if val_int was 0. So, would the following make it
> clearer?
>
> if (val_int == 0) {
> if (val_fract == 0) {
> // 0 provided, default values
> } else {
> // >0s, e.g. 0.123s, use free-fall register
> } else {
> // 1s - 255s, use inactivity register
> }
>
> Actually - I did not touch that - I saw some places where I'm already
> using nested if/else in the third level. I guess, by the style advice
> according to switch/case, this also applies to if/else, right?
>
> If yes, when the according parts go into another round, I might give
> it a try to separate as well using helper functions.
You can think through the patches. It might make sense to consider as well this
helper_1()
{
// for default
}
helper_2()
{
// for free-fall
}
helper_3()
{
// for inactive
}
...
if ()
helper_1();
else if ()
helper_2();
else
helper_3();
> > > > > + /* Time >= 1s, inactivity */
> > > > > + st->inact_time_ms = MILLI * val_int;
> > > > > +
> > > > > + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
> > > > > }
--
With Best Regards,
Andy Shevchenko
© 2016 - 2026 Red Hat, Inc.