All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kalhan Trisal <kalhan.trisal@intel.com>
To: lm-sensors@vger.kernel.org
Subject: [lm-sensors] Accelerometer driver
Date: Tue, 11 Aug 2009 08:11:00 +0000	[thread overview]
Message-ID: <20090811184948.GA32002@intel.com> (raw)

From 0d9b356e19170242fcbb746744b7ccb5156211eb Mon Sep 17 00:00:00 2001
From: Kalhan Trisal <kalhan.trisal@intel.com>
Date: Tue, 11 Aug 2009 11:12:02 -0400
Subject: [PATCH] STMicroeletronics LIS331DL three-axis digital accelerometer

This driver provides support for the LIS3331DL accelerometer
accelerometer, connected to I2C. The accelerometer data is readable via
sys/class/hwmon.

Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>

---
 drivers/hwmon/Kconfig    |    9 ++
 drivers/hwmon/Makefile   |    1 +
 drivers/hwmon/lis331dl.c |  283 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 293 insertions(+), 0 deletions(-)
 create mode 100755 drivers/hwmon/lis331dl.c

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d50166..ac6117a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -975,6 +975,15 @@ config SENSORS_LIS3LV02D
 	  Say Y here if you have an applicable laptop and want to experience
 	  the awesome power of lis3lv02d.
 
+config SENSORS_LIS331DL
+	tristate "STMicroeletronics LIS331DL three-axis digital accelerometer"
+	depends on I2C_MRST
+	default n
+	help
+	  This driver provides support for the LIS3331DL accelerometer
+	  accelerometer, connected or I2C. The accelerometer data is readable via
+	  sys/class/hwmon.
+
 config SENSORS_LIS3_SPI
 	tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
 	depends on !ACPI && SPI_MASTER && INPUT
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b793dce..3b1e424 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_SENSORS_VT8231)	+= vt8231.o
 obj-$(CONFIG_SENSORS_W83627EHF)	+= w83627ehf.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 obj-$(CONFIG_SENSORS_W83L786NG)	+= w83l786ng.o
+obj-$(CONFIG_SENSORS_LIS331DL)	+= lis331dl.o
 
 ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/hwmon/lis331dl.c b/drivers/hwmon/lis331dl.c
