Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
adis16060_core.c
Go to the documentation of this file.
1 /*
2  * ADIS16060 Wide Bandwidth Yaw Rate Gyroscope with SPI driver
3  *
4  * Copyright 2010 Analog Devices Inc.
5  *
6  * Licensed under the GPL-2 or later.
7  */
8 
9 #include <linux/module.h>
10 #include <linux/delay.h>
11 #include <linux/mutex.h>
12 #include <linux/device.h>
13 #include <linux/kernel.h>
14 #include <linux/spi/spi.h>
15 #include <linux/slab.h>
16 #include <linux/sysfs.h>
17 
18 #include <linux/iio/iio.h>
19 #include <linux/iio/sysfs.h>
20 
21 #define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
22 #define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */
23 #define ADIS16060_AIN2 0x80 /* Measure AIN2 */
24 #define ADIS16060_AIN1 0x40 /* Measure AIN1 */
25 
34  struct spi_device *us_w;
35  struct spi_device *us_r;
36  struct mutex buf_lock;
37 
39 };
40 
41 static struct iio_dev *adis16060_iio_dev;
42 
43 static int adis16060_spi_write(struct iio_dev *indio_dev, u8 val)
44 {
45  int ret;
46  struct adis16060_state *st = iio_priv(indio_dev);
47 
48  mutex_lock(&st->buf_lock);
49  st->buf[2] = val; /* The last 8 bits clocked in are latched */
50  ret = spi_write(st->us_w, st->buf, 3);
51  mutex_unlock(&st->buf_lock);
52 
53  return ret;
54 }
55 
56 static int adis16060_spi_read(struct iio_dev *indio_dev, u16 *val)
57 {
58  int ret;
59  struct adis16060_state *st = iio_priv(indio_dev);
60 
61  mutex_lock(&st->buf_lock);
62 
63  ret = spi_read(st->us_r, st->buf, 3);
64 
65  /* The internal successive approximation ADC begins the
66  * conversion process on the falling edge of MSEL1 and
67  * starts to place data MSB first on the DOUT line at
68  * the 6th falling edge of SCLK
69  */
70  if (ret == 0)
71  *val = ((st->buf[0] & 0x3) << 12) |
72  (st->buf[1] << 4) |
73  ((st->buf[2] >> 4) & 0xF);
74  mutex_unlock(&st->buf_lock);
75 
76  return ret;
77 }
78 
79 static int adis16060_read_raw(struct iio_dev *indio_dev,
80  struct iio_chan_spec const *chan,
81  int *val, int *val2,
82  long mask)
83 {
84  u16 tval = 0;
85  int ret;
86 
87  switch (mask) {
88  case IIO_CHAN_INFO_RAW:
89  /* Take the iio_dev status lock */
90  mutex_lock(&indio_dev->mlock);
91  ret = adis16060_spi_write(indio_dev, chan->address);
92  if (ret < 0) {
93  mutex_unlock(&indio_dev->mlock);
94  return ret;
95  }
96  ret = adis16060_spi_read(indio_dev, &tval);
97  mutex_unlock(&indio_dev->mlock);
98  *val = tval;
99  return IIO_VAL_INT;
101  *val = -7;
102  *val2 = 461117;
103  return IIO_VAL_INT_PLUS_MICRO;
104  case IIO_CHAN_INFO_SCALE:
105  *val = 0;
106  *val2 = 34000;
107  return IIO_VAL_INT_PLUS_MICRO;
108  }
109 
110  return -EINVAL;
111 }
112 
113 static const struct iio_info adis16060_info = {
114  .read_raw = &adis16060_read_raw,
115  .driver_module = THIS_MODULE,
116 };
117 
118 static const struct iio_chan_spec adis16060_channels[] = {
119  {
120  .type = IIO_ANGL_VEL,
121  .modified = 1,
122  .channel2 = IIO_MOD_Z,
123  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
124  .address = ADIS16060_GYRO,
125  }, {
126  .type = IIO_VOLTAGE,
127  .indexed = 1,
128  .channel = 0,
129  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
130  .address = ADIS16060_AIN1,
131  }, {
132  .type = IIO_VOLTAGE,
133  .indexed = 1,
134  .channel = 1,
135  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
136  .address = ADIS16060_AIN2,
137  }, {
138  .type = IIO_TEMP,
139  .indexed = 1,
140  .channel = 0,
141  .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
144  .address = ADIS16060_TEMP_OUT,
145  }
146 };
147 
148 static int __devinit adis16060_r_probe(struct spi_device *spi)
149 {
150  int ret;
151  struct adis16060_state *st;
152  struct iio_dev *indio_dev;
153 
154  /* setup the industrialio driver allocated elements */
155  indio_dev = iio_device_alloc(sizeof(*st));
156  if (indio_dev == NULL) {
157  ret = -ENOMEM;
158  goto error_ret;
159  }
160  /* this is only used for removal purposes */
161  spi_set_drvdata(spi, indio_dev);
162  st = iio_priv(indio_dev);
163  st->us_r = spi;
164  mutex_init(&st->buf_lock);
165 
166  indio_dev->name = spi->dev.driver->name;
167  indio_dev->dev.parent = &spi->dev;
168  indio_dev->info = &adis16060_info;
169  indio_dev->modes = INDIO_DIRECT_MODE;
170  indio_dev->channels = adis16060_channels;
171  indio_dev->num_channels = ARRAY_SIZE(adis16060_channels);
172 
173  ret = iio_device_register(indio_dev);
174  if (ret)
175  goto error_free_dev;
176 
177  adis16060_iio_dev = indio_dev;
178  return 0;
179 
180 error_free_dev:
181  iio_device_free(indio_dev);
182 error_ret:
183  return ret;
184 }
185 
186 /* fixme, confirm ordering in this function */
187 static int __devexit adis16060_r_remove(struct spi_device *spi)
188 {
189  iio_device_unregister(spi_get_drvdata(spi));
190  iio_device_free(spi_get_drvdata(spi));
191 
192  return 0;
193 }
194 
195 static int __devinit adis16060_w_probe(struct spi_device *spi)
196 {
197  int ret;
198  struct iio_dev *indio_dev = adis16060_iio_dev;
199  struct adis16060_state *st;
200  if (!indio_dev) {
201  ret = -ENODEV;
202  goto error_ret;
203  }
204  st = iio_priv(indio_dev);
205  spi_set_drvdata(spi, indio_dev);
206  st->us_w = spi;
207  return 0;
208 
209 error_ret:
210  return ret;
211 }
212 
213 static int __devexit adis16060_w_remove(struct spi_device *spi)
214 {
215  return 0;
216 }
217 
218 static struct spi_driver adis16060_r_driver = {
219  .driver = {
220  .name = "adis16060_r",
221  .owner = THIS_MODULE,
222  },
223  .probe = adis16060_r_probe,
224  .remove = __devexit_p(adis16060_r_remove),
225 };
226 
227 static struct spi_driver adis16060_w_driver = {
228  .driver = {
229  .name = "adis16060_w",
230  .owner = THIS_MODULE,
231  },
232  .probe = adis16060_w_probe,
233  .remove = __devexit_p(adis16060_w_remove),
234 };
235 
236 static __init int adis16060_init(void)
237 {
238  int ret;
239 
240  ret = spi_register_driver(&adis16060_r_driver);
241  if (ret < 0)
242  return ret;
243 
244  ret = spi_register_driver(&adis16060_w_driver);
245  if (ret < 0) {
246  spi_unregister_driver(&adis16060_r_driver);
247  return ret;
248  }
249 
250  return 0;
251 }
252 module_init(adis16060_init);
253 
254 static __exit void adis16060_exit(void)
255 {
256  spi_unregister_driver(&adis16060_w_driver);
257  spi_unregister_driver(&adis16060_r_driver);
258 }
259 module_exit(adis16060_exit);
260 
261 MODULE_AUTHOR("Barry Song <[email protected]>");
262 MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope Driver");
263 MODULE_LICENSE("GPL v2");