linux/drivers/iio/accel/bmi088-accel-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
   4 *  - BMI088
   5 *
   6 * Copyright (c) 2018-2021, Topic Embedded Products
   7 */
   8
   9#include <linux/delay.h>
  10#include <linux/iio/iio.h>
  11#include <linux/iio/sysfs.h>
  12#include <linux/interrupt.h>
  13#include <linux/module.h>
  14#include <linux/pm.h>
  15#include <linux/pm_runtime.h>
  16#include <linux/regmap.h>
  17#include <linux/slab.h>
  18#include <asm/unaligned.h>
  19
  20#include "bmi088-accel.h"
  21
  22#define BMI088_ACCEL_REG_CHIP_ID                        0x00
  23#define BMI088_ACCEL_REG_ERROR                          0x02
  24
  25#define BMI088_ACCEL_REG_INT_STATUS                     0x1D
  26#define BMI088_ACCEL_INT_STATUS_BIT_DRDY                BIT(7)
  27
  28#define BMI088_ACCEL_REG_RESET                          0x7E
  29#define BMI088_ACCEL_RESET_VAL                          0xB6
  30
  31#define BMI088_ACCEL_REG_PWR_CTRL                       0x7D
  32#define BMI088_ACCEL_REG_PWR_CONF                       0x7C
  33
  34#define BMI088_ACCEL_REG_INT_MAP_DATA                   0x58
  35#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT1_DRDY         BIT(2)
  36#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT2_FWM          BIT(5)
  37
  38#define BMI088_ACCEL_REG_INT1_IO_CONF                   0x53
  39#define BMI088_ACCEL_INT1_IO_CONF_BIT_ENABLE_OUT        BIT(3)
  40#define BMI088_ACCEL_INT1_IO_CONF_BIT_LVL               BIT(1)
  41
  42#define BMI088_ACCEL_REG_INT2_IO_CONF                   0x54
  43#define BMI088_ACCEL_INT2_IO_CONF_BIT_ENABLE_OUT        BIT(3)
  44#define BMI088_ACCEL_INT2_IO_CONF_BIT_LVL               BIT(1)
  45
  46#define BMI088_ACCEL_REG_ACC_CONF                       0x40
  47#define BMI088_ACCEL_MODE_ODR_MASK                      0x0f
  48
  49#define BMI088_ACCEL_REG_ACC_RANGE                      0x41
  50#define BMI088_ACCEL_RANGE_3G                           0x00
  51#define BMI088_ACCEL_RANGE_6G                           0x01
  52#define BMI088_ACCEL_RANGE_12G                          0x02
  53#define BMI088_ACCEL_RANGE_24G                          0x03
  54
  55#define BMI088_ACCEL_REG_TEMP                           0x22
  56#define BMI088_ACCEL_REG_TEMP_SHIFT                     5
  57#define BMI088_ACCEL_TEMP_UNIT                          125
  58#define BMI088_ACCEL_TEMP_OFFSET                        23000
  59
  60#define BMI088_ACCEL_REG_XOUT_L                         0x12
  61#define BMI088_ACCEL_AXIS_TO_REG(axis) \
  62        (BMI088_ACCEL_REG_XOUT_L + (axis * 2))
  63
  64#define BMI088_ACCEL_MAX_STARTUP_TIME_US                1000
  65#define BMI088_AUTO_SUSPEND_DELAY_MS                    2000
  66
  67#define BMI088_ACCEL_REG_FIFO_STATUS                    0x0E
  68#define BMI088_ACCEL_REG_FIFO_CONFIG0                   0x48
  69#define BMI088_ACCEL_REG_FIFO_CONFIG1                   0x49
  70#define BMI088_ACCEL_REG_FIFO_DATA                      0x3F
  71#define BMI088_ACCEL_FIFO_LENGTH                        100
  72
  73#define BMI088_ACCEL_FIFO_MODE_FIFO                     0x40
  74#define BMI088_ACCEL_FIFO_MODE_STREAM                   0x80
  75
  76enum bmi088_accel_axis {
  77        AXIS_X,
  78        AXIS_Y,
  79        AXIS_Z,
  80};
  81
  82static const int bmi088_sample_freqs[] = {
  83        12, 500000,
  84        25, 0,
  85        50, 0,
  86        100, 0,
  87        200, 0,
  88        400, 0,
  89        800, 0,
  90        1600, 0,
  91};
  92
  93/* Available OSR (over sampling rate) sets the 3dB cut-off frequency */
  94enum bmi088_osr_modes {
  95        BMI088_ACCEL_MODE_OSR_NORMAL = 0xA,
  96        BMI088_ACCEL_MODE_OSR_2 = 0x9,
  97        BMI088_ACCEL_MODE_OSR_4 = 0x8,
  98};
  99
 100/* Available ODR (output data rates) in Hz */
 101enum bmi088_odr_modes {
 102        BMI088_ACCEL_MODE_ODR_12_5 = 0x5,
 103        BMI088_ACCEL_MODE_ODR_25 = 0x6,
 104        BMI088_ACCEL_MODE_ODR_50 = 0x7,
 105        BMI088_ACCEL_MODE_ODR_100 = 0x8,
 106        BMI088_ACCEL_MODE_ODR_200 = 0x9,
 107        BMI088_ACCEL_MODE_ODR_400 = 0xa,
 108        BMI088_ACCEL_MODE_ODR_800 = 0xb,
 109        BMI088_ACCEL_MODE_ODR_1600 = 0xc,
 110};
 111
 112struct bmi088_scale_info {
 113        int scale;
 114        u8 reg_range;
 115};
 116
 117struct bmi088_accel_chip_info {
 118        const char *name;
 119        u8 chip_id;
 120        const struct iio_chan_spec *channels;
 121        int num_channels;
 122};
 123
 124struct bmi088_accel_data {
 125        struct regmap *regmap;
 126        const struct bmi088_accel_chip_info *chip_info;
 127        u8 buffer[2] ____cacheline_aligned; /* shared DMA safe buffer */
 128};
 129
 130static const struct regmap_range bmi088_volatile_ranges[] = {
 131        /* All registers below 0x40 are volatile, except the CHIP ID. */
 132        regmap_reg_range(BMI088_ACCEL_REG_ERROR, 0x3f),
 133        /* Mark the RESET as volatile too, it is self-clearing */
 134        regmap_reg_range(BMI088_ACCEL_REG_RESET, BMI088_ACCEL_REG_RESET),
 135};
 136
 137static const struct regmap_access_table bmi088_volatile_table = {
 138        .yes_ranges     = bmi088_volatile_ranges,
 139        .n_yes_ranges   = ARRAY_SIZE(bmi088_volatile_ranges),
 140};
 141
 142const struct regmap_config bmi088_regmap_conf = {
 143        .reg_bits = 8,
 144        .val_bits = 8,
 145        .max_register = 0x7E,
 146        .volatile_table = &bmi088_volatile_table,
 147        .cache_type = REGCACHE_RBTREE,
 148};
 149EXPORT_SYMBOL_GPL(bmi088_regmap_conf);
 150
 151static int bmi088_accel_power_up(struct bmi088_accel_data *data)
 152{
 153        int ret;
 154
 155        /* Enable accelerometer and temperature sensor */
 156        ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x4);
 157        if (ret)
 158                return ret;
 159
 160        /* Datasheet recommends to wait at least 5ms before communication */
 161        usleep_range(5000, 6000);
 162
 163        /* Disable suspend mode */
 164        ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x0);
 165        if (ret)
 166                return ret;
 167
 168        /* Recommended at least 1ms before further communication */
 169        usleep_range(1000, 1200);
 170
 171        return 0;
 172}
 173
 174static int bmi088_accel_power_down(struct bmi088_accel_data *data)
 175{
 176        int ret;
 177
 178        /* Enable suspend mode */
 179        ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x3);
 180        if (ret)
 181                return ret;
 182
 183        /* Recommended at least 1ms before further communication */
 184        usleep_range(1000, 1200);
 185
 186        /* Disable accelerometer and temperature sensor */
 187        ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x0);
 188        if (ret)
 189                return ret;
 190
 191        /* Datasheet recommends to wait at least 5ms before communication */
 192        usleep_range(5000, 6000);
 193
 194        return 0;
 195}
 196
 197static int bmi088_accel_get_sample_freq(struct bmi088_accel_data *data,
 198                                        int *val, int *val2)
 199{
 200        unsigned int value;
 201        int ret;
 202
 203        ret = regmap_read(data->regmap, BMI088_ACCEL_REG_ACC_CONF,
 204                          &value);
 205        if (ret)
 206                return ret;
 207
 208        value &= BMI088_ACCEL_MODE_ODR_MASK;
 209        value -= BMI088_ACCEL_MODE_ODR_12_5;
 210        value <<= 1;
 211
 212        if (value >= ARRAY_SIZE(bmi088_sample_freqs) - 1)
 213                return -EINVAL;
 214
 215        *val = bmi088_sample_freqs[value];
 216        *val2 = bmi088_sample_freqs[value + 1];
 217
 218        return IIO_VAL_INT_PLUS_MICRO;
 219}
 220
 221static int bmi088_accel_set_sample_freq(struct bmi088_accel_data *data, int val)
 222{
 223        unsigned int regval;
 224        int index = 0;
 225
 226        while (index < ARRAY_SIZE(bmi088_sample_freqs) &&
 227               bmi088_sample_freqs[index] != val)
 228                index += 2;
 229
 230        if (index >= ARRAY_SIZE(bmi088_sample_freqs))
 231                return -EINVAL;
 232
 233        regval = (index >> 1) + BMI088_ACCEL_MODE_ODR_12_5;
 234
 235        return regmap_update_bits(data->regmap, BMI088_ACCEL_REG_ACC_CONF,
 236                                  BMI088_ACCEL_MODE_ODR_MASK, regval);
 237}
 238
 239static int bmi088_accel_get_temp(struct bmi088_accel_data *data, int *val)
 240{
 241        int ret;
 242        s16 temp;
 243
 244        ret = regmap_bulk_read(data->regmap, BMI088_ACCEL_REG_TEMP,
 245                               &data->buffer, sizeof(__be16));
 246        if (ret)
 247                return ret;
 248
 249        /* data->buffer is cacheline aligned */
 250        temp = be16_to_cpu(*(__be16 *)data->buffer);
 251
 252        *val = temp >> BMI088_ACCEL_REG_TEMP_SHIFT;
 253
 254        return IIO_VAL_INT;
 255}
 256
 257static int bmi088_accel_get_axis(struct bmi088_accel_data *data,
 258                                 struct iio_chan_spec const *chan,
 259                                 int *val)
 260{
 261        int ret;
 262        s16 raw_val;
 263
 264        ret = regmap_bulk_read(data->regmap,
 265                               BMI088_ACCEL_AXIS_TO_REG(chan->scan_index),
 266                               data->buffer, sizeof(__le16));
 267        if (ret)
 268                return ret;
 269
 270        raw_val = le16_to_cpu(*(__le16 *)data->buffer);
 271        *val = raw_val;
 272
 273        return IIO_VAL_INT;
 274}
 275
 276static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
 277                                 struct iio_chan_spec const *chan,
 278                                 int *val, int *val2, long mask)
 279{
 280        struct bmi088_accel_data *data = iio_priv(indio_dev);
 281        struct device *dev = regmap_get_device(data->regmap);
 282        int ret;
 283
 284        switch (mask) {
 285        case IIO_CHAN_INFO_RAW:
 286                switch (chan->type) {
 287                case IIO_TEMP:
 288                        ret = pm_runtime_resume_and_get(dev);
 289                        if (ret)
 290                                return ret;
 291
 292                        ret = bmi088_accel_get_temp(data, val);
 293                        goto out_read_raw_pm_put;
 294                case IIO_ACCEL:
 295                        ret = pm_runtime_resume_and_get(dev);
 296                        if (ret)
 297                                return ret;
 298
 299                        ret = iio_device_claim_direct_mode(indio_dev);
 300                        if (ret)
 301                                goto out_read_raw_pm_put;
 302
 303                        ret = bmi088_accel_get_axis(data, chan, val);
 304                        iio_device_release_direct_mode(indio_dev);
 305                        if (!ret)
 306                                ret = IIO_VAL_INT;
 307
 308                        goto out_read_raw_pm_put;
 309                default:
 310                        return -EINVAL;
 311                }
 312        case IIO_CHAN_INFO_OFFSET:
 313                switch (chan->type) {
 314                case IIO_TEMP:
 315                        /* Offset applies before scale */
 316                        *val = BMI088_ACCEL_TEMP_OFFSET/BMI088_ACCEL_TEMP_UNIT;
 317                        return IIO_VAL_INT;
 318                default:
 319                        return -EINVAL;
 320                }
 321        case IIO_CHAN_INFO_SCALE:
 322                switch (chan->type) {
 323                case IIO_TEMP:
 324                        /* 0.125 degrees per LSB */
 325                        *val = BMI088_ACCEL_TEMP_UNIT;
 326                        return IIO_VAL_INT;
 327                case IIO_ACCEL:
 328                        ret = pm_runtime_resume_and_get(dev);
 329                        if (ret)
 330                                return ret;
 331
 332                        ret = regmap_read(data->regmap,
 333                                          BMI088_ACCEL_REG_ACC_RANGE, val);
 334                        if (ret)
 335                                goto out_read_raw_pm_put;
 336
 337                        *val2 = 15 - (*val & 0x3);
 338                        *val = 3 * 980;
 339                        ret = IIO_VAL_FRACTIONAL_LOG2;
 340
 341                        goto out_read_raw_pm_put;
 342                default:
 343                        return -EINVAL;
 344                }
 345        case IIO_CHAN_INFO_SAMP_FREQ:
 346                ret = pm_runtime_resume_and_get(dev);
 347                if (ret)
 348                        return ret;
 349
 350                ret = bmi088_accel_get_sample_freq(data, val, val2);
 351                goto out_read_raw_pm_put;
 352        default:
 353                break;
 354        }
 355
 356        return -EINVAL;
 357
 358out_read_raw_pm_put:
 359        pm_runtime_mark_last_busy(dev);
 360        pm_runtime_put_autosuspend(dev);
 361
 362        return ret;
 363}
 364
 365static int bmi088_accel_read_avail(struct iio_dev *indio_dev,
 366                             struct iio_chan_spec const *chan,
 367                             const int **vals, int *type, int *length,
 368                             long mask)
 369{
 370        switch (mask) {
 371        case IIO_CHAN_INFO_SAMP_FREQ:
 372                *type = IIO_VAL_INT_PLUS_MICRO;
 373                *vals = bmi088_sample_freqs;
 374                *length = ARRAY_SIZE(bmi088_sample_freqs);
 375                return IIO_AVAIL_LIST;
 376        default:
 377                return -EINVAL;
 378        }
 379}
 380
 381static int bmi088_accel_write_raw(struct iio_dev *indio_dev,
 382                                  struct iio_chan_spec const *chan,
 383                                  int val, int val2, long mask)
 384{
 385        struct bmi088_accel_data *data = iio_priv(indio_dev);
 386        struct device *dev = regmap_get_device(data->regmap);
 387        int ret;
 388
 389        switch (mask) {
 390        case IIO_CHAN_INFO_SAMP_FREQ:
 391                ret = pm_runtime_resume_and_get(dev);
 392                if (ret)
 393                        return ret;
 394
 395                ret = bmi088_accel_set_sample_freq(data, val);
 396                pm_runtime_mark_last_busy(dev);
 397                pm_runtime_put_autosuspend(dev);
 398                return ret;
 399        default:
 400                return -EINVAL;
 401        }
 402}
 403
 404#define BMI088_ACCEL_CHANNEL(_axis) { \
 405        .type = IIO_ACCEL, \
 406        .modified = 1, \
 407        .channel2 = IIO_MOD_##_axis, \
 408        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
 409        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
 410                                BIT(IIO_CHAN_INFO_SAMP_FREQ), \
 411        .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
 412        .scan_index = AXIS_##_axis, \
 413}
 414
 415static const struct iio_chan_spec bmi088_accel_channels[] = {
 416        {
 417                .type = IIO_TEMP,
 418                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 419                                      BIT(IIO_CHAN_INFO_SCALE) |
 420                                      BIT(IIO_CHAN_INFO_OFFSET),
 421                .scan_index = -1,
 422        },
 423        BMI088_ACCEL_CHANNEL(X),
 424        BMI088_ACCEL_CHANNEL(Y),
 425        BMI088_ACCEL_CHANNEL(Z),
 426        IIO_CHAN_SOFT_TIMESTAMP(3),
 427};
 428
 429static const struct bmi088_accel_chip_info bmi088_accel_chip_info_tbl[] = {
 430        [0] = {
 431                .name = "bmi088a",
 432                .chip_id = 0x1E,
 433                .channels = bmi088_accel_channels,
 434                .num_channels = ARRAY_SIZE(bmi088_accel_channels),
 435        },
 436};
 437
 438static const struct iio_info bmi088_accel_info = {
 439        .read_raw       = bmi088_accel_read_raw,
 440        .write_raw      = bmi088_accel_write_raw,
 441        .read_avail     = bmi088_accel_read_avail,
 442};
 443
 444static const unsigned long bmi088_accel_scan_masks[] = {
 445        BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
 446        0
 447};
 448
 449static int bmi088_accel_chip_init(struct bmi088_accel_data *data)
 450{
 451        struct device *dev = regmap_get_device(data->regmap);
 452        int ret, i;
 453        unsigned int val;
 454
 455        /* Do a dummy read to enable SPI interface, won't harm I2C */
 456        regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
 457
 458        /*
 459         * Reset chip to get it in a known good state. A delay of 1ms after
 460         * reset is required according to the data sheet
 461         */
 462        ret = regmap_write(data->regmap, BMI088_ACCEL_REG_RESET,
 463                           BMI088_ACCEL_RESET_VAL);
 464        if (ret)
 465                return ret;
 466
 467        usleep_range(1000, 2000);
 468
 469        /* Do a dummy read again after a reset to enable the SPI interface */
 470        regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
 471
 472        /* Read chip ID */
 473        ret = regmap_read(data->regmap, BMI088_ACCEL_REG_CHIP_ID, &val);
 474        if (ret) {
 475                dev_err(dev, "Error: Reading chip id\n");
 476                return ret;
 477        }
 478
 479        /* Validate chip ID */
 480        for (i = 0; i < ARRAY_SIZE(bmi088_accel_chip_info_tbl); i++) {
 481                if (bmi088_accel_chip_info_tbl[i].chip_id == val) {
 482                        data->chip_info = &bmi088_accel_chip_info_tbl[i];
 483                        break;
 484                }
 485        }
 486        if (i == ARRAY_SIZE(bmi088_accel_chip_info_tbl)) {
 487                dev_err(dev, "Invalid chip %x\n", val);
 488                return -ENODEV;
 489        }
 490
 491        return 0;
 492}
 493
 494int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
 495        int irq, const char *name, bool block_supported)
 496{
 497        struct bmi088_accel_data *data;
 498        struct iio_dev *indio_dev;
 499        int ret;
 500
 501        indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 502        if (!indio_dev)
 503                return -ENOMEM;
 504
 505        data = iio_priv(indio_dev);
 506        dev_set_drvdata(dev, indio_dev);
 507
 508        data->regmap = regmap;
 509
 510        ret = bmi088_accel_chip_init(data);
 511        if (ret)
 512                return ret;
 513
 514        indio_dev->channels = data->chip_info->channels;
 515        indio_dev->num_channels = data->chip_info->num_channels;
 516        indio_dev->name = name ? name : data->chip_info->name;
 517        indio_dev->available_scan_masks = bmi088_accel_scan_masks;
 518        indio_dev->modes = INDIO_DIRECT_MODE;
 519        indio_dev->info = &bmi088_accel_info;
 520
 521        /* Enable runtime PM */
 522        pm_runtime_get_noresume(dev);
 523        pm_runtime_set_suspended(dev);
 524        pm_runtime_enable(dev);
 525        /* We need ~6ms to startup, so set the delay to 6 seconds */
 526        pm_runtime_set_autosuspend_delay(dev, 6000);
 527        pm_runtime_use_autosuspend(dev);
 528        pm_runtime_put(dev);
 529
 530        ret = iio_device_register(indio_dev);
 531        if (ret)
 532                dev_err(dev, "Unable to register iio device\n");
 533
 534        return ret;
 535}
 536EXPORT_SYMBOL_GPL(bmi088_accel_core_probe);
 537
 538
 539int bmi088_accel_core_remove(struct device *dev)
 540{
 541        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 542        struct bmi088_accel_data *data = iio_priv(indio_dev);
 543
 544        iio_device_unregister(indio_dev);
 545
 546        pm_runtime_disable(dev);
 547        pm_runtime_set_suspended(dev);
 548        bmi088_accel_power_down(data);
 549
 550        return 0;
 551}
 552EXPORT_SYMBOL_GPL(bmi088_accel_core_remove);
 553
 554static int __maybe_unused bmi088_accel_runtime_suspend(struct device *dev)
 555{
 556        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 557        struct bmi088_accel_data *data = iio_priv(indio_dev);
 558
 559        return bmi088_accel_power_down(data);
 560}
 561
 562static int __maybe_unused bmi088_accel_runtime_resume(struct device *dev)
 563{
 564        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 565        struct bmi088_accel_data *data = iio_priv(indio_dev);
 566
 567        return bmi088_accel_power_up(data);
 568}
 569
 570const struct dev_pm_ops bmi088_accel_pm_ops = {
 571        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 572                                pm_runtime_force_resume)
 573        SET_RUNTIME_PM_OPS(bmi088_accel_runtime_suspend,
 574                           bmi088_accel_runtime_resume, NULL)
 575};
 576EXPORT_SYMBOL_GPL(bmi088_accel_pm_ops);
 577
 578MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>");
 579MODULE_LICENSE("GPL v2");
 580MODULE_DESCRIPTION("BMI088 accelerometer driver (core)");
 581