new file mode 100755
index 0000000..9b999a3
--- /dev/null
+++ b/drivers/hwmon/lis331dl.c
@@ -0,0 +1,283 @@
+/*
+ * lis331dl.c - ST LIS331DL  Accelerometer Driver
+ *
+ * Copyright (C) 2009 Intel Corp
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_DESCRIPTION("STMacroelectronics LIS331DL Accelerometer Driver");
+MODULE_LICENSE("GPL v2");
+
+#define ACCEL_DATA_RATE_100HZ 0
+#define ACCEL_DATA_RATE_400HZ 1
+#define ACCEL_POWER_MODE_DOWN 0
+#define ACCEL_POWER_MODE_ACTIVE 1
+#define ACCEL_NORMAL_MODE 0
+#define ACCEL_MEMORY_REBOOT 1
+
+/* internal return values */
+
+struct acclero_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+};
+
+static unsigned int i2c_write_current_data(struct i2c_client *client,
+					unsigned int reg, unsigned int value)
+{
+	int ret_val;
+
+	ret_val = i2c_smbus_write_byte_data(client, reg, value);
+	return ret_val;
+}
+
+static ssize_t rate_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret_val, val;
+
+	val = i2c_smbus_read_byte_data(client, 0x20);
+	ret_val = (val & 0x80); /* 1= 400HZ 0= 100HZ */
+	if (ret_val = 0x80)
+		ret_val = 1;
+	return sprintf(buf, "%d\n", ret_val);
+
+}
+
+static ssize_t state_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret_val, val;
+
+	val = i2c_smbus_read_byte_data(client, 0x20);
+	ret_val = (val & 0x40);
+	if (ret_val = 0x40)
+		ret_val = 1;
+	return sprintf(buf, "%d\n", ret_val);
+}
+
+static ssize_t xyz_pos_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int x, y, z;
+	struct i2c_client *client = to_i2c_client(dev);
+
+	x = i2c_smbus_read_byte_data(client, 0x29);
+	y = i2c_smbus_read_byte_data(client, 0x2B);
+	z = i2c_smbus_read_byte_data(client, 0x2D);
+	return sprintf(buf, "%d, %d, %d \n", x, y, z);
+}
+
+static ssize_t rate_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct acclero_data *data = i2c_get_clientdata(client);
+	unsigned int ret_val, set_val;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+	ret_val = i2c_smbus_read_byte_data(client, 0x20);
+
+	mutex_lock(&data->update_lock);
+	if (val = ACCEL_DATA_RATE_100HZ)
+		set_val = (ret_val & 0x7F); /* setting the 8th bit to 0 */
+	else if (val = ACCEL_DATA_RATE_400HZ)
+		set_val = (ret_val | (1 << 7));
+	else
+		goto invarg;
+
+	i2c_write_current_data(client, 0x20, set_val);
+	mutex_unlock(&data->update_lock);
+	return count;
+invarg:
+	mutex_unlock(&data->update_lock);
+	return -EINVAL;
+}
+
+static ssize_t state_store(struct device *dev,
+		struct device_attribute *attr, const  char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct acclero_data *data = i2c_get_clientdata(client);
+	unsigned int ret_val, set_val;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+	ret_val = i2c_smbus_read_byte_data(client, 0x20);
+
+	mutex_lock(&data->update_lock);
+	if (val = ACCEL_POWER_MODE_DOWN)
+		set_val = ret_val & 0xBF; /* if value id 0 */
+	else if (val = ACCEL_POWER_MODE_ACTIVE)
+		set_val = (ret_val | (1<<6)); /* if value is 1 */
+	else
+		goto invarg;
+
+	i2c_write_current_data(client, 0x20, set_val);
+	mutex_unlock(&data->update_lock);
+	return count;
+invarg:
+	mutex_unlock(&data->update_lock);
+	return -EINVAL;
+}
+
+static ssize_t reboot_mem_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct acclero_data *data = i2c_get_clientdata(client);
+	unsigned int ret_val, set_val;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+	ret_val = i2c_smbus_read_byte_data(client, 0x21);
+	if (val = ACCEL_MEMORY_REBOOT) {
+		mutex_lock(&data->update_lock);
+		set_val = (ret_val | (1 << 6)); /* setting the 6th  bit */
+		i2c_write_current_data(client, 0x21, set_val);
+		mutex_unlock(&data->update_lock);
+	} else
+		return -EINVAL;
+	return count;
+}
+
+static DEVICE_ATTR(data_rate, S_IRUGO | S_IWUSR, rate_show, rate_store);
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, state_show, state_store);
+static DEVICE_ATTR(reboot_mem, S_IWUSR, NULL, reboot_mem_store);
+static DEVICE_ATTR(position, S_IRUGO, xyz_pos_show, NULL);
+
+static struct attribute *mid_att_acclero[] = {
+	&dev_attr_data_rate.attr,
+	&dev_attr_power_state.attr,
+	&dev_attr_reboot_mem.attr,
+	&dev_attr_position.attr,
+	NULL
+};
+
+static struct attribute_group m_acclero_gr = {
+	.name = "lis331dl",
+	.attrs = mid_att_acclero
+};
+
+static void accel_set_default_config(struct i2c_client *client)
+{
+	i2c_write_current_data(client, 0x20, 0x47);
+}
+
+static int  lis331dl_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	int res;
+	struct acclero_data *data;
+
+	data = kzalloc(sizeof(struct acclero_data), GFP_KERNEL);
+	if (data = NULL) {
+		printk(KERN_WARNING "lis331dl: Memory initi failed \n");
+		return -ENOMEM;
+	}
+	mutex_init(&data->update_lock);
+	i2c_set_clientdata(client, data);
+
+	res = sysfs_create_group(&client->dev.kobj, &m_acclero_gr);
+	if (res) {
+		printk(KERN_WARNING "lis331dl: Sysfs  group failed!!\n");
+		goto acclero_error1;
+	}
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		res = PTR_ERR(data->hwmon_dev);
+		data->hwmon_dev = NULL;
+		sysfs_remove_group(&client->dev.kobj, &m_acclero_gr);
+		printk(KERN_WARNING "lis331dl: unable to register \
+						hwmon device\n");
+		goto acclero_error1;
+	}
+	accel_set_default_config(client);
+
+	dev_info(&client->dev, "%s lis331dl:  Accelerometer chip \
+							foundn", client->name);
+	return res;
+
+acclero_error1:
+	i2c_set_clientdata(client, NULL);
+	kfree(data);
+	return res;
+}
+
+static int lis331dl_remove(struct i2c_client *client)
+{
+	struct acclero_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &m_acclero_gr);
+	kfree(data);
+	return 0;
+}
+
+static struct i2c_device_id lis331dl_id[] = {
+	{ "i2c_accel", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, lis331dl_id);
+
+static struct i2c_driver lis331dl_driver = {
+	.driver = {
+	.name = "lis331dl",
+	},
+	.probe = lis331dl_probe,
+	.remove = lis331dl_remove,
+	.id_table = lis331dl_id,
+};
+
+static int __init sensor_lis331dl_init(void)
+{
+	int res;
+
+	res = i2c_add_driver(&lis331dl_driver);
+	return res;
+}
+
+static void  __exit sensor_lis331dl_exit(void)
+{
+	i2c_del_driver(&lis331dl_driver);
+}
+
+module_init(sensor_lis331dl_init);
+module_exit(sensor_lis331dl_exit);
-- 
1.6.0.6


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

             reply	other threads:[~2009-08-11  8:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-08-11  8:11 Kalhan Trisal [this message]
2009-08-14 14:22 ` [lm-sensors] Accelerometer driver Kalhan Trisal
2009-08-17 13:42 ` Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090811184948.GA32002@intel.com \
    --to=kalhan.trisal@intel.com \
    --cc=lm-sensors@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.