lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1246542464-6974-6-git-send-email-jic23@cam.ac.uk>
Date:	Thu,  2 Jul 2009 13:47:35 +0000
From:	Jonathan Cameron <jic23@....ac.uk>
To:	linux-kernel@...r.kernel.org
Cc:	chrisv@...erswitching.com, daniel@...aq.de, iws@...o.caltech.edu,
	dmitry.torokhov@...il.com, hmh@....eng.br, david-b@...bell.net,
	khali@...ux-fr.org, Jonathan Cameron <jic23@....ac.uk>
Subject: [PATCH 05/14] IIO: kxsd9 accelerometer minimal support

Signed-off-by: Jonathan Cameron <jic23@....ac.uk>

This provides only very minimal support for this device.
Note that an alternate driver has been posted to the input
mailing list.

When the original LMKL discussion that led to the descision
to develop IIO occured, the question on whether the differing
requirements of IIO and input drivers made it a good idea
to have unified drivers was left as an open question.
It still is.  All opinions on this question welcome.
---
 drivers/iio/accel/Kconfig  |    7 +
 drivers/iio/accel/Makefile |    2 +
 drivers/iio/accel/kxsd9.c  |  395 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iio/adc.h    |   13 ++
 4 files changed, 417 insertions(+), 0 deletions(-)
 create mode 100644 drivers/iio/accel/kxsd9.c
 create mode 100644 include/linux/iio/adc.h

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index a3abffc..548059f 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -4,6 +4,13 @@
 comment "Accelerometers"
 	depends on IIO
 
+config KXSD9
+	tristate "Kionix KXSD9 Accelerometer Driver"
+	depends on IIO && SPI
+	help
+	  Say yes here to build support for the Kionix KXSD9 accelerometer.
+	  Currently this only supports the device via an SPI interface.
+
 config LIS3L02DQ
 	tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver"
 	depends on IIO && SPI
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 5a7ef9d..cbec688 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -1,5 +1,7 @@
 #
 # Makefile for industrial I/O accelerometer drivers
 #
