blob: 9155cf6cf287f078ce7947f12ec7812642406e75 [file] [log] [blame]
Barry Song7a83f602010-10-27 21:44:06 -04001/*
2 * ADIS16130 Digital Output, High Precision Angular Rate Sensor driver
3 *
4 * Copyright 2010 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
Barry Song7a83f602010-10-27 21:44:06 -04009#include <linux/mutex.h>
Barry Song7a83f602010-10-27 21:44:06 -040010#include <linux/kernel.h>
11#include <linux/spi/spi.h>
Paul Gortmaker99c97852011-07-03 15:49:50 -040012#include <linux/module.h>
Barry Song7a83f602010-10-27 21:44:06 -040013
Jonathan Cameron06458e22012-04-25 15:54:58 +010014#include <linux/iio/iio.h>
Barry Song7a83f602010-10-27 21:44:06 -040015
Jonathan Cameron8e678752011-02-26 17:30:18 +000016#define ADIS16130_CON 0x0
17#define ADIS16130_CON_RD (1 << 6)
18#define ADIS16130_IOP 0x1
19
20/* 1 = data-ready signal low when unread data on all channels; */
21#define ADIS16130_IOP_ALL_RDY (1 << 3)
22#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
23#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
24#define ADIS16130_TEMPDATA 0xA /* Temperature output */
25#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
26#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
27#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
28#define ADIS16130_TEMPCS_EN (1 << 3)
29#define ADIS16130_RATECONV 0x30
30#define ADIS16130_TEMPCONV 0x32
31#define ADIS16130_MODE 0x38
32#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
33
34/**
35 * struct adis16130_state - device instance specific data
36 * @us: actual spi_device to write data
Jonathan Cameron8e678752011-02-26 17:30:18 +000037 * @buf_lock: mutex to protect tx and rx
38 * @buf: unified tx/rx buffer
39 **/
40struct adis16130_state {
41 struct spi_device *us;
Jonathan Cameron8e678752011-02-26 17:30:18 +000042 struct mutex buf_lock;
43 u8 buf[4] ____cacheline_aligned;
44};
Barry Song7a83f602010-10-27 21:44:06 -040045
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +010046static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val)
Barry Song7a83f602010-10-27 21:44:06 -040047{
48 int ret;
Jonathan Cameron9f8632d2011-06-27 13:07:45 +010049 struct adis16130_state *st = iio_priv(indio_dev);
Jonathan Cameroncdf6e812011-08-12 16:55:28 +010050 struct spi_message msg;
51 struct spi_transfer xfer = {
52 .tx_buf = st->buf,
53 .rx_buf = st->buf,
Jonathan Camerona5e73632011-08-12 17:08:41 +010054 .len = 4,
Jonathan Cameroncdf6e812011-08-12 16:55:28 +010055 };
Barry Song7a83f602010-10-27 21:44:06 -040056
57 mutex_lock(&st->buf_lock);
58
Jonathan Cameron8e678752011-02-26 17:30:18 +000059 st->buf[0] = ADIS16130_CON_RD | reg_addr;
Jonathan Cameroncdf6e812011-08-12 16:55:28 +010060 st->buf[1] = st->buf[2] = st->buf[3] = 0;
Barry Song7a83f602010-10-27 21:44:06 -040061
Jonathan Cameroncdf6e812011-08-12 16:55:28 +010062 spi_message_init(&msg);
63 spi_message_add_tail(&xfer, &msg);
64 ret = spi_sync(st->us, &msg);
Barry Song7a83f602010-10-27 21:44:06 -040065
Jonathan Camerona5e73632011-08-12 17:08:41 +010066 if (ret == 0)
67 *val = (st->buf[1] << 16) | (st->buf[2] << 8) | st->buf[3];
Barry Song7a83f602010-10-27 21:44:06 -040068 mutex_unlock(&st->buf_lock);
69
70 return ret;
71}
72
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +010073static int adis16130_read_raw(struct iio_dev *indio_dev,
74 struct iio_chan_spec const *chan,
75 int *val, int *val2,
76 long mask)
Barry Song7a83f602010-10-27 21:44:06 -040077{
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +010078 int ret;
79 u32 temp;
Barry Song7a83f602010-10-27 21:44:06 -040080
Lars-Peter Clausen597e1a82013-06-10 15:00:00 +010081 switch (mask) {
82 case IIO_CHAN_INFO_RAW:
83 /* Take the iio_dev status lock */
84 mutex_lock(&indio_dev->mlock);
85 ret = adis16130_spi_read(indio_dev, chan->address, &temp);
86 mutex_unlock(&indio_dev->mlock);
87 if (ret)
88 return ret;
89 *val = temp;
90 return IIO_VAL_INT;
91 case IIO_CHAN_INFO_SCALE:
92 switch (chan->type) {
93 case IIO_ANGL_VEL:
94 /* 0 degree = 838860, 250 degree = 14260608 */
95 *val = 250;
96 *val2 = 336440817; /* RAD_TO_DEGREE(14260608 - 8388608) */
97 return IIO_VAL_FRACTIONAL;
98 case IIO_TEMP:
99 /* 0C = 8036283, 105C = 9516048 */
100 *val = 105000;
101 *val2 = 9516048 - 8036283;
102 return IIO_VAL_FRACTIONAL;
103 default:
104 return -EINVAL;
105 }
Lars-Peter Clausen597e1a82013-06-10 15:00:00 +0100106 case IIO_CHAN_INFO_OFFSET:
107 switch (chan->type) {
108 case IIO_ANGL_VEL:
109 *val = -8388608;
110 return IIO_VAL_INT;
111 case IIO_TEMP:
112 *val = -8036283;
113 return IIO_VAL_INT;
114 default:
115 return -EINVAL;
116 }
Lars-Peter Clausen597e1a82013-06-10 15:00:00 +0100117 }
118
119 return -EINVAL;
Barry Song7a83f602010-10-27 21:44:06 -0400120}
121
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +0100122static const struct iio_chan_spec adis16130_channels[] = {
123 {
Jonathan Cameron41ea0402011-10-05 15:27:59 +0100124 .type = IIO_ANGL_VEL,
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +0100125 .modified = 1,
126 .channel2 = IIO_MOD_Z,
Lars-Peter Clausen597e1a82013-06-10 15:00:00 +0100127 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
128 BIT(IIO_CHAN_INFO_SCALE) |
129 BIT(IIO_CHAN_INFO_OFFSET),
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +0100130 .address = ADIS16130_RATEDATA,
131 }, {
132 .type = IIO_TEMP,
133 .indexed = 1,
134 .channel = 0,
Lars-Peter Clausen597e1a82013-06-10 15:00:00 +0100135 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
136 BIT(IIO_CHAN_INFO_SCALE) |
137 BIT(IIO_CHAN_INFO_OFFSET),
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +0100138 .address = ADIS16130_TEMPDATA,
139 }
Barry Song7a83f602010-10-27 21:44:06 -0400140};
141
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100142static const struct iio_info adis16130_info = {
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +0100143 .read_raw = &adis16130_read_raw,
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100144 .driver_module = THIS_MODULE,
145};
146
Bill Pemberton4ae1c612012-11-19 13:21:57 -0500147static int adis16130_probe(struct spi_device *spi)
Barry Song7a83f602010-10-27 21:44:06 -0400148{
Jonathan Cameron9f8632d2011-06-27 13:07:45 +0100149 struct adis16130_state *st;
150 struct iio_dev *indio_dev;
151
152 /* setup the industrialio driver allocated elements */
Sachin Kamat42aceff2013-08-13 07:34:00 +0100153 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
154 if (!indio_dev)
155 return -ENOMEM;
Jonathan Cameron9f8632d2011-06-27 13:07:45 +0100156 st = iio_priv(indio_dev);
Barry Song7a83f602010-10-27 21:44:06 -0400157 /* this is only used for removal purposes */
Jonathan Cameron9f8632d2011-06-27 13:07:45 +0100158 spi_set_drvdata(spi, indio_dev);
Barry Song7a83f602010-10-27 21:44:06 -0400159 st->us = spi;
160 mutex_init(&st->buf_lock);
Jonathan Cameron9f8632d2011-06-27 13:07:45 +0100161 indio_dev->name = spi->dev.driver->name;
Jonathan Cameronae0b4bdd2011-08-12 17:47:59 +0100162 indio_dev->channels = adis16130_channels;
163 indio_dev->num_channels = ARRAY_SIZE(adis16130_channels);
Jonathan Cameron9f8632d2011-06-27 13:07:45 +0100164 indio_dev->dev.parent = &spi->dev;
165 indio_dev->info = &adis16130_info;
166 indio_dev->modes = INDIO_DIRECT_MODE;
Barry Song7a83f602010-10-27 21:44:06 -0400167
Sachin Kamat42aceff2013-08-13 07:34:00 +0100168 return iio_device_register(indio_dev);
Barry Song7a83f602010-10-27 21:44:06 -0400169}
170
Bill Pemberton447d4f22012-11-19 13:26:37 -0500171static int adis16130_remove(struct spi_device *spi)
Barry Song7a83f602010-10-27 21:44:06 -0400172{
Jonathan Cameron9f8632d2011-06-27 13:07:45 +0100173 iio_device_unregister(spi_get_drvdata(spi));
Barry Song7a83f602010-10-27 21:44:06 -0400174 return 0;
175}
176
177static struct spi_driver adis16130_driver = {
178 .driver = {
179 .name = "adis16130",
180 .owner = THIS_MODULE,
181 },
182 .probe = adis16130_probe,
Bill Pembertone543acf2012-11-19 13:21:38 -0500183 .remove = adis16130_remove,
Barry Song7a83f602010-10-27 21:44:06 -0400184};
Lars-Peter Clausenae6ae6f2011-11-16 10:13:39 +0100185module_spi_driver(adis16130_driver);
Barry Song7a83f602010-10-27 21:44:06 -0400186
187MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
Jonathan Cameron8e678752011-02-26 17:30:18 +0000188MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate");
Barry Song7a83f602010-10-27 21:44:06 -0400189MODULE_LICENSE("GPL v2");
Lars-Peter Clausen55e43902011-11-16 08:53:31 +0100190MODULE_ALIAS("spi:adis16130");