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