linux/drivers/iio/gyro/adis16080.c
<<
>>
Prefs
   1/*
   2 * ADIS16080/100 Yaw Rate Gyroscope with SPI driver
   3 *
   4 * Copyright 2010 Analog Devices Inc.
   5 *
   6 * Licensed under the GPL-2 or later.
   7 */
   8#include <linux/delay.h>
   9#include <linux/mutex.h>
  10#include <linux/device.h>
  11#include <linux/kernel.h>
  12#include <linux/spi/spi.h>
  13#include <linux/slab.h>
  14#include <linux/sysfs.h>
  15#include <linux/module.h>
  16
  17#include <linux/iio/iio.h>
  18#include <linux/iio/sysfs.h>
  19
  20#define ADIS16080_DIN_GYRO   (0 << 10) /* Gyroscope output */
  21#define ADIS16080_DIN_TEMP   (1 << 10) /* Temperature output */
  22#define ADIS16080_DIN_AIN1   (2 << 10)
  23#define ADIS16080_DIN_AIN2   (3 << 10)
  24
  25/*
  26 * 1: Write contents on DIN to control register.
  27 * 0: No changes to control register.
  28 */
  29
  30#define ADIS16080_DIN_WRITE  (1 << 15)
  31
  32struct adis16080_chip_info {
  33        int scale_val;
  34        int scale_val2;
  35};
  36
  37/**
  38 * struct adis16080_state - device instance specific data
  39 * @us:                 actual spi_device to write data
  40 * @info:               chip specific parameters
  41 * @buf:                transmit or receive buffer
  42 **/
  43struct adis16080_state {
  44        struct spi_device               *us;
  45        const struct adis16080_chip_info *info;
  46
  47        __be16 buf ____cacheline_aligned;
  48};
  49
  50static int adis16080_read_sample(struct iio_dev *indio_dev,
  51                u16 addr, int *val)
  52{
  53        struct adis16080_state *st = iio_priv(indio_dev);
  54        int ret;
  55        struct spi_transfer     t[] = {
  56                {
  57                        .tx_buf         = &st->buf,
  58                        .len            = 2,
  59                        .cs_change      = 1,
  60                }, {
  61                        .rx_buf         = &st->buf,
  62                        .len            = 2,
  63                },
  64        };
  65
  66        st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE);
  67
  68        ret = spi_sync_transfer(st->us, t, ARRAY_SIZE(t));
  69        if (ret == 0)
  70                *val = sign_extend32(be16_to_cpu(st->buf), 11);
  71
  72        return ret;
  73}
  74
  75static int adis16080_read_raw(struct iio_dev *indio_dev,
  76                             struct iio_chan_spec const *chan,
  77                             int *val,
  78                             int *val2,
  79                             long mask)
  80{
  81        struct adis16080_state *st = iio_priv(indio_dev);
  82        int ret;
  83
  84        switch (mask) {
  85        case IIO_CHAN_INFO_RAW:
  86                mutex_lock(&indio_dev->mlock);
  87                ret = adis16080_read_sample(indio_dev, chan->address, val);
  88                mutex_unlock(&indio_dev->mlock);
  89                return ret ? ret : IIO_VAL_INT;
  90        case IIO_CHAN_INFO_SCALE:
  91                switch (chan->type) {
  92                case IIO_ANGL_VEL:
  93                        *val = st->info->scale_val;
  94                        *val2 = st->info->scale_val2;
  95                        return IIO_VAL_FRACTIONAL;
  96                case IIO_VOLTAGE:
  97                        /* VREF = 5V, 12 bits */
  98                        *val = 5000;
  99                        *val2 = 12;
 100                        return IIO_VAL_FRACTIONAL_LOG2;
 101                case IIO_TEMP:
 102                        /* 85 C = 585, 25 C = 0 */
 103                        *val = 85000 - 25000;
 104                        *val2 = 585;
 105                        return IIO_VAL_FRACTIONAL;
 106                default:
 107                        return -EINVAL;
 108                }
 109        case IIO_CHAN_INFO_OFFSET:
 110                switch (chan->type) {
 111                case IIO_VOLTAGE:
 112                        /* 2.5 V = 0 */
 113                        *val = 2048;
 114                        return IIO_VAL_INT;
 115                case IIO_TEMP:
 116                        /* 85 C = 585, 25 C = 0 */
 117                        *val = DIV_ROUND_CLOSEST(25 * 585, 85 - 25);
 118                        return IIO_VAL_INT;
 119                default:
 120                        return -EINVAL;
 121                }
 122        default:
 123                break;
 124        }
 125
 126        return -EINVAL;
 127}
 128
 129static const struct iio_chan_spec adis16080_channels[] = {
 130        {
 131                .type = IIO_ANGL_VEL,
 132                .modified = 1,
 133                .channel2 = IIO_MOD_Z,
 134                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 135                        BIT(IIO_CHAN_INFO_SCALE),
 136                .address = ADIS16080_DIN_GYRO,
 137        }, {
 138                .type = IIO_VOLTAGE,
 139                .indexed = 1,
 140                .channel = 0,
 141                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 142                        BIT(IIO_CHAN_INFO_SCALE) |
 143                        BIT(IIO_CHAN_INFO_OFFSET),
 144                .address = ADIS16080_DIN_AIN1,
 145        }, {
 146                .type = IIO_VOLTAGE,
 147                .indexed = 1,
 148                .channel = 1,
 149                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 150                        BIT(IIO_CHAN_INFO_SCALE) |
 151                        BIT(IIO_CHAN_INFO_OFFSET),
 152                .address = ADIS16080_DIN_AIN2,
 153        }, {
 154                .type = IIO_TEMP,
 155                .indexed = 1,
 156                .channel = 0,
 157                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 158                        BIT(IIO_CHAN_INFO_SCALE) |
 159                        BIT(IIO_CHAN_INFO_OFFSET),
 160                .address = ADIS16080_DIN_TEMP,
 161        }
 162};
 163
 164static const struct iio_info adis16080_info = {
 165        .read_raw = &adis16080_read_raw,
 166};
 167
 168enum {
 169        ID_ADIS16080,
 170        ID_ADIS16100,
 171};
 172
 173static const struct adis16080_chip_info adis16080_chip_info[] = {
 174        [ID_ADIS16080] = {
 175                /* 80 degree = 819, 819 rad = 46925 degree */
 176                .scale_val = 80,
 177                .scale_val2 = 46925,
 178        },
 179        [ID_ADIS16100] = {
 180                /* 300 degree = 1230, 1230 rad = 70474 degree */
 181                .scale_val = 300,
 182                .scale_val2 = 70474,
 183        },
 184};
 185
 186static int adis16080_probe(struct spi_device *spi)
 187{
 188        const struct spi_device_id *id = spi_get_device_id(spi);
 189        struct adis16080_state *st;
 190        struct iio_dev *indio_dev;
 191
 192        /* setup the industrialio driver allocated elements */
 193        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 194        if (!indio_dev)
 195                return -ENOMEM;
 196        st = iio_priv(indio_dev);
 197        /* this is only used for removal purposes */
 198        spi_set_drvdata(spi, indio_dev);
 199
 200        /* Allocate the comms buffers */
 201        st->us = spi;
 202        st->info = &adis16080_chip_info[id->driver_data];
 203
 204        indio_dev->name = spi->dev.driver->name;
 205        indio_dev->channels = adis16080_channels;
 206        indio_dev->num_channels = ARRAY_SIZE(adis16080_channels);
 207        indio_dev->dev.parent = &spi->dev;
 208        indio_dev->info = &adis16080_info;
 209        indio_dev->modes = INDIO_DIRECT_MODE;
 210
 211        return iio_device_register(indio_dev);
 212}
 213
 214static int adis16080_remove(struct spi_device *spi)
 215{
 216        iio_device_unregister(spi_get_drvdata(spi));
 217        return 0;
 218}
 219
 220static const struct spi_device_id adis16080_ids[] = {
 221        { "adis16080", ID_ADIS16080 },
 222        { "adis16100", ID_ADIS16100 },
 223        {},
 224};
 225MODULE_DEVICE_TABLE(spi, adis16080_ids);
 226
 227static struct spi_driver adis16080_driver = {
 228        .driver = {
 229                .name = "adis16080",
 230        },
 231        .probe = adis16080_probe,
 232        .remove = adis16080_remove,
 233        .id_table = adis16080_ids,
 234};
 235module_spi_driver(adis16080_driver);
 236
 237MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
 238MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver");
 239MODULE_LICENSE("GPL v2");
 240