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.
Signed-off-by: Shubhrajyoti D <[email protected]>
---
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 <[email protected]>
+
+ 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);
+
--
1.5.4.7
Am Montag, 14. Juni 2010 12:13:44 schrieb Datta, Shubhrajyoti:
> +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];
Please use the macros for reading be16 data.
Regards
Oliver
Am Montag, 14. Juni 2010 12:13:44 schrieb Datta, Shubhrajyoti:
> +/* 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;
> +}
What happens if somebody writes a non-numerical value?
Regards
Oliver
Hello.
On Mon, 2010-06-14 at 15:43, 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.
Did you coordinate with Christoph on this driver? I used it myself and the last
time I talked to Christoph he was planning to brining it mainline himself. Added
him to cc to keep him in the loop.
regards
Stefan Schmidt
> Signed-off-by: Shubhrajyoti D <[email protected]>
> ---
> 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 <[email protected]>
> +
> + 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);
> +
> --
> 1.5.4.7
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
Hello,
On Mon, Jun 14, 2010 at 12:35 PM, Stefan Schmidt
<[email protected]> wrote:
> Hello.
>
> On Mon, 2010-06-14 at 15:43, 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.
>
> Did you coordinate with Christoph on this driver? I used it myself and the last
> time I talked to Christoph he was planning to brining it mainline himself. Added
> him to cc to keep him in the loop.
I already merged the input specific additions from Shubhrajyoti into
my latest code, but I still have to push the changes to my repository.
I'll do this as soon as I can test the driver. Then I will send a new
patch which will also contain fixes for issues raised on the ML.
Best Regards,
Christoph Mair
> -----Original Message-----
> From: Stefan Schmidt [mailto:[email protected]]
> Sent: Monday, June 14, 2010 4:06 PM
> To: Datta, Shubhrajyoti
> Cc: [email protected]; [email protected];
> [email protected]
> Subject: Re: [RFC] [PATCH] Adding support for BMP085 pressure sensor.
>
> Hello.
>
> On Mon, 2010-06-14 at 15:43, 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.
>
> Did you coordinate with Christoph on this driver? I used it myself and the
> last
> time I talked to Christoph he was planning to brining it mainline himself.
> Added
> him to cc to keep him in the loop.
I modified the initial version to use it as an input device an a few bug fixes and sent him the patch for his signoff. Also I have kept the copyright banner that he had.
However since it is not really a human input device I thought of making it an misc as it doesn't really justify a hwmon.
>
> regards
> Stefan Schmidt
>
> > Signed-off-by: Shubhrajyoti D <[email protected]>
> > ---
> > 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 <[email protected]>
> > +
> > + 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);
> > +
> > --
> > 1.5.4.7
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel"
> in
> > the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at http://www.tux.org/lkml/
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 <[email protected]> ---
> 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 <[email protected]>
>+
>+ 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);
>+
>
Hi Jonathan,
> -----Original Message-----
> From: J.I. Cameron [mailto:[email protected]] On Behalf Of J.I.
> Cameron
> Sent: Monday, June 14, 2010 5:26 PM
> To: Datta, Shubhrajyoti
> Cc: [email protected]; [email protected]
> 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 <[email protected]> ---
> > 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 <[email protected]>
> >+
> >+ 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);
> >+
> >