• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/misc/
1/*  Copyright (c) 2010  Christoph Mair <christoph.mair@gmail.com>
2
3    This driver supports the bmp085 digital barometric pressure
4    and temperature sensor from Bosch Sensortec. The datasheet
5    is avaliable 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
71static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
72							I2C_CLIENT_END };
73
74struct 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 */
83struct 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
95static 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
125static 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
154exit:
155	mutex_unlock(&data->lock);
156	return status;
157}
158
159static 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
191exit:
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 */
201static 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
218exit:
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 */
228static 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
276exit:
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 */
287static 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 */
298static unsigned char bmp085_get_oversampling(struct bmp085_data *data)
299{
300	return data->oversampling_setting;
301}
302
303/* sysfs callbacks */
304static 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
319static 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}
326static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
327					show_oversampling, set_oversampling);
328
329
330static 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}
344static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL);
345
346
347static 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}
361static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL);
362
363
364static 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
371static const struct attribute_group bmp085_attr_group = {
372	.attrs = bmp085_attributes,
373};
374
375static 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
386static 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);
401exit:
402	return status;
403}
404
405static int 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, "Succesfully initialized bmp085!\n");
433	goto exit;
434
435exit_free:
436	kfree(data);
437exit:
438	return err;
439}
440
441static int 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
448static const struct i2c_device_id bmp085_id[] = {
449	{ "bmp085", 0 },
450	{ }
451};
452
453static struct i2c_driver bmp085_driver = {
454	.driver = {
455		.owner = THIS_MODULE,
456		.name	= "bmp085"
457	},
458	.id_table	= bmp085_id,
459	.probe		= bmp085_probe,
460	.remove		= bmp085_remove,
461
462	.detect		= bmp085_detect,
463	.address_list	= normal_i2c
464};
465
466static int __init bmp085_init(void)
467{
468	return i2c_add_driver(&bmp085_driver);
469}
470
471static void __exit bmp085_exit(void)
472{
473	i2c_del_driver(&bmp085_driver);
474}
475
476
477MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com");
478MODULE_DESCRIPTION("BMP085 driver");
479MODULE_LICENSE("GPL");
480
481module_init(bmp085_init);
482module_exit(bmp085_exit);
483