Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: accel: adxl345: add single tap feature

Add the single tap feature with a threshold in 62.5mg/LSB points and a
scaled duration in us. Keep singletap threshold in regmap cache but
the scaled value of duration in us as member variable.

Both use IIO channels for individual enable of the x/y/z axis. Initializes
threshold and duration with reasonable content. When an interrupt is
caught it will be pushed to the according IIO channel.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
Link: https://patch.msgid.link/20250414184245.100280-3-l.rubusch@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Lothar Rubusch and committed by
Jonathan Cameron
7478933f 5aec2b6e

+369 -3
+369 -3
drivers/iio/accel/adxl345_core.c
··· 8 8 */ 9 9 10 10 #include <linux/bitfield.h> 11 + #include <linux/bitops.h> 11 12 #include <linux/interrupt.h> 12 13 #include <linux/module.h> 13 14 #include <linux/property.h> ··· 18 17 #include <linux/iio/iio.h> 19 18 #include <linux/iio/sysfs.h> 20 19 #include <linux/iio/buffer.h> 20 + #include <linux/iio/events.h> 21 21 #include <linux/iio/kfifo_buf.h> 22 22 23 23 #include "adxl345.h" ··· 33 31 #define ADXL345_INT1 0 34 32 #define ADXL345_INT2 1 35 33 34 + #define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0) 35 + 36 + #define ADXL345_TAP_Z_EN BIT(0) 37 + #define ADXL345_TAP_Y_EN BIT(1) 38 + #define ADXL345_TAP_X_EN BIT(2) 39 + 40 + /* single/double tap */ 41 + enum adxl345_tap_type { 42 + ADXL345_SINGLE_TAP, 43 + }; 44 + 45 + static const unsigned int adxl345_tap_int_reg[] = { 46 + [ADXL345_SINGLE_TAP] = ADXL345_INT_SINGLE_TAP, 47 + }; 48 + 49 + enum adxl345_tap_time_type { 50 + ADXL345_TAP_TIME_DUR, 51 + }; 52 + 53 + static const unsigned int adxl345_tap_time_reg[] = { 54 + [ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR, 55 + }; 56 + 36 57 struct adxl345_state { 37 58 const struct adxl345_chip_info *info; 38 59 struct regmap *regmap; ··· 63 38 int irq; 64 39 u8 watermark; 65 40 u8 fifo_mode; 41 + 42 + u32 tap_duration_us; 43 + 66 44 __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN); 45 + }; 46 + 47 + static struct iio_event_spec adxl345_events[] = { 48 + { 49 + /* single tap */ 50 + .type = IIO_EV_TYPE_GESTURE, 51 + .dir = IIO_EV_DIR_SINGLETAP, 52 + .mask_separate = BIT(IIO_EV_INFO_ENABLE), 53 + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 54 + BIT(IIO_EV_INFO_TIMEOUT), 55 + }, 67 56 }; 68 57 69 58 #define ADXL345_CHANNEL(index, reg, axis) { \ ··· 96 57 .storagebits = 16, \ 97 58 .endianness = IIO_LE, \ 98 59 }, \ 60 + .event_spec = adxl345_events, \ 61 + .num_event_specs = ARRAY_SIZE(adxl345_events), \ 99 62 } 100 63 101 64 enum adxl345_chans { ··· 152 111 unsigned int val = en ? ADXL345_POWER_CTL_MEASURE : ADXL345_POWER_CTL_STANDBY; 153 112 154 113 return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val); 114 + } 115 + 116 + /* tap */ 117 + 118 + static int _adxl345_set_tap_int(struct adxl345_state *st, 119 + enum adxl345_tap_type type, bool state) 120 + { 121 + unsigned int int_map = 0x00; 122 + unsigned int tap_threshold; 123 + bool axis_valid; 124 + bool singletap_args_valid = false; 125 + bool en = false; 126 + u32 axis_ctrl; 127 + int ret; 128 + 129 + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); 130 + if (ret) 131 + return ret; 132 + 133 + axis_valid = FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) > 0; 134 + 135 + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, &tap_threshold); 136 + if (ret) 137 + return ret; 138 + 139 + /* 140 + * Note: A value of 0 for threshold and/or dur may result in undesirable 141 + * behavior if single tap/double tap interrupts are enabled. 142 + */ 143 + singletap_args_valid = tap_threshold > 0 && st->tap_duration_us > 0; 144 + 145 + if (type == ADXL345_SINGLE_TAP) 146 + en = axis_valid && singletap_args_valid; 147 + 148 + if (state && en) 149 + int_map |= adxl345_tap_int_reg[type]; 150 + 151 + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, 152 + adxl345_tap_int_reg[type], int_map); 153 + } 154 + 155 + static int adxl345_is_tap_en(struct adxl345_state *st, 156 + enum iio_modifier axis, 157 + enum adxl345_tap_type type, bool *en) 158 + { 159 + unsigned int regval; 160 + u32 axis_ctrl; 161 + int ret; 162 + 163 + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); 164 + if (ret) 165 + return ret; 166 + 167 + /* Verify if axis is enabled for the tap detection. */ 168 + switch (axis) { 169 + case IIO_MOD_X: 170 + *en = FIELD_GET(ADXL345_TAP_X_EN, axis_ctrl); 171 + break; 172 + case IIO_MOD_Y: 173 + *en = FIELD_GET(ADXL345_TAP_Y_EN, axis_ctrl); 174 + break; 175 + case IIO_MOD_Z: 176 + *en = FIELD_GET(ADXL345_TAP_Z_EN, axis_ctrl); 177 + break; 178 + default: 179 + *en = false; 180 + return -EINVAL; 181 + } 182 + 183 + if (*en) { 184 + /* 185 + * If axis allow for tap detection, verify if the interrupt is 186 + * enabled for tap detection. 187 + */ 188 + ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, &regval); 189 + if (ret) 190 + return ret; 191 + 192 + *en = adxl345_tap_int_reg[type] & regval; 193 + } 194 + 195 + return 0; 196 + } 197 + 198 + static int adxl345_set_singletap_en(struct adxl345_state *st, 199 + enum iio_modifier axis, bool en) 200 + { 201 + int ret; 202 + u32 axis_ctrl; 203 + 204 + switch (axis) { 205 + case IIO_MOD_X: 206 + axis_ctrl = ADXL345_TAP_X_EN; 207 + break; 208 + case IIO_MOD_Y: 209 + axis_ctrl = ADXL345_TAP_Y_EN; 210 + break; 211 + case IIO_MOD_Z: 212 + axis_ctrl = ADXL345_TAP_Z_EN; 213 + break; 214 + default: 215 + return -EINVAL; 216 + } 217 + 218 + if (en) 219 + ret = regmap_set_bits(st->regmap, ADXL345_REG_TAP_AXIS, 220 + axis_ctrl); 221 + else 222 + ret = regmap_clear_bits(st->regmap, ADXL345_REG_TAP_AXIS, 223 + axis_ctrl); 224 + if (ret) 225 + return ret; 226 + 227 + return _adxl345_set_tap_int(st, ADXL345_SINGLE_TAP, en); 228 + } 229 + 230 + static int _adxl345_set_tap_time(struct adxl345_state *st, 231 + enum adxl345_tap_time_type type, u32 val_us) 232 + { 233 + unsigned int regval; 234 + 235 + switch (type) { 236 + case ADXL345_TAP_TIME_DUR: 237 + st->tap_duration_us = val_us; 238 + break; 239 + } 240 + 241 + /* 242 + * The scale factor is 1250us / LSB for tap_window_us and tap_latent_us. 243 + * For tap_duration_us the scale factor is 625us / LSB. 244 + */ 245 + if (type == ADXL345_TAP_TIME_DUR) 246 + regval = DIV_ROUND_CLOSEST(val_us, 625); 247 + else 248 + regval = DIV_ROUND_CLOSEST(val_us, 1250); 249 + 250 + return regmap_write(st->regmap, adxl345_tap_time_reg[type], regval); 251 + } 252 + 253 + static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int, 254 + u32 val_fract_us) 255 + { 256 + /* 257 + * Max value is 255 * 625 us = 0.159375 seconds 258 + * 259 + * Note: the scaling is similar to the scaling in the ADXL380 260 + */ 261 + if (val_int || val_fract_us > 159375) 262 + return -EINVAL; 263 + 264 + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_DUR, val_fract_us); 155 265 } 156 266 157 267 static int adxl345_read_raw(struct iio_dev *indio_dev, ··· 388 196 } 389 197 390 198 return -EINVAL; 199 + } 200 + 201 + static int adxl345_read_event_config(struct iio_dev *indio_dev, 202 + const struct iio_chan_spec *chan, 203 + enum iio_event_type type, 204 + enum iio_event_direction dir) 205 + { 206 + struct adxl345_state *st = iio_priv(indio_dev); 207 + bool int_en; 208 + int ret; 209 + 210 + switch (type) { 211 + case IIO_EV_TYPE_GESTURE: 212 + switch (dir) { 213 + case IIO_EV_DIR_SINGLETAP: 214 + ret = adxl345_is_tap_en(st, chan->channel2, 215 + ADXL345_SINGLE_TAP, &int_en); 216 + if (ret) 217 + return ret; 218 + return int_en; 219 + default: 220 + return -EINVAL; 221 + } 222 + default: 223 + return -EINVAL; 224 + } 225 + } 226 + 227 + static int adxl345_write_event_config(struct iio_dev *indio_dev, 228 + const struct iio_chan_spec *chan, 229 + enum iio_event_type type, 230 + enum iio_event_direction dir, 231 + bool state) 232 + { 233 + struct adxl345_state *st = iio_priv(indio_dev); 234 + 235 + switch (type) { 236 + case IIO_EV_TYPE_GESTURE: 237 + switch (dir) { 238 + case IIO_EV_DIR_SINGLETAP: 239 + return adxl345_set_singletap_en(st, chan->channel2, state); 240 + default: 241 + return -EINVAL; 242 + } 243 + default: 244 + return -EINVAL; 245 + } 246 + } 247 + 248 + static int adxl345_read_event_value(struct iio_dev *indio_dev, 249 + const struct iio_chan_spec *chan, 250 + enum iio_event_type type, 251 + enum iio_event_direction dir, 252 + enum iio_event_info info, 253 + int *val, int *val2) 254 + { 255 + struct adxl345_state *st = iio_priv(indio_dev); 256 + unsigned int tap_threshold; 257 + int ret; 258 + 259 + switch (type) { 260 + case IIO_EV_TYPE_GESTURE: 261 + switch (info) { 262 + case IIO_EV_INFO_VALUE: 263 + /* 264 + * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but 265 + * not applied here. In context of this general purpose sensor, 266 + * what imports is rather signal intensity than the absolute 267 + * measured g value. 268 + */ 269 + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, 270 + &tap_threshold); 271 + if (ret) 272 + return ret; 273 + *val = sign_extend32(tap_threshold, 7); 274 + return IIO_VAL_INT; 275 + case IIO_EV_INFO_TIMEOUT: 276 + *val = st->tap_duration_us; 277 + *val2 = 1000000; 278 + return IIO_VAL_FRACTIONAL; 279 + default: 280 + return -EINVAL; 281 + } 282 + default: 283 + return -EINVAL; 284 + } 285 + } 286 + 287 + static int adxl345_write_event_value(struct iio_dev *indio_dev, 288 + const struct iio_chan_spec *chan, 289 + enum iio_event_type type, 290 + enum iio_event_direction dir, 291 + enum iio_event_info info, 292 + int val, int val2) 293 + { 294 + struct adxl345_state *st = iio_priv(indio_dev); 295 + int ret; 296 + 297 + ret = adxl345_set_measure_en(st, false); 298 + if (ret) 299 + return ret; 300 + 301 + switch (type) { 302 + case IIO_EV_TYPE_GESTURE: 303 + switch (info) { 304 + case IIO_EV_INFO_VALUE: 305 + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, 306 + min(val, 0xFF)); 307 + if (ret) 308 + return ret; 309 + break; 310 + case IIO_EV_INFO_TIMEOUT: 311 + ret = adxl345_set_tap_duration(st, val, val2); 312 + if (ret) 313 + return ret; 314 + break; 315 + default: 316 + return -EINVAL; 317 + } 318 + break; 319 + default: 320 + return -EINVAL; 321 + } 322 + 323 + return adxl345_set_measure_en(st, true); 391 324 } 392 325 393 326 static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg, ··· 733 416 return 0; 734 417 } 735 418 736 - static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat) 419 + static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, 420 + enum iio_modifier tap_dir) 737 421 { 422 + s64 ts = iio_get_time_ns(indio_dev); 738 423 struct adxl345_state *st = iio_priv(indio_dev); 739 424 int samples; 425 + int ret = -ENOENT; 426 + 427 + if (FIELD_GET(ADXL345_INT_SINGLE_TAP, int_stat)) { 428 + ret = iio_push_event(indio_dev, 429 + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir, 430 + IIO_EV_TYPE_GESTURE, 431 + IIO_EV_DIR_SINGLETAP), 432 + ts); 433 + if (ret) 434 + return ret; 435 + } 740 436 741 437 if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { 742 438 samples = adxl345_get_samples(st); ··· 758 428 759 429 if (adxl345_fifo_push(indio_dev, samples) < 0) 760 430 return -EINVAL; 431 + 432 + ret = 0; 761 433 } 762 434 763 - return 0; 435 + return ret; 764 436 } 765 437 766 438 /** ··· 776 444 { 777 445 struct iio_dev *indio_dev = p; 778 446 struct adxl345_state *st = iio_priv(indio_dev); 447 + unsigned int regval; 448 + enum iio_modifier tap_dir = IIO_NO_MOD; 449 + u32 axis_ctrl; 779 450 int int_stat; 451 + int ret; 452 + 453 + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); 454 + if (ret) 455 + return IRQ_NONE; 456 + 457 + if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl)) { 458 + ret = regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, &regval); 459 + if (ret) 460 + return IRQ_NONE; 461 + 462 + if (FIELD_GET(ADXL345_TAP_Z_EN, regval)) 463 + tap_dir = IIO_MOD_Z; 464 + else if (FIELD_GET(ADXL345_TAP_Y_EN, regval)) 465 + tap_dir = IIO_MOD_Y; 466 + else if (FIELD_GET(ADXL345_TAP_X_EN, regval)) 467 + tap_dir = IIO_MOD_X; 468 + } 780 469 781 470 if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat)) 782 471 return IRQ_NONE; 783 472 784 - if (adxl345_push_event(indio_dev, int_stat)) 473 + if (adxl345_push_event(indio_dev, int_stat, tap_dir)) 785 474 goto err; 786 475 787 476 if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat)) ··· 821 468 .read_raw = adxl345_read_raw, 822 469 .write_raw = adxl345_write_raw, 823 470 .write_raw_get_fmt = adxl345_write_raw_get_fmt, 471 + .read_event_config = adxl345_read_event_config, 472 + .write_event_config = adxl345_write_event_config, 473 + .read_event_value = adxl345_read_event_value, 474 + .write_event_value = adxl345_write_event_value, 824 475 .debugfs_reg_access = &adxl345_reg_access, 825 476 .hwfifo_set_watermark = adxl345_set_watermark, 826 477 }; ··· 858 501 ADXL345_DATA_FORMAT_JUSTIFY | 859 502 ADXL345_DATA_FORMAT_FULL_RES | 860 503 ADXL345_DATA_FORMAT_SELF_TEST); 504 + unsigned int tap_threshold; 861 505 int ret; 862 506 863 507 indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); ··· 871 513 if (!st->info) 872 514 return -ENODEV; 873 515 st->fifo_delay = fifo_delay_default; 516 + 517 + /* Init with reasonable values */ 518 + tap_threshold = 48; /* 48 [0x30] -> ~3g */ 519 + st->tap_duration_us = 16; /* 16 [0x10] -> .010 */ 874 520 875 521 indio_dev->name = st->info->name; 876 522 indio_dev->info = &adxl345_info; ··· 945 583 regval = intio ? 0xff : 0; 946 584 947 585 ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, regval); 586 + if (ret) 587 + return ret; 588 + 589 + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); 948 590 if (ret) 949 591 return ret; 950 592