1
2
3
4
5
6
7
8
9#include <linux/interrupt.h>
10#include <linux/irq.h>
11#include <linux/gpio.h>
12#include <linux/delay.h>
13#include <linux/mutex.h>
14#include <linux/device.h>
15#include <linux/kernel.h>
16#include <linux/spi/spi.h>
17#include <linux/slab.h>
18#include <linux/sysfs.h>
19#include <linux/list.h>
20
21#include "../iio.h"
22#include "../sysfs.h"
23#include "gyro.h"
24#include "../adc/adc.h"
25
26#include "adis16080.h"
27
28#define DRIVER_NAME "adis16080"
29
30struct adis16080_state *adis16080_st;
31
32int adis16080_spi_write(struct device *dev,
33 u16 val)
34{
35 int ret;
36 struct iio_dev *indio_dev = dev_get_drvdata(dev);
37 struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
38
39 mutex_lock(&st->buf_lock);
40 st->tx[0] = val >> 8;
41 st->tx[1] = val;
42
43 ret = spi_write(st->us, st->tx, 2);
44 mutex_unlock(&st->buf_lock);
45
46 return ret;
47}
48
49int adis16080_spi_read(struct device *dev,
50 u16 *val)
51{
52 int ret;
53 struct iio_dev *indio_dev = dev_get_drvdata(dev);
54 struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
55
56 mutex_lock(&st->buf_lock);
57
58 ret = spi_read(st->us, st->rx, 2);
59
60 if (ret == 0)
61 *val = ((st->rx[0] & 0xF) << 8) | st->rx[1];
62 mutex_unlock(&st->buf_lock);
63
64 return ret;
65}
66
67static ssize_t adis16080_read(struct device *dev,
68 struct device_attribute *attr,
69 char *buf)
70{
71 struct iio_dev *indio_dev = dev_get_drvdata(dev);
72 u16 val;
73 ssize_t ret;
74
75
76 mutex_lock(&indio_dev->mlock);
77 ret = adis16080_spi_read(dev, &val);
78 mutex_unlock(&indio_dev->mlock);
79
80 if (ret == 0)
81 return sprintf(buf, "%d\n", val);
82 else
83 return ret;
84}
85
86static ssize_t adis16080_write(struct device *dev,
87 struct device_attribute *attr,
88 const char *buf,
89 size_t len)
90{
91 int ret;
92 long val;
93
94 ret = strict_strtol(buf, 16, &val);
95 if (ret)
96 goto error_ret;
97 ret = adis16080_spi_write(dev, val);
98
99error_ret:
100 return ret ? ret : len;
101}
102
103#define IIO_DEV_ATTR_IN(_show) \
104 IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
105
106#define IIO_DEV_ATTR_OUT(_store) \
107 IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
108
109static IIO_DEV_ATTR_IN(adis16080_read);
110static IIO_DEV_ATTR_OUT(adis16080_write);
111
112static IIO_CONST_ATTR(name, "adis16080");
113
114static struct attribute *adis16080_event_attributes[] = {
115 NULL
116};
117
118static struct attribute_group adis16080_event_attribute_group = {
119 .attrs = adis16080_event_attributes,
120};
121
122static struct attribute *adis16080_attributes[] = {
123 &iio_dev_attr_in.dev_attr.attr,
124 &iio_dev_attr_out.dev_attr.attr,
125 &iio_const_attr_name.dev_attr.attr,
126 NULL
127};
128
129static const struct attribute_group adis16080_attribute_group = {
130 .attrs = adis16080_attributes,
131};
132
133static int __devinit adis16080_probe(struct spi_device *spi)
134{
135 int ret, regdone = 0;
136 struct adis16080_state *st = kzalloc(sizeof *st, GFP_KERNEL);
137 if (!st) {
138 ret = -ENOMEM;
139 goto error_ret;
140 }
141
142 spi_set_drvdata(spi, st);
143
144
145 st->rx = kzalloc(sizeof(*st->rx)*ADIS16080_MAX_RX, GFP_KERNEL);
146 if (st->rx == NULL) {
147 ret = -ENOMEM;
148 goto error_free_st;
149 }
150 st->tx = kzalloc(sizeof(*st->tx)*ADIS16080_MAX_TX, GFP_KERNEL);
151 if (st->tx == NULL) {
152 ret = -ENOMEM;
153 goto error_free_rx;
154 }
155 st->us = spi;
156 mutex_init(&st->buf_lock);
157
158 st->indio_dev = iio_allocate_device();
159 if (st->indio_dev == NULL) {
160 ret = -ENOMEM;
161 goto error_free_tx;
162 }
163
164 st->indio_dev->dev.parent = &spi->dev;
165 st->indio_dev->num_interrupt_lines = 1;
166 st->indio_dev->event_attrs = &adis16080_event_attribute_group;
167 st->indio_dev->attrs = &adis16080_attribute_group;
168 st->indio_dev->dev_data = (void *)(st);
169 st->indio_dev->driver_module = THIS_MODULE;
170 st->indio_dev->modes = INDIO_DIRECT_MODE;
171
172 ret = adis16080_configure_ring(st->indio_dev);
173 if (ret)
174 goto error_free_dev;
175
176 ret = iio_device_register(st->indio_dev);
177 if (ret)
178 goto error_unreg_ring_funcs;
179 regdone = 1;
180
181 ret = adis16080_initialize_ring(st->indio_dev->ring);
182 if (ret) {
183 printk(KERN_ERR "failed to initialize the ring\n");
184 goto error_unreg_ring_funcs;
185 }
186
187 if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
188 ret = iio_register_interrupt_line(spi->irq,
189 st->indio_dev,
190 0,
191 IRQF_TRIGGER_RISING,
192 "adis16080");
193 if (ret)
194 goto error_uninitialize_ring;
195
196 ret = adis16080_probe_trigger(st->indio_dev);
197 if (ret)
198 goto error_unregister_line;
199 }
200
201 adis16080_st = st;
202 return 0;
203
204error_unregister_line:
205 if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
206 iio_unregister_interrupt_line(st->indio_dev, 0);
207error_uninitialize_ring:
208 adis16080_uninitialize_ring(st->indio_dev->ring);
209error_unreg_ring_funcs:
210 adis16080_unconfigure_ring(st->indio_dev);
211error_free_dev:
212 if (regdone)
213 iio_device_unregister(st->indio_dev);
214 else
215 iio_free_device(st->indio_dev);
216error_free_tx:
217 kfree(st->tx);
218error_free_rx:
219 kfree(st->rx);
220error_free_st:
221 kfree(st);
222error_ret:
223 return ret;
224}
225
226
227static int adis16080_remove(struct spi_device *spi)
228{
229 struct adis16080_state *st = spi_get_drvdata(spi);
230 struct iio_dev *indio_dev = st->indio_dev;
231
232 flush_scheduled_work();
233
234 adis16080_remove_trigger(indio_dev);
235 if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
236 iio_unregister_interrupt_line(indio_dev, 0);
237
238 adis16080_uninitialize_ring(indio_dev->ring);
239 adis16080_unconfigure_ring(indio_dev);
240 iio_device_unregister(indio_dev);
241 kfree(st->tx);
242 kfree(st->rx);
243 kfree(st);
244
245 return 0;
246}
247
248static struct spi_driver adis16080_driver = {
249 .driver = {
250 .name = "adis16080",
251 .owner = THIS_MODULE,
252 },
253 .probe = adis16080_probe,
254 .remove = __devexit_p(adis16080_remove),
255};
256
257static __init int adis16080_init(void)
258{
259 return spi_register_driver(&adis16080_driver);
260}
261module_init(adis16080_init);
262
263static __exit void adis16080_exit(void)
264{
265 spi_unregister_driver(&adis16080_driver);
266}
267module_exit(adis16080_exit);
268
269MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
270MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver");
271MODULE_LICENSE("GPL v2");
272