Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14-rc6 507 lines 14 kB view raw
1/* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com> 2 * Copyright (c) 2012 Bosch Sensortec GmbH 3 * Copyright (c) 2012 Unixphere AB 4 * 5 * This driver supports the bmp085 and bmp18x digital barometric pressure 6 * and temperature sensors from Bosch Sensortec. The datasheets 7 * are available from their website: 8 * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf 9 * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf 10 * 11 * A pressure measurement is issued by reading from pressure0_input. 12 * The return value ranges from 30000 to 110000 pascal with a resulution 13 * of 1 pascal (0.01 millibar) which enables measurements from 9000m above 14 * to 500m below sea level. 15 * 16 * The temperature can be read from temp0_input. Values range from 17 * -400 to 850 representing the ambient temperature in degree celsius 18 * multiplied by 10.The resolution is 0.1 celsius. 19 * 20 * Because ambient pressure is temperature dependent, a temperature 21 * measurement will be executed automatically even if the user is reading 22 * from pressure0_input. This happens if the last temperature measurement 23 * has been executed more then one second ago. 24 * 25 * To decrease RMS noise from pressure measurements, the bmp085 can 26 * autonomously calculate the average of up to eight samples. This is 27 * set up by writing to the oversampling sysfs file. Accepted values 28 * are 0, 1, 2 and 3. 2^x when x is the value written to this file 29 * specifies the number of samples used to calculate the ambient pressure. 30 * RMS noise is specified with six pascal (without averaging) and decreases 31 * down to 3 pascal when using an oversampling setting of 3. 32 * 33 * This program is free software; you can redistribute it and/or modify 34 * it under the terms of the GNU General Public License as published by 35 * the Free Software Foundation; either version 2 of the License, or 36 * (at your option) any later version. 37 * 38 * This program is distributed in the hope that it will be useful, 39 * but WITHOUT ANY WARRANTY; without even the implied warranty of 40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41 * GNU General Public License for more details. 42 * 43 * You should have received a copy of the GNU General Public License 44 * along with this program; if not, write to the Free Software 45 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 46 */ 47 48#include <linux/module.h> 49#include <linux/device.h> 50#include <linux/init.h> 51#include <linux/slab.h> 52#include <linux/of.h> 53#include "bmp085.h" 54#include <linux/interrupt.h> 55#include <linux/completion.h> 56#include <linux/gpio.h> 57 58#define BMP085_CHIP_ID 0x55 59#define BMP085_CALIBRATION_DATA_START 0xAA 60#define BMP085_CALIBRATION_DATA_LENGTH 11 /* 16 bit values */ 61#define BMP085_CHIP_ID_REG 0xD0 62#define BMP085_CTRL_REG 0xF4 63#define BMP085_TEMP_MEASUREMENT 0x2E 64#define BMP085_PRESSURE_MEASUREMENT 0x34 65#define BMP085_CONVERSION_REGISTER_MSB 0xF6 66#define BMP085_CONVERSION_REGISTER_LSB 0xF7 67#define BMP085_CONVERSION_REGISTER_XLSB 0xF8 68#define BMP085_TEMP_CONVERSION_TIME 5 69 70struct bmp085_calibration_data { 71 s16 AC1, AC2, AC3; 72 u16 AC4, AC5, AC6; 73 s16 B1, B2; 74 s16 MB, MC, MD; 75}; 76 77struct bmp085_data { 78 struct device *dev; 79 struct regmap *regmap; 80 struct mutex lock; 81 struct bmp085_calibration_data calibration; 82 u8 oversampling_setting; 83 u32 raw_temperature; 84 u32 raw_pressure; 85 u32 temp_measurement_period; 86 unsigned long last_temp_measurement; 87 u8 chip_id; 88 s32 b6; /* calculated temperature correction coefficient */ 89 int irq; 90 struct completion done; 91}; 92 93static irqreturn_t bmp085_eoc_isr(int irq, void *devid) 94{ 95 struct bmp085_data *data = devid; 96 97 complete(&data->done); 98 99 return IRQ_HANDLED; 100} 101 102static s32 bmp085_read_calibration_data(struct bmp085_data *data) 103{ 104 u16 tmp[BMP085_CALIBRATION_DATA_LENGTH]; 105 struct bmp085_calibration_data *cali = &(data->calibration); 106 s32 status = regmap_bulk_read(data->regmap, 107 BMP085_CALIBRATION_DATA_START, (u8 *)tmp, 108 (BMP085_CALIBRATION_DATA_LENGTH << 1)); 109 if (status < 0) 110 return status; 111 112 cali->AC1 = be16_to_cpu(tmp[0]); 113 cali->AC2 = be16_to_cpu(tmp[1]); 114 cali->AC3 = be16_to_cpu(tmp[2]); 115 cali->AC4 = be16_to_cpu(tmp[3]); 116 cali->AC5 = be16_to_cpu(tmp[4]); 117 cali->AC6 = be16_to_cpu(tmp[5]); 118 cali->B1 = be16_to_cpu(tmp[6]); 119 cali->B2 = be16_to_cpu(tmp[7]); 120 cali->MB = be16_to_cpu(tmp[8]); 121 cali->MC = be16_to_cpu(tmp[9]); 122 cali->MD = be16_to_cpu(tmp[10]); 123 return 0; 124} 125 126static s32 bmp085_update_raw_temperature(struct bmp085_data *data) 127{ 128 u16 tmp; 129 s32 status; 130 131 mutex_lock(&data->lock); 132 133 init_completion(&data->done); 134 135 status = regmap_write(data->regmap, BMP085_CTRL_REG, 136 BMP085_TEMP_MEASUREMENT); 137 if (status < 0) { 138 dev_err(data->dev, 139 "Error while requesting temperature measurement.\n"); 140 goto exit; 141 } 142 wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies( 143 BMP085_TEMP_CONVERSION_TIME)); 144 145 status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB, 146 &tmp, sizeof(tmp)); 147 if (status < 0) { 148 dev_err(data->dev, 149 "Error while reading temperature measurement result\n"); 150 goto exit; 151 } 152 data->raw_temperature = be16_to_cpu(tmp); 153 data->last_temp_measurement = jiffies; 154 status = 0; /* everything ok, return 0 */ 155 156exit: 157 mutex_unlock(&data->lock); 158 return status; 159} 160 161static s32 bmp085_update_raw_pressure(struct bmp085_data *data) 162{ 163 u32 tmp = 0; 164 s32 status; 165 166 mutex_lock(&data->lock); 167 168 init_completion(&data->done); 169 170 status = regmap_write(data->regmap, BMP085_CTRL_REG, 171 BMP085_PRESSURE_MEASUREMENT + 172 (data->oversampling_setting << 6)); 173 if (status < 0) { 174 dev_err(data->dev, 175 "Error while requesting pressure measurement.\n"); 176 goto exit; 177 } 178 179 /* wait for the end of conversion */ 180 wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies( 181 2+(3 << data->oversampling_setting))); 182 /* copy data into a u32 (4 bytes), but skip the first byte. */ 183 status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB, 184 ((u8 *)&tmp)+1, 3); 185 if (status < 0) { 186 dev_err(data->dev, 187 "Error while reading pressure measurement results\n"); 188 goto exit; 189 } 190 data->raw_pressure = be32_to_cpu((tmp)); 191 data->raw_pressure >>= (8-data->oversampling_setting); 192 status = 0; /* everything ok, return 0 */ 193 194exit: 195 mutex_unlock(&data->lock); 196 return status; 197} 198 199/* 200 * This function starts the temperature measurement and returns the value 201 * in tenth of a degree celsius. 202 */ 203static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature) 204{ 205 struct bmp085_calibration_data *cali = &data->calibration; 206 long x1, x2; 207 int status; 208 209 status = bmp085_update_raw_temperature(data); 210 if (status < 0) 211 goto exit; 212 213 x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15; 214 x2 = (cali->MC << 11) / (x1 + cali->MD); 215 data->b6 = x1 + x2 - 4000; 216 /* if NULL just update b6. Used for pressure only measurements */ 217 if (temperature != NULL) 218 *temperature = (x1+x2+8) >> 4; 219 220exit: 221 return status; 222} 223 224/* 225 * This function starts the pressure measurement and returns the value 226 * in millibar. Since the pressure depends on the ambient temperature, 227 * a temperature measurement is executed according to the given temperature 228 * measurement period (default is 1 sec boundary). This period could vary 229 * and needs to be adjusted according to the sensor environment, i.e. if big 230 * temperature variations then the temperature needs to be read out often. 231 */ 232static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure) 233{ 234 struct bmp085_calibration_data *cali = &data->calibration; 235 s32 x1, x2, x3, b3; 236 u32 b4, b7; 237 s32 p; 238 int status; 239 240 /* alt least every second force an update of the ambient temperature */ 241 if ((data->last_temp_measurement == 0) || 242 time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) { 243 status = bmp085_get_temperature(data, NULL); 244 if (status < 0) 245 return status; 246 } 247 248 status = bmp085_update_raw_pressure(data); 249 if (status < 0) 250 return status; 251 252 x1 = (data->b6 * data->b6) >> 12; 253 x1 *= cali->B2; 254 x1 >>= 11; 255 256 x2 = cali->AC2 * data->b6; 257 x2 >>= 11; 258 259 x3 = x1 + x2; 260 261 b3 = (((((s32)cali->AC1) * 4 + x3) << data->oversampling_setting) + 2); 262 b3 >>= 2; 263 264 x1 = (cali->AC3 * data->b6) >> 13; 265 x2 = (cali->B1 * ((data->b6 * data->b6) >> 12)) >> 16; 266 x3 = (x1 + x2 + 2) >> 2; 267 b4 = (cali->AC4 * (u32)(x3 + 32768)) >> 15; 268 269 b7 = ((u32)data->raw_pressure - b3) * 270 (50000 >> data->oversampling_setting); 271 p = ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2)); 272 273 x1 = p >> 8; 274 x1 *= x1; 275 x1 = (x1 * 3038) >> 16; 276 x2 = (-7357 * p) >> 16; 277 p += (x1 + x2 + 3791) >> 4; 278 279 *pressure = p; 280 281 return 0; 282} 283 284/* 285 * This function sets the chip-internal oversampling. Valid values are 0..3. 286 * The chip will use 2^oversampling samples for internal averaging. 287 * This influences the measurement time and the accuracy; larger values 288 * increase both. The datasheet gives an overview on how measurement time, 289 * accuracy and noise correlate. 290 */ 291static void bmp085_set_oversampling(struct bmp085_data *data, 292 unsigned char oversampling) 293{ 294 if (oversampling > 3) 295 oversampling = 3; 296 data->oversampling_setting = oversampling; 297} 298 299/* 300 * Returns the currently selected oversampling. Range: 0..3 301 */ 302static unsigned char bmp085_get_oversampling(struct bmp085_data *data) 303{ 304 return data->oversampling_setting; 305} 306 307/* sysfs callbacks */ 308static ssize_t set_oversampling(struct device *dev, 309 struct device_attribute *attr, 310 const char *buf, size_t count) 311{ 312 struct bmp085_data *data = dev_get_drvdata(dev); 313 unsigned long oversampling; 314 int err = kstrtoul(buf, 10, &oversampling); 315 316 if (err == 0) { 317 mutex_lock(&data->lock); 318 bmp085_set_oversampling(data, oversampling); 319 mutex_unlock(&data->lock); 320 return count; 321 } 322 323 return err; 324} 325 326static ssize_t show_oversampling(struct device *dev, 327 struct device_attribute *attr, char *buf) 328{ 329 struct bmp085_data *data = dev_get_drvdata(dev); 330 331 return sprintf(buf, "%u\n", bmp085_get_oversampling(data)); 332} 333static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO, 334 show_oversampling, set_oversampling); 335 336 337static ssize_t show_temperature(struct device *dev, 338 struct device_attribute *attr, char *buf) 339{ 340 int temperature; 341 int status; 342 struct bmp085_data *data = dev_get_drvdata(dev); 343 344 status = bmp085_get_temperature(data, &temperature); 345 if (status < 0) 346 return status; 347 else 348 return sprintf(buf, "%d\n", temperature); 349} 350static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL); 351 352 353static ssize_t show_pressure(struct device *dev, 354 struct device_attribute *attr, char *buf) 355{ 356 int pressure; 357 int status; 358 struct bmp085_data *data = dev_get_drvdata(dev); 359 360 status = bmp085_get_pressure(data, &pressure); 361 if (status < 0) 362 return status; 363 else 364 return sprintf(buf, "%d\n", pressure); 365} 366static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL); 367 368 369static struct attribute *bmp085_attributes[] = { 370 &dev_attr_temp0_input.attr, 371 &dev_attr_pressure0_input.attr, 372 &dev_attr_oversampling.attr, 373 NULL 374}; 375 376static const struct attribute_group bmp085_attr_group = { 377 .attrs = bmp085_attributes, 378}; 379 380int bmp085_detect(struct device *dev) 381{ 382 struct bmp085_data *data = dev_get_drvdata(dev); 383 unsigned int id; 384 int ret; 385 386 ret = regmap_read(data->regmap, BMP085_CHIP_ID_REG, &id); 387 if (ret < 0) 388 return ret; 389 390 if (id != data->chip_id) 391 return -ENODEV; 392 393 return 0; 394} 395EXPORT_SYMBOL_GPL(bmp085_detect); 396 397static void bmp085_get_of_properties(struct bmp085_data *data) 398{ 399#ifdef CONFIG_OF 400 struct device_node *np = data->dev->of_node; 401 u32 prop; 402 403 if (!np) 404 return; 405 406 if (!of_property_read_u32(np, "chip-id", &prop)) 407 data->chip_id = prop & 0xff; 408 409 if (!of_property_read_u32(np, "temp-measurement-period", &prop)) 410 data->temp_measurement_period = (prop/100)*HZ; 411 412 if (!of_property_read_u32(np, "default-oversampling", &prop)) 413 data->oversampling_setting = prop & 0xff; 414#endif 415} 416 417static int bmp085_init_client(struct bmp085_data *data) 418{ 419 int status = bmp085_read_calibration_data(data); 420 421 if (status < 0) 422 return status; 423 424 /* default settings */ 425 data->chip_id = BMP085_CHIP_ID; 426 data->last_temp_measurement = 0; 427 data->temp_measurement_period = 1*HZ; 428 data->oversampling_setting = 3; 429 430 bmp085_get_of_properties(data); 431 432 mutex_init(&data->lock); 433 434 return 0; 435} 436 437struct regmap_config bmp085_regmap_config = { 438 .reg_bits = 8, 439 .val_bits = 8 440}; 441EXPORT_SYMBOL_GPL(bmp085_regmap_config); 442 443int bmp085_probe(struct device *dev, struct regmap *regmap, int irq) 444{ 445 struct bmp085_data *data; 446 int err = 0; 447 448 data = kzalloc(sizeof(struct bmp085_data), GFP_KERNEL); 449 if (!data) { 450 err = -ENOMEM; 451 goto exit; 452 } 453 454 dev_set_drvdata(dev, data); 455 data->dev = dev; 456 data->regmap = regmap; 457 data->irq = irq; 458 459 if (data->irq > 0) { 460 err = devm_request_irq(dev, data->irq, bmp085_eoc_isr, 461 IRQF_TRIGGER_RISING, "bmp085", 462 data); 463 if (err < 0) 464 goto exit_free; 465 } 466 467 /* Initialize the BMP085 chip */ 468 err = bmp085_init_client(data); 469 if (err < 0) 470 goto exit_free; 471 472 err = bmp085_detect(dev); 473 if (err < 0) { 474 dev_err(dev, "%s: chip_id failed!\n", BMP085_NAME); 475 goto exit_free; 476 } 477 478 /* Register sysfs hooks */ 479 err = sysfs_create_group(&dev->kobj, &bmp085_attr_group); 480 if (err) 481 goto exit_free; 482 483 dev_info(dev, "Successfully initialized %s!\n", BMP085_NAME); 484 485 return 0; 486 487exit_free: 488 kfree(data); 489exit: 490 return err; 491} 492EXPORT_SYMBOL_GPL(bmp085_probe); 493 494int bmp085_remove(struct device *dev) 495{ 496 struct bmp085_data *data = dev_get_drvdata(dev); 497 498 sysfs_remove_group(&data->dev->kobj, &bmp085_attr_group); 499 kfree(data); 500 501 return 0; 502} 503EXPORT_SYMBOL_GPL(bmp085_remove); 504 505MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com>"); 506MODULE_DESCRIPTION("BMP085 driver"); 507MODULE_LICENSE("GPL");