lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-Id: <20250610215933.84795-11-l.rubusch@gmail.com> Date: Tue, 10 Jun 2025 21:59:32 +0000 From: Lothar Rubusch <l.rubusch@...il.com> To: lars@...afoo.de, Michael.Hennerich@...log.com, jic23@...nel.org, dlechner@...libre.com, nuno.sa@...log.com, andy@...nel.org, corbet@....net Cc: linux-iio@...r.kernel.org, linux-kernel@...r.kernel.org, linux-doc@...r.kernel.org, eraretuya@...il.com, l.rubusch@...il.com Subject: [PATCH v9 10/11] iio: accel: adxl345: extend inactivity time for less than 1s Inactivity event and free-fall event are actually the same type of sensor events. Hence, inactivity detection using a period of 1 to 255s can be extended to be used for lower periods than 1s for covering free-fall detection. When lower periods are defined, the driver automatically will setup threshold and period on the free-fall register, while using the inactivity threshold and period for periods above 1s. Using the free-fall register, no link bit will be set, and therefore no auto-sleep can be set in cases where also activity will be enabled. Signed-off-by: Lothar Rubusch <l.rubusch@...il.com> --- drivers/iio/accel/adxl345_core.c | 165 +++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 52 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 6a4af559ad9e..7afc120b4a45 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -86,6 +86,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 +94,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 +102,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 +110,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] = 0x00, }; enum adxl345_odr { @@ -189,6 +193,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,12 +340,31 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en) /* act/inact */ +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 sec. If a val_s of 0 + * Inactivity time can be configured between 1 and 255 sec. If a val_s of 0.00 * is configured by a user, then a default inactivity time will be computed. * * In such case, it should take power consumption into consideration. Thus it @@ -355,16 +381,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) { unsigned int max_boundary = 255; unsigned int min_boundary = 10; - unsigned int val = min(val_s, max_boundary); + 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; @@ -373,9 +401,41 @@ static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s) val = (adxl345_odr_tbl[odr][0] > max_boundary) ? min_boundary : max_boundary - adxl345_odr_tbl[odr][0]; + + st->inact_time_ms = MILLI * val; + + /* Inactivity time in s */ + ret = regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); + if (ret) + return ret; + + } 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); + + ret = regmap_write(st->regmap, ADXL345_REG_TIME_FF, + DIV_ROUND_CLOSEST(val_fract, 5)); + if (ret) + return ret; + } else if (val_int > 0) { + /* Time >= 1s, inactivity */ + st->inact_time_ms = MILLI * val_int; + + ret = regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int); + if (ret) + return ret; + } else { + /* Do not support negative or wrong input. */ + return -EINVAL; } - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); + return 0; } /** @@ -398,6 +458,9 @@ static int adxl345_is_act_inact_ac(struct adxl345_state *st, bool coupling; int ret; + if (type == ADXL345_INACTIVITY_FF) + return 1; + ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); if (ret) return ret; @@ -499,6 +562,9 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st, FIELD_GET(ADXL345_INACT_Y_EN, axis_ctrl) | FIELD_GET(ADXL345_INACT_Z_EN, axis_ctrl); break; + case ADXL345_INACTIVITY_FF: + en = true; + break; default: return -EINVAL; } @@ -537,15 +603,19 @@ static int adxl345_set_act_inact_linkbit(struct adxl345_state *st, act_en = act_en || 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; + } en = en && act_en && inact_en; @@ -559,7 +629,6 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, bool cmd_en) { bool en; - unsigned int inact_time_s; unsigned int threshold; u32 axis_ctrl; int ret; @@ -582,14 +651,16 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, if (type == ADXL345_ACTIVITY || type == ADXL345_ACTIVITY_AC) { axis_ctrl = ADXL345_ACT_X_EN | ADXL345_ACT_Y_EN | ADXL345_ACT_Z_EN; + + ret = regmap_read(st->regmap, adxl345_act_thresh_reg[type], &threshold); + if (ret) + return ret; } else { axis_ctrl = ADXL345_INACT_X_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_Z_EN; - } - ret = regmap_read(st->regmap, adxl345_act_thresh_reg[type], &threshold); - if (ret) - return ret; + threshold = st->inact_threshold; + } ret = regmap_assign_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL, axis_ctrl, cmd_en); @@ -610,12 +681,9 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, break; case ADXL345_INACTIVITY: case ADXL345_INACTIVITY_AC: - ret = regmap_read(st->regmap, ADXL345_REG_TIME_INACT, &inact_time_s); - if (ret) - return ret; - + case ADXL345_INACTIVITY_FF: en = FIELD_GET(ADXL345_REG_INACT_AXIS_MSK, axis_ctrl) && - threshold && inact_time_s; + threshold && st->inact_time_ms; break; default: return -EINVAL; @@ -873,7 +941,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, @@ -910,12 +978,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)); @@ -926,6 +988,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)); @@ -935,8 +998,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, @@ -1183,7 +1245,7 @@ static int adxl345_read_mag_value(struct adxl345_state *st, enum iio_event_info info, int *val, int *val2) { - unsigned int act_threshold, inact_threshold; + unsigned int act_threshold; int ret; switch (info) { @@ -1199,22 +1261,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], - &inact_threshold); - if (ret) - return ret; - *val = 62500 * inact_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, - val); - return IIO_VAL_INT; + *val = st->inact_time_ms; + *val2 = MILLI; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -1239,14 +1295,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; } @@ -1657,6 +1711,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) @@ -1888,15 +1953,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
Powered by blists - more mailing lists