]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/iio/gyro/adis16130_core.c
Merge remote-tracking branch 'moduleh/module.h-split'
[karo-tx-linux.git] / drivers / staging / iio / gyro / adis16130_core.c
1 /*
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
9 #include <linux/delay.h>
10 #include <linux/mutex.h>
11 #include <linux/device.h>
12 #include <linux/kernel.h>
13 #include <linux/spi/spi.h>
14 #include <linux/slab.h>
15 #include <linux/sysfs.h>
16 #include <linux/list.h>
17 #include <linux/module.h>
18
19 #include "../iio.h"
20 #include "../sysfs.h"
21
22 #define ADIS16130_CON         0x0
23 #define ADIS16130_CON_RD      (1 << 6)
24 #define ADIS16130_IOP         0x1
25
26 /* 1 = data-ready signal low when unread data on all channels; */
27 #define ADIS16130_IOP_ALL_RDY (1 << 3)
28 #define ADIS16130_IOP_SYNC    (1 << 0) /* 1 = synchronization enabled */
29 #define ADIS16130_RATEDATA    0x8 /* Gyroscope output, rate of rotation */
30 #define ADIS16130_TEMPDATA    0xA /* Temperature output */
31 #define ADIS16130_RATECS      0x28 /* Gyroscope channel setup */
32 #define ADIS16130_RATECS_EN   (1 << 3) /* 1 = channel enable; */
33 #define ADIS16130_TEMPCS      0x2A /* Temperature channel setup */
34 #define ADIS16130_TEMPCS_EN   (1 << 3)
35 #define ADIS16130_RATECONV    0x30
36 #define ADIS16130_TEMPCONV    0x32
37 #define ADIS16130_MODE        0x38
38 #define ADIS16130_MODE_24BIT  (1 << 1) /* 1 = 24-bit resolution; */
39
40 /**
41  * struct adis16130_state - device instance specific data
42  * @us:                 actual spi_device to write data
43  * @buf_lock:           mutex to protect tx and rx
44  * @buf:                unified tx/rx buffer
45  **/
46 struct adis16130_state {
47         struct spi_device               *us;
48         struct mutex                    buf_lock;
49         u8                              buf[4] ____cacheline_aligned;
50 };
51
52 static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val)
53 {
54         int ret;
55         struct adis16130_state *st = iio_priv(indio_dev);
56         struct spi_message msg;
57         struct spi_transfer xfer = {
58                 .tx_buf = st->buf,
59                 .rx_buf = st->buf,
60                 .len = 4,
61         };
62
63         mutex_lock(&st->buf_lock);
64
65         st->buf[0] = ADIS16130_CON_RD | reg_addr;
66         st->buf[1] = st->buf[2] = st->buf[3] = 0;
67
68         spi_message_init(&msg);
69         spi_message_add_tail(&xfer, &msg);
70         ret = spi_sync(st->us, &msg);
71         ret = spi_read(st->us, st->buf, 4);
72
73         if (ret == 0)
74                 *val = (st->buf[1] << 16) | (st->buf[2] << 8) | st->buf[3];
75         mutex_unlock(&st->buf_lock);
76
77         return ret;
78 }
79
80 static int adis16130_read_raw(struct iio_dev *indio_dev,
81                               struct iio_chan_spec const *chan,
82                               int *val, int *val2,
83                               long mask)
84 {
85         int ret;
86         u32 temp;
87
88         /* Take the iio_dev status lock */
89         mutex_lock(&indio_dev->mlock);
90         ret =  adis16130_spi_read(indio_dev, chan->address, &temp);
91         mutex_unlock(&indio_dev->mlock);
92         if (ret)
93                 return ret;
94         *val = temp;
95         return IIO_VAL_INT;
96 }
97
98 static const struct iio_chan_spec adis16130_channels[] = {
99         {
100                 .type = IIO_GYRO,
101                 .modified = 1,
102                 .channel2 = IIO_MOD_Z,
103                 .address = ADIS16130_RATEDATA,
104         }, {
105                 .type = IIO_TEMP,
106                 .indexed = 1,
107                 .channel = 0,
108                 .address = ADIS16130_TEMPDATA,
109         }
110 };
111
112 static const struct iio_info adis16130_info = {
113         .read_raw = &adis16130_read_raw,
114         .driver_module = THIS_MODULE,
115 };
116
117 static int __devinit adis16130_probe(struct spi_device *spi)
118 {
119         int ret;
120         struct adis16130_state *st;
121         struct iio_dev *indio_dev;
122
123         /* setup the industrialio driver allocated elements */
124         indio_dev = iio_allocate_device(sizeof(*st));
125         if (indio_dev == NULL) {
126                 ret = -ENOMEM;
127                 goto error_ret;
128         }
129         st = iio_priv(indio_dev);
130         /* this is only used for removal purposes */
131         spi_set_drvdata(spi, indio_dev);
132         st->us = spi;
133         mutex_init(&st->buf_lock);
134         indio_dev->name = spi->dev.driver->name;
135         indio_dev->channels = adis16130_channels;
136         indio_dev->num_channels = ARRAY_SIZE(adis16130_channels);
137         indio_dev->dev.parent = &spi->dev;
138         indio_dev->info = &adis16130_info;
139         indio_dev->modes = INDIO_DIRECT_MODE;
140
141         ret = iio_device_register(indio_dev);
142         if (ret)
143                 goto error_free_dev;
144
145         return 0;
146
147 error_free_dev:
148         iio_free_device(indio_dev);
149
150 error_ret:
151         return ret;
152 }
153
154 /* fixme, confirm ordering in this function */
155 static int adis16130_remove(struct spi_device *spi)
156 {
157         iio_device_unregister(spi_get_drvdata(spi));
158
159         return 0;
160 }
161
162 static struct spi_driver adis16130_driver = {
163         .driver = {
164                 .name = "adis16130",
165                 .owner = THIS_MODULE,
166         },
167         .probe = adis16130_probe,
168         .remove = __devexit_p(adis16130_remove),
169 };
170
171 static __init int adis16130_init(void)
172 {
173         return spi_register_driver(&adis16130_driver);
174 }
175 module_init(adis16130_init);
176
177 static __exit void adis16130_exit(void)
178 {
179         spi_unregister_driver(&adis16130_driver);
180 }
181 module_exit(adis16130_exit);
182
183 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
184 MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate");
185 MODULE_LICENSE("GPL v2");