+obj-$(CONFIG_KXSD9)	+= kxsd9.o
+
 lis3l02dq-y		:= lis3l02dq_core.o
 obj-$(CONFIG_LIS3L02DQ)	+= lis3l02dq.o
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
new file mode 100644
index 0000000..c213295
--- /dev/null
+++ b/drivers/iio/accel/kxsd9.c
@@ -0,0 +1,395 @@
+/*
+ * kxsd9.c	simple support for the Kionix KXSD9 3D
+ *		accelerometer.
+ *
+ * Copyright (c) 2008-2009 Jonathan Cameron <jic23@....ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The i2c interface is very similar, so shouldn't be a problem once
+ * I have a suitable wire made up.
+ *
+ * TODO:	Support the motion detector
+ *		Uses register address incrementing so could have a
+ *		heavily optimized ring buffer access function.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/adc.h>
+#include <linux/iio/accel.h>
+
+#define KXSD9_REG_X		0x00
+#define KXSD9_REG_Y		0x02
+#define KXSD9_REG_Z		0x04
+#define KXSD9_REG_AUX		0x06
+#define KXSD9_REG_RESET		0x0a
+#define KXSD9_REG_CTRL_C	0x0c
+
+#define KXSD9_FS_8		0x00
+#define KXSD9_FS_6		0x01
+#define KXSD9_FS_4		0x02
+#define KXSD9_FS_2		0x03
+#define KXSD9_FS_MASK		0x03
+
+#define KXSD9_REG_CTRL_B	0x0d
+#define KXSD9_REG_CTRL_A	0x0e
+
+#define KXSD9_READ(a) (0x80 | (a))
+#define KXSD9_WRITE(a) (a)
+
+#define IIO_DEV_ATTR_ACCEL_SET_RANGE(_mode, _show, _store)	\
+	IIO_DEVICE_ATTR(accel_range, _mode, _show, _store, 0)
+
+#define KXSD9_STATE_RX_SIZE 2
+#define KXSD9_STATE_TX_SIZE 4
+/**
+ * struct kxsd9_state - device related storage
+ * @buf_lock:	protect the rx and tx buffers.
+ * @indio_dev:	associated industrial IO device
+ * @us:		spi device
+ * @rx:		single rx buffer storage
+ * @tx:		single tx buffer storage
+ **/
+struct kxsd9_state {
+	struct mutex buf_lock;
+	struct iio_dev *indio_dev;
+	struct spi_device *us;
+	u8 *rx;
+	u8 *tx;
+};
+
+/* This may want to move to mili g to allow for non integer ranges */
+static ssize_t kxsd9_read_accel_range(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	int ret;
+	ssize_t len = 0;
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct kxsd9_state *st = indio_dev->dev_data;
+	struct spi_transfer xfer = {
+		.bits_per_word = 8,
+		.len = 2,
+		.cs_change = 1,
+		.tx_buf = st->tx,
+		.rx_buf = st->rx,
+	};
+	struct spi_message msg;
+
+	mutex_lock(&st->buf_lock);
+	st->tx[0] = KXSD9_READ(KXSD9_REG_CTRL_C);
+	st->tx[1] = 0;
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	ret = spi_sync(st->us, &msg);
+	if (ret)
+		goto error_ret;
+
+	switch (st->rx[1] & KXSD9_FS_MASK) {
+	case KXSD9_FS_8:
+		len += sprintf(buf, "8\n");
+		break;
+	case KXSD9_FS_6:
+		len += sprintf(buf, "6\n");
+		break;
+	case KXSD9_FS_4:
+		len += sprintf(buf, "4\n");
+		break;
+	case KXSD9_FS_2:
+		len += sprintf(buf, "2\n");
+		break;
+	}
+
+error_ret:
+	mutex_unlock(&st->buf_lock);
+
+	return ret ? ret : len;
+}
+static ssize_t kxsd9_write_accel_range(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf,
+				      size_t len)
+{
+	long readin;
+	struct spi_message msg;
+	int ret;
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct kxsd9_state *st = indio_dev->dev_data;
+	u8 val;
+	struct spi_transfer xfers[] = {
+		{
+			.bits_per_word = 8,
+			.len = 2,
+			.cs_change = 1,
+			.tx_buf = st->tx,
+			.rx_buf = st->rx,
+		}, {
+			.bits_per_word = 8,
+			.len = 2,
+			.cs_change = 1,
+			.tx_buf = st->tx,
+		},
+	};
+
+	ret = strict_strtol(buf, 10, &readin);
+	if (ret)
+		return ret;
+	switch (readin) {
+	case 8:
+		val = KXSD9_FS_8;
+		break;
+	case 6:
+		val = KXSD9_FS_6;
+		break;
+	case 4:
+		val = KXSD9_FS_4;
+		break;
+	case 2:
+		val = KXSD9_FS_2;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mutex_lock(&st->buf_lock);
+	st->tx[0] = KXSD9_READ(KXSD9_REG_CTRL_C);
+	st->tx[1] = 0;
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfers[0], &msg);
+	ret = spi_sync(st->us, &msg);
+	if (ret)
+		goto error_ret;
+	st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
+	st->tx[1] = (st->rx[1] & ~KXSD9_FS_MASK) | val;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfers[1], &msg);
+	ret = spi_sync(st->us, &msg);
+error_ret:
+	mutex_unlock(&st->buf_lock);
+	return ret ? ret : len;
+}
+static ssize_t kxsd9_read_accel(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct spi_message msg;
+	int ret;
+	ssize_t len = 0;
+	u16 val;
+	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct kxsd9_state *st = indio_dev->dev_data;
+	struct spi_transfer xfers[] = {
+		{
+			.bits_per_word = 8,
+			.len = 1,
+			.cs_change = 0,
+			.delay_usecs = 200,
+			.tx_buf = st->tx,
+		}, {
+			.bits_per_word = 8,
+			.len = 2,
+			.cs_change = 1,
+			.rx_buf = st->rx,
+		},
+	};
+
+	mutex_lock(&st->buf_lock);
+	st->tx[0] = KXSD9_READ(this_attr->address);
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfers[0], &msg);
+	spi_message_add_tail(&xfers[1], &msg);
+	ret = spi_sync(st->us, &msg);
+	if (ret)
+		goto error_ret;
+	val = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
+	len = sprintf(buf, "%d\n", val);
+error_ret:
+	mutex_unlock(&st->buf_lock);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_ACCEL_X(kxsd9_read_accel, KXSD9_REG_X);
+static IIO_DEV_ATTR_ACCEL_Y(kxsd9_read_accel, KXSD9_REG_Y);
+static IIO_DEV_ATTR_ACCEL_Z(kxsd9_read_accel, KXSD9_REG_Z);
+static IIO_DEV_ATTR_ADC(0, kxsd9_read_accel, KXSD9_REG_AUX);
+static IIO_DEV_ATTR_ACCEL_SET_RANGE(S_IRUGO | S_IWUSR,
+				    kxsd9_read_accel_range,
+				    kxsd9_write_accel_range);
+
+static struct attribute *kxsd9_attributes[] = {
+	&iio_dev_attr_accel_x.dev_attr.attr,
+	&iio_dev_attr_accel_y.dev_attr.attr,
+	&iio_dev_attr_accel_z.dev_attr.attr,
+	&iio_dev_attr_adc_0.dev_attr.attr,
+	&iio_dev_attr_accel_range.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group kxsd9_attribute_group = {
+	.attrs = kxsd9_attributes,
+};
+
+static int __devinit kxsd9_power_up(struct spi_device *spi)
+{
+	int ret;
+	struct spi_transfer xfers[2] = {
+		{
+			.bits_per_word = 8,
+			.len = 2,
+			.cs_change = 1,
+		}, {
+			.bits_per_word = 8,
+			.len = 2,
+			.cs_change = 1,
+		},
+	};
+	struct spi_message msg;
+	u8 *tx2;
+	u8 *tx = kmalloc(2, GFP_KERNEL);
+
+	if (tx == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	tx2 = kmalloc(2, GFP_KERNEL);
+	if (tx2 == NULL) {
+		ret = -ENOMEM;
+		goto error_free_tx;
+	}
+	tx[0] = 0x0d;
+	tx[1] = 0x40;
+
+	tx2[0] = 0x0c;
+	tx2[1] = 0x9b;
+
+	xfers[0].tx_buf = tx;
+	xfers[1].tx_buf = tx2;
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfers[0], &msg);
+	spi_message_add_tail(&xfers[1], &msg);
+	ret = spi_sync(spi, &msg);
+
+	kfree(tx2);
+error_free_tx:
+	kfree(tx);
+error_ret:
+	return ret;
+
+};
+
+static int __devinit kxsd9_probe(struct spi_device *spi)
+{
+
+	struct kxsd9_state *st;
+	int ret = 0;
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (st == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	spi_set_drvdata(spi, st);
+
+	st->rx = kmalloc(sizeof(*st->rx)*KXSD9_STATE_RX_SIZE,
+			 GFP_KERNEL);
+	if (st->rx == NULL) {
+		ret = -ENOMEM;
+		goto error_free_st;
+	}
+	st->tx = kmalloc(sizeof(*st->tx)*KXSD9_STATE_TX_SIZE,
+			 GFP_KERNEL);
+	if (st->tx == NULL) {
+		ret = -ENOMEM;
+		goto error_free_rx;
+	}
+
+	st->us = spi;
+	mutex_init(&st->buf_lock);
+	st->indio_dev = iio_allocate_device();
+	if (st->indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_free_tx;
+	}
+	st->indio_dev->dev.parent = &spi->dev;
+	/* for now */
+	st->indio_dev->num_interrupt_lines = 0;
+	st->indio_dev->event_attrs = NULL;
+
+	st->indio_dev->attrs = &kxsd9_attribute_group;
+	st->indio_dev->dev_data = (void *)(st);
+	st->indio_dev->driver_module = THIS_MODULE;
+	st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(st->indio_dev);
+	if (ret)
+		goto error_free_dev;
+
+	spi->mode = SPI_MODE_0;
+	spi_setup(spi);
+	kxsd9_power_up(spi);
+
+	return 0;
+
+error_free_dev:
+	iio_free_device(st->indio_dev);
+error_free_tx:
+	kfree(st->tx);
+error_free_rx:
+	kfree(st->rx);
+error_free_st:
+	kfree(st);
+error_ret:
+	return ret;
+}
+
+static int __devexit kxsd9_remove(struct spi_device *spi)
+{
+	struct kxsd9_state *st = spi_get_drvdata(spi);
+
+	iio_device_unregister(st->indio_dev);
+	iio_free_device(st->indio_dev);
+	kfree(st->tx);
+	kfree(st->rx);
+	kfree(st);
+
+	return 0;
+}
+
+static struct spi_driver kxsd9_driver = {
+	.driver = {
+		.name = "kxsd9",
+		.owner = THIS_MODULE,
+	},
+	.probe = kxsd9_probe,
+	.remove = __devexit_p(kxsd9_remove),
+};
+
+static __init int kxsd9_spi_init(void)
+{
+	return spi_register_driver(&kxsd9_driver);
+}
+module_init(kxsd9_spi_init);
+
+static __exit void kxsd9_spi_exit(void)
+{
+	spi_unregister_driver(&kxsd9_driver);
+}
+module_exit(kxsd9_spi_exit);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@....ac.uk>");
+MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/iio/adc.h b/include/linux/iio/adc.h
new file mode 100644
index 0000000..d925b2c
--- /dev/null
+++ b/include/linux/iio/adc.h
@@ -0,0 +1,13 @@
+/*
+ * adc.h - sysfs attributes associated with ADCs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Copyright (c) 2008 Jonathan Cameron <jic23@....ac.uk>
+ *
+ */
+
+#define IIO_DEV_ATTR_ADC(_num, _show, _addr)			\
+  IIO_DEVICE_ATTR(adc_##_num, S_IRUGO, _show, NULL, _addr)
-- 
1.6.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