|
8 | 8 | #include <linux/regmap.h>
|
9 | 9 | #include <linux/units.h>
|
10 | 10 |
|
| 11 | +#include <linux/iio/events.h> |
11 | 12 | #include <linux/iio/iio.h>
|
12 | 13 | #include <linux/iio/sysfs.h>
|
13 | 14 | #include <linux/iio/trigger.h>
|
|
28 | 29 | #define BMI270_ACCEL_X_REG 0x0c
|
29 | 30 | #define BMI270_ANG_VEL_X_REG 0x12
|
30 | 31 |
|
| 32 | +#define BMI270_INT_STATUS_0_REG 0x1c |
| 33 | +#define BMI270_INT_STATUS_0_STEP_CNT_MSK BIT(1) |
| 34 | + |
31 | 35 | #define BMI270_INT_STATUS_1_REG 0x1d
|
32 | 36 | #define BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK GENMASK(7, 6)
|
33 | 37 |
|
|
74 | 78 | #define BMI270_INT_LATCH_REG 0x55
|
75 | 79 | #define BMI270_INT_LATCH_REG_MSK BIT(0)
|
76 | 80 |
|
| 81 | +#define BMI270_INT1_MAP_FEAT_REG 0x56 |
| 82 | +#define BMI270_INT2_MAP_FEAT_REG 0x57 |
| 83 | +#define BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK BIT(1) |
| 84 | + |
77 | 85 | #define BMI270_INT_MAP_DATA_REG 0x58
|
78 | 86 | #define BMI270_INT_MAP_DATA_DRDY_INT1_MSK BIT(2)
|
79 | 87 | #define BMI270_INT_MAP_DATA_DRDY_INT2_MSK BIT(6)
|
|
94 | 102 | #define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2)
|
95 | 103 | #define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3)
|
96 | 104 |
|
| 105 | +#define BMI270_STEP_SC26_WTRMRK_MSK GENMASK(9, 0) |
97 | 106 | #define BMI270_STEP_SC26_RST_CNT_MSK BIT(10)
|
98 | 107 | #define BMI270_STEP_SC26_EN_CNT_MSK BIT(12)
|
99 | 108 |
|
100 | 109 | /* See datasheet section 4.6.14, Temperature Sensor */
|
101 | 110 | #define BMI270_TEMP_OFFSET 11776
|
102 | 111 | #define BMI270_TEMP_SCALE 1953125
|
103 | 112 |
|
| 113 | +/* See page 90 of datasheet. The step counter "holds implicitly a 20x factor" */ |
| 114 | +#define BMI270_STEP_COUNTER_FACTOR 20 |
| 115 | +#define BMI270_STEP_COUNTER_MAX 20460 |
| 116 | + |
104 | 117 | #define BMI260_INIT_DATA_FILE "bmi260-init-data.fw"
|
105 | 118 | #define BMI270_INIT_DATA_FILE "bmi270-init-data.fw"
|
106 | 119 |
|
@@ -396,6 +409,36 @@ static int bmi270_read_steps(struct bmi270_data *data, int *val)
|
396 | 409 | return IIO_VAL_INT;
|
397 | 410 | }
|
398 | 411 |
|
| 412 | +static int bmi270_int_map_reg(enum bmi270_irq_pin pin) |
| 413 | +{ |
| 414 | + switch (pin) { |
| 415 | + case BMI270_IRQ_INT1: |
| 416 | + return BMI270_INT1_MAP_FEAT_REG; |
| 417 | + case BMI270_IRQ_INT2: |
| 418 | + return BMI270_INT2_MAP_FEAT_REG; |
| 419 | + default: |
| 420 | + return -EINVAL; |
| 421 | + } |
| 422 | +} |
| 423 | + |
| 424 | +static int bmi270_step_wtrmrk_en(struct bmi270_data *data, bool state) |
| 425 | +{ |
| 426 | + int reg; |
| 427 | + |
| 428 | + guard(mutex)(&data->mutex); |
| 429 | + if (!data->steps_enabled) |
| 430 | + return -EINVAL; |
| 431 | + |
| 432 | + reg = bmi270_int_map_reg(data->irq_pin); |
| 433 | + if (reg < 0) |
| 434 | + return reg; |
| 435 | + |
| 436 | + return regmap_update_bits(data->regmap, reg, |
| 437 | + BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK, |
| 438 | + FIELD_PREP(BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK, |
| 439 | + state)); |
| 440 | +} |
| 441 | + |
399 | 442 | static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale)
|
400 | 443 | {
|
401 | 444 | int i;
|
@@ -552,19 +595,31 @@ static irqreturn_t bmi270_irq_thread_handler(int irq, void *private)
|
552 | 595 | {
|
553 | 596 | struct iio_dev *indio_dev = private;
|
554 | 597 | struct bmi270_data *data = iio_priv(indio_dev);
|
555 |
| - unsigned int status; |
| 598 | + unsigned int status0, status1; |
| 599 | + s64 timestamp = iio_get_time_ns(indio_dev); |
556 | 600 | int ret;
|
557 | 601 |
|
558 | 602 | scoped_guard(mutex, &data->mutex) {
|
| 603 | + ret = regmap_read(data->regmap, BMI270_INT_STATUS_0_REG, |
| 604 | + &status0); |
| 605 | + if (ret) |
| 606 | + return IRQ_NONE; |
| 607 | + |
559 | 608 | ret = regmap_read(data->regmap, BMI270_INT_STATUS_1_REG,
|
560 |
| - &status); |
| 609 | + &status1); |
561 | 610 | if (ret)
|
562 | 611 | return IRQ_NONE;
|
563 | 612 | }
|
564 | 613 |
|
565 |
| - if (FIELD_GET(BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK, status)) |
| 614 | + if (FIELD_GET(BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK, status1)) |
566 | 615 | iio_trigger_poll_nested(data->trig);
|
567 | 616 |
|
| 617 | + if (FIELD_GET(BMI270_INT_STATUS_0_STEP_CNT_MSK, status0)) |
| 618 | + iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0, |
| 619 | + IIO_EV_TYPE_CHANGE, |
| 620 | + IIO_EV_DIR_NONE), |
| 621 | + timestamp); |
| 622 | + |
568 | 623 | return IRQ_HANDLED;
|
569 | 624 | }
|
570 | 625 |
|
@@ -772,10 +827,116 @@ static int bmi270_read_avail(struct iio_dev *indio_dev,
|
772 | 827 | }
|
773 | 828 | }
|
774 | 829 |
|
| 830 | +static int bmi270_write_event_config(struct iio_dev *indio_dev, |
| 831 | + const struct iio_chan_spec *chan, |
| 832 | + enum iio_event_type type, |
| 833 | + enum iio_event_direction dir, bool state) |
| 834 | +{ |
| 835 | + struct bmi270_data *data = iio_priv(indio_dev); |
| 836 | + |
| 837 | + switch (type) { |
| 838 | + case IIO_EV_TYPE_CHANGE: |
| 839 | + return bmi270_step_wtrmrk_en(data, state); |
| 840 | + default: |
| 841 | + return -EINVAL; |
| 842 | + } |
| 843 | +} |
| 844 | + |
| 845 | +static int bmi270_read_event_config(struct iio_dev *indio_dev, |
| 846 | + const struct iio_chan_spec *chan, |
| 847 | + enum iio_event_type type, |
| 848 | + enum iio_event_direction dir) |
| 849 | +{ |
| 850 | + struct bmi270_data *data = iio_priv(indio_dev); |
| 851 | + int ret, reg, regval; |
| 852 | + |
| 853 | + guard(mutex)(&data->mutex); |
| 854 | + |
| 855 | + switch (chan->type) { |
| 856 | + case IIO_STEPS: |
| 857 | + reg = bmi270_int_map_reg(data->irq_pin); |
| 858 | + if (reg) |
| 859 | + return reg; |
| 860 | + |
| 861 | + ret = regmap_read(data->regmap, reg, ®val); |
| 862 | + if (ret) |
| 863 | + return ret; |
| 864 | + return FIELD_GET(BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK, |
| 865 | + regval) ? 1 : 0; |
| 866 | + default: |
| 867 | + return -EINVAL; |
| 868 | + } |
| 869 | +} |
| 870 | + |
| 871 | +static int bmi270_write_event_value(struct iio_dev *indio_dev, |
| 872 | + const struct iio_chan_spec *chan, |
| 873 | + enum iio_event_type type, |
| 874 | + enum iio_event_direction dir, |
| 875 | + enum iio_event_info info, |
| 876 | + int val, int val2) |
| 877 | +{ |
| 878 | + struct bmi270_data *data = iio_priv(indio_dev); |
| 879 | + unsigned int raw; |
| 880 | + |
| 881 | + guard(mutex)(&data->mutex); |
| 882 | + |
| 883 | + switch (type) { |
| 884 | + case IIO_EV_TYPE_CHANGE: |
| 885 | + if (!in_range(val, 0, BMI270_STEP_COUNTER_MAX + 1)) |
| 886 | + return -EINVAL; |
| 887 | + |
| 888 | + raw = val / BMI270_STEP_COUNTER_FACTOR; |
| 889 | + return bmi270_update_feature_reg(data, BMI270_SC_26_REG, |
| 890 | + BMI270_STEP_SC26_WTRMRK_MSK, |
| 891 | + FIELD_PREP(BMI270_STEP_SC26_WTRMRK_MSK, |
| 892 | + raw)); |
| 893 | + default: |
| 894 | + return -EINVAL; |
| 895 | + } |
| 896 | +} |
| 897 | + |
| 898 | +static int bmi270_read_event_value(struct iio_dev *indio_dev, |
| 899 | + const struct iio_chan_spec *chan, |
| 900 | + enum iio_event_type type, |
| 901 | + enum iio_event_direction dir, |
| 902 | + enum iio_event_info info, |
| 903 | + int *val, int *val2) |
| 904 | +{ |
| 905 | + struct bmi270_data *data = iio_priv(indio_dev); |
| 906 | + unsigned int raw; |
| 907 | + u16 regval; |
| 908 | + int ret; |
| 909 | + |
| 910 | + guard(mutex)(&data->mutex); |
| 911 | + |
| 912 | + switch (type) { |
| 913 | + case IIO_EV_TYPE_CHANGE: |
| 914 | + ret = bmi270_read_feature_reg(data, BMI270_SC_26_REG, ®val); |
| 915 | + if (ret) |
| 916 | + return ret; |
| 917 | + |
| 918 | + raw = FIELD_GET(BMI270_STEP_SC26_WTRMRK_MSK, regval); |
| 919 | + *val = raw * BMI270_STEP_COUNTER_FACTOR; |
| 920 | + return IIO_VAL_INT; |
| 921 | + default: |
| 922 | + return -EINVAL; |
| 923 | + } |
| 924 | +} |
| 925 | + |
| 926 | +static const struct iio_event_spec bmi270_step_wtrmrk_event = { |
| 927 | + .type = IIO_EV_TYPE_CHANGE, |
| 928 | + .dir = IIO_EV_DIR_NONE, |
| 929 | + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), |
| 930 | +}; |
| 931 | + |
775 | 932 | static const struct iio_info bmi270_info = {
|
776 | 933 | .read_raw = bmi270_read_raw,
|
777 | 934 | .write_raw = bmi270_write_raw,
|
778 | 935 | .read_avail = bmi270_read_avail,
|
| 936 | + .write_event_config = bmi270_write_event_config, |
| 937 | + .read_event_config = bmi270_read_event_config, |
| 938 | + .write_event_value = bmi270_write_event_value, |
| 939 | + .read_event_value = bmi270_read_event_value, |
779 | 940 | };
|
780 | 941 |
|
781 | 942 | #define BMI270_ACCEL_CHANNEL(_axis) { \
|
@@ -835,6 +996,8 @@ static const struct iio_chan_spec bmi270_channels[] = {
|
835 | 996 | .info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE) |
|
836 | 997 | BIT(IIO_CHAN_INFO_PROCESSED),
|
837 | 998 | .scan_index = -1, /* No buffer support */
|
| 999 | + .event_spec = &bmi270_step_wtrmrk_event, |
| 1000 | + .num_event_specs = 1, |
838 | 1001 | },
|
839 | 1002 | IIO_CHAN_SOFT_TIMESTAMP(BMI270_SCAN_TIMESTAMP),
|
840 | 1003 | };
|
|
0 commit comments