1 /* Bosch BMP180 pressure sensor
2  *
3  * Copyright (c) 2024 , Chris Ruehl
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.mouser.hk/datasheet/2/783/BST-BMP180-DS000-1509579.pdf
9  */
10 
11 #include <math.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/sensor.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/pm/device.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/sys/util.h>
20 
21 #include "bmp180.h"
22 
23 #define DT_DRV_COMPAT bosch_bmp180
24 
25 LOG_MODULE_REGISTER(BMP180, CONFIG_SENSOR_LOG_LEVEL);
26 
27 /*
28  * byte swap added for signed (int16_t)
29  * and named _u16 and _s16 to make clear what its used for
30  * macro from include/zephyr/sys/byteorder.h
31  */
32 #define BSWAP_u16(x) sys_cpu_to_be16(x)
33 #define BSWAP_s16(x) ((int16_t) sys_cpu_to_be16(x))
34 
35 /* Calibration Registers structure */
36 struct bmp180_cal_data {
37 	int16_t ac1;
38 	int16_t ac2;
39 	int16_t ac3;
40 	uint16_t ac4;
41 	uint16_t ac5;
42 	uint16_t ac6;
43 	int16_t b1;
44 	int16_t b2;
45 	int16_t mb;
46 	int16_t mc;
47 	int16_t md;
48 } __packed;
49 
50 struct bmp180_config {
51 	const struct i2c_dt_spec i2c;
52 };
53 
54 struct bmp180_data {
55 	uint8_t osr_pressure;
56 	int32_t raw_press;
57 	int32_t raw_temp;
58 	int32_t comp_temp;
59 	struct bmp180_cal_data cal;
60 };
61 
bmp180_bus_check(const struct device * dev)62 static inline int bmp180_bus_check(const struct device *dev)
63 {
64 	const struct bmp180_config *cfg = dev->config;
65 
66 	return i2c_is_ready_dt(&cfg->i2c) ? 0 : -ENODEV;
67 }
68 
bmp180_reg_read(const struct device * dev,uint8_t start,uint8_t * buf,int size)69 static inline int bmp180_reg_read(const struct device *dev, uint8_t start,
70 				 uint8_t *buf, int size)
71 {
72 	const struct bmp180_config *cfg = dev->config;
73 
74 	return i2c_burst_read_dt(&cfg->i2c, start, buf, size);
75 }
76 
bmp180_reg_write(const struct device * dev,uint8_t reg,uint8_t val)77 static inline int bmp180_reg_write(const struct device *dev, uint8_t reg,
78 				   uint8_t val)
79 {
80 	const struct bmp180_config *cfg = dev->config;
81 
82 	return i2c_reg_write_byte_dt(&cfg->i2c, reg, val);
83 }
84 
85 #ifdef CONFIG_BMP180_OSR_RUNTIME
bmp180_attr_set_oversampling(const struct device * dev,enum sensor_channel chan,uint16_t val)86 static int bmp180_attr_set_oversampling(const struct device *dev,
87 					enum sensor_channel chan, uint16_t val)
88 {
89 	struct bmp180_data *data = dev->data;
90 
91 	/* Value must be a positive value 0-3 */
92 	if ((chan != SENSOR_CHAN_PRESS) || (val > 3)) {
93 		return -EINVAL;
94 	}
95 
96 	data->osr_pressure = val;
97 
98 	return 0;
99 }
100 #endif /* CONFIG_BMP180_OSR_RUNTIME */
101 
bmp180_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)102 static int bmp180_attr_set(const struct device *dev, enum sensor_channel chan,
103 			   enum sensor_attribute attr,
104 			   const struct sensor_value *val)
105 {
106 	int ret;
107 
108 #ifdef CONFIG_PM_DEVICE
109 	enum pm_device_state state;
110 
111 	(void)pm_device_state_get(dev, &state);
112 	if (state != PM_DEVICE_STATE_ACTIVE) {
113 		return -EBUSY;
114 	}
115 #endif /* CONFIG_PM_DEVICE */
116 
117 	switch (attr) {
118 #ifdef CONFIG_BMP180_OSR_RUNTIME
119 	case SENSOR_ATTR_OVERSAMPLING:
120 		ret = bmp180_attr_set_oversampling(dev, chan, val->val1);
121 		break;
122 #endif /* CONFIG_BMP180_OSR_RUNTIME */
123 
124 	default:
125 		ret = -EINVAL;
126 	}
127 
128 	return ret;
129 }
130 
bmp180_conv_ready(const struct device * dev,uint32_t time_wait_ms)131 static inline int bmp180_conv_ready(const struct device *dev, uint32_t time_wait_ms)
132 {
133 	int ret;
134 	uint8_t ctrlreg;
135 	uint8_t retry = 2;
136 
137 	k_sleep(K_MSEC(time_wait_ms));
138 
139 	/*
140 	 * for the first while read 'delay+1' ms which is the convension time
141 	 * descripted in the data-sheet in case the register not yet ready wait again
142 	 * and return error if retry exhaused
143 	 */
144 	while (true) {
145 		k_sleep(K_MSEC(1));
146 		ret = bmp180_reg_read(dev, BMP180_REG_MEAS_CTRL, &ctrlreg, 1);
147 		if (ret) {
148 			return ret;
149 		}
150 
151 		/* bit 5 is 1 until data registers are ready */
152 		if ((ctrlreg & BMP180_STATUS_CMD_RDY) == 0) {
153 			break;
154 		}
155 
156 		--retry;
157 		if (retry == 0) {
158 			return -ETIMEDOUT;
159 		}
160 	}
161 
162 	return 0;
163 }
164 
read_raw_temperature(const struct device * dev)165 static int read_raw_temperature(const struct device *dev)
166 {
167 	int ret;
168 	uint8_t reg16[2];
169 	struct bmp180_data *data = dev->data;
170 
171 	/* send temperature measurement command */
172 	ret = bmp180_reg_write(dev, BMP180_REG_MEAS_CTRL, BMP180_CMD_GET_TEMPERATURE);
173 	if (ret) {
174 		return ret;
175 	}
176 
177 	ret = bmp180_conv_ready(dev, BMP180_CMD_GET_TEMP_DELAY);
178 	if (ret) {
179 		return ret;
180 	}
181 
182 	/* read msb and lsb */
183 	ret = bmp180_reg_read(dev, BMP180_REG_MSB, (uint8_t *)&reg16, 2);
184 	if (ret) {
185 		return ret;
186 	}
187 
188 	data->raw_temp = (int32_t)(sys_get_be16(reg16));
189 	data->comp_temp = 0;
190 
191 	return 0;
192 }
193 
read_raw_pressure(const struct device * dev)194 static int read_raw_pressure(const struct device *dev)
195 {
196 	int ret;
197 	uint8_t ctrlreg;
198 	uint8_t reg24[3];
199 	uint32_t delay;
200 	int32_t pressure;
201 	struct bmp180_data *data = dev->data;
202 
203 	switch (data->osr_pressure) {
204 	case BMP180_ULTRALOWPOWER:
205 		ctrlreg = BMP180_CMD_GET_OSS0_PRESS;
206 		delay = BMP180_CMD_GET_OSS0_DELAY;
207 		break;
208 	case BMP180_STANDARD:
209 		ctrlreg = BMP180_CMD_GET_OSS1_PRESS;
210 		delay = BMP180_CMD_GET_OSS1_DELAY;
211 		break;
212 	case BMP180_HIGHRES:
213 		ctrlreg = BMP180_CMD_GET_OSS2_PRESS;
214 		delay = BMP180_CMD_GET_OSS2_DELAY;
215 		break;
216 	case BMP180_ULTRAHIGH:
217 		ctrlreg = BMP180_CMD_GET_OSS3_PRESS;
218 		delay = BMP180_CMD_GET_OSS3_DELAY;
219 		break;
220 	default:
221 		return -EINVAL;
222 	}
223 
224 	ret = bmp180_reg_write(dev, BMP180_REG_MEAS_CTRL, ctrlreg);
225 	if (ret) {
226 		return ret;
227 	}
228 
229 	ret = bmp180_conv_ready(dev, delay);
230 	if (ret) {
231 		return ret;
232 	}
233 
234 	/* read msb,lsb and xlsb */
235 	ret = bmp180_reg_read(dev, BMP180_REG_MSB, (uint8_t *)&reg24, 3);
236 	if (ret) {
237 		return ret;
238 	}
239 
240 	pressure = (int32_t)sys_get_be24(reg24);
241 	pressure >>= (8 - data->osr_pressure);
242 	data->raw_press = pressure;
243 
244 	return 0;
245 }
246 
bmp180_sample_fetch(const struct device * dev,enum sensor_channel chan)247 static int bmp180_sample_fetch(const struct device *dev,
248 			       enum sensor_channel chan)
249 {
250 	int ret = 0;
251 
252 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
253 
254 #ifdef CONFIG_PM_DEVICE
255 	enum pm_device_state state;
256 
257 	(void)pm_device_state_get(dev, &state);
258 	if (state != PM_DEVICE_STATE_ACTIVE) {
259 		return -EBUSY;
260 	}
261 #endif /* CONFIG_PM_DEVICE */
262 
263 	pm_device_busy_set(dev);
264 
265 	ret = read_raw_temperature(dev);
266 	if (ret < 0) {
267 		goto error;
268 	}
269 
270 	ret = read_raw_pressure(dev);
271 
272 error:
273 	pm_device_busy_clear(dev);
274 	return ret;
275 }
276 
bmp180_compensate_temp(struct bmp180_data * data)277 static void bmp180_compensate_temp(struct bmp180_data *data)
278 {
279 	int32_t partial_data1;
280 	int32_t partial_data2;
281 	int32_t divisor;
282 	struct bmp180_cal_data *cal = &data->cal;
283 
284 	partial_data1 = (data->raw_temp - cal->ac6) * cal->ac5 / 0x8000;
285 
286 	/* Check divisor before division */
287 	divisor = partial_data1 + cal->md;
288 	__ASSERT(divisor != 0, "divisor is zero: partial_data1=%d, md=%d", partial_data1, cal->md);
289 
290 	partial_data2 = cal->mc * 0x800 / divisor;
291 
292 	/* Store for pressure calculation */
293 	data->comp_temp = (partial_data1 + partial_data2);
294 }
295 
bmp180_temp_channel_get(const struct device * dev,struct sensor_value * val)296 static int bmp180_temp_channel_get(const struct device *dev,
297 				   struct sensor_value *val)
298 {
299 	struct bmp180_data *data = dev->data;
300 
301 	if (data->comp_temp == 0) {
302 		bmp180_compensate_temp(data);
303 	}
304 
305 	float ftmp = ((data->comp_temp + 8) >> 4) / 10.0;
306 	int64_t tmp = (int64_t)floorf(ftmp * 1000000);
307 
308 	val->val1 = tmp / 1000000;
309 	val->val2 = tmp % 1000000;
310 
311 	return 0;
312 }
313 
bmp180_compensate_press(struct bmp180_data * data)314 static uint32_t bmp180_compensate_press(struct bmp180_data *data)
315 {
316 	uint64_t partial_B7;
317 	uint64_t partial_B4;
318 	int32_t partial_X1;
319 	int32_t partial_X2;
320 	int32_t partial_X3;
321 	int32_t partial_B3;
322 	int32_t partial_B6;
323 	uint32_t comp_press;
324 	int32_t raw_pressure = data->raw_press;
325 	struct bmp180_cal_data *cal = &data->cal;
326 
327 	partial_B6 = data->comp_temp - 4000;
328 	partial_X1 = cal->b2 * partial_B6 * (float)(1.0f * partial_B6 / 0x800000);
329 	partial_X2 = (cal->ac2 * partial_B6) / 0x800;
330 	partial_X3 = partial_X1 + partial_X2;
331 	partial_B3 = (((cal->ac1 * 4 + partial_X3) << data->osr_pressure) + 2) / 4;
332 
333 	partial_X1 = (cal->ac3 * partial_B6) / 0x2000;
334 	partial_X2 = cal->b1 * partial_B6 * (float)(1.0f * partial_B6 / 0x8000000);
335 	partial_X3 = (partial_X1 + partial_X2 + 2) / 4;
336 	partial_B4 = (uint64_t)(cal->ac4 * ((int64_t)(partial_X3) + 32768)) >> 15;
337 	partial_B7 = (uint64_t)(raw_pressure - partial_B3) * (50000 >> data->osr_pressure);
338 
339 	comp_press = (uint32_t)(partial_B7 / partial_B4 * 2);
340 
341 	partial_X1 = comp_press * (float)(1.0f * comp_press / 0x10000);
342 	partial_X1 = (partial_X1 * 3038) / 0x10000;
343 	partial_X2 = ((int32_t)(-7357 * comp_press)) / 0x10000;
344 	comp_press += (partial_X1 + partial_X2 + 3791) / 16;
345 
346 	/* returned value is Pa */
347 	return comp_press;
348 }
349 
bmp180_press_channel_get(const struct device * dev,struct sensor_value * val)350 static int bmp180_press_channel_get(const struct device *dev,
351 				    struct sensor_value *val)
352 {
353 	struct bmp180_data *data = dev->data;
354 
355 	if (data->comp_temp == 0) {
356 		bmp180_compensate_temp(data);
357 	}
358 
359 	uint32_t tmp = bmp180_compensate_press(data);
360 
361 	/* tmp is Pa. Convert to kPa as specified in sensor
362 	 * interface.
363 	 */
364 	val->val1 = tmp / 1000;
365 	val->val2 = (tmp % 1000) * 1000;
366 
367 	return 0;
368 }
369 
bmp180_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)370 static int bmp180_channel_get(const struct device *dev,
371 			      enum sensor_channel chan,
372 			      struct sensor_value *val)
373 {
374 	switch (chan) {
375 	case SENSOR_CHAN_PRESS:
376 		bmp180_press_channel_get(dev, val);
377 		break;
378 
379 	case SENSOR_CHAN_DIE_TEMP:
380 		bmp180_temp_channel_get(dev, val);
381 		break;
382 
383 	default:
384 		LOG_DBG("Channel not supported.");
385 		return -ENOTSUP;
386 	}
387 
388 	return 0;
389 }
390 
391 
bmp180_get_calibration_data(const struct device * dev)392 static int bmp180_get_calibration_data(const struct device *dev)
393 {
394 	struct bmp180_data *data = dev->data;
395 	struct bmp180_cal_data *cal = &data->cal;
396 
397 	if (bmp180_reg_read(dev, BMP180_REG_CALIB0, (uint8_t *)cal,
398 			    sizeof(struct bmp180_cal_data)) < 0) {
399 		return -EIO;
400 	}
401 
402 	cal->ac1 = BSWAP_s16(cal->ac1);
403 	cal->ac2 = BSWAP_s16(cal->ac2);
404 	cal->ac3 = BSWAP_s16(cal->ac3);
405 	cal->ac4 = BSWAP_u16(cal->ac4);
406 	cal->ac5 = BSWAP_u16(cal->ac5);
407 	cal->ac6 = BSWAP_u16(cal->ac6);
408 	cal->b1 = BSWAP_s16(cal->b1);
409 	cal->b2 = BSWAP_s16(cal->b2);
410 	cal->mb = BSWAP_s16(cal->mb);
411 	cal->mc = BSWAP_s16(cal->mc);
412 	cal->md = BSWAP_s16(cal->md);
413 
414 	return 0;
415 }
416 
417 #ifdef CONFIG_PM_DEVICE
bmp180_pm_action(const struct device * dev,enum pm_device_action action)418 static int bmp180_pm_action(const struct device *dev,
419 			    enum pm_device_action action)
420 {
421 	/* no power saving feature in bmp180 */
422 	return 0;
423 }
424 #endif /* CONFIG_PM_DEVICE */
425 
426 static DEVICE_API(sensor, bmp180_api) = {
427 	.attr_set = bmp180_attr_set,
428 	.sample_fetch = bmp180_sample_fetch,
429 	.channel_get = bmp180_channel_get,
430 };
431 
bmp180_init(const struct device * dev)432 static int bmp180_init(const struct device *dev)
433 {
434 	uint8_t val = 0U;
435 
436 	if (bmp180_bus_check(dev) < 0) {
437 		LOG_DBG("bus check failed");
438 		return -ENODEV;
439 	}
440 
441 	/* reboot the chip */
442 	if (bmp180_reg_write(dev, BMP180_REG_CMD, BMP180_CMD_SOFT_RESET) < 0) {
443 		LOG_ERR("Cannot reboot chip.");
444 		return -EIO;
445 	}
446 
447 	k_sleep(K_MSEC(2));
448 
449 	if (bmp180_reg_read(dev, BMP180_REG_CHIPID, &val, 1) < 0) {
450 		LOG_ERR("Failed to read chip id.");
451 		return -EIO;
452 	}
453 
454 	if (val != BMP180_CHIP_ID) {
455 		LOG_ERR("Unsupported chip detected (0x%x)!", val);
456 		return -ENODEV;
457 	}
458 
459 	/* Read calibration data */
460 	if (bmp180_get_calibration_data(dev) < 0) {
461 		LOG_ERR("Failed to read calibration data.");
462 		return -EIO;
463 	}
464 
465 	return 0;
466 }
467 
468 #define BMP180_INST(inst) \
469 	static struct bmp180_data bmp180_data_##inst = {\
470 		.osr_pressure = DT_INST_ENUM_IDX(inst, osr_press),\
471 	};\
472 	static const struct bmp180_config bmp180_config_##inst = {\
473 		.i2c = I2C_DT_SPEC_INST_GET(inst),\
474 	};\
475 	PM_DEVICE_DT_INST_DEFINE(inst, bmp180_pm_action);\
476 	SENSOR_DEVICE_DT_INST_DEFINE(inst, bmp180_init, PM_DEVICE_DT_INST_GET(inst),\
477 				    &bmp180_data_##inst, &bmp180_config_##inst,\
478 				    POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,\
479 				    &bmp180_api);
480 
481 DT_INST_FOREACH_STATUS_OKAY(BMP180_INST)
482