Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
0004  *  - BMI088
0005  *
0006  * Copyright (c) 2018-2021, Topic Embedded Products
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 /* Available OSR (over sampling rate) sets the 3dB cut-off frequency */
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 /* Available ODR (output data rates) in Hz */
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); /* shared DMA safe buffer */
0132 };
0133 
0134 static const struct regmap_range bmi088_volatile_ranges[] = {
0135     /* All registers below 0x40 are volatile, except the CHIP ID. */
0136     regmap_reg_range(BMI088_ACCEL_REG_ERROR, 0x3f),
0137     /* Mark the RESET as volatile too, it is self-clearing */
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     /* Enable accelerometer and temperature sensor */
0160     ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x4);
0161     if (ret)
0162         return ret;
0163 
0164     /* Datasheet recommends to wait at least 5ms before communication */
0165     usleep_range(5000, 6000);
0166 
0167     /* Disable suspend mode */
0168     ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x0);
0169     if (ret)
0170         return ret;
0171 
0172     /* Recommended at least 1ms before further communication */
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     /* Enable suspend mode */
0183     ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x3);
0184     if (ret)
0185         return ret;
0186 
0187     /* Recommended at least 1ms before further communication */
0188     usleep_range(1000, 1200);
0189 
0190     /* Disable accelerometer and temperature sensor */
0191     ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x0);
0192     if (ret)
0193         return ret;
0194 
0195     /* Datasheet recommends to wait at least 5ms before communication */
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     /* data->buffer is cacheline aligned */
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             /* Offset applies before scale */
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             /* 0.125 degrees per LSB */
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, &reg);
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     /* Do a dummy read to enable SPI interface, won't harm I2C */
0512     regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
0513 
0514     /*
0515      * Reset chip to get it in a known good state. A delay of 1ms after
0516      * reset is required according to the data sheet
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     /* Do a dummy read again after a reset to enable the SPI interface */
0526     regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
0527 
0528     /* Read chip ID */
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     /* Validate chip ID */
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     /* Enable runtime PM */
0579     pm_runtime_get_noresume(dev);
0580     pm_runtime_set_suspended(dev);
0581     pm_runtime_enable(dev);
0582     /* We need ~6ms to startup, so set the delay to 6 seconds */
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)");