]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iio: imu: bmi270: add channel for step counter
authorGustavo Silva <gustavograzs@gmail.com>
Mon, 16 Jun 2025 23:53:09 +0000 (20:53 -0300)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 6 Jul 2025 09:37:50 +0000 (10:37 +0100)
Add a channel for enabling/disabling the step counter, reading the
number of steps and resetting the counter.

Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
Link: https://patch.msgid.link/20250616-bmi270-events-v3-1-16e37588604f@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/imu/bmi270/bmi270_core.c

index b54658f972ad2bd673de1acd19b7132926ec8640..e369151bd713b0256a6b8598d7fe1ba73409bc07 100644 (file)
@@ -31,6 +31,8 @@
 #define BMI270_INT_STATUS_1_REG                                0x1d
 #define BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK           GENMASK(7, 6)
 
+#define BMI270_SC_OUT_0_REG                            0x1e
+
 #define BMI270_INTERNAL_STATUS_REG                     0x21
 #define BMI270_INTERNAL_STATUS_MSG_MSK                 GENMASK(3, 0)
 #define BMI270_INTERNAL_STATUS_MSG_INIT_OK             0x01
@@ -39,6 +41,8 @@
 
 #define BMI270_TEMPERATURE_0_REG                       0x22
 
+#define BMI270_FEAT_PAGE_REG                           0x2f
+
 #define BMI270_ACC_CONF_REG                            0x40
 #define BMI270_ACC_CONF_ODR_MSK                                GENMASK(3, 0)
 #define BMI270_ACC_CONF_ODR_100HZ                      0x08
@@ -90,6 +94,9 @@
 #define BMI270_PWR_CTRL_ACCEL_EN_MSK                   BIT(2)
 #define BMI270_PWR_CTRL_TEMP_EN_MSK                    BIT(3)
 
+#define BMI270_STEP_SC26_RST_CNT_MSK                   BIT(10)
+#define BMI270_STEP_SC26_EN_CNT_MSK                    BIT(12)
+
 /* See datasheet section 4.6.14, Temperature Sensor */
 #define BMI270_TEMP_OFFSET                             11776
 #define BMI270_TEMP_SCALE                              1953125
@@ -111,6 +118,7 @@ struct bmi270_data {
        struct iio_trigger *trig;
         /* Protect device's private data from concurrent access */
        struct mutex mutex;
+       bool steps_enabled;
 
        /*
         * Where IIO_DMA_MINALIGN may be larger than 8 bytes, align to
@@ -120,6 +128,11 @@ struct bmi270_data {
                __le16 channels[6];
                aligned_s64 timestamp;
        } buffer __aligned(IIO_DMA_MINALIGN);
+       /*
+        * Variable to access feature registers. It can be accessed concurrently
+        * with the 'buffer' variable
+        */
+       __le16 regval __aligned(IIO_DMA_MINALIGN);
 };
 
 enum bmi270_scan {
@@ -282,6 +295,107 @@ static const struct  bmi270_odr_item bmi270_odr_table[] = {
        },
 };
 
