linux/drivers/iio/accel/bma220_spi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * BMA220 Digital triaxial acceleration sensor driver
   4 *
   5 * Copyright (c) 2016,2020 Intel Corporation.
   6 */
   7
   8#include <linux/bits.h>
   9#include <linux/kernel.h>
  10#include <linux/mod_devicetable.h>
  11#include <linux/module.h>
  12#include <linux/spi/spi.h>
  13
  14#include <linux/iio/buffer.h>
  15#include <linux/iio/iio.h>
  16#include <linux/iio/sysfs.h>
  17#include <linux/iio/trigger_consumer.h>
  18#include <linux/iio/triggered_buffer.h>
  19
  20#define BMA220_REG_ID                           0x00
  21#define BMA220_REG_ACCEL_X                      0x02
  22#define BMA220_REG_ACCEL_Y                      0x03
  23#define BMA220_REG_ACCEL_Z                      0x04
  24#define BMA220_REG_RANGE                        0x11
  25#define BMA220_REG_SUSPEND                      0x18
  26
  27#define BMA220_CHIP_ID                          0xDD
  28#define BMA220_READ_MASK                        BIT(7)
  29#define BMA220_RANGE_MASK                       GENMASK(1, 0)
  30#define BMA220_DATA_SHIFT                       2
  31#define BMA220_SUSPEND_SLEEP                    0xFF
  32#define BMA220_SUSPEND_WAKE                     0x00
  33
  34#define BMA220_DEVICE_NAME                      "bma220"
  35
  36#define BMA220_ACCEL_CHANNEL(index, reg, axis) {                        \
  37        .type = IIO_ACCEL,                                              \
  38        .address = reg,                                                 \
  39        .modified = 1,                                                  \
  40        .channel2 = IIO_MOD_##axis,                                     \
  41        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
  42        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
  43        .scan_index = index,                                            \
  44        .scan_type = {                                                  \
  45                .sign = 's',                                            \
  46                .realbits = 6,                                          \
  47                .storagebits = 8,                                       \
  48                .shift = BMA220_DATA_SHIFT,                             \
  49                .endianness = IIO_CPU,                                  \
  50        },                                                              \
  51}
  52
  53enum bma220_axis {
  54        AXIS_X,
  55        AXIS_Y,
  56        AXIS_Z,
  57};
  58
  59static const int bma220_scale_table[][2] = {
  60        {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000},
  61};
  62
  63struct bma220_data {
  64        struct spi_device *spi_device;
  65        struct mutex lock;
  66        s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
  67        u8 tx_buf[2] ____cacheline_aligned;
  68};
  69
  70static const struct iio_chan_spec bma220_channels[] = {
  71        BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X),
  72        BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y),
  73        BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z),
  74        IIO_CHAN_SOFT_TIMESTAMP(3),
  75};
  76
  77static inline int bma220_read_reg(struct spi_device *spi, u8 reg)
  78{
  79        return spi_w8r8(spi, reg | BMA220_READ_MASK);
  80}
  81
  82static const unsigned long bma220_accel_scan_masks[] = {
  83        BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
  84        0
  85};
  86
  87static irqreturn_t bma220_trigger_handler(int irq, void *p)
  88{
  89        int ret;
  90        struct iio_poll_func *pf = p;
  91        struct iio_dev *indio_dev = pf->indio_dev;
  92        struct bma220_data *data = iio_priv(indio_dev);
  93        struct spi_device *spi = data->spi_device;
  94
  95        mutex_lock(&data->lock);
  96        data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
  97        ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
  98                                  ARRAY_SIZE(bma220_channels) - 1);
  99        if (ret < 0)
 100                goto err;
 101
 102        iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 103                                           pf->timestamp);
 104err:
 105        mutex_unlock(&data->lock);
 106        iio_trigger_notify_done(indio_dev->trig);
 107
 108        return IRQ_HANDLED;
 109}
 110
 111static int bma220_read_raw(struct iio_dev *indio_dev,
 112                           struct iio_chan_spec const *chan,
 113                           int *val, int *val2, long mask)
 114{
 115        int ret;
 116        u8 range_idx;
 117        struct bma220_data *data = iio_priv(indio_dev);
 118
 119        switch (mask) {
 120        case IIO_CHAN_INFO_RAW:
 121                ret = bma220_read_reg(data->spi_device, chan->address);
 122                if (ret < 0)
 123                        return -EINVAL;
 124                *val = sign_extend32(ret >> BMA220_DATA_SHIFT, 5);
 125                return IIO_VAL_INT;
 126        case IIO_CHAN_INFO_SCALE:
 127                ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE);
 128                if (ret < 0)
 129                        return ret;
 130                range_idx = ret & BMA220_RANGE_MASK;
 131                *val = bma220_scale_table[range_idx][0];
 132                *val2 = bma220_scale_table[range_idx][1];
 133                return IIO_VAL_INT_PLUS_MICRO;
 134        }
 135
 136        return -EINVAL;
 137}
 138
 139static int bma220_write_raw(struct iio_dev *indio_dev,
 140                            struct iio_chan_spec const *chan,
 141                            int val, int val2, long mask)
 142{
 143        int i;
 144        int ret;
 145        int index = -1;
 146        struct bma220_data *data = iio_priv(indio_dev);
 147
 148        switch (mask) {
 149        case IIO_CHAN_INFO_SCALE:
 150                for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++)
 151                        if (val == bma220_scale_table[i][0] &&
 152                            val2 == bma220_scale_table[i][1]) {
 153                                index = i;
 154                                break;
 155                        }
 156                if (index < 0)
 157                        return -EINVAL;
 158
 159                mutex_lock(&data->lock);
 160                data->tx_buf[0] = BMA220_REG_RANGE;
 161                data->tx_buf[1] = index;
 162                ret = spi_write(data->spi_device, data->tx_buf,
 163                                sizeof(data->tx_buf));
 164                if (ret < 0)
 165                        dev_err(&data->spi_device->dev,
 166                                "failed to set measurement range\n");
 167                mutex_unlock(&data->lock);
 168
 169                return 0;
 170        }
 171
 172        return -EINVAL;
 173}
 174
 175static int bma220_read_avail(struct iio_dev *indio_dev,
 176                             struct iio_chan_spec const *chan,
 177                             const int **vals, int *type, int *length,
 178                             long mask)
 179{
 180        switch (mask) {
 181        case IIO_CHAN_INFO_SCALE:
 182                *vals = (int *)bma220_scale_table;
 183                *type = IIO_VAL_INT_PLUS_MICRO;
 184                *length = ARRAY_SIZE(bma220_scale_table) * 2;
 185                return IIO_AVAIL_LIST;
 186        default:
 187                return -EINVAL;
 188        }
 189}
 190
 191static const struct iio_info bma220_info = {
 192        .read_raw               = bma220_read_raw,
 193        .write_raw              = bma220_write_raw,
 194        .read_avail             = bma220_read_avail,
 195};
 196
 197static int bma220_init(struct spi_device *spi)
 198{
 199        int ret;
 200
 201        ret = bma220_read_reg(spi, BMA220_REG_ID);
 202        if (ret != BMA220_CHIP_ID)
 203                return -ENODEV;
 204
 205        /* Make sure the chip is powered on */
 206        ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
 207        if (ret == BMA220_SUSPEND_WAKE)
 208                ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
 209        if (ret < 0)
 210                return ret;
 211        if (ret == BMA220_SUSPEND_WAKE)
 212                return -EBUSY;
 213
 214        return 0;
 215}
 216
 217static int bma220_deinit(struct spi_device *spi)
 218{
 219        int ret;
 220
 221        /* Make sure the chip is powered off */
 222        ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
 223        if (ret == BMA220_SUSPEND_SLEEP)
 224                ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
 225        if (ret < 0)
 226                return ret;
 227        if (ret == BMA220_SUSPEND_SLEEP)
 228                return -EBUSY;
 229
 230        return 0;
 231}
 232
 233static int bma220_probe(struct spi_device *spi)
 234{
 235        int ret;
 236        struct iio_dev *indio_dev;
 237        struct bma220_data *data;
 238
 239        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
 240        if (!indio_dev) {
 241                dev_err(&spi->dev, "iio allocation failed!\n");
 242                return -ENOMEM;
 243        }
 244
 245        data = iio_priv(indio_dev);
 246        data->spi_device = spi;
 247        spi_set_drvdata(spi, indio_dev);
 248        mutex_init(&data->lock);
 249
 250        indio_dev->info = &bma220_info;
 251        indio_dev->name = BMA220_DEVICE_NAME;
 252        indio_dev->modes = INDIO_DIRECT_MODE;
 253        indio_dev->channels = bma220_channels;
 254        indio_dev->num_channels = ARRAY_SIZE(bma220_channels);
 255        indio_dev->available_scan_masks = bma220_accel_scan_masks;
 256
 257        ret = bma220_init(data->spi_device);
 258        if (ret)
 259                return ret;
 260
 261        ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
 262                                         bma220_trigger_handler, NULL);
 263        if (ret < 0) {
 264                dev_err(&spi->dev, "iio triggered buffer setup failed\n");
 265                goto err_suspend;
 266        }
 267
 268        ret = iio_device_register(indio_dev);
 269        if (ret < 0) {
 270                dev_err(&spi->dev, "iio_device_register failed\n");
 271                iio_triggered_buffer_cleanup(indio_dev);
 272                goto err_suspend;
 273        }
 274
 275        return 0;
 276
 277err_suspend:
 278        return bma220_deinit(spi);
 279}
 280
 281static int bma220_remove(struct spi_device *spi)
 282{
 283        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 284
 285        iio_device_unregister(indio_dev);
 286        iio_triggered_buffer_cleanup(indio_dev);
 287
 288        return bma220_deinit(spi);
 289}
 290
 291static __maybe_unused int bma220_suspend(struct device *dev)
 292{
 293        struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
 294
 295        /* The chip can be suspended/woken up by a simple register read. */
 296        return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
 297}
 298
 299static __maybe_unused int bma220_resume(struct device *dev)
 300{
 301        struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
 302
 303        return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
 304}
 305static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
 306
 307static const struct spi_device_id bma220_spi_id[] = {
 308        {"bma220", 0},
 309        {}
 310};
 311
 312static const struct acpi_device_id bma220_acpi_id[] = {
 313        {"BMA0220", 0},
 314        {}
 315};
 316MODULE_DEVICE_TABLE(spi, bma220_spi_id);
 317
 318static struct spi_driver bma220_driver = {
 319        .driver = {
 320                .name = "bma220_spi",
 321                .pm = &bma220_pm_ops,
 322                .acpi_match_table = bma220_acpi_id,
 323        },
 324        .probe =            bma220_probe,
 325        .remove =           bma220_remove,
 326        .id_table =         bma220_spi_id,
 327};
 328module_spi_driver(bma220_driver);
 329
 330MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
 331MODULE_DESCRIPTION("BMA220 acceleration sensor driver");
 332MODULE_LICENSE("GPL v2");
 333