]> Pileus Git - ~andy/linux/blob - drivers/staging/iio/gyro/adis16130_core.c
Merge branch 'iommu-for-tony' of git://github.com/ohadbc/omap-iommu into devel-fixes
[~andy/linux] / 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
18 #include "../iio.h"
19 #include "../sysfs.h"
20 #include "gyro.h"
21 #include "../adc/adc.h"
22
23 #define ADIS16130_CON         0x0
24 #define ADIS16130_CON_RD      (1 << 6)
25 #define ADIS16130_IOP         0x1
26
27 /* 1 = data-ready signal low when unread data on all channels; */
28 #define ADIS16130_IOP_ALL_RDY (1 << 3)
29 #define ADIS16130_IOP_SYNC    (1 << 0) /* 1 = synchronization enabled */
30 #define ADIS16130_RATEDATA    0x8 /* Gyroscope output, rate of rotation */
31 #define ADIS16130_TEMPDATA    0xA /* Temperature output */
32 #define ADIS16130_RATECS      0x28 /* Gyroscope channel setup */
33 #define ADIS16130_RATECS_EN   (1 << 3) /* 1 = channel enable; */
34 #define ADIS16130_TEMPCS      0x2A /* Temperature channel setup */
35 #define ADIS16130_TEMPCS_EN   (1 << 3)
36 #define ADIS16130_RATECONV    0x30
37 #define ADIS16130_TEMPCONV    0x32
38 #define ADIS16130_MODE        0x38
39 #define ADIS16130_MODE_24BIT  (1 << 1) /* 1 = 24-bit resolution; */
40
41 /**
42  * struct adis16130_state - device instance specific data
43  * @us:                 actual spi_device to write data
44  * @indio_dev:          industrial I/O device structure
45  * @mode:               24 bits (1) or 16 bits (0)
46  * @buf_lock:           mutex to protect tx and rx
47  * @buf:                unified tx/rx buffer
48  **/
49 struct adis16130_state {
50         struct spi_device               *us;
51         struct iio_dev                  *indio_dev;
52         u32                             mode;
53         struct mutex                    buf_lock;
54         u8                              buf[4] ____cacheline_aligned;
55 };
56
57 static int adis16130_spi_write(struct device *dev, u8 reg_addr,
58                 u8 val)
59 {
60         int ret;
61         struct iio_dev *indio_dev = dev_get_drvdata(dev);
62         struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
63
64         mutex_lock(&st->buf_lock);
65         st->buf[0] = reg_addr;
66         st->buf[1] = val;
67
68         ret = spi_write(st->us, st->buf, 2);
69         mutex_unlock(&st->buf_lock);
70
71         return ret;
72 }
73
74 static int adis16130_spi_read(struct device *dev, u8 reg_addr,
75                 u32 *val)
76 {
77         int ret;
78         struct iio_dev *indio_dev = dev_get_drvdata(dev);
79         struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
80
81         mutex_lock(&st->buf_lock);
82
83         st->buf[0] = ADIS16130_CON_RD | reg_addr;
84         if (st->mode)
85                 ret = spi_read(st->us, st->buf, 4);
86         else
87                 ret = spi_read(st->us, st->buf, 3);
88
89         if (ret == 0) {
90                 if (st->mode)
91                         *val = (st->buf[1] << 16) |
92                                 (st->buf[2] << 8) |
93                                 st->buf[3];
94                 else
95                         *val = (st->buf[1] << 8) | st->buf[2];
96         }
97
98         mutex_unlock(&st->buf_lock);
99
100         return ret;
101 }
102
103 static ssize_t adis16130_val_read(struct device *dev,
104                 struct device_attribute *attr,
105                 char *buf)
106 {
107         struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
108         struct iio_dev *indio_dev = dev_get_drvdata(dev);
109         u32 val;
110         ssize_t ret;
111
112         /* Take the iio_dev status lock */
113         mutex_lock(&indio_dev->mlock);
114         ret =  adis16130_spi_read(dev, this_attr->address, &val);
115         mutex_unlock(&indio_dev->mlock);
116
117         if (ret == 0)
118                 return sprintf(buf, "%d\n", val);
119         else
120                 return ret;
121 }
122
123 static ssize_t adis16130_bitsmode_read(struct device *dev,
124                 struct device_attribute *attr,
125                 char *buf)
126 {
127         struct iio_dev *indio_dev = dev_get_drvdata(dev);
128         struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
129
130         if (st->mode == 1)
131                 return sprintf(buf, "s24\n");
132         else
133                 return sprintf(buf, "s16\n");
134 }
135
136 static ssize_t adis16130_bitsmode_write(struct device *dev,
137                 struct device_attribute *attr,
138                 const char *buf,
139                 size_t len)
140 {
141         int ret;
142         u8 val;
143
144         if (sysfs_streq(buf, "s16"))
145                 val = 0;
146         else if (sysfs_streq(buf, "s24"))
147                 val = 1;
148         else
149                 return -EINVAL;
150
151         ret = adis16130_spi_write(dev, ADIS16130_MODE, val);
152
153         return ret ? ret : len;
154 }
155 static IIO_DEVICE_ATTR(temp_raw, S_IRUGO, adis16130_val_read, NULL,
156                       ADIS16130_TEMPDATA);
157
158 static IIO_DEV_ATTR_GYRO_Z(adis16130_val_read, ADIS16130_RATEDATA);
159
160 static IIO_DEVICE_ATTR(gyro_z_type, S_IWUSR | S_IRUGO, adis16130_bitsmode_read,
161                         adis16130_bitsmode_write,
162                         ADIS16130_MODE);
163
164 static IIO_CONST_ATTR(gyro_z_type_available, "s16 s24");
165
166 static struct attribute *adis16130_attributes[] = {
167         &iio_dev_attr_temp_raw.dev_attr.attr,
168         &iio_dev_attr_gyro_z_raw.dev_attr.attr,
169         &iio_dev_attr_gyro_z_type.dev_attr.attr,
170         &iio_const_attr_gyro_z_type_available.dev_attr.attr,
171         NULL
172 };
173
174 static const struct attribute_group adis16130_attribute_group = {
175         .attrs = adis16130_attributes,
176 };
177
178 static const struct iio_info adis16130_info = {
179         .attrs = &adis16130_attribute_group,
180         .driver_module = THIS_MODULE,
181 };
182
183 static int __devinit adis16130_probe(struct spi_device *spi)
184 {
185         int ret;
186         struct adis16130_state *st = kzalloc(sizeof *st, GFP_KERNEL);
187         if (!st) {
188                 ret =  -ENOMEM;
189                 goto error_ret;
190         }
191         /* this is only used for removal purposes */
192         spi_set_drvdata(spi, st);
193         st->us = spi;
194         mutex_init(&st->buf_lock);
195         /* setup the industrialio driver allocated elements */
196         st->indio_dev = iio_allocate_device(0);
197         if (st->indio_dev == NULL) {
198                 ret = -ENOMEM;
199                 goto error_free_st;
200         }
201
202         st->indio_dev->name = spi->dev.driver->name;
203         st->indio_dev->dev.parent = &spi->dev;
204         st->indio_dev->info = &adis16130_info;
205         st->indio_dev->dev_data = (void *)(st);
206         st->indio_dev->modes = INDIO_DIRECT_MODE;
207         st->mode = 1;
208
209         ret = iio_device_register(st->indio_dev);
210         if (ret)
211                 goto error_free_dev;
212
213         return 0;
214
215 error_free_dev:
216         iio_free_device(st->indio_dev);
217 error_free_st:
218         kfree(st);
219 error_ret:
220         return ret;
221 }
222
223 /* fixme, confirm ordering in this function */
224 static int adis16130_remove(struct spi_device *spi)
225 {
226         struct adis16130_state *st = spi_get_drvdata(spi);
227         struct iio_dev *indio_dev = st->indio_dev;
228
229         iio_device_unregister(indio_dev);
230         kfree(st);
231
232         return 0;
233 }
234
235 static struct spi_driver adis16130_driver = {
236         .driver = {
237                 .name = "adis16130",
238                 .owner = THIS_MODULE,
239         },
240         .probe = adis16130_probe,
241         .remove = __devexit_p(adis16130_remove),
242 };
243
244 static __init int adis16130_init(void)
245 {
246         return spi_register_driver(&adis16130_driver);
247 }
248 module_init(adis16130_init);
249
250 static __exit void adis16130_exit(void)
251 {
252         spi_unregister_driver(&adis16130_driver);
253 }
254 module_exit(adis16130_exit);
255
256 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
257 MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate");
258 MODULE_LICENSE("GPL v2");