+enum bmi270_feature_reg_id {
+       BMI270_SC_26_REG,
+};
+
+struct bmi270_feature_reg {
+       u8 page;
+       u8 addr;
+};
+
+static const struct bmi270_feature_reg bmi270_feature_regs[] = {
+       [BMI270_SC_26_REG] = {
+               .page = 6,
+               .addr = 0x32,
+       },
+};
+
+static int bmi270_write_feature_reg(struct bmi270_data *data,
+                                   enum bmi270_feature_reg_id id,
+                                   u16 val)
+{
+       const struct bmi270_feature_reg *reg = &bmi270_feature_regs[id];
+       int ret;
+
+       ret = regmap_write(data->regmap, BMI270_FEAT_PAGE_REG, reg->page);
+       if (ret)
+               return ret;
+
+       data->regval = cpu_to_le16(val);
+       return regmap_bulk_write(data->regmap, reg->addr, &data->regval,
+                                sizeof(data->regval));
+}
+
+static int bmi270_read_feature_reg(struct bmi270_data *data,
+                                  enum bmi270_feature_reg_id id,
+                                  u16 *val)
+{
+       const struct bmi270_feature_reg *reg = &bmi270_feature_regs[id];
+       int ret;
+
+       ret = regmap_write(data->regmap, BMI270_FEAT_PAGE_REG, reg->page);
+       if (ret)
+               return ret;
+
+       ret = regmap_bulk_read(data->regmap, reg->addr, &data->regval,
+                              sizeof(data->regval));
+       if (ret)
+               return ret;
+
+       *val = le16_to_cpu(data->regval);
+       return 0;
+}
+
+static int bmi270_update_feature_reg(struct bmi270_data *data,
+                                    enum bmi270_feature_reg_id id,
+                                    u16 mask, u16 val)
+{
+       u16 regval;
+       int ret;
+
+       ret = bmi270_read_feature_reg(data, id, &regval);
+       if (ret)
+               return ret;
+
+       regval = (regval & ~mask) | (val & mask);
+
+       return bmi270_write_feature_reg(data, id, regval);
+}
+
+static int bmi270_enable_steps(struct bmi270_data *data, int val)
+{
+       int ret;
+
+       guard(mutex)(&data->mutex);
+       if (data->steps_enabled)
+               return 0;
+
+       ret = bmi270_update_feature_reg(data, BMI270_SC_26_REG,
+                                       BMI270_STEP_SC26_EN_CNT_MSK,
+                                       FIELD_PREP(BMI270_STEP_SC26_EN_CNT_MSK,
+                                                  val ? 1 : 0));
+       if (ret)
+               return ret;
+
+       data->steps_enabled = true;
+       return 0;
+}
+
+static int bmi270_read_steps(struct bmi270_data *data, int *val)
+{
+       __le16 steps_count;
+       int ret;
+
+       ret = regmap_bulk_read(data->regmap, BMI270_SC_OUT_0_REG, &steps_count,
+                              sizeof(steps_count));
+       if (ret)
+               return ret;
+
+       *val = sign_extend32(le16_to_cpu(steps_count), 15);
+       return IIO_VAL_INT;
+}
+
 static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale)
 {
        int i;
@@ -551,6 +665,8 @@ static int bmi270_read_raw(struct iio_dev *indio_dev,
        struct bmi270_data *data = iio_priv(indio_dev);
 
        switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               return bmi270_read_steps(data, val);
        case IIO_CHAN_INFO_RAW:
                if (!iio_device_claim_direct(indio_dev))
                        return -EBUSY;
@@ -571,6 +687,9 @@ static int bmi270_read_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SAMP_FREQ:
                ret = bmi270_get_odr(data, chan->type, val, val2);
                return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_ENABLE:
+               *val = data->steps_enabled ? 1 : 0;
+               return IIO_VAL_INT;
        default:
                return -EINVAL;
        }
@@ -596,6 +715,19 @@ static int bmi270_write_raw(struct iio_dev *indio_dev,
                ret = bmi270_set_odr(data, chan->type, val, val2);
                iio_device_release_direct(indio_dev);
                return ret;
+       case IIO_CHAN_INFO_ENABLE:
+               return bmi270_enable_steps(data, val);
+       case IIO_CHAN_INFO_PROCESSED: {
+               if (val || !data->steps_enabled)
+                       return -EINVAL;
+
+               guard(mutex)(&data->mutex);
+               /* Clear step counter value */
+               return bmi270_update_feature_reg(data, BMI270_SC_26_REG,
+                                                BMI270_STEP_SC26_RST_CNT_MSK,
+                                                FIELD_PREP(BMI270_STEP_SC26_RST_CNT_MSK,
+                                                           1));
+       }
        default:
                return -EINVAL;
        }
@@ -698,6 +830,12 @@ static const struct iio_chan_spec bmi270_channels[] = {
                                      BIT(IIO_CHAN_INFO_OFFSET),
                .scan_index = -1, /* No buffer support */
        },
+       {
+               .type = IIO_STEPS,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE) |
+                                     BIT(IIO_CHAN_INFO_PROCESSED),
+               .scan_index = -1, /* No buffer support */
+       },
        IIO_CHAN_SOFT_TIMESTAMP(BMI270_SCAN_TIMESTAMP),
 };