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: imu: bmi270: Add scale and sampling frequency to BMI270 IMU

Add read and write functions and create _available entries.

Signed-off-by: Justin Weiss <justin@justinweiss.com>
Link: https://patch.msgid.link/20241027172029.160134-3-justin@justinweiss.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Justin Weiss and committed by
Jonathan Cameron
99e46bbb eaba902d

+339
+339
drivers/iio/imu/bmi270/bmi270_core.c
··· 7 7 #include <linux/regmap.h> 8 8 9 9 #include <linux/iio/iio.h> 10 + #include <linux/iio/sysfs.h> 10 11 #include <linux/iio/triggered_buffer.h> 11 12 #include <linux/iio/trigger_consumer.h> 12 13 ··· 34 33 #define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 35 34 #define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) 36 35 36 + #define BMI270_ACC_CONF_RANGE_REG 0x41 37 + #define BMI270_ACC_CONF_RANGE_MSK GENMASK(1, 0) 38 + 37 39 #define BMI270_GYR_CONF_REG 0x42 38 40 #define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) 39 41 #define BMI270_GYR_CONF_ODR_200HZ 0x09 ··· 44 40 #define BMI270_GYR_CONF_BWP_NORMAL_MODE 0x02 45 41 #define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) 46 42 #define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) 43 + 44 + #define BMI270_GYR_CONF_RANGE_REG 0x43 45 + #define BMI270_GYR_CONF_RANGE_MSK GENMASK(2, 0) 47 46 48 47 #define BMI270_INIT_CTRL_REG 0x59 49 48 #define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) ··· 92 85 .fw_name = BMI270_INIT_DATA_FILE, 93 86 }; 94 87 EXPORT_SYMBOL_NS_GPL(bmi270_chip_info, IIO_BMI270); 88 + 89 + enum bmi270_sensor_type { 90 + BMI270_ACCEL = 0, 91 + BMI270_GYRO, 92 + }; 93 + 94 + struct bmi270_scale { 95 + int scale; 96 + int uscale; 97 + }; 98 + 99 + struct bmi270_odr { 100 + int odr; 101 + int uodr; 102 + }; 103 + 104 + static const struct bmi270_scale bmi270_accel_scale[] = { 105 + { 0, 598 }, 106 + { 0, 1197 }, 107 + { 0, 2394 }, 108 + { 0, 4788 }, 109 + }; 110 + 111 + static const struct bmi270_scale bmi270_gyro_scale[] = { 112 + { 0, 1065 }, 113 + { 0, 532 }, 114 + { 0, 266 }, 115 + { 0, 133 }, 116 + { 0, 66 }, 117 + }; 118 + 119 + struct bmi270_scale_item { 120 + const struct bmi270_scale *tbl; 121 + int num; 122 + }; 123 + 124 + static const struct bmi270_scale_item bmi270_scale_table[] = { 125 + [BMI270_ACCEL] = { 126 + .tbl = bmi270_accel_scale, 127 + .num = ARRAY_SIZE(bmi270_accel_scale), 128 + }, 129 + [BMI270_GYRO] = { 130 + .tbl = bmi270_gyro_scale, 131 + .num = ARRAY_SIZE(bmi270_gyro_scale), 132 + }, 133 + }; 134 + 135 + static const struct bmi270_odr bmi270_accel_odr[] = { 136 + { 0, 781250 }, 137 + { 1, 562500 }, 138 + { 3, 125000 }, 139 + { 6, 250000 }, 140 + { 12, 500000 }, 141 + { 25, 0 }, 142 + { 50, 0 }, 143 + { 100, 0 }, 144 + { 200, 0 }, 145 + { 400, 0 }, 146 + { 800, 0 }, 147 + { 1600, 0 }, 148 + }; 149 + 150 + static const u8 bmi270_accel_odr_vals[] = { 151 + 0x01, 152 + 0x02, 153 + 0x03, 154 + 0x04, 155 + 0x05, 156 + 0x06, 157 + 0x07, 158 + 0x08, 159 + 0x09, 160 + 0x0A, 161 + 0x0B, 162 + 0x0C, 163 + }; 164 + 165 + static const struct bmi270_odr bmi270_gyro_odr[] = { 166 + { 25, 0 }, 167 + { 50, 0 }, 168 + { 100, 0 }, 169 + { 200, 0 }, 170 + { 400, 0 }, 171 + { 800, 0 }, 172 + { 1600, 0 }, 173 + { 3200, 0 }, 174 + }; 175 + 176 + static const u8 bmi270_gyro_odr_vals[] = { 177 + 0x06, 178 + 0x07, 179 + 0x08, 180 + 0x09, 181 + 0x0A, 182 + 0x0B, 183 + 0x0C, 184 + 0x0D, 185 + }; 186 + 187 + struct bmi270_odr_item { 188 + const struct bmi270_odr *tbl; 189 + const u8 *vals; 190 + int num; 191 + }; 192 + 193 + static const struct bmi270_odr_item bmi270_odr_table[] = { 194 + [BMI270_ACCEL] = { 195 + .tbl = bmi270_accel_odr, 196 + .vals = bmi270_accel_odr_vals, 197 + .num = ARRAY_SIZE(bmi270_accel_odr), 198 + }, 199 + [BMI270_GYRO] = { 200 + .tbl = bmi270_gyro_odr, 201 + .vals = bmi270_gyro_odr_vals, 202 + .num = ARRAY_SIZE(bmi270_gyro_odr), 203 + }, 204 + }; 205 + 206 + static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale) 207 + { 208 + int i; 209 + int reg, mask; 210 + struct bmi270_scale_item bmi270_scale_item; 211 + 212 + switch (chan_type) { 213 + case IIO_ACCEL: 214 + reg = BMI270_ACC_CONF_RANGE_REG; 215 + mask = BMI270_ACC_CONF_RANGE_MSK; 216 + bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL]; 217 + break; 218 + case IIO_ANGL_VEL: 219 + reg = BMI270_GYR_CONF_RANGE_REG; 220 + mask = BMI270_GYR_CONF_RANGE_MSK; 221 + bmi270_scale_item = bmi270_scale_table[BMI270_GYRO]; 222 + break; 223 + default: 224 + return -EINVAL; 225 + } 226 + 227 + for (i = 0; i < bmi270_scale_item.num; i++) { 228 + if (bmi270_scale_item.tbl[i].uscale != uscale) 229 + continue; 230 + 231 + return regmap_update_bits(data->regmap, reg, mask, i); 232 + } 233 + 234 + return -EINVAL; 235 + } 236 + 237 + static int bmi270_get_scale(struct bmi270_data *bmi270_device, int chan_type, 238 + int *uscale) 239 + { 240 + int ret; 241 + unsigned int val; 242 + struct bmi270_scale_item bmi270_scale_item; 243 + 244 + switch (chan_type) { 245 + case IIO_ACCEL: 246 + ret = regmap_read(bmi270_device->regmap, 247 + BMI270_ACC_CONF_RANGE_REG, &val); 248 + if (ret) 249 + return ret; 250 + 251 + val = FIELD_GET(BMI270_ACC_CONF_RANGE_MSK, val); 252 + bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL]; 253 + break; 254 + case IIO_ANGL_VEL: 255 + ret = regmap_read(bmi270_device->regmap, 256 + BMI270_GYR_CONF_RANGE_REG, &val); 257 + if (ret) 258 + return ret; 259 + 260 + val = FIELD_GET(BMI270_GYR_CONF_RANGE_MSK, val); 261 + bmi270_scale_item = bmi270_scale_table[BMI270_GYRO]; 262 + break; 263 + default: 264 + return -EINVAL; 265 + } 266 + 267 + if (val >= bmi270_scale_item.num) 268 + return -EINVAL; 269 + 270 + *uscale = bmi270_scale_item.tbl[val].uscale; 271 + return 0; 272 + } 273 + 274 + static int bmi270_set_odr(struct bmi270_data *data, int chan_type, int odr, 275 + int uodr) 276 + { 277 + int i; 278 + int reg, mask; 279 + struct bmi270_odr_item bmi270_odr_item; 280 + 281 + switch (chan_type) { 282 + case IIO_ACCEL: 283 + reg = BMI270_ACC_CONF_REG; 284 + mask = BMI270_ACC_CONF_ODR_MSK; 285 + bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL]; 286 + break; 287 + case IIO_ANGL_VEL: 288 + reg = BMI270_GYR_CONF_REG; 289 + mask = BMI270_GYR_CONF_ODR_MSK; 290 + bmi270_odr_item = bmi270_odr_table[BMI270_GYRO]; 291 + break; 292 + default: 293 + return -EINVAL; 294 + } 295 + 296 + for (i = 0; i < bmi270_odr_item.num; i++) { 297 + if (bmi270_odr_item.tbl[i].odr != odr || 298 + bmi270_odr_item.tbl[i].uodr != uodr) 299 + continue; 300 + 301 + return regmap_update_bits(data->regmap, reg, mask, 302 + bmi270_odr_item.vals[i]); 303 + } 304 + 305 + return -EINVAL; 306 + } 307 + 308 + static int bmi270_get_odr(struct bmi270_data *data, int chan_type, int *odr, 309 + int *uodr) 310 + { 311 + int i, val, ret; 312 + struct bmi270_odr_item bmi270_odr_item; 313 + 314 + switch (chan_type) { 315 + case IIO_ACCEL: 316 + ret = regmap_read(data->regmap, BMI270_ACC_CONF_REG, &val); 317 + if (ret) 318 + return ret; 319 + 320 + val = FIELD_GET(BMI270_ACC_CONF_ODR_MSK, val); 321 + bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL]; 322 + break; 323 + case IIO_ANGL_VEL: 324 + ret = regmap_read(data->regmap, BMI270_GYR_CONF_REG, &val); 325 + if (ret) 326 + return ret; 327 + 328 + val = FIELD_GET(BMI270_GYR_CONF_ODR_MSK, val); 329 + bmi270_odr_item = bmi270_odr_table[BMI270_GYRO]; 330 + break; 331 + default: 332 + return -EINVAL; 333 + } 334 + 335 + for (i = 0; i < bmi270_odr_item.num; i++) { 336 + if (val != bmi270_odr_item.vals[i]) 337 + continue; 338 + 339 + *odr = bmi270_odr_item.tbl[i].odr; 340 + *uodr = bmi270_odr_item.tbl[i].uodr; 341 + return 0; 342 + } 343 + 344 + return -EINVAL; 345 + } 95 346 96 347 static irqreturn_t bmi270_trigger_handler(int irq, void *p) 97 348 { ··· 413 148 return ret; 414 149 415 150 return IIO_VAL_INT; 151 + case IIO_CHAN_INFO_SCALE: 152 + *val = 0; 153 + ret = bmi270_get_scale(bmi270_device, chan->type, val2); 154 + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; 155 + case IIO_CHAN_INFO_SAMP_FREQ: 156 + ret = bmi270_get_odr(bmi270_device, chan->type, val, val2); 157 + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; 158 + default: 159 + return -EINVAL; 160 + } 161 + } 162 + 163 + static int bmi270_write_raw(struct iio_dev *indio_dev, 164 + struct iio_chan_spec const *chan, 165 + int val, int val2, long mask) 166 + { 167 + struct bmi270_data *data = iio_priv(indio_dev); 168 + 169 + switch (mask) { 170 + case IIO_CHAN_INFO_SCALE: 171 + return bmi270_set_scale(data, chan->type, val2); 172 + case IIO_CHAN_INFO_SAMP_FREQ: 173 + return bmi270_set_odr(data, chan->type, val, val2); 174 + default: 175 + return -EINVAL; 176 + } 177 + } 178 + 179 + static int bmi270_read_avail(struct iio_dev *indio_dev, 180 + struct iio_chan_spec const *chan, 181 + const int **vals, int *type, int *length, 182 + long mask) 183 + { 184 + switch (mask) { 185 + case IIO_CHAN_INFO_SCALE: 186 + *type = IIO_VAL_INT_PLUS_MICRO; 187 + switch (chan->type) { 188 + case IIO_ANGL_VEL: 189 + *vals = (const int *)bmi270_gyro_scale; 190 + *length = ARRAY_SIZE(bmi270_gyro_scale) * 2; 191 + return IIO_AVAIL_LIST; 192 + case IIO_ACCEL: 193 + *vals = (const int *)bmi270_accel_scale; 194 + *length = ARRAY_SIZE(bmi270_accel_scale) * 2; 195 + return IIO_AVAIL_LIST; 196 + default: 197 + return -EINVAL; 198 + } 199 + case IIO_CHAN_INFO_SAMP_FREQ: 200 + *type = IIO_VAL_INT_PLUS_MICRO; 201 + switch (chan->type) { 202 + case IIO_ANGL_VEL: 203 + *vals = (const int *)bmi270_gyro_odr; 204 + *length = ARRAY_SIZE(bmi270_gyro_odr) * 2; 205 + return IIO_AVAIL_LIST; 206 + case IIO_ACCEL: 207 + *vals = (const int *)bmi270_accel_odr; 208 + *length = ARRAY_SIZE(bmi270_accel_odr) * 2; 209 + return IIO_AVAIL_LIST; 210 + default: 211 + return -EINVAL; 212 + } 416 213 default: 417 214 return -EINVAL; 418 215 } ··· 482 155 483 156 static const struct iio_info bmi270_info = { 484 157 .read_raw = bmi270_read_raw, 158 + .write_raw = bmi270_write_raw, 159 + .read_avail = bmi270_read_avail, 485 160 }; 486 161 487 162 #define BMI270_ACCEL_CHANNEL(_axis) { \ ··· 491 162 .modified = 1, \ 492 163 .channel2 = IIO_MOD_##_axis, \ 493 164 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 165 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 166 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 167 + .info_mask_shared_by_type_available = \ 168 + BIT(IIO_CHAN_INFO_SCALE) | \ 169 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 494 170 .scan_index = BMI270_SCAN_ACCEL_##_axis, \ 495 171 .scan_type = { \ 496 172 .sign = 's', \ ··· 510 176 .modified = 1, \ 511 177 .channel2 = IIO_MOD_##_axis, \ 512 178 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 179 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 180 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 181 + .info_mask_shared_by_type_available = \ 182 + BIT(IIO_CHAN_INFO_SCALE) | \ 183 + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 513 184 .scan_index = BMI270_SCAN_GYRO_##_axis, \ 514 185 .scan_type = { \ 515 186 .sign = 's', \