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: adxl313: add inactivity sensing

Enhance the interrupt handler to process inactivity events. Introduce
functions to configure the threshold and period registers for
inactivity detection, as well as to enable or disable the inactivity
feature. Extend the fake IIO channel to handle inactivity events by
combining the x, y, and z axes using a logical AND operation.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/20250702230819.19353-6-l.rubusch@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Lothar Rubusch and committed by
Jonathan Cameron
e3fc1cad 385eb69e

+110 -2
+2
drivers/iio/accel/adxl313.h
··· 18 18 #define ADXL313_REG_SOFT_RESET 0x18 19 19 #define ADXL313_REG_OFS_AXIS(index) (0x1E + (index)) 20 20 #define ADXL313_REG_THRESH_ACT 0x24 21 + #define ADXL313_REG_THRESH_INACT 0x25 22 + #define ADXL313_REG_TIME_INACT 0x26 21 23 #define ADXL313_REG_ACT_INACT_CTL 0x27 22 24 #define ADXL313_REG_BW_RATE 0x2C 23 25 #define ADXL313_REG_POWER_CTL 0x2D
+108 -2
drivers/iio/accel/adxl313_core.c
··· 28 28 #define ADXL313_REG_XYZ_BASE ADXL313_REG_DATA_AXIS(0) 29 29 30 30 #define ADXL313_ACT_XYZ_EN GENMASK(6, 4) 31 + #define ADXL313_INACT_XYZ_EN GENMASK(2, 0) 31 32 32 33 /* activity/inactivity */ 33 34 enum adxl313_activity_type { 34 35 ADXL313_ACTIVITY, 36 + ADXL313_INACTIVITY, 35 37 }; 36 38 37 39 static const unsigned int adxl313_act_int_reg[] = { 38 40 [ADXL313_ACTIVITY] = ADXL313_INT_ACTIVITY, 41 + [ADXL313_INACTIVITY] = ADXL313_INT_INACTIVITY, 39 42 }; 40 43 41 44 static const unsigned int adxl313_act_thresh_reg[] = { 42 45 [ADXL313_ACTIVITY] = ADXL313_REG_THRESH_ACT, 46 + [ADXL313_INACTIVITY] = ADXL313_REG_THRESH_INACT, 43 47 }; 44 48 45 49 static const struct regmap_range adxl312_readable_reg_range[] = { ··· 257 253 }, 258 254 }; 259 255 256 + static const struct iio_event_spec adxl313_inactivity_events[] = { 257 + { 258 + /* inactivity */ 259 + .type = IIO_EV_TYPE_MAG, 260 + .dir = IIO_EV_DIR_FALLING, 261 + .mask_separate = BIT(IIO_EV_INFO_ENABLE), 262 + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | 263 + BIT(IIO_EV_INFO_PERIOD), 264 + }, 265 + }; 266 + 260 267 enum adxl313_chans { 261 268 chan_x, chan_y, chan_z, 262 269 }; ··· 283 268 .scan_index = -1, /* Fake channel for axis OR'ing */ 284 269 .event_spec = adxl313_activity_events, 285 270 .num_event_specs = ARRAY_SIZE(adxl313_activity_events), 271 + }, 272 + { 273 + .type = IIO_ACCEL, 274 + .modified = 1, 275 + .channel2 = IIO_MOD_X_AND_Y_AND_Z, 276 + .scan_index = -1, /* Fake channel for axis AND'ing */ 277 + .event_spec = adxl313_inactivity_events, 278 + .num_event_specs = ARRAY_SIZE(adxl313_inactivity_events), 286 279 }, 287 280 }; 288 281 ··· 354 331 } 355 332 } 356 333 334 + static int adxl313_set_inact_time_s(struct adxl313_data *data, 335 + unsigned int val_s) 336 + { 337 + unsigned int max_boundary = U8_MAX; /* by register size */ 338 + unsigned int val = min(val_s, max_boundary); 339 + 340 + return regmap_write(data->regmap, ADXL313_REG_TIME_INACT, val); 341 + } 342 + 357 343 static int adxl313_is_act_inact_en(struct adxl313_data *data, 358 344 enum adxl313_activity_type type) 359 345 { ··· 378 346 switch (type) { 379 347 case ADXL313_ACTIVITY: 380 348 if (!FIELD_GET(ADXL313_ACT_XYZ_EN, axis_ctrl)) 349 + return false; 350 + break; 351 + case ADXL313_INACTIVITY: 352 + if (!FIELD_GET(ADXL313_INACT_XYZ_EN, axis_ctrl)) 381 353 return false; 382 354 break; 383 355 default: ··· 402 366 { 403 367 unsigned int axis_ctrl; 404 368 unsigned int threshold; 369 + unsigned int inact_time_s; 405 370 int ret; 406 371 407 372 if (cmd_en) { ··· 414 377 415 378 if (!threshold) /* Just ignore the command if threshold is 0 */ 416 379 return 0; 380 + 381 + /* When turning on inactivity, check if inact time is valid */ 382 + if (type == ADXL313_INACTIVITY) { 383 + ret = regmap_read(data->regmap, 384 + ADXL313_REG_TIME_INACT, 385 + &inact_time_s); 386 + if (ret) 387 + return ret; 388 + 389 + if (!inact_time_s) 390 + return 0; 391 + } 417 392 } 418 393 419 394 /* Start modifying configuration registers */ ··· 437 388 switch (type) { 438 389 case ADXL313_ACTIVITY: 439 390 axis_ctrl = ADXL313_ACT_XYZ_EN; 391 + break; 392 + case ADXL313_INACTIVITY: 393 + axis_ctrl = ADXL313_INACT_XYZ_EN; 440 394 break; 441 395 default: 442 396 return -EINVAL; ··· 533 481 534 482 static int adxl313_read_mag_config(struct adxl313_data *data, 535 483 enum iio_event_direction dir, 536 - enum adxl313_activity_type type_act) 484 + enum adxl313_activity_type type_act, 485 + enum adxl313_activity_type type_inact) 537 486 { 538 487 switch (dir) { 539 488 case IIO_EV_DIR_RISING: 540 489 return !!adxl313_is_act_inact_en(data, type_act); 490 + case IIO_EV_DIR_FALLING: 491 + return !!adxl313_is_act_inact_en(data, type_inact); 541 492 default: 542 493 return -EINVAL; 543 494 } ··· 549 494 static int adxl313_write_mag_config(struct adxl313_data *data, 550 495 enum iio_event_direction dir, 551 496 enum adxl313_activity_type type_act, 497 + enum adxl313_activity_type type_inact, 552 498 bool state) 553 499 { 554 500 switch (dir) { 555 501 case IIO_EV_DIR_RISING: 556 502 return adxl313_set_act_inact_en(data, type_act, state); 503 + case IIO_EV_DIR_FALLING: 504 + return adxl313_set_act_inact_en(data, type_inact, state); 557 505 default: 558 506 return -EINVAL; 559 507 } ··· 572 514 switch (type) { 573 515 case IIO_EV_TYPE_MAG: 574 516 return adxl313_read_mag_config(data, dir, 575 - ADXL313_ACTIVITY); 517 + ADXL313_ACTIVITY, 518 + ADXL313_INACTIVITY); 576 519 default: 577 520 return -EINVAL; 578 521 } ··· 591 532 case IIO_EV_TYPE_MAG: 592 533 return adxl313_write_mag_config(data, dir, 593 534 ADXL313_ACTIVITY, 535 + ADXL313_INACTIVITY, 594 536 state); 595 537 default: 596 538 return -EINVAL; ··· 602 542 enum iio_event_direction dir, 603 543 enum iio_event_info info, 604 544 enum adxl313_activity_type type_act, 545 + enum adxl313_activity_type type_inact, 605 546 int *val, int *val2) 606 547 { 607 548 unsigned int threshold; 549 + unsigned int period; 608 550 int ret; 609 551 610 552 switch (info) { ··· 621 559 *val = threshold * 15625; 622 560 *val2 = MICRO; 623 561 return IIO_VAL_FRACTIONAL; 562 + case IIO_EV_DIR_FALLING: 563 + ret = regmap_read(data->regmap, 564 + adxl313_act_thresh_reg[type_inact], 565 + &threshold); 566 + if (ret) 567 + return ret; 568 + *val = threshold * 15625; 569 + *val2 = MICRO; 570 + return IIO_VAL_FRACTIONAL; 624 571 default: 625 572 return -EINVAL; 626 573 } 574 + case IIO_EV_INFO_PERIOD: 575 + ret = regmap_read(data->regmap, ADXL313_REG_TIME_INACT, 576 + &period); 577 + if (ret) 578 + return ret; 579 + *val = period; 580 + return IIO_VAL_INT; 627 581 default: 628 582 return -EINVAL; 629 583 } ··· 649 571 enum iio_event_direction dir, 650 572 enum iio_event_info info, 651 573 enum adxl313_activity_type type_act, 574 + enum adxl313_activity_type type_inact, 652 575 int val, int val2) 653 576 { 654 577 unsigned int regval; ··· 663 584 return regmap_write(data->regmap, 664 585 adxl313_act_thresh_reg[type_act], 665 586 regval); 587 + case IIO_EV_DIR_FALLING: 588 + return regmap_write(data->regmap, 589 + adxl313_act_thresh_reg[type_inact], 590 + regval); 666 591 default: 667 592 return -EINVAL; 668 593 } 594 + case IIO_EV_INFO_PERIOD: 595 + return adxl313_set_inact_time_s(data, val); 669 596 default: 670 597 return -EINVAL; 671 598 } ··· 690 605 case IIO_EV_TYPE_MAG: 691 606 return adxl313_read_mag_value(data, dir, info, 692 607 ADXL313_ACTIVITY, 608 + ADXL313_INACTIVITY, 693 609 val, val2); 694 610 default: 695 611 return -EINVAL; ··· 710 624 case IIO_EV_TYPE_MAG: 711 625 return adxl313_write_mag_value(data, dir, info, 712 626 ADXL313_ACTIVITY, 627 + ADXL313_INACTIVITY, 713 628 val, val2); 714 629 default: 715 630 return -EINVAL; ··· 866 779 IIO_MOD_X_OR_Y_OR_Z, 867 780 IIO_EV_TYPE_MAG, 868 781 IIO_EV_DIR_RISING), 782 + ts); 783 + if (ret) 784 + return ret; 785 + } 786 + 787 + if (FIELD_GET(ADXL313_INT_INACTIVITY, int_stat)) { 788 + ret = iio_push_event(indio_dev, 789 + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, 790 + IIO_MOD_X_AND_Y_AND_Z, 791 + IIO_EV_TYPE_MAG, 792 + IIO_EV_DIR_FALLING), 869 793 ts); 870 794 if (ret) 871 795 return ret; ··· 1084 986 * behavior if the interrupts are enabled. 1085 987 */ 1086 988 ret = regmap_write(data->regmap, ADXL313_REG_ACT_INACT_CTL, 0x00); 989 + if (ret) 990 + return ret; 991 + 992 + ret = regmap_write(data->regmap, ADXL313_REG_TIME_INACT, 5); 993 + if (ret) 994 + return ret; 995 + 996 + ret = regmap_write(data->regmap, ADXL313_REG_THRESH_INACT, 0x4f); 1087 997 if (ret) 1088 998 return ret; 1089 999