]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/iio/gyro/adis16080_core.c
Merge commit '6bb27d7349db51b50c40534710fe164ca0d58902' into omap-timer-for-v3.10
[karo-tx-linux.git] / drivers / staging / iio / gyro / adis16080_core.c
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
32 /**
33  * struct adis16080_state - device instance specific data
34  * @us:                 actual spi_device to write data
35  * @buf:                transmit or receive buffer
36  * @buf_lock:           mutex to protect tx and rx
37  **/
38 struct adis16080_state {
39         struct spi_device               *us;
40         struct mutex                    buf_lock;
41
42         u8 buf[2] ____cacheline_aligned;
43 };
44
45 static int adis16080_spi_write(struct iio_dev *indio_dev,
46                 u16 val)
47 {
48         int ret;
49         struct adis16080_state *st = iio_priv(indio_dev);
50
51         mutex_lock(&st->buf_lock);
52         st->buf[0] = val >> 8;
53         st->buf[1] = val;
54
55         ret = spi_write(st->us, st->buf, 2);
56         mutex_unlock(&st->buf_lock);
57
58         return ret;
59 }
60
61 static int adis16080_spi_read(struct iio_dev *indio_dev,
62                               u16 *val)
63 {
64         int ret;
65         struct adis16080_state *st = iio_priv(indio_dev);
66
67         mutex_lock(&st->buf_lock);
68
69         ret = spi_read(st->us, st->buf, 2);
70
71         if (ret == 0)
72                 *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11);
73         mutex_unlock(&st->buf_lock);
74
75         return ret;
76 }
77
78 static int adis16080_read_raw(struct iio_dev *indio_dev,
79                              struct iio_chan_spec const *chan,
80                              int *val,
81                              int *val2,
82                              long mask)
83 {
84         int ret = -EINVAL;
85         u16 ut = 0;
86         /* Take the iio_dev status lock */
87
88         mutex_lock(&indio_dev->mlock);
89         switch (mask) {
90         case IIO_CHAN_INFO_RAW:
91                 ret = adis16080_spi_write(indio_dev,
92                                           chan->address |
93                                           ADIS16080_DIN_WRITE);
94                 if (ret < 0)
95                         break;
96                 ret = adis16080_spi_read(indio_dev, &ut);
97                 if (ret < 0)
98                         break;
99                 *val = ut;
100                 ret = IIO_VAL_INT;
101                 break;
102         }
103         mutex_unlock(&indio_dev->mlock);
104
105         return ret;
106 }
107
108 static const struct iio_chan_spec adis16080_channels[] = {
109         {
110                 .type = IIO_ANGL_VEL,
111                 .modified = 1,
112                 .channel2 = IIO_MOD_Z,
113                 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
114                 .address = ADIS16080_DIN_GYRO,
115         }, {
116                 .type = IIO_VOLTAGE,
117                 .indexed = 1,
118                 .channel = 0,
119                 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
120                 .address = ADIS16080_DIN_AIN1,
121         }, {
122                 .type = IIO_VOLTAGE,
123                 .indexed = 1,
124                 .channel = 1,
125                 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
126                 .address = ADIS16080_DIN_AIN2,
127         }, {
128                 .type = IIO_TEMP,
129                 .indexed = 1,
130                 .channel = 0,
131                 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
132                 .address = ADIS16080_DIN_TEMP,
133         }
134 };
135
136 static const struct iio_info adis16080_info = {
137         .read_raw = &adis16080_read_raw,
138         .driver_module = THIS_MODULE,
139 };
140
141 static int adis16080_probe(struct spi_device *spi)
142 {
143         int ret;
144         struct adis16080_state *st;
145         struct iio_dev *indio_dev;
146
147         /* setup the industrialio driver allocated elements */
148         indio_dev = iio_device_alloc(sizeof(*st));
149         if (indio_dev == NULL) {
150                 ret = -ENOMEM;
151                 goto error_ret;
152         }
153         st = iio_priv(indio_dev);
154         /* this is only used for removal purposes */
155         spi_set_drvdata(spi, indio_dev);
156
157         /* Allocate the comms buffers */
158         st->us = spi;
159         mutex_init(&st->buf_lock);
160
161         indio_dev->name = spi->dev.driver->name;
162         indio_dev->channels = adis16080_channels;
163         indio_dev->num_channels = ARRAY_SIZE(adis16080_channels);
164         indio_dev->dev.parent = &spi->dev;
165         indio_dev->info = &adis16080_info;
166         indio_dev->modes = INDIO_DIRECT_MODE;
167
168         ret = iio_device_register(indio_dev);
169         if (ret)
170                 goto error_free_dev;
171         return 0;
172
173 error_free_dev:
174         iio_device_free(indio_dev);
175 error_ret:
176         return ret;
177 }
178
179 /* fixme, confirm ordering in this function */
180 static int adis16080_remove(struct spi_device *spi)
181 {
182         iio_device_unregister(spi_get_drvdata(spi));
183         iio_device_free(spi_get_drvdata(spi));
184
185         return 0;
186 }
187
188 static struct spi_driver adis16080_driver = {
189         .driver = {
190                 .name = "adis16080",
191                 .owner = THIS_MODULE,
192         },
193         .probe = adis16080_probe,
194         .remove = adis16080_remove,
195 };
196 module_spi_driver(adis16080_driver);
197
198 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
199 MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver");
200 MODULE_LICENSE("GPL v2");
201 MODULE_ALIAS("spi:adis16080");