]> www.infradead.org Git - users/hch/misc.git/commitdiff
iio: accel: adxl345: add g-range configuration
authorLothar Rubusch <l.rubusch@gmail.com>
Sat, 10 May 2025 22:44:00 +0000 (22:44 +0000)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Mon, 9 Jun 2025 06:45:35 +0000 (07:45 +0100)
Introduce a mechanism to be able to configure and work with the available
g-ranges keeping the precision of 13 digits.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
Link: https://patch.msgid.link/20250510224405.17910-3-l.rubusch@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/accel/adxl345_core.c

index 760ee013e3e0292e6d3ef35be8461044bc035df1..95eb596b7d9698c0fc6135b84766c2afe3dcfa0d 100644 (file)
@@ -83,6 +83,13 @@ enum adxl345_odr {
        ADXL345_ODR_3200HZ,
 };
 
+enum adxl345_range {
+       ADXL345_2G_RANGE = 0,
+       ADXL345_4G_RANGE,
+       ADXL345_8G_RANGE,
+       ADXL345_16G_RANGE,
+};
+
 /* Certain features recommend 12.5 Hz - 400 Hz ODR */
 static const int adxl345_odr_tbl[][2] = {
        [ADXL345_ODR_0P10HZ]    = {    0,  97000 },
@@ -103,6 +110,25 @@ static const int adxl345_odr_tbl[][2] = {
        [ADXL345_ODR_3200HZ]    = { 3200, 0 },
 };
 
+/*
+ * Full resolution frequency table:
+ * (g * 2 * 9.80665) / (2^(resolution) - 1)
+ *
+ * resolution := 13 (full)
+ * g := 2|4|8|16
+ *
+ *  2g at 13bit: 0.004789
+ *  4g at 13bit: 0.009578
+ *  8g at 13bit: 0.019156
+ * 16g at 16bit: 0.038312
+ */
+static const int adxl345_fullres_range_tbl[][2] = {
+       [ADXL345_2G_RANGE]  = { 0, 4789 },
+       [ADXL345_4G_RANGE]  = { 0, 9578 },
+       [ADXL345_8G_RANGE]  = { 0, 19156 },
+       [ADXL345_16G_RANGE] = { 0, 38312 },
+};
+
 struct adxl345_state {
        const struct adxl345_chip_info *info;
        struct regmap *regmap;
@@ -146,7 +172,8 @@ static struct iio_event_spec adxl345_events[] = {
                BIT(IIO_CHAN_INFO_CALIBBIAS),                           \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |          \
                BIT(IIO_CHAN_INFO_SAMP_FREQ),                           \
-       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),             \
+       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \
+               BIT(IIO_CHAN_INFO_SAMP_FREQ),           \
        .scan_index = (index),                          \
        .scan_type = {                                  \
                .sign = 's',                            \
@@ -446,12 +473,40 @@ static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr)
                                 FIELD_PREP(ADXL345_BW_RATE_MSK, odr));
 }
 
+static int adxl345_find_range(struct adxl345_state *st, int val, int val2,
+                             enum adxl345_range *range)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adxl345_fullres_range_tbl); i++) {
+               if (val == adxl345_fullres_range_tbl[i][0] &&
+                   val2 == adxl345_fullres_range_tbl[i][1]) {
+                       *range = i;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range)
+{
+       return regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
+                                ADXL345_DATA_FORMAT_RANGE,
+                                FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range));
+}
+
 static int adxl345_read_avail(struct iio_dev *indio_dev,
                              struct iio_chan_spec const *chan,
                              const int **vals, int *type,
                              int *length, long mask)
 {
        switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               *vals = (int *)adxl345_fullres_range_tbl;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = ARRAY_SIZE(adxl345_fullres_range_tbl) * 2;
+               return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_SAMP_FREQ:
                *vals = (int *)adxl345_odr_tbl;
                *type = IIO_VAL_INT_PLUS_MICRO;
@@ -470,6 +525,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
        __le16 accel;
        unsigned int regval;
        enum adxl345_odr odr;
+       enum adxl345_range range;
        int ret;
 
        switch (mask) {
@@ -488,8 +544,12 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
                *val = sign_extend32(le16_to_cpu(accel), 12);
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
-               *val = 0;
-               *val2 = st->info->uscale;
+               ret = regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, &regval);
+               if (ret)
+                       return ret;
+               range = FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval);
+               *val = adxl345_fullres_range_tbl[range][0];
+               *val2 = adxl345_fullres_range_tbl[range][1];
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_CALIBBIAS:
                ret = regmap_read(st->regmap,
@@ -521,6 +581,7 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
                             int val, int val2, long mask)
 {
        struct adxl345_state *st = iio_priv(indio_dev);
+       enum adxl345_range range;
        enum adxl345_odr odr;
        int ret;
 
@@ -549,6 +610,15 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
                if (ret)
                        return ret;
                break;
+       case IIO_CHAN_INFO_SCALE:
+               ret = adxl345_find_range(st, val, val2, &range);
+               if (ret)
+                       return ret;
+
+               ret = adxl345_set_range(st, range);
+               if (ret)
+                       return ret;
+               break;
        default:
                return -EINVAL;
        }
@@ -741,6 +811,8 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
        switch (mask) {
        case IIO_CHAN_INFO_CALIBBIAS:
                return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_SAMP_FREQ:
                return IIO_VAL_INT_PLUS_MICRO;
        default:
@@ -1083,6 +1155,10 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
        if (ret)
                return ret;
 
+       ret = adxl345_set_range(st, ADXL345_16G_RANGE);
+       if (ret)
+               return ret;
+
        /* Reset interrupts at start up */
        ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
        if (ret)