[PATCH] iio - add barometer bmp085

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds:
- digital barometer support to the iio subsytem
- Bosch Sensortec bmp085 driver

I resend the patches I sent yesterday, because I merged them to one.
Also the comments and the define has been deleted and so, from my point of view is ready to merge.

Signed-off-by: Matthias Brugger <m_brugger@xxxxxx>
---
 drivers/staging/iio/Kconfig            |    1 +
 drivers/staging/iio/Makefile           |    1 +
 drivers/staging/iio/barometer/Kconfig  |   12 +
 drivers/staging/iio/barometer/Makefile |    5 +
 drivers/staging/iio/barometer/baro.h   |    8 +
 drivers/staging/iio/barometer/bmp085.c |  418 ++++++++++++++++++++++++++++++++
 drivers/staging/iio/barometer/bmp085.h |   73 ++++++
 7 files changed, 518 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/barometer/Kconfig
 create mode 100644 drivers/staging/iio/barometer/Makefile
 create mode 100644 drivers/staging/iio/barometer/baro.h
 create mode 100644 drivers/staging/iio/barometer/bmp085.c
 create mode 100644 drivers/staging/iio/barometer/bmp085.h

diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index ed48815..d5ca09a 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -46,6 +46,7 @@ source "drivers/staging/iio/gyro/Kconfig"
 source "drivers/staging/iio/imu/Kconfig"
 source "drivers/staging/iio/light/Kconfig"
 source "drivers/staging/iio/magnetometer/Kconfig"
+source "drivers/staging/iio/barometer/Kconfig"
 
 source "drivers/staging/iio/trigger/Kconfig"
 
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index e909674..73112b2 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -16,3 +16,4 @@ obj-y += imu/
 obj-y += light/
 obj-y += trigger/
 obj-y += magnetometer/
