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]
Date:	14 Jun 2010 12:55:39 +0100
From:	"J.I. Cameron" <jic23@....ac.uk>
To:	"Datta, Shubhrajyoti" <shubhrajyoti@...com>
Cc:	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"linux-input@...r.kernel.org" <linux-input@...r.kernel.org>
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!)

Also 'oversampling' needs some documentation as does pressure
as both are new interfaces in the kernel (as far as I know)

Jonathan
>
> Signed-off-by: Shubhrajyoti D <shubhrajyoti@...com> --- 
> 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@...il.com>
>+
>+    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-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