RE: [RFC] [PATCH] Adding support for BMP085 pressure sensor.

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

 



Hi Jonathan,

> -----Original Message-----
> From: J.I. Cameron [mailto:jic23@xxxxxxxxxxxxxxxx] On Behalf Of J.I.
> Cameron
> Sent: Monday, June 14, 2010 5:26 PM
> To: Datta, Shubhrajyoti
> Cc: linux-kernel@xxxxxxxxxxxxxxx; linux-input@xxxxxxxxxxxxxxx
> Subject: Re: [RFC] [PATCH] Adding support for BMP085 pressure sensor.
> 
> On Jun 14 2010, Datta, Shubhrajyoti wrote:
> 
> >Adding support for BMP085 pressure sensor.
> >The interface of the device is I2C.
> >The driver is based on a version initially written by Christoph
> >Mair.
> 
> Hi,
> 
> Looks good now. My only comment is that a new
> driver should try and match existing attribute naming
> wherever possible.  I don't think there are any
> similar sensors in place so you have a fair bit of
> flexibility. However, temperature for example has
> a well defined naming convention (hwmon, temp0_input)
> and personally I'd be in favour of keeping close to that
> convention for new sensor types.  Hence pressure0_input.
> We went through the whole question of what to call things
> in IIO and ended up extending hwmon's interface to cover
> everything we needed.  Note you may get some friction
> from Andrew Morton if you don't do this (and as he
> is maintainer of misc, I'd CC him on the patches!)
Agree to it.
Will send a patch shortly.
> 
> Also 'oversampling' needs some documentation as does pressure
> as both are new interfaces in the kernel (as far as I know)
> 
I am taking an action item for that.
For now will add more comments.
> Jonathan
> >
> > Signed-off-by: Shubhrajyoti D <shubhrajyoti@xxxxxx> ---
> > drivers/misc/bmp085.c | 333
> > +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 333
> > insertions(+), 0 deletions(-) create mode 100755 drivers/misc/bmp085.c
> >
> >diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
> >new file mode 100755
> >index 0000000..fab2480
> >--- /dev/null
> >+++ b/drivers/misc/bmp085.c
> >@@ -0,0 +1,333 @@
> >+/*  Copyright (c) 2009  Christoph Mair <christoph.mair@xxxxxxxxx>
> >+
> >+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
> >+*/
> >+
> >+#include <linux/i2c.h>
> >+#include <linux/slab.h>
> >+#include <linux/delay.h>
> >+#include <linux/jiffies.h>
> >+
> >+#define BMP085_I2C_ADDRESS		0x77
> >+#define BMP085_CALIBRATION_DATA_START	0xAA
> >+#define BMP085_CALIBRATION_DATA_LENGTH	22
> >+#define BMP085_CHIP_ID_REG		0xD0
> >+#define BMP085_VERSION_REG		0xD1
> >+#define BMP085_CHIP_ID			0x55
> >+#define BMP085_CTRL_REG			0xF4
> >+#define BMP085_TEMP_REG			0x2E
> >+#define BMP085_PRESSURE_OSRS0		0x34
> >+#define BMP085_MSB 			0xF6
> >+#define BMP085_LSB 			0xF7
> >+#define BMP085_XLSB 			0xF8
> >+#define BMP085_TEMP_CONV_TIME		5
> >+
> >+struct bmp085_calibration_data {
> >+	s16 AC1, AC2, AC3;
> >+	u16 AC4, AC5, AC6;
> >+	s16 B1, B2;
> >+	s16 MB, MC, MD;
> >+};
> >+
> >+/* Each client has this additional data */
> >+struct bmp085_data {
> >+	struct i2c_client *client;
> >+	struct mutex lock;
> >+	struct bmp085_calibration_data calibration;
> >+	unsigned char oversampling_setting;
> >+	s32 b6; /* calculated temperature correction coefficient */
> >+};
> >+
> >+static void bmp085_init_client(struct i2c_client *client);
> >+
> >+static s32 bmp085_get_calibration_data(struct i2c_client *client)
> >+{
> >+	u8 tmp[BMP085_CALIBRATION_DATA_LENGTH];
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+	struct bmp085_calibration_data *cali = &(data->calibration);
> >+	s32 status = i2c_smbus_read_i2c_block_data(client,
> >+				BMP085_CALIBRATION_DATA_START,
> >+				BMP085_CALIBRATION_DATA_LENGTH, tmp);
> >+
> >+	cali->AC1 =  (tmp[0] << 8) | tmp[1];
> >+	cali->AC2 =  (tmp[2] << 8) | tmp[3];
> >+	cali->AC3 =  (tmp[4] << 8) | tmp[5];
> >+	cali->AC4 =  (tmp[6] << 8) | tmp[7];
> >+	cali->AC5 =  (tmp[8] << 8) | tmp[9];
> >+	cali->AC6 = (tmp[10] << 8) | tmp[11];
> >+
> >+	/*parameters B1,B2*/
> >+	cali->B1 =  (tmp[12] << 8) | tmp[13];
> >+	cali->B2 =  (tmp[14] << 8) | tmp[15];
> >+
> >+	/*parameters MB,MC,MD*/
> >+	cali->MB =  (tmp[16] << 8) | tmp[17];
> >+	cali->MC =  (tmp[18] << 8) | tmp[19];
> >+	cali->MD =  (tmp[20] << 8) | tmp[21];
> >+	return status;
> >+}
> >+
> >+static s32 bmp085_get_temperature(struct i2c_client *client)
> >+{
> >+	u16 temperature = 0x00;
> >+	u8 tmp[2];
> >+	s32 status = i2c_smbus_write_byte_data(client, BMP085_CTRL_REG,
> >+						BMP085_TEMP_REG);
> >+	if (status != 0) {
> >+		dev_err(&client->dev, "bmp085: Error requesting\
> >+				temperature measurement.\n");
> >+		return status;
> >+	}
> >+	msleep(BMP085_TEMP_CONV_TIME);
> >+
> >+	i2c_smbus_read_i2c_block_data(client, BMP085_MSB, 2, tmp);
> >+	/* next temperature measurement is needed in one second */
> >+	temperature = (tmp[0] << 8) + tmp[1];
> >+	pr_info("temperature: %u\n", temperature);
> >+	return temperature;
> >+}
> >+
> >+static s32 bmp085_read_pressure(struct i2c_client *client, u32
> *pressure)
> >+{
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+	u8 tmp[3];
> >+	s32 status;
> >+
> >+	status = i2c_smbus_write_byte_data(client, BMP085_CTRL_REG,
> >+		BMP085_PRESSURE_OSRS0 + (data->oversampling_setting<<6));
> >+	if (status != 0)
> >+		return status;
> >+
> >+	/* wait for the end of conversion */
> >+	msleep(2+(3 << data->oversampling_setting));
> >+
> >+	status = i2c_smbus_read_i2c_block_data(client, BMP085_MSB, 0x03,
> tmp);
> >+	/* swap positions to correct the MSB/LSB positions*/
> >+	*pressure = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
> >+	*pressure = *pressure >> (8-data->oversampling_setting);
> >+	return status;
> >+}
> >+
> >+/* sysfs callbacks */
> >+static ssize_t set_oversampling(struct device *dev,
> >+				struct device_attribute *attr,
> >+				const char *buf,
> >+				size_t count)
> >+{
> >+	struct i2c_client *client = to_i2c_client(dev);
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+	data->oversampling_setting = simple_strtoul(buf, NULL, 10);
> >+	if (data->oversampling_setting > 3)
> >+		data->oversampling_setting = 3;
> >+	return count;
> >+}
> >+
> >+static ssize_t show_oversampling(struct device *dev,
> >+				struct device_attribute *attr,
> >+				char *buf)
> >+{
> >+	struct i2c_client *client = to_i2c_client(dev);
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+	return sprintf(buf, "%u\n", data->oversampling_setting);
> >+}
> >+static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
> >+	show_oversampling, set_oversampling);
> >+
> >+static void bmp085_read_temperature(struct i2c_client *client,  s32
> *buf)
> >+{
> >+	s32 raw_temp, x1 , x2;
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+	struct bmp085_calibration_data *cali = &data->calibration;
> >+
> >+	raw_temp = bmp085_get_temperature(client);
> >+	x1 = ((raw_temp - cali->AC6) * cali->AC5) >> 15;
> >+	x2 = (cali->MC << 11) / (x1 + cali->MD);
> >+	data->b6 = x1 + x2 - 4000;
> >+	*buf = ((x1+x2+8) >> 4) ;
> >+}
> >+
> >+static int bmp085_read_sensor(struct bmp085_data *bmp085,
> >+					s32 *pressure,
> >+					s32 *temp)
> >+{
> >+
> >+	struct i2c_client *client = bmp085->client;
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+	struct bmp085_calibration_data *cali = &data->calibration;
> >+	s32 x1, x2, x3, b3;
> >+	u32 b4, b7;
> >+	s32 p;
> >+	unsigned int raw_pressure=0;
> >+	s32 raw_temp;
> >+
> >+	bmp085_read_temperature(client,  &raw_temp);
> >+	*temp = raw_temp ;
> >+	bmp085_read_pressure(client, &raw_pressure);
> >+
> >+	x1 = (data->b6 * data->b6) >> 12;
> >+	x1 *= cali->B2;
> >+	x1 >>= 11;
> >+
> >+	x2 = cali->AC2 * data->b6;
> >+	x2 >>= 11;
> >+
> >+	x3 = x1 + x2;
> >+
> >+	b3 = (((((s32)cali->AC1) * 4 + x3) <<
> >+				data->oversampling_setting) + 2) >> 2;
> >+
> >+	x1 = (cali->AC3 * data->b6) >> 13;
> >+	x2 = (cali->B1 * ((data->b6 * data->b6) >> 12)) >> 16;
> >+	x3 = (x1 + x2 + 2) >> 2;
> >+	b4 = (cali->AC4 * (u32)(x3 + 32768)) >> 15;
> >+
> >+	b7 = ((u32)raw_pressure - b3) *
> >+				(50000 >> data->oversampling_setting);
> >+	p = ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2));
> >+
> >+	x1 = p >> 8;
> >+	x1 *= x1;
> >+	x1 = (x1 * 3038) >> 16;
> >+	x2 = (-7357 * p) >> 16;
> >+	p += (x1 + x2 + 3791) >> 4;
> >+	*pressure = p;
> >+	return 0;
> >+}
> >+static ssize_t show_temperature(struct device *dev,
> >+				struct device_attribute *attr, char *buf)
> >+{
> >+	struct i2c_client *client = to_i2c_client(dev);
> >+	return sprintf(buf, "%d\n", bmp085_get_temperature(client));
> >+}
> >+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
> >+
> >+
> >+static ssize_t show_pressure(struct device *dev,
> >+			     struct device_attribute *attr, char *buf)
> >+{
> >+	struct i2c_client *client = to_i2c_client(dev);
> >+	struct bmp085_data *bmp085 = i2c_get_clientdata(client);
> >+	s32 pressure_read, temperature;
> >+
> >+	bmp085_read_sensor(bmp085, &pressure_read, &temperature);
> >+
> >+	return sprintf(buf, "%d\n", pressure_read);
> >+}
> >+static DEVICE_ATTR(pressure, S_IRUGO, show_pressure, NULL);
> >+
> >+static struct attribute *bmp085_attributes[] = {
> >+	&dev_attr_oversampling.attr,
> >+	&dev_attr_pressure.attr,
> >+	&dev_attr_temperature.attr,
> >+	NULL
> >+};
> >+
> >+static const struct attribute_group bmp085_attr_group = {
> >+	.attrs = bmp085_attributes,
> >+};
> >+
> >+static int bmp085_probe(struct i2c_client *client,
> >+			 const struct i2c_device_id *id)
> >+{
> >+	struct bmp085_data *bmp085_data;
> >+	int err;
> >+
> >+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> >+		dev_dbg(&client->dev, "adapter doesn't support I2C\n");
> >+		return -ENODEV;
> >+	}
> >+
> >+	bmp085_data = kzalloc(sizeof(struct bmp085_data), GFP_KERNEL);
> >+	if (!bmp085_data) {
> >+		err = -ENOMEM;
> >+		goto exit;
> >+	}
> >+	bmp085_data->client = client;
> >+
> >+	/* default settings after POR */
> >+	bmp085_data->oversampling_setting = 0x00;
> >+
> >+	i2c_set_clientdata(client, bmp085_data);
> >+
> >+	/* Initialize the BMP085 chip */
> >+	bmp085_init_client(client);
> >+
> >+	/* Register sysfs hooks */
> >+	err = sysfs_create_group(&client->dev.kobj, &bmp085_attr_group);
> >+	if (err)
> >+		dev_err(&client->dev,
> >+			"failed to create sysfs entries\n");
> >+
> >+	return 0;
> >+
> >+exit:
> >+	return err;
> >+}
> >+
> >+static int bmp085_remove(struct i2c_client *client)
> >+{
> >+	struct bmp085_data *bmp085 = i2c_get_clientdata(client);
> >+
> >+	pr_info("bmp085 remove\n");
> >+	sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group);
> >+	kfree(bmp085);
> >+	return 0;
> >+}
> >+
> >+static void bmp085_init_client(struct i2c_client *client)
> >+{
> >+	u8 version;
> >+	struct bmp085_data *data = i2c_get_clientdata(client);
> >+
> >+	bmp085_get_calibration_data(client);
> >+	version = i2c_smbus_read_byte_data(client, BMP085_VERSION_REG);
> >+	data->oversampling_setting = 3;
> >+	mutex_init(&data->lock);
> >+	pr_info("BMP085 ver. %d.%d initialized\n",
> >+			(version & 0x0F), (version & 0xF0) >> 4);
> >+}
> >+
> >+static const struct i2c_device_id bmp085_id[] = {
> >+	{ "bmp085", 0 },
> >+	{ }
> >+};
> >+
> >+static struct i2c_driver bmp085_driver = {
> >+	.driver = {
> >+		.name	= "bmp085",
> >+		.owner = THIS_MODULE,
> >+	},
> >+	.probe		= bmp085_probe,
> >+	.remove		= bmp085_remove,
> >+	.id_table	= bmp085_id,
> >+};
> >+
> >+static int __init bmp085_init(void)
> >+{
> >+	return i2c_add_driver(&bmp085_driver);
> >+}
> >+
> >+static void __exit bmp085_exit(void)
> >+{
> >+	i2c_del_driver(&bmp085_driver);
> >+}
> >+
> >+MODULE_AUTHOR("Christoph Mair, Shubhrajyoti");
> >+MODULE_DESCRIPTION("BMP085 driver");
> >+MODULE_LICENSE("GPL");
> >+
> >+module_init(bmp085_init);
> >+module_exit(bmp085_exit);
> >+
> >

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux