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        struct spi_message m;
  55        int ret;
  56        struct spi_transfer     t[] = {
  57                {
  58                        .tx_buf         = &st->buf,
  59                        .len            = 2,
  60                        .cs_change      = 1,
  61                }, {
  62                        .rx_buf         = &st->buf,
  63                        .len            = 2,
  64                },
  65        };
  66
  67        st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE);
  68
  69        spi_message_init(&m);
  70        spi_message_add_tail(&t[0], &m);
  71        spi_message_add_tail(&t[1], &m);
  72
  73        ret = spi_sync(st->us, &m);
  74        if (ret == 0)
  75                *val = sign_extend32(be16_to_cpu(st->buf), 11);
  76
  77        return ret;
  78}
  79
  80static int adis16080_read_raw(struct iio_dev *indio_dev,
  81                             struct iio_chan_spec const *chan,
  82                             int *val,
  83                             int *val2,
  84                             long mask)
  85{
  86        struct adis16080_state *st = iio_priv(indio_dev);
  87        int ret;
  88
  89        switch (mask) {
  90        case IIO_CHAN_INFO_RAW:
  91                mutex_lock(&indio_dev->mlock);
  92                ret = adis16080_read_sample(indio_dev, chan->address, val);
  93                mutex_unlock(&indio_dev->mlock);
  94                return ret ? ret : IIO_VAL_INT;
  95        case IIO_CHAN_INFO_SCALE:
  96                switch (chan->type) {
  97                case IIO_ANGL_VEL:
  98                        *val = st->info->scale_val;
  99                        *val2 = st->info->scale_val2;
 100                        return IIO_VAL_FRACTIONAL;
 101                case IIO_VOLTAGE:
 102                        /* VREF = 5V, 12 bits */
 103                        *val = 5000;
 104                        *val2 = 12;
 105                        return IIO_VAL_FRACTIONAL_LOG2;
 106                case IIO_TEMP:
 107                        /* 85 C = 585, 25 C = 0 */
 108                        *val = 85000 - 25000;
 109                        *val2 = 585;
 110                        return IIO_VAL_FRACTIONAL;
 111                default:
 112                        return -EINVAL;
 113                }
 114        case IIO_CHAN_INFO_OFFSET:
 115                switch (chan->type) {
 116                case IIO_VOLTAGE:
 117                        /* 2.5 V = 0 */
 118                        *val = 2048;
 119                        return IIO_VAL_INT;
 120                case IIO_TEMP:
 121                        /* 85 C = 585, 25 C = 0 */
 122                        *val = DIV_ROUND_CLOSEST(25 * 585, 85 - 25);
 123                        return IIO_VAL_INT;
 124                default:
 125                        return -EINVAL;
 126                }
 127        default:
 128                break;
 129        }
 130
 131        return -EINVAL;
 132}
 133
 134static const struct iio_chan_spec adis16080_channels[] = {
 135        {
 136                .type = IIO_ANGL_VEL,
 137                .modified = 1,
 138                .channel2 = IIO_MOD_Z,
 139                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 140                        BIT(IIO_CHAN_INFO_SCALE),
 141                .address = ADIS16080_DIN_GYRO,
 142        }, {
 143                .type = IIO_VOLTAGE,
 144                .indexed = 1,
 145                .channel = 0,
 146                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 147                        BIT(IIO_CHAN_INFO_SCALE) |
 148                        BIT(IIO_CHAN_INFO_OFFSET),
 149                .address = ADIS16080_DIN_AIN1,
 150        }, {
 151                .type = IIO_VOLTAGE,
 152                .indexed = 1,
 153                .channel = 1,
 154                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 155                        BIT(IIO_CHAN_INFO_SCALE) |
 156                        BIT(IIO_CHAN_INFO_OFFSET),
 157                .address = ADIS16080_DIN_AIN2,
 158        }, {
 159                .type = IIO_TEMP,
 160                .indexed = 1,
 161                .channel = 0,
 162                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 163                        BIT(IIO_CHAN_INFO_SCALE) |
 164                        BIT(IIO_CHAN_INFO_OFFSET),
 165                .address = ADIS16080_DIN_TEMP,
 166        }
 167};
 168
 169static const struct iio_info adis16080_info = {
 170        .read_raw = &adis16080_read_raw,
 171        .driver_module = THIS_MODULE,
 172};
 173
 174enum {
 175        ID_ADIS16080,
 176        ID_ADIS16100,
 177};
 178
 179static const struct adis16080_chip_info adis16080_chip_info[] = {
 180        [ID_ADIS16080] = {
 181                /* 80 degree = 819, 819 rad = 46925 degree */
 182                .scale_val = 80,
 183                .scale_val2 = 46925,
 184        },
 185        [ID_ADIS16100] = {
 186                /* 300 degree = 1230, 1230 rad = 70474 degree */
 187                .scale_val = 300,
 188                .scale_val2 = 70474,
 189        },
 190};
 191
 192static int adis16080_probe(struct spi_device *spi)
 193{
 194        const struct spi_device_id *id = spi_get_device_id(spi);
 195        int ret;
 196        struct adis16080_state *st;
 197        struct iio_dev *indio_dev;
 198
 199        /* setup the industrialio driver allocated elements */
 200        indio_dev = iio_device_alloc(sizeof(*st));
 201        if (indio_dev == NULL) {
 202                ret = -ENOMEM;
 203                goto error_ret;
 204        }
 205        st = iio_priv(indio_dev);
 206        /* this is only used for removal purposes */
 207        spi_set_drvdata(spi, indio_dev);
 208
 209        /* Allocate the comms buffers */
 210        st->us = spi;
 211        st->info = &adis16080_chip_info[id->driver_data];
 212
 213        indio_dev->name = spi->dev.driver->name;
 214        indio_dev->channels = adis16080_channels;
 215        indio_dev->num_channels = ARRAY_SIZE(adis16080_channels);
 216        indio_dev->dev.parent = &spi->dev;
 217        indio_dev->info = &adis16080_info;
 218        indio_dev->modes = INDIO_DIRECT_MODE;
 219
 220        ret = iio_device_register(indio_dev);
 221        if (ret)
 222                goto error_free_dev;
 223        return 0;
 224
 225error_free_dev:
 226        iio_device_free(indio_dev);
 227error_ret:
 228        return ret;
 229}
 230
 231static int adis16080_remove(struct spi_device *spi)
 232{
 233        iio_device_unregister(spi_get_drvdata(spi));
 234        iio_device_free(spi_get_drvdata(spi));
 235
 236        return 0;
 237}
 238
 239static const struct spi_device_id adis16080_ids[] = {
 240        { "adis16080", ID_ADIS16080 },
 241        { "adis16100", ID_ADIS16100 },
 242        {},
 243};
 244MODULE_DEVICE_TABLE(spi, adis16080_ids);
 245
 246static struct spi_driver adis16080_driver = {
 247        .driver = {
 248                .name = "adis16080",
 249                .owner = THIS_MODULE,
 250        },
 251        .probe = adis16080_probe,
 252        .remove = adis16080_remove,
 253        .id_table = adis16080_ids,
 254};
 255module_spi_driver(adis16080_driver);
 256
 257MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
 258MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver");
 259MODULE_LICENSE("GPL v2");
 260