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