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