+obj-y += barometer/
diff --git a/drivers/staging/iio/barometer/Kconfig b/drivers/staging/iio/barometer/Kconfig
new file mode 100644
index 0000000..d5942e9
--- /dev/null
+++ b/drivers/staging/iio/barometer/Kconfig
@@ -0,0 +1,12 @@
+#
+# IIO Digital Barometer Sensor drivers configuration
+#
+comment "Digital barometer sensors"
+
+config BMP085
+
+	tristate "BMP085 Barometer Sensor I2C driver"
+	depends on I2C
+	help
+	  Say yes here to build support for Bosch Sensortec BMP085,
+	  digital barometer sensor.
diff --git a/drivers/staging/iio/barometer/Makefile b/drivers/staging/iio/barometer/Makefile
new file mode 100644
index 0000000..3234d96
--- /dev/null
+++ b/drivers/staging/iio/barometer/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for digital barometer sensor drivers
+#
+
+obj-$(CONFIG_BMP085) += bmp085.o
diff --git a/drivers/staging/iio/barometer/baro.h b/drivers/staging/iio/barometer/baro.h
new file mode 100644
index 0000000..e3b73a1
--- /dev/null
+++ b/drivers/staging/iio/barometer/baro.h
@@ -0,0 +1,8 @@
+
+#include "../sysfs.h"
+
+/* Barometer types of attribute */
+
+#define IIO_DEV_ATTR_BARO_PRESSURE(_mode, _show, _store, _addr)	\
+	IIO_DEVICE_ATTR(baro_pressure, _mode, _show, NULL, _addr)
+
diff --git a/drivers/staging/iio/barometer/bmp085.c b/drivers/staging/iio/barometer/bmp085.c
new file mode 100644
index 0000000..67dac39
--- /dev/null
+++ b/drivers/staging/iio/barometer/bmp085.c
@@ -0,0 +1,418 @@
+/**
+ * Bosch Sensortec BMP085 Digital Pressure Sensor
+ *
+ * Written by: Matthias Brugger <m_brugger@xxxxxx>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/mutex.h>
+
+#include "bmp085.h"
+
+int oss = 3;
+module_param(oss, int , S_IRUSR);
+MODULE_PARM_DESC(oss, "Oversampling setting [0-3]");
+
+/**************************************************************************
+ * Calcualtion of temperature and pressure
+ **************************************************************************/
+static short bmp085_calc_temperature(struct i2c_client *client,
+	       unsigned long ut)
+{
+	struct bmp085_data *data = i2c_get_clientdata(client);
+	long x1, x2;
+	short temp;
+
+	x1 = ((long) ut - (long) data->ac6) * (long) data->ac5 >> 15;
+	x2 = ((long) data->mc << 11) / (x1 + data->md);
+	data->b5 = x1 + x2;
+	temp = ((data->b5 + 8) >> 4);
+
+	return temp;
+}
+
+static long bmp085_calc_pressure(struct i2c_client *client, unsigned long up)
+{
+	struct bmp085_data *data = i2c_get_clientdata(client);
+	long b6, x1, x2, x3, b3;
+	unsigned long b4, b7;
+	long pressure, p;
+	long tmp;
+
+	b6 = data->b5 - 4000;
+	x1 = (data->b2 * (b6 * b6 / (1<<12))) / (1<<11);
+	x2 = data->ac2 * b6 / (1<<11);
+	x3 = x1 + x2;
+	b3 = (((data->ac1 * 4 + x3) << data->oss) + 2) / 4;
+
+	x1 = data->ac3 * b6 / (1<<13);
+	x2 = (data->b1 * ((b6 * b6) / (1<<12))) / (1<<16);
+	x3 = ((x1 + x2) + 2) / (1<<2);
+	b4 = data->ac4 * (unsigned long) (x3 + 32768) / (1<<15);
+	b7 = ((unsigned long)up - b3) * (50000 >> data->oss);
+
+	if (b7 < 0x80000000)
+		p = (b7 * 2) / b4;
+	else
+		p = (b7 / b4) * 2;
+	tmp = (p / (1<<8)) * (p / (1<<8));
+	x1 = (tmp * 3038) / (1<<16);
+	x2 = (-7357 * p) / (1<<16);
+	pressure = p + ((x1 + x2 + 3791) / (1<<4));
+
+	return pressure;
+}
+
+/**************************************************************************
+ * Digital interface to sensor
+ **************************************************************************/
+
+static ssize_t bmp085_read(struct i2c_client *client, u8 reg, size_t count,
+	       unsigned char *buffer)
+{
+	int rc;
+	rc = i2c_smbus_read_i2c_block_data(client, reg, count, buffer);
+	if (rc < 0)
+			return -EIO;
+
+	return count;
+}
+
+static short bmp085_read_temp(struct i2c_client *client)
+{
+	s32 ret;
+	short temp;
+	struct bmp085_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->bmp085_lock);
+	ret = i2c_smbus_write_byte_data(client, BMP085_START_CONV,
+		       BMP085_START_TEMP);
+	mutex_unlock(&data->bmp085_lock);
+	if (ret < 0) {
+		dev_warn(&client->dev, "starting temperature conversation "
+			       "failed\n");
+		return ret;
+	}
+
+	mdelay(5);
+	ret = bmp085_read(client, BMP085_REG_CONV, 2, data->data);
+	if (ret < 0) {
+		dev_warn(&client->dev, "reading ut failed, value is %#x\n"
+				, ret);
+		return ret;
+	}
+
+	data->ut = (data->data[0] << 8) | data->data[1];
+
+	temp = bmp085_calc_temperature(client, data->ut);
+
+	return temp;
+}
+
+static long bmp085_read_pressure(struct i2c_client *client)
+{
+	unsigned long up = 0;
+	int ret;
+	u8 xlsb, ret1, ret2;
+	long pressure;
+	u8 reg;
+	/* TODO should be 4.5, 7.5, 13.5, 25.5 ms */
+	int time_delay[4] = {5, 8, 14, 26};
+	struct bmp085_data *data = i2c_get_clientdata(client);
+
+	if (data->oss == 0)
+		reg = BMP085_START_PRESS_OSRS0;
+	else if (data->oss == 1)
+		reg = BMP085_START_PRESS_OSRS1;
+	else if (data->oss == 2)
+		reg = BMP085_START_PRESS_OSRS2;
+	else if (data->oss == 3)
+		reg = BMP085_START_PRESS_OSRS3;
+	else {
+		dev_warn(&client->dev, "undefined oss value, use oss = 0\n");
+		data->oss = 0;
+		reg = BMP085_START_PRESS_OSRS0;
+	}
+
+	mutex_lock(&data->bmp085_lock);
+	ret = i2c_smbus_write_byte_data(client, BMP085_START_CONV, reg);
+	mutex_unlock(&data->bmp085_lock);
+	if (ret < 0)
+		return ret;
+
+	mdelay(time_delay[data->oss]);
+
+	mutex_lock(&data->bmp085_lock);
+	ret1 = i2c_smbus_read_byte_data(client, 0xf6);
+	ret2 = i2c_smbus_read_byte_data(client, 0xf7);
+	xlsb = i2c_smbus_read_byte_data(client, 0xf8);
+	mutex_unlock(&data->bmp085_lock);
+
+	up = (((unsigned long) ret1 << 16) | ((unsigned long) ret2 << 8)
+				| (unsigned long) xlsb) >> (8 - data->oss);
+	data->up = up;
+
+	pressure = bmp085_calc_pressure(client, up);
+	data->pressure = pressure;
+
+	return pressure;
+}
+
+/**************************************************************************
+ * sysfs attributes
+ **************************************************************************/
+static ssize_t barometer_show_temp(struct device *dev,
+		struct device_attribute *da, char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct bmp085_data *data = indio_dev->dev_data;
+	struct i2c_client *client = data->client;
+	long status;
+
+	status = bmp085_read_temp(client);
+	if (status < 0)
+		dev_warn(&client->dev, "error reading temperature: %ld\n",
+				status);
+
+	data->temp = status;
+
+	return sprintf(buf, "%ld\n", data->temp);
+}
+static IIO_DEV_ATTR_TEMP_RAW(barometer_show_temp);
+
+/**
+ * In standard mode, the temperature has to be reat every second before the
+ * pressure can be reat. We leave this semantics to the userspace, if later
+ * on a trigger based reading will be implemented, this should be taken into
+ * account.
+ */
+static ssize_t barometer_show_pressure(struct device *dev,
+		struct device_attribute *da, char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct bmp085_data *data = indio_dev->dev_data;
+	struct i2c_client *client = data->client;
+	long status;
+
+	status = bmp085_read_pressure(client);
+	if (status < 0)
+		dev_warn(&client->dev, "error reading pressure: %ld\n", status);
+
+	data->pressure = status;
+
+	return sprintf(buf, "%ld\n", data->pressure);
+}
+static IIO_DEV_ATTR_BARO_PRESSURE(S_IRUGO, barometer_show_pressure, NULL, 0);
+
+static ssize_t barometer_show_id_version(struct device *dev,
+		struct device_attribute *da, char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct bmp085_data *data = indio_dev->dev_data;
+
+	return sprintf(buf, "%x_%x\n", data->chip_id, data->chip_version);
+}
+static IIO_DEV_ATTR_REV(barometer_show_id_version);
+
+static ssize_t barometer_show_oss(struct device *dev,
+		struct device_attribute *da, char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct bmp085_data *data = indio_dev->dev_data;
+
+	return sprintf(buf, "%d\n", data->oss);
+}
+static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO, barometer_show_oss, NULL);
+
+static IIO_CONST_ATTR_TEMP_SCALE("0.1");
+
+static struct attribute *bmp085_attributes[] = {
+	&iio_dev_attr_temp_raw.dev_attr.attr,
+	&iio_dev_attr_baro_pressure.dev_attr.attr,
+	&iio_dev_attr_revision.dev_attr.attr,
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	&iio_const_attr_temp_scale.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group bmp085_attr_group = {
+	.attrs = bmp085_attributes,
+};
+
+/**************************************************************************
+ * Calibration data processing
+ **************************************************************************/
+
+static int bmp085_init_client(struct i2c_client *client)
+{
+	struct bmp085_data *data = i2c_get_clientdata(client);
+	int i;
+
+	i = bmp085_read(client, BMP085_REG_CHIP_ID, 1, &data->chip_id);
+	if (i < 0)
+		dev_warn(&client->dev, "Chip ID not read\n");
+
+	i = bmp085_read(client, BMP085_REG_VERSION, 1, &data->chip_version);
+	if (i < 0)
+		dev_warn(&client->dev, "Version not read\n");
+
+	i = bmp085_read(client, BMP085_REG_PROM, BMP085_PROM_LENGTH,
+			data->data);
+	if (i < 0)
+		dev_warn(&client->dev, "Unable to read %d bytes from address "
+				"%#x\n", BMP085_PROM_LENGTH, BMP085_REG_PROM);
+
+	data->ac1 = (data->data[0] << 8) | data->data[1];
+	data->ac2 = (data->data[2] << 8) | data->data[3];
+	data->ac3 = (data->data[4] << 8) | data->data[5];
+	data->ac4 = (data->data[6] << 8) | data->data[7];
+	data->ac5 = (data->data[8] << 8) | data->data[9];
+	data->ac6 = (data->data[10] << 8) | data->data[11];
+	data->b1 = (data->data[12] << 8) | data->data[13];
+	data->b2 = (data->data[14] << 8) | data->data[15];
+	data->mb = (data->data[16] << 8) | data->data[17];
+	data->mc = (data->data[18] << 8) | data->data[19];
+	data->md = (data->data[20] << 8) | data->data[21];
+
+	return 0;
+}
+
+static struct i2c_driver bmp085_drv;
+static int bmp085_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct bmp085_data *data;
+	struct bmp085_data *data2;
+	int status = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				I2C_FUNC_SMBUS_WORD_DATA))
+		return -EIO;
+
+	/* Allocate driver data */
+	data = kzalloc(sizeof(struct bmp085_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if ((oss < 0) || (oss > 3)) {
+		status = -EINVAL;
+		goto err;
+	}
+	data->oss = oss;
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+	data2 = i2c_get_clientdata(client);
+
+	/* Initialize the BMP085 chip */
+	bmp085_init_client(client);
+
+	__mutex_init(&data->bmp085_lock, "bmp085_lock", NULL);
+
+	/* Register with IIO */
+	data->indio_dev = iio_allocate_device();
+	if (data->indio_dev == NULL) {
+		status = -ENOMEM;
+		goto err;
+	}
+
+	data->indio_dev->dev.parent = &client->dev;
+	data->indio_dev->attrs = &bmp085_attr_group;
+	data->indio_dev->dev_data = (void *)(data);
+	data->indio_dev->driver_module = THIS_MODULE;
+	data->indio_dev->modes = INDIO_DIRECT_MODE;
+
+	status = iio_device_register(data->indio_dev);
+	if (status < 0)
+		goto err_iio;
+
+	dev_info(&client->dev, "driver enabled\n");
+
+	return 0;
+
+err_iio:
+	kfree(data->indio_dev);
+err:
+	kfree(data);
+	return status;
+}
+
+static int __devexit bmp085_remove(struct i2c_client *client)
+{
+	struct bmp085_data *data = i2c_get_clientdata(client);
+
+	if (mutex_is_locked(&data->bmp085_lock))
+		mutex_unlock(&data->bmp085_lock);
+
+	iio_device_unregister(data->indio_dev);
+	iio_free_device(data->indio_dev);
+
+	kfree(data);
+
+	dev_info(&client->dev, "driver removed\n");
+
+	return 0;
+}
+
+static const struct i2c_device_id bmp085_id[] = {
+	{ "bmp085", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, bmp085_id);
+
+static struct i2c_driver bmp085_drv = {
+	.driver = {
+		.name =  "bmp085",
+		.owner = THIS_MODULE,
+	},
+	.suspend = NULL,
+	.resume = NULL,
+	.probe = bmp085_probe,
+	.remove = __devexit_p(bmp085_remove),
+	.id_table = bmp085_id,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init bmp085_init_module(void)
+{
+	printk(KERN_INFO"bmp085 loading...\n");
+
+	return i2c_add_driver(&bmp085_drv);
+}
+
+static void __exit bmp085_exit_module(void)
+{
+	i2c_del_driver(&bmp085_drv);
+}
+
+MODULE_AUTHOR("Matthias Brugger <matthias.brugger@xxxxxxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("I2c device driver for BMP085 barometererator sensor");
+MODULE_LICENSE("GPL");
+
+module_init(bmp085_init_module);
+module_exit(bmp085_exit_module);
diff --git a/drivers/staging/iio/barometer/bmp085.h b/drivers/staging/iio/barometer/bmp085.h
new file mode 100644
index 0000000..5ed2fb1
--- /dev/null
+++ b/drivers/staging/iio/barometer/bmp085.h
@@ -0,0 +1,73 @@
+#ifndef BMP085_H
+#define BMP085_H
+
+#include "../iio.h"
+#include "baro.h"
+
+#define BMP085_REG_CONV		0xF6 /* Temperature/pressure value UT or UP */
+#define BMP085_REG_CONV_XLS	0xF8
+
+#define BMP085_REG_PROM		0xAA
+#define BMP085_PROM_LENGTH	22
+
+#define BMP085_REG_AC1		0xAA
+#define BMP085_REG_AC2		0xAC
+#define BMP085_REG_AC3		0xAE
+#define BMP085_REG_AC4		0xB0
+#define BMP085_REG_AC5		0xB2
+#define BMP085_REG_AC6		0xB4
+#define BMP085_REG_B1		0xB6
+#define BMP085_REG_B2		0xB8
+#define BMP085_REG_MB		0xBA
+#define BMP085_REG_MC		0xBC
+#define BMP085_REG_MD		0xBE
+
+#define BMP085_START_CONV	0xF4
+
+#define BMP085_START_TEMP	0x2E  /* wait 4.5 ms */
+
+#define BMP085_START_PRESS_OSRS0 0x34 /* wait 4.5 ms */
+#define BMP085_START_PRESS_OSRS1 0x74 /* wait 7.5 ms */
+#define BMP085_START_PRESS_OSRS2 0xB4 /* wait 13.5 ms */
+#define BMP085_START_PRESS_OSRS3 0xF4 /* wait 25.5 ms */
+
+#define BMP085_REG_CHIP_ID	0xD0
+#define BMP085_REG_VERSION	0xD1
+#define BMP085_CHIP_ID		0x55
+
+struct bmp085_data {
+	struct i2c_client *client;
+	struct iio_dev *indio_dev;
+
+	struct mutex bmp085_lock;
+
+	int oss;
+	long temp;
+	long pressure;
+
+	short ac1;
+	short ac2;
+	short ac3;
+	unsigned short ac4;
+	unsigned short ac5;
+	unsigned short ac6;
+
+	short b1;
+	short b2;
+	long b5;
+
+	short mb;
+	short mc;
+	short md;
+
+	unsigned long ut;
+	unsigned long up;
+
+	u8 chip_id;
+	u8 chip_version;
+
+	unsigned char data[22];
+};
+
+
+#endif
-- 
1.5.6.5
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux