• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/adis16255/
1/*
2 * Analog Devices ADIS16250/ADIS16255 Low Power Gyroscope
3 *
4 * Written by: Matthias Brugger <m_brugger@web.de>
5 *
6 * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 */
23
24/*
25 * The driver just has a bare interface to the sysfs (sample rate in Hz,
26 * orientation (x, y, z) and gyroscope data in ��/sec.
27 *
28 * It should be added to iio subsystem when this has left staging.
29 *
30 */
31
32#include <linux/init.h>
33#include <linux/module.h>
34#include <linux/device.h>
35#include <linux/list.h>
36#include <linux/errno.h>
37#include <linux/mutex.h>
38#include <linux/slab.h>
39
40#include <linux/interrupt.h>
41#include <linux/sysfs.h>
42#include <linux/stat.h>
43#include <linux/delay.h>
44
45#include <linux/gpio.h>
46
47#include <linux/spi/spi.h>
48#include <linux/workqueue.h>
49
50#include "adis16255.h"
51
52#define ADIS_STATUS        0x3d
53#define ADIS_SMPL_PRD_MSB  0x37
54#define ADIS_SMPL_PRD_LSB  0x36
55#define ADIS_MSC_CTRL_MSB  0x35
56#define ADIS_MSC_CTRL_LSB  0x34
57#define ADIS_GPIO_CTRL     0x33
58#define ADIS_ALM_SMPL1     0x25
59#define ADIS_ALM_MAG1      0x21
60#define ADIS_GYRO_SCALE    0x17
61#define ADIS_GYRO_OUT      0x05
62#define ADIS_SUPPLY_OUT    0x03
63#define ADIS_ENDURANCE     0x01
64
65/*
66 * data structure for every sensor
67 *
68 * @dev:       Driver model representation of the device.
69 * @spi:       Pointer to the spi device which will manage i/o to spi bus.
70 * @data:      Last read data from device.
71 * @irq_adis:  GPIO Number of IRQ signal
72 * @irq:       irq line manage by kernel
73 * @negative:  indicates if sensor is upside down (negative == 1)
74 * @direction: indicates axis (x, y, z) the sensor is meassuring
75 */
76struct spi_adis16255_data {
77	struct device dev;
78	struct spi_device *spi;
79	s16 data;
80	int irq;
81	u8 negative;
82	char direction;
83};
84
85/*-------------------------------------------------------------------------*/
86
87static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis,
88					u8 adr,
89					u8 *rbuf)
90{
91	struct spi_device *spi = spiadis->spi;
92	struct spi_message msg;
93	struct spi_transfer xfer1, xfer2;
94	u8 *buf, *rx;
95	int ret;
96
97	buf = kzalloc(4, GFP_KERNEL);
98	if (buf == NULL)
99		return -ENOMEM;
100
101	rx = kzalloc(4, GFP_KERNEL);
102	if (rx == NULL) {
103		ret = -ENOMEM;
104		goto err_buf;
105	}
106
107	buf[0] = adr;
108
109	spi_message_init(&msg);
110	memset(&xfer1, 0, sizeof(xfer1));
111	memset(&xfer2, 0, sizeof(xfer2));
112
113	xfer1.tx_buf = buf;
114	xfer1.rx_buf = buf + 2;
115	xfer1.len = 2;
116	xfer1.delay_usecs = 9;
117
118	xfer2.tx_buf = rx + 2;
119	xfer2.rx_buf = rx;
120	xfer2.len = 2;
121
122	spi_message_add_tail(&xfer1, &msg);
123	spi_message_add_tail(&xfer2, &msg);
124
125	ret = spi_sync(spi, &msg);
126	if (ret == 0) {
127		rbuf[0] = rx[0];
128		rbuf[1] = rx[1];
129	}
130
131	kfree(rx);
132err_buf:
133	kfree(buf);
134
135	return ret;
136}
137
138static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis,
139					u8 adr1,
140					u8 adr2,
141					u8 *wbuf)
142{
143	struct spi_device *spi = spiadis->spi;
144	struct spi_message   msg;
145	struct spi_transfer  xfer1, xfer2;
146	u8       *buf, *rx;
147	int         ret;
148
149	buf = kmalloc(4, GFP_KERNEL);
150	if (buf == NULL)
151		return -ENOMEM;
152
153	rx = kzalloc(4, GFP_KERNEL);
154	if (rx == NULL) {
155		ret = -ENOMEM;
156		goto err_buf;
157	}
158
159	spi_message_init(&msg);
160	memset(&xfer1, 0, sizeof(xfer1));
161	memset(&xfer2, 0, sizeof(xfer2));
162
163	buf[0] = adr1 | 0x80;
164	buf[1] = *wbuf;
165
166	buf[2] = adr2 | 0x80;
167	buf[3] = *(wbuf + 1);
168
169	xfer1.tx_buf = buf;
170	xfer1.rx_buf = rx;
171	xfer1.len = 2;
172	xfer1.delay_usecs = 9;
173
174	xfer2.tx_buf = buf+2;
175	xfer2.rx_buf = rx+2;
176	xfer2.len = 2;
177
178	spi_message_add_tail(&xfer1, &msg);
179	spi_message_add_tail(&xfer2, &msg);
180
181	ret = spi_sync(spi, &msg);
182	if (ret != 0)
183		dev_warn(&spi->dev, "write data to %#x %#x failed\n",
184				buf[0], buf[2]);
185
186	kfree(rx);
187err_buf:
188	kfree(buf);
189	return ret;
190}
191
192/*-------------------------------------------------------------------------*/
193
194static irqreturn_t adis_irq_thread(int irq, void *dev_id)
195{
196	struct spi_adis16255_data *spiadis = dev_id;
197	int status;
198	u16 value = 0;
199
200	status =  spi_adis16255_read_data(spiadis, ADIS_GYRO_OUT, (u8 *)&value);
201	if (status != 0) {
202		dev_warn(&spiadis->spi->dev, "SPI FAILED\n");
203		goto exit;
204	}
205
206	/* perform on new data only... */
207	if (value & 0x8000) {
208		/* delete error and new data bit */
209		value = value & 0x3fff;
210		/* set negative value */
211		if (value & 0x2000)
212			value = value | 0xe000;
213
214		if (likely(spiadis->negative))
215			value = -value;
216
217		spiadis->data = (s16) value;
218	}
219
220exit:
221	return IRQ_HANDLED;
222}
223
224/*-------------------------------------------------------------------------*/
225
226ssize_t adis16255_show_data(struct device *device,
227		struct device_attribute *da,
228		char *buf)
229{
230	struct spi_adis16255_data *spiadis = dev_get_drvdata(device);
231	return snprintf(buf, PAGE_SIZE, "%d\n", spiadis->data);
232}
233DEVICE_ATTR(data, S_IRUGO , adis16255_show_data, NULL);
234
235ssize_t adis16255_show_direction(struct device *device,
236		struct device_attribute *da,
237		char *buf)
238{
239	struct spi_adis16255_data *spiadis = dev_get_drvdata(device);
240	return snprintf(buf, PAGE_SIZE, "%c\n", spiadis->direction);
241}
242DEVICE_ATTR(direction, S_IRUGO , adis16255_show_direction, NULL);
243
244ssize_t adis16255_show_sample_rate(struct device *device,
245		struct device_attribute *da,
246		char *buf)
247{
248	struct spi_adis16255_data *spiadis = dev_get_drvdata(device);
249	int status = 0;
250	u16 value = 0;
251	int ts = 0;
252
253	status = spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB,
254				(u8 *)&value);
255	if (status != 0)
256		return -EINVAL;
257
258	if (value & 0x80) {
259		/* timebase = 60.54 ms */
260		ts = 60540 * ((0x7f & value) + 1);
261	} else {
262		/* timebase = 1.953 ms */
263		ts = 1953 * ((0x7f & value) + 1);
264	}
265
266	return snprintf(buf, PAGE_SIZE, "%d\n", (1000*1000)/ts);
267}
268DEVICE_ATTR(sample_rate, S_IRUGO , adis16255_show_sample_rate, NULL);
269
270static struct attribute *adis16255_attributes[] = {
271	&dev_attr_data.attr,
272	&dev_attr_direction.attr,
273	&dev_attr_sample_rate.attr,
274	NULL
275};
276
277static const struct attribute_group adis16255_attr_group = {
278	.attrs = adis16255_attributes,
279};
280
281/*-------------------------------------------------------------------------*/
282
283static int spi_adis16255_shutdown(struct spi_adis16255_data *spiadis)
284{
285	u16 value = 0;
286	/* turn sensor off */
287	spi_adis16255_write_data(spiadis,
288			ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB,
289			(u8 *)&value);
290	spi_adis16255_write_data(spiadis,
291			ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
292			(u8 *)&value);
293	return 0;
294}
295
296static int spi_adis16255_bringup(struct spi_adis16255_data *spiadis)
297{
298	int status = 0;
299	u16 value = 0;
300
301	status = spi_adis16255_read_data(spiadis, ADIS_GYRO_SCALE,
302				(u8 *)&value);
303	if (status != 0)
304		goto err;
305	if (value != 0x0800) {
306		dev_warn(&spiadis->spi->dev, "Scale factor is none default "
307				"value (%.4x)\n", value);
308	}
309
310	/* timebase = 1.953 ms, Ns = 0 -> 512 Hz sample rate */
311	value =  0x0001;
312	status = spi_adis16255_write_data(spiadis,
313				ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB,
314				(u8 *)&value);
315	if (status != 0)
316		goto err;
317
318	/* start internal self-test */
319	value = 0x0400;
320	status = spi_adis16255_write_data(spiadis,
321				ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
322				(u8 *)&value);
323	if (status != 0)
324		goto err;
325
326	/* wait 35 ms to finish self-test */
327	msleep(35);
328
329	value = 0x0000;
330	status = spi_adis16255_read_data(spiadis, ADIS_STATUS,
331				(u8 *)&value);
332	if (status != 0)
333		goto err;
334
335	if (value & 0x23) {
336		if (value & 0x20) {
337			dev_warn(&spiadis->spi->dev, "self-test error\n");
338			status = -ENODEV;
339			goto err;
340		} else if (value & 0x3)	{
341			dev_warn(&spiadis->spi->dev, "Sensor voltage "
342						"out of range.\n");
343			status = -ENODEV;
344			goto err;
345		}
346	}
347
348	/* set interrupt to active high on DIO0 when data ready */
349	value = 0x0006;
350	status = spi_adis16255_write_data(spiadis,
351				ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
352				(u8 *)&value);
353	if (status != 0)
354		goto err;
355	return status;
356
357err:
358	spi_adis16255_shutdown(spiadis);
359	return status;
360}
361
362/*-------------------------------------------------------------------------*/
363
364static int __devinit spi_adis16255_probe(struct spi_device *spi)
365{
366
367	struct adis16255_init_data *init_data = spi->dev.platform_data;
368	struct spi_adis16255_data  *spiadis;
369	int status = 0;
370
371	spiadis = kzalloc(sizeof(*spiadis), GFP_KERNEL);
372	if (!spiadis)
373		return -ENOMEM;
374
375	spiadis->spi = spi;
376	spiadis->direction = init_data->direction;
377
378	if (init_data->negative)
379		spiadis->negative = 1;
380
381	status = gpio_request(init_data->irq, "adis16255");
382	if (status != 0)
383		goto err;
384
385	status = gpio_direction_input(init_data->irq);
386	if (status != 0)
387		goto gpio_err;
388
389	spiadis->irq = gpio_to_irq(init_data->irq);
390
391	status = request_threaded_irq(spiadis->irq,
392			NULL, adis_irq_thread,
393			IRQF_DISABLED, "adis-driver", spiadis);
394
395	if (status != 0) {
396		dev_err(&spi->dev, "IRQ request failed\n");
397		goto gpio_err;
398	}
399
400	dev_dbg(&spi->dev, "GPIO %d IRQ %d\n", init_data->irq, spiadis->irq);
401
402	dev_set_drvdata(&spi->dev, spiadis);
403	status = sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group);
404	if (status != 0)
405		goto irq_err;
406
407	status = spi_adis16255_bringup(spiadis);
408	if (status != 0)
409		goto irq_err;
410
411	dev_info(&spi->dev, "spi_adis16255 driver added!\n");
412
413	return status;
414
415irq_err:
416	free_irq(spiadis->irq, spiadis);
417gpio_err:
418	gpio_free(init_data->irq);
419err:
420	kfree(spiadis);
421	return status;
422}
423
424static int __devexit spi_adis16255_remove(struct spi_device *spi)
425{
426	struct spi_adis16255_data  *spiadis    = dev_get_drvdata(&spi->dev);
427
428	spi_adis16255_shutdown(spiadis);
429
430	free_irq(spiadis->irq, spiadis);
431	gpio_free(irq_to_gpio(spiadis->irq));
432
433	sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group);
434
435	kfree(spiadis);
436
437	dev_info(&spi->dev, "spi_adis16255 driver removed!\n");
438	return 0;
439}
440
441static struct spi_driver spi_adis16255_drv = {
442	.driver = {
443		.name =  "spi_adis16255",
444		.owner = THIS_MODULE,
445	},
446	.probe = spi_adis16255_probe,
447	.remove =   __devexit_p(spi_adis16255_remove),
448};
449
450/*-------------------------------------------------------------------------*/
451
452static int __init spi_adis16255_init(void)
453{
454	return spi_register_driver(&spi_adis16255_drv);
455}
456module_init(spi_adis16255_init);
457
458static void __exit spi_adis16255_exit(void)
459{
460	spi_unregister_driver(&spi_adis16255_drv);
461}
462module_exit(spi_adis16255_exit);
463
464MODULE_AUTHOR("Matthias Brugger");
465MODULE_DESCRIPTION("SPI device driver for ADIS16255 sensor");
466MODULE_LICENSE("GPL");
467