Title: [8767] trunk/drivers/staging: Staging: add driver for adis16255 gyroscope
Revision
8767
Author
vapier
Date
2010-05-22 23:24:34 -0400 (Sat, 22 May 2010)

Log Message

Staging: add driver for adis16255 gyroscope

From: matthias <[email protected]>

This drivers allows a communication with the Analog Devices ADIS16255
Low Power Gyroscope over SPI.

Added Paths

Diff

Added: trunk/drivers/staging/adis16255/Kconfig (0 => 8767)


--- trunk/drivers/staging/adis16255/Kconfig	                        (rev 0)
+++ trunk/drivers/staging/adis16255/Kconfig	2010-05-23 03:24:34 UTC (rev 8767)
@@ -0,0 +1,9 @@
+config ADIS16255
+	tristate "Ananlog Devices ADIS16250/16255"
+	depends on SPI && SYSFS
+	---help---
+      If you say yes here you get support for the Analog Devices
+      ADIS16250/16255 Low Power Gyroscope.
+
+      This driver can also be built as a module. If so, the module
+      will be called adis16255.

Added: trunk/drivers/staging/adis16255/Makefile (0 => 8767)


--- trunk/drivers/staging/adis16255/Makefile	                        (rev 0)
+++ trunk/drivers/staging/adis16255/Makefile	2010-05-23 03:24:34 UTC (rev 8767)
@@ -0,0 +1 @@
+obj-$(CONFIG_ADIS16255) +\xFAdis16255.o

Added: trunk/drivers/staging/adis16255/TODO (0 => 8767)


--- trunk/drivers/staging/adis16255/TODO	                        (rev 0)
+++ trunk/drivers/staging/adis16255/TODO	2010-05-23 03:24:34 UTC (rev 8767)
@@ -0,0 +1,8 @@
+* sample rate changeable or at least readable from sysfs
+* reset gyroscope
+* encapsulate adis_init and adis_turn_off
+* AD_CHK deletion
+* chip selftest in adis_init
+* reduce kernel messages to reasonable amount
+
+Contact: Matthias Brugger <[email protected]>

Added: trunk/drivers/staging/adis16255/adis16255.c (0 => 8767)


