0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/bitfield.h>
0010 #include <linux/delay.h>
0011 #include <linux/iio/iio.h>
0012 #include <linux/iio/sysfs.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/module.h>
0015 #include <linux/pm.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/regmap.h>
0018 #include <linux/slab.h>
0019 #include <asm/unaligned.h>
0020
0021 #include "bmi088-accel.h"
0022
0023 #define BMI088_ACCEL_REG_CHIP_ID 0x00
0024 #define BMI088_ACCEL_REG_ERROR 0x02
0025
0026 #define BMI088_ACCEL_REG_INT_STATUS 0x1D
0027 #define BMI088_ACCEL_INT_STATUS_BIT_DRDY BIT(7)
0028
0029 #define BMI088_ACCEL_REG_RESET 0x7E
0030 #define BMI088_ACCEL_RESET_VAL 0xB6
0031
0032 #define BMI088_ACCEL_REG_PWR_CTRL 0x7D
0033 #define BMI088_ACCEL_REG_PWR_CONF 0x7C
0034
0035 #define BMI088_ACCEL_REG_INT_MAP_DATA 0x58
0036 #define BMI088_ACCEL_INT_MAP_DATA_BIT_INT1_DRDY BIT(2)
0037 #define BMI088_ACCEL_INT_MAP_DATA_BIT_INT2_FWM BIT(5)
0038
0039 #define BMI088_ACCEL_REG_INT1_IO_CONF 0x53
0040 #define BMI088_ACCEL_INT1_IO_CONF_BIT_ENABLE_OUT BIT(3)
0041 #define BMI088_ACCEL_INT1_IO_CONF_BIT_LVL BIT(1)
0042
0043 #define BMI088_ACCEL_REG_INT2_IO_CONF 0x54
0044 #define BMI088_ACCEL_INT2_IO_CONF_BIT_ENABLE_OUT BIT(3)
0045 #define BMI088_ACCEL_INT2_IO_CONF_BIT_LVL BIT(1)
0046
0047 #define BMI088_ACCEL_REG_ACC_CONF 0x40
0048 #define BMI088_ACCEL_MODE_ODR_MASK 0x0f
0049
0050 #define BMI088_ACCEL_REG_ACC_RANGE 0x41
0051 #define BMI088_ACCEL_RANGE_3G 0x00
0052 #define BMI088_ACCEL_RANGE_6G 0x01
0053 #define BMI088_ACCEL_RANGE_12G 0x02
0054 #define BMI088_ACCEL_RANGE_24G 0x03
0055
0056 #define BMI088_ACCEL_REG_TEMP 0x22
0057 #define BMI088_ACCEL_REG_TEMP_SHIFT 5
0058 #define BMI088_ACCEL_TEMP_UNIT 125
0059 #define BMI088_ACCEL_TEMP_OFFSET 23000
0060
0061 #define BMI088_ACCEL_REG_XOUT_L 0x12
0062 #define BMI088_ACCEL_AXIS_TO_REG(axis) \
0063 (BMI088_ACCEL_REG_XOUT_L + (axis * 2))
0064
0065 #define BMI088_ACCEL_MAX_STARTUP_TIME_US 1000
0066 #define BMI088_AUTO_SUSPEND_DELAY_MS 2000
0067
0068 #define BMI088_ACCEL_REG_FIFO_STATUS 0x0E
0069 #define BMI088_ACCEL_REG_FIFO_CONFIG0 0x48
0070 #define BMI088_ACCEL_REG_FIFO_CONFIG1 0x49
0071 #define BMI088_ACCEL_REG_FIFO_DATA 0x3F
0072 #define BMI088_ACCEL_FIFO_LENGTH 100
0073
0074 #define BMI088_ACCEL_FIFO_MODE_FIFO 0x40
0075 #define BMI088_ACCEL_FIFO_MODE_STREAM 0x80
0076
0077 #define BMIO088_ACCEL_ACC_RANGE_MSK GENMASK(1, 0)
0078
0079 enum bmi088_accel_axis {
0080 AXIS_X,
0081 AXIS_Y,
0082 AXIS_Z,
0083 };
0084
0085 static const int bmi088_sample_freqs[] = {
0086 12, 500000,
0087 25, 0,
0088 50, 0,
0089 100, 0,
0090 200, 0,
0091 400, 0,
0092 800, 0,
0093 1600, 0,
0094 };
0095
0096
0097 enum bmi088_osr_modes {
0098 BMI088_ACCEL_MODE_OSR_NORMAL = 0xA,
0099 BMI088_ACCEL_MODE_OSR_2 = 0x9,
0100 BMI088_ACCEL_MODE_OSR_4 = 0x8,
0101 };
0102
0103
0104 enum bmi088_odr_modes {
0105 BMI088_ACCEL_MODE_ODR_12_5 = 0x5,
0106 BMI088_ACCEL_MODE_ODR_25 = 0x6,
0107 BMI088_ACCEL_MODE_ODR_50 = 0x7,
0108 BMI088_ACCEL_MODE_ODR_100 = 0x8,
0109 BMI088_ACCEL_MODE_ODR_200 = 0x9,
0110 BMI088_ACCEL_MODE_ODR_400 = 0xa,
0111 BMI088_ACCEL_MODE_ODR_800 = 0xb,
0112 BMI088_ACCEL_MODE_ODR_1600 = 0xc,
0113 };
0114
0115 struct bmi088_scale_info {
0116 int scale;
0117 u8 reg_range;
0118 };
0119
0120 struct bmi088_accel_chip_info {
0121 const char *name;
0122 u8 chip_id;
0123 const struct iio_chan_spec *channels;
0124 int num_channels;
0125 const int scale_table[4][2];
0126 };
0127
0128 struct bmi088_accel_data {
0129 struct regmap *regmap;
0130 const struct bmi088_accel_chip_info *chip_info;
0131 u8 buffer[2] __aligned(IIO_DMA_MINALIGN);
0132 };
0133
0134 static const struct regmap_range bmi088_volatile_ranges[] = {
0135
0136 regmap_reg_range(BMI088_ACCEL_REG_ERROR, 0x3f),
0137
0138 regmap_reg_range(BMI088_ACCEL_REG_RESET, BMI088_ACCEL_REG_RESET),
0139 };
0140
0141 static const struct regmap_access_table bmi088_volatile_table = {
0142 .yes_ranges = bmi088_volatile_ranges,
0143 .n_yes_ranges = ARRAY_SIZE(bmi088_volatile_ranges),
0144 };
0145
0146 const struct regmap_config bmi088_regmap_conf = {
0147 .reg_bits = 8,
0148 .val_bits = 8,
0149 .max_register = 0x7E,
0150 .volatile_table = &bmi088_volatile_table,
0151 .cache_type = REGCACHE_RBTREE,
0152 };
0153 EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, IIO_BMI088);
0154
0155 static int bmi088_accel_power_up(struct bmi088_accel_data *data)
0156 {
0157 int ret;
0158
0159
0160 ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x4);
0161 if (ret)
0162 return ret;
0163
0164
0165 usleep_range(5000, 6000);
0166
0167
0168 ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x0);
0169 if (ret)
0170 return ret;
0171
0172
0173 usleep_range(1000, 1200);
0174
0175 return 0;
0176 }
0177
0178 static int bmi088_accel_power_down(struct bmi088_accel_data *data)
0179 {
0180 int ret;
0181
0182
0183 ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x3);
0184 if (ret)
0185 return ret;
0186
0187
0188 usleep_range(1000, 1200);
0189
0190
0191 ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x0);
0192 if (ret)
0193 return ret;
0194
0195
0196 usleep_range(5000, 6000);
0197
0198 return 0;
0199 }
0200
0201 static int bmi088_accel_get_sample_freq(struct bmi088_accel_data *data,
0202 int *val, int *val2)
0203 {
0204 unsigned int value;
0205 int ret;
0206
0207 ret = regmap_read(data->regmap, BMI088_ACCEL_REG_ACC_CONF,
0208 &value);
0209 if (ret)
0210 return ret;
0211
0212 value &= BMI088_ACCEL_MODE_ODR_MASK;
0213 value -= BMI088_ACCEL_MODE_ODR_12_5;
0214 value <<= 1;
0215
0216 if (value >= ARRAY_SIZE(bmi088_sample_freqs) - 1)
0217 return -EINVAL;
0218
0219 *val = bmi088_sample_freqs[value];
0220 *val2 = bmi088_sample_freqs[value + 1];
0221
0222 return IIO_VAL_INT_PLUS_MICRO;
0223 }
0224
0225 static int bmi088_accel_set_sample_freq(struct bmi088_accel_data *data, int val)
0226 {
0227 unsigned int regval;
0228 int index = 0;
0229
0230 while (index < ARRAY_SIZE(bmi088_sample_freqs) &&
0231 bmi088_sample_freqs[index] != val)
0232 index += 2;
0233
0234 if (index >= ARRAY_SIZE(bmi088_sample_freqs))
0235 return -EINVAL;
0236
0237 regval = (index >> 1) + BMI088_ACCEL_MODE_ODR_12_5;
0238
0239 return regmap_update_bits(data->regmap, BMI088_ACCEL_REG_ACC_CONF,
0240 BMI088_ACCEL_MODE_ODR_MASK, regval);
0241 }
0242
0243 static int bmi088_accel_set_scale(struct bmi088_accel_data *data, int val, int val2)
0244 {
0245 unsigned int i;
0246
0247 for (i = 0; i < 4; i++)
0248 if (val == data->chip_info->scale_table[i][0] &&
0249 val2 == data->chip_info->scale_table[i][1])
0250 break;
0251
0252 if (i == 4)
0253 return -EINVAL;
0254
0255 return regmap_write(data->regmap, BMI088_ACCEL_REG_ACC_RANGE, i);
0256 }
0257
0258 static int bmi088_accel_get_temp(struct bmi088_accel_data *data, int *val)
0259 {
0260 int ret;
0261 s16 temp;
0262
0263 ret = regmap_bulk_read(data->regmap, BMI088_ACCEL_REG_TEMP,
0264 &data->buffer, sizeof(__be16));
0265 if (ret)
0266 return ret;
0267
0268
0269 temp = be16_to_cpu(*(__be16 *)data->buffer);
0270
0271 *val = temp >> BMI088_ACCEL_REG_TEMP_SHIFT;
0272
0273 return IIO_VAL_INT;
0274 }
0275
0276 static int bmi088_accel_get_axis(struct bmi088_accel_data *data,
0277 struct iio_chan_spec const *chan,
0278 int *val)
0279 {
0280 int ret;
0281 s16 raw_val;
0282
0283 ret = regmap_bulk_read(data->regmap,
0284 BMI088_ACCEL_AXIS_TO_REG(chan->scan_index),
0285 data->buffer, sizeof(__le16));
0286 if (ret)
0287 return ret;
0288
0289 raw_val = le16_to_cpu(*(__le16 *)data->buffer);
0290 *val = raw_val;
0291
0292 return IIO_VAL_INT;
0293 }
0294
0295 static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
0296 struct iio_chan_spec const *chan,
0297 int *val, int *val2, long mask)
0298 {
0299 struct bmi088_accel_data *data = iio_priv(indio_dev);
0300 struct device *dev = regmap_get_device(data->regmap);
0301 int ret;
0302 int reg;
0303
0304 switch (mask) {
0305 case IIO_CHAN_INFO_RAW:
0306 switch (chan->type) {
0307 case IIO_TEMP:
0308 ret = pm_runtime_resume_and_get(dev);
0309 if (ret)
0310 return ret;
0311
0312 ret = bmi088_accel_get_temp(data, val);
0313 goto out_read_raw_pm_put;
0314 case IIO_ACCEL:
0315 ret = pm_runtime_resume_and_get(dev);
0316 if (ret)
0317 return ret;
0318
0319 ret = iio_device_claim_direct_mode(indio_dev);
0320 if (ret)
0321 goto out_read_raw_pm_put;
0322
0323 ret = bmi088_accel_get_axis(data, chan, val);
0324 iio_device_release_direct_mode(indio_dev);
0325 if (!ret)
0326 ret = IIO_VAL_INT;
0327
0328 goto out_read_raw_pm_put;
0329 default:
0330 return -EINVAL;
0331 }
0332 case IIO_CHAN_INFO_OFFSET:
0333 switch (chan->type) {
0334 case IIO_TEMP:
0335
0336 *val = BMI088_ACCEL_TEMP_OFFSET/BMI088_ACCEL_TEMP_UNIT;
0337 return IIO_VAL_INT;
0338 default:
0339 return -EINVAL;
0340 }
0341 case IIO_CHAN_INFO_SCALE:
0342 switch (chan->type) {
0343 case IIO_TEMP:
0344
0345 *val = BMI088_ACCEL_TEMP_UNIT;
0346 return IIO_VAL_INT;
0347 case IIO_ACCEL:
0348 ret = pm_runtime_resume_and_get(dev);
0349 if (ret)
0350 return ret;
0351
0352 ret = regmap_read(data->regmap,
0353 BMI088_ACCEL_REG_ACC_RANGE, ®);
0354 if (ret)
0355 goto out_read_raw_pm_put;
0356
0357 reg = FIELD_GET(BMIO088_ACCEL_ACC_RANGE_MSK, reg);
0358 *val = data->chip_info->scale_table[reg][0];
0359 *val2 = data->chip_info->scale_table[reg][1];
0360 ret = IIO_VAL_INT_PLUS_MICRO;
0361
0362 goto out_read_raw_pm_put;
0363 default:
0364 return -EINVAL;
0365 }
0366 case IIO_CHAN_INFO_SAMP_FREQ:
0367 ret = pm_runtime_resume_and_get(dev);
0368 if (ret)
0369 return ret;
0370
0371 ret = bmi088_accel_get_sample_freq(data, val, val2);
0372 goto out_read_raw_pm_put;
0373 default:
0374 break;
0375 }
0376
0377 return -EINVAL;
0378
0379 out_read_raw_pm_put:
0380 pm_runtime_mark_last_busy(dev);
0381 pm_runtime_put_autosuspend(dev);
0382
0383 return ret;
0384 }
0385
0386 static int bmi088_accel_read_avail(struct iio_dev *indio_dev,
0387 struct iio_chan_spec const *chan,
0388 const int **vals, int *type, int *length,
0389 long mask)
0390 {
0391 struct bmi088_accel_data *data = iio_priv(indio_dev);
0392
0393 switch (mask) {
0394 case IIO_CHAN_INFO_SCALE:
0395 *vals = (const int *)data->chip_info->scale_table;
0396 *length = 8;
0397 *type = IIO_VAL_INT_PLUS_MICRO;
0398 return IIO_AVAIL_LIST;
0399 case IIO_CHAN_INFO_SAMP_FREQ:
0400 *type = IIO_VAL_INT_PLUS_MICRO;
0401 *vals = bmi088_sample_freqs;
0402 *length = ARRAY_SIZE(bmi088_sample_freqs);
0403 return IIO_AVAIL_LIST;
0404 default:
0405 return -EINVAL;
0406 }
0407 }
0408
0409 static int bmi088_accel_write_raw(struct iio_dev *indio_dev,
0410 struct iio_chan_spec const *chan,
0411 int val, int val2, long mask)
0412 {
0413 struct bmi088_accel_data *data = iio_priv(indio_dev);
0414 struct device *dev = regmap_get_device(data->regmap);
0415 int ret;
0416
0417 switch (mask) {
0418 case IIO_CHAN_INFO_SCALE:
0419 ret = pm_runtime_resume_and_get(dev);
0420 if (ret)
0421 return ret;
0422
0423 ret = bmi088_accel_set_scale(data, val, val2);
0424 pm_runtime_mark_last_busy(dev);
0425 pm_runtime_put_autosuspend(dev);
0426 return ret;
0427 case IIO_CHAN_INFO_SAMP_FREQ:
0428 ret = pm_runtime_resume_and_get(dev);
0429 if (ret)
0430 return ret;
0431
0432 ret = bmi088_accel_set_sample_freq(data, val);
0433 pm_runtime_mark_last_busy(dev);
0434 pm_runtime_put_autosuspend(dev);
0435 return ret;
0436 default:
0437 return -EINVAL;
0438 }
0439 }
0440
0441 #define BMI088_ACCEL_CHANNEL(_axis) { \
0442 .type = IIO_ACCEL, \
0443 .modified = 1, \
0444 .channel2 = IIO_MOD_##_axis, \
0445 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
0446 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
0447 BIT(IIO_CHAN_INFO_SAMP_FREQ), \
0448 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
0449 BIT(IIO_CHAN_INFO_SCALE), \
0450 .scan_index = AXIS_##_axis, \
0451 }
0452
0453 static const struct iio_chan_spec bmi088_accel_channels[] = {
0454 {
0455 .type = IIO_TEMP,
0456 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0457 BIT(IIO_CHAN_INFO_SCALE) |
0458 BIT(IIO_CHAN_INFO_OFFSET),
0459 .scan_index = -1,
0460 },
0461 BMI088_ACCEL_CHANNEL(X),
0462 BMI088_ACCEL_CHANNEL(Y),
0463 BMI088_ACCEL_CHANNEL(Z),
0464 IIO_CHAN_SOFT_TIMESTAMP(3),
0465 };
0466
0467 static const struct bmi088_accel_chip_info bmi088_accel_chip_info_tbl[] = {
0468 [BOSCH_BMI085] = {
0469 .name = "bmi085-accel",
0470 .chip_id = 0x1F,
0471 .channels = bmi088_accel_channels,
0472 .num_channels = ARRAY_SIZE(bmi088_accel_channels),
0473 .scale_table = {{0, 598}, {0, 1196}, {0, 2393}, {0, 4785}},
0474 },
0475 [BOSCH_BMI088] = {
0476 .name = "bmi088-accel",
0477 .chip_id = 0x1E,
0478 .channels = bmi088_accel_channels,
0479 .num_channels = ARRAY_SIZE(bmi088_accel_channels),
0480 .scale_table = {{0, 897}, {0, 1794}, {0, 3589}, {0, 7178}},
0481 },
0482 [BOSCH_BMI090L] = {
0483 .name = "bmi090l-accel",
0484 .chip_id = 0x1A,
0485 .channels = bmi088_accel_channels,
0486 .num_channels = ARRAY_SIZE(bmi088_accel_channels),
0487 .scale_table = {{0, 897}, {0, 1794}, {0, 3589}, {0, 7178}},
0488 },
0489 };
0490
0491 static const struct iio_info bmi088_accel_info = {
0492 .read_raw = bmi088_accel_read_raw,
0493 .write_raw = bmi088_accel_write_raw,
0494 .read_avail = bmi088_accel_read_avail,
0495 };
0496
0497 static const unsigned long bmi088_accel_scan_masks[] = {
0498 BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0499 0
0500 };
0501
0502 static int bmi088_accel_chip_init(struct bmi088_accel_data *data, enum bmi_device_type type)
0503 {
0504 struct device *dev = regmap_get_device(data->regmap);
0505 int ret, i;
0506 unsigned int val;
0507
0508 if (type >= BOSCH_UNKNOWN)
0509 return -ENODEV;
0510
0511
0512 regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
0513
0514
0515
0516
0517
0518 ret = regmap_write(data->regmap, BMI088_ACCEL_REG_RESET,
0519 BMI088_ACCEL_RESET_VAL);
0520 if (ret)
0521 return ret;
0522
0523 usleep_range(1000, 2000);
0524
0525
0526 regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
0527
0528
0529 ret = regmap_read(data->regmap, BMI088_ACCEL_REG_CHIP_ID, &val);
0530 if (ret) {
0531 dev_err(dev, "Error: Reading chip id\n");
0532 return ret;
0533 }
0534
0535
0536 for (i = 0; i < ARRAY_SIZE(bmi088_accel_chip_info_tbl); i++)
0537 if (bmi088_accel_chip_info_tbl[i].chip_id == val)
0538 break;
0539
0540 if (i == ARRAY_SIZE(bmi088_accel_chip_info_tbl))
0541 data->chip_info = &bmi088_accel_chip_info_tbl[type];
0542 else
0543 data->chip_info = &bmi088_accel_chip_info_tbl[i];
0544
0545 if (i != type)
0546 dev_warn(dev, "unexpected chip id 0x%X\n", val);
0547
0548 return 0;
0549 }
0550
0551 int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
0552 int irq, enum bmi_device_type type)
0553 {
0554 struct bmi088_accel_data *data;
0555 struct iio_dev *indio_dev;
0556 int ret;
0557
0558 indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
0559 if (!indio_dev)
0560 return -ENOMEM;
0561
0562 data = iio_priv(indio_dev);
0563 dev_set_drvdata(dev, indio_dev);
0564
0565 data->regmap = regmap;
0566
0567 ret = bmi088_accel_chip_init(data, type);
0568 if (ret)
0569 return ret;
0570
0571 indio_dev->channels = data->chip_info->channels;
0572 indio_dev->num_channels = data->chip_info->num_channels;
0573 indio_dev->name = data->chip_info->name;
0574 indio_dev->available_scan_masks = bmi088_accel_scan_masks;
0575 indio_dev->modes = INDIO_DIRECT_MODE;
0576 indio_dev->info = &bmi088_accel_info;
0577
0578
0579 pm_runtime_get_noresume(dev);
0580 pm_runtime_set_suspended(dev);
0581 pm_runtime_enable(dev);
0582
0583 pm_runtime_set_autosuspend_delay(dev, 6000);
0584 pm_runtime_use_autosuspend(dev);
0585 pm_runtime_put(dev);
0586
0587 ret = iio_device_register(indio_dev);
0588 if (ret)
0589 dev_err(dev, "Unable to register iio device\n");
0590
0591 return ret;
0592 }
0593 EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, IIO_BMI088);
0594
0595
0596 void bmi088_accel_core_remove(struct device *dev)
0597 {
0598 struct iio_dev *indio_dev = dev_get_drvdata(dev);
0599 struct bmi088_accel_data *data = iio_priv(indio_dev);
0600
0601 iio_device_unregister(indio_dev);
0602
0603 pm_runtime_disable(dev);
0604 pm_runtime_set_suspended(dev);
0605 bmi088_accel_power_down(data);
0606 }
0607 EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, IIO_BMI088);
0608
0609 static int __maybe_unused bmi088_accel_runtime_suspend(struct device *dev)
0610 {
0611 struct iio_dev *indio_dev = dev_get_drvdata(dev);
0612 struct bmi088_accel_data *data = iio_priv(indio_dev);
0613
0614 return bmi088_accel_power_down(data);
0615 }
0616
0617 static int __maybe_unused bmi088_accel_runtime_resume(struct device *dev)
0618 {
0619 struct iio_dev *indio_dev = dev_get_drvdata(dev);
0620 struct bmi088_accel_data *data = iio_priv(indio_dev);
0621
0622 return bmi088_accel_power_up(data);
0623 }
0624
0625 const struct dev_pm_ops bmi088_accel_pm_ops = {
0626 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0627 pm_runtime_force_resume)
0628 SET_RUNTIME_PM_OPS(bmi088_accel_runtime_suspend,
0629 bmi088_accel_runtime_resume, NULL)
0630 };
0631 EXPORT_SYMBOL_NS_GPL(bmi088_accel_pm_ops, IIO_BMI088);
0632
0633 MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>");
0634 MODULE_LICENSE("GPL v2");
0635 MODULE_DESCRIPTION("BMI088 accelerometer driver (core)");