--- trunk/drivers/staging/adis16255/adis16255.c	                        (rev 0)
+++ trunk/drivers/staging/adis16255/adis16255.c	2010-05-23 03:24:34 UTC (rev 8767)
@@ -0,0 +1,396 @@
+/*
+ * Analog Devices ADIS16250/ADIS16255 Low Power Gyroscope
+ *
+ * Written by: Matthias Brugger <[email protected]>
+ *
+ * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+
+#include <linux/gpio.h>
+
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+#include "adis16255.h"
+
+#define ADIS_STATUS        0x3d
+#define ADIS_SMPL_PRD_MSB  0x37
+#define ADIS_SMPL_PRD_LSB  0x36
+#define ADIS_MSC_CTRL_MSB  0x35
+#define ADIS_MSC_CTRL_LSB  0x34
+#define ADIS_GPIO_CTRL     0x33
+#define ADIS_ALM_SMPL1     0x25
+#define ADIS_ALM_MAG1      0x21
+#define ADIS_GYRO_SCALE    0x17
+#define ADIS_GYRO_OUT      0x05
+#define ADIS_SUPPLY_OUT    0x03
+#define ADIS_ENDURANCE     0x01
+
+/*
+ * data structure for every sensor
+ *
+ * @dev:       Driver model representation of the device.
+ * @spi:       Pointer to the spi device which will manage i/o to spi bus.
+ * @data:      Last read data from device.
+ * @irq_adis:  GPIO Number of IRQ signal
+ * @irq:       irq line manage by kernel
+ * @negative:  indicates if sensor is upside down (negative \xFF1)
+ * @direction: indicates axis (x, y, z) the sensor is meassuring
+ */
+struct spi_adis16255_data {
+	struct device dev;
+	struct spi_device *spi;
+	s16 data;
+	int irq_adis;
+	int irq;
+	u8 negative;
+	char direction;
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis,
+					u8 adr,
+					u8 *rbuf)
+{
+	struct spi_device *spi \xFFpiadis->spi;
+	struct spi_message msg;
+	struct spi_transfer xfer1, xfer2;
+	u8 *buf, *rx;
+	int ret;
+
+	buf \xFFmalloc(4, GFP_KERNEL);
+	if (buf \xFFNULL)
+		return -ENOMEM;
+
+	rx \xFFzalloc(4, GFP_KERNEL);
+	if (rx \xFFNULL) {
+		ret \xFFENOMEM;
+		goto err_buf;
+	}
+
+	buf[0] \xFAdr;
+	buf[1] \xF0x00;
+	buf[2] \xF0x00;
+	buf[3] \xF0x00;
+
+	spi_message_init(&msg);
+	memset(&xfer1, 0, sizeof(xfer1));
+	memset(&xfer2, 0, sizeof(xfer2));
+
+	xfer1.tx_buf \xFBuf;
+	xfer1.rx_buf \xFBuf + 2;
+	xfer1.len \xF2;
+	xfer1.delay_usecs \xF9;
+
+	xfer2.tx_buf \xFFx + 2;
+	xfer2.rx_buf \xFFx;
+	xfer2.len \xF2;
+
+	spi_message_add_tail(&xfer1, &msg);
+	spi_message_add_tail(&xfer2, &msg);
+
+	ret \xFFpi_sync(spi, &msg);
+	if (ret \xFF0) {
+		rbuf[0] \xFFx[0];
+		rbuf[1] \xFFx[1];
+	}
+
+	kfree(rx);
+err_buf:
+	kfree(buf);
+
+	return ret;
+}
+
+static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis,
+					u8 adr1,
+					u8 adr2,
+					u8 *wbuf)
+{
+	struct spi_device *spi \xFFpiadis->spi;
+	struct spi_message   msg;
+	struct spi_transfer  xfer1, xfer2;
+	u8       *buf, *rx;
+	int         ret;
+
+	buf \xFFmalloc(4, GFP_KERNEL);
+	if (buf \xFFNULL)
+		return -ENOMEM;
+
+	rx \xFFzalloc(4, GFP_KERNEL);
+	if (rx \xFFNULL) {
+		ret \xFFENOMEM;
+		goto err_buf;
+	}
+
+	spi_message_init(&msg);
+	memset(&xfer1, 0, sizeof(xfer1));
+	memset(&xfer2, 0, sizeof(xfer2));
+
+	buf[0] \xFAdr1 | 0x80;
+	buf[1] \xFFwbuf;
+
+	buf[2] \xFAdr2 | 0x80;
+	buf[3] \xFF(wbuf + 1);
+
+	xfer1.tx_buf \xFBuf;
+	xfer1.rx_buf \xFFx;
+	xfer1.len \xF2;
+	xfer1.delay_usecs \xF9;
+
+	xfer2.tx_buf \xFBuf+2;
+	xfer2.rx_buf \xFFx+2;
+	xfer2.len \xF2;
+
+	spi_message_add_tail(&xfer1, &msg);
+	spi_message_add_tail(&xfer2, &msg);
+
+	ret \xFFpi_sync(spi, &msg);
+	if (ret !\xF0)
+		dev_warn(&spi->dev, "wirte data to %#x %#x failed\n",
+				buf[0], buf[2]);
+
+	kfree(rx);
+err_buf:
+	kfree(buf);
+	return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t adis_irq_thread(int irq, void *dev_id)
+{
+	struct spi_adis16255_data *spiadis \xFDev_id;
+	int status;
+	u16 value;
+
+	status \xFFspi_adis16255_read_data(spiadis, ADIS_GYRO_OUT, (u8 *)&value);
+	if (status \xFF0) {
+		/* perform on new data only... */
+		if (value & 0x8000) {
+			/* delete error and new data bit */
+			value \xFFalue & 0x3fff;
+			/* set negative value */
+			if (value & 0x2000)
+				value \xFFalue | 0xe000;
+
+			if (likely(spiadis->negative))
+				value \xFFvalue;
+
+			spiadis->data \xFFs16) value;
+		}
+	} else {
+		dev_warn(&spiadis->spi->dev, "SPI FAILED\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+ssize_t adis16255_show_data(struct device *device,
+		struct device_attribute *da,
+		char *buf)
+{
+	struct spi_adis16255_data *spiadis \xFDev_get_drvdata(device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", spiadis->data);
+}
+DEVICE_ATTR(data, S_IRUGO , adis16255_show_data, NULL);
+
+ssize_t adis16255_show_direction(struct device *device,
+		struct device_attribute *da,
+		char *buf)
+{
+	struct spi_adis16255_data *spiadis \xFDev_get_drvdata(device);
+	return snprintf(buf, PAGE_SIZE, "%c\n", spiadis->direction);
+}
+DEVICE_ATTR(direction, S_IRUGO , adis16255_show_direction, NULL);
+
+static struct attribute *adis16255_attributes[] \xFF
+	&dev_attr_data.attr,
+	&dev_attr_direction.attr,
+	NULL
+};
+
+static const struct attribute_group adis16255_attr_group \xFF
+	.attrs \xFAdis16255_attributes,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int spi_adis16255_probe(struct spi_device *spi)
+{
+
+#define AD_CHK(_ss)\
+	do {\
+		status \xFFss;\
+		if (status !\xF0)\
+			goto irq_err;\
+	} while (0);
+
+	struct adis16255_init_data *init_data \xFFpi->dev.platform_data;
+	struct spi_adis16255_data  *spiadis;
+	int status \xF0;
+	u16 value;
+
+	spiadis \xFFzalloc(sizeof(*spiadis), GFP_KERNEL);
+	if (!spiadis)
+		return -ENOMEM;
+
+	spiadis->spi \xFFpi;
+	spiadis->irq_adis \xFFnit_data->irq;
+	spiadis->direction \xFFnit_data->direction;
+
+	if (init_data->negative)
+		spiadis->negative \xF1;
+
+	status \xFFpio_request(spiadis->irq_adis, "adis16255");
+	if (status !\xF0)
+		goto err;
+
+	status \xFFpio_direction_input(spiadis->irq_adis);
+	if (status !\xF0)
+		goto gpio_err;
+
+	spiadis->irq \xFFpio_to_irq(spiadis->irq_adis);
+
+	status \xFFequest_threaded_irq(spiadis->irq,
+			NULL, adis_irq_thread,
+			IRQF_DISABLED, "adis-driver", spiadis);
+
+	if (status !\xF0) {
+		dev_err(&spi->dev, "IRQ request failed\n");
+		goto gpio_err;
+	}
+
+	dev_dbg(&spi->dev, "GPIO %d IRQ %d\n", spiadis->irq_adis, spiadis->irq);
+
+	dev_set_drvdata(&spi->dev, spiadis);
+	AD_CHK(sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group));
+
+	dev_info(&spi->dev, "spi_adis16255 driver added!\n");
+
+	AD_CHK(spi_adis16255_read_data(spiadis, ADIS_SUPPLY_OUT, (u8 *)&value));
+	dev_info(&spi->dev, "sensor works with %d mV (%.4x)!\n",
+			((value & 0x0fff)*18315)/10000,
+			(value & 0x0fff));
+
+	AD_CHK(spi_adis16255_read_data(spiadis, ADIS_GYRO_SCALE, (u8 *)&value));
+	dev_info(&spi->dev, "adis GYRO_SCALE is %.4x\n", value);
+
+	AD_CHK(spi_adis16255_read_data(spiadis, ADIS_STATUS, (u8 *)&value));
+	dev_info(&spi->dev, "adis STATUS is %.4x\n", value);
+
+	/* timebase \xF1.953 ms, Ns \xF0 -> 512 Hz sample rate */
+	value \xFF0x0001;
+	AD_CHK(spi_adis16255_write_data(spiadis,
+				ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB,
+				(u8 *)&value));
+	value \xF0x0000;
+	AD_CHK(spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB,
+				(u8 *)&value));
+	dev_info(&spi->dev, "adis SMP_PRD is %.4x\n", value);
+
+	/* set interrupt on new data... */
+	value \xF0x0006;
+	AD_CHK(spi_adis16255_write_data(spiadis,
+				ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
+				(u8 *)&value));
+	value \xF0x0000;
+	AD_CHK(spi_adis16255_read_data(spiadis, ADIS_MSC_CTRL_MSB,
+				(u8 *)&value));
+	dev_info(&spi->dev, "adis MSC_CONTROL is %.4x\n", value);
+
+	return status;
+
+irq_err:
+	free_irq(spiadis->irq, spiadis);
+gpio_err:
+	gpio_free(spiadis->irq_adis);
+err:
+	kfree(spiadis);
+	return status;
+}
+
+static int spi_adis16255_remove(struct spi_device *spi)
+{
+	u16 value \xF0;
+	struct spi_adis16255_data  *spiadis    \xFDev_get_drvdata(&spi->dev);
+
+	/* turn sensor off */
+	spi_adis16255_write_data(spiadis,
+			ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB,
+			(u8 *)&value);
+	spi_adis16255_write_data(spiadis,
+			ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
+			(u8 *)&value);
+
+	dev_info(&spi->dev, "unregister: GPIO %d IRQ %d\n",
+		spiadis->irq_adis, spiadis->irq);
+
+	free_irq(spiadis->irq, spiadis);
+	gpio_free(spiadis->irq_adis);
+
+	sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group);
+
+	kfree(spiadis);
+
+	dev_info(&spi->dev, "spi_adis16255 driver removed!\n");
+	return 0;
+}
+
+static struct spi_driver spi_adis16255_drv \xFF
+	.driver \xFF
+		.name \xFF"spi_adis16255",
+		.owner \xFFHIS_MODULE,
+	},
+	.probe \xFFpi_adis16255_probe,
+	.remove \xFF __devexit_p(spi_adis16255_remove),
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init spi_adis16255_init(void)
+{
+	return spi_register_driver(&spi_adis16255_drv);
+}
+module_init(spi_adis16255_init);
+
+static void __exit spi_adis16255_exit(void)
+{
+	spi_unregister_driver(&spi_adis16255_drv);
+}
+module_exit(spi_adis16255_exit);
+
+MODULE_AUTHOR("Matthias Brugger");
+MODULE_DESCRIPTION("SPI device driver for ADIS16255 sensor");
+MODULE_LICENSE("GPL");

Added: trunk/drivers/staging/adis16255/adis16255.h (0 => 8767)


--- trunk/drivers/staging/adis16255/adis16255.h	                        (rev 0)
+++ trunk/drivers/staging/adis16255/adis16255.h	2010-05-23 03:24:34 UTC (rev 8767)
@@ -0,0 +1,12 @@
+#ifndef ADIS16255_H
+#define ADIS16255_H
+
+#include <linux/types.h>
+
+struct adis16255_init_data {
+	char direction;
+	u8   negative;
+	int  irq;
+};
+
+#endif
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to