1 /* Bosch BMP388 pressure sensor
2  *
3  * Copyright (c) 2020 Facebook, Inc. and its affiliates
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf
9  */
10 
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/pm/device.h>
14 
15 #include "bmp388.h"
16 
17 LOG_MODULE_REGISTER(BMP388, CONFIG_SENSOR_LOG_LEVEL);
18 
19 #if defined(CONFIG_BMP388_ODR_RUNTIME)
20 static const struct {
21 	uint16_t freq_int;
22 	uint16_t freq_milli;
23 } bmp388_odr_map[] = {
24 	{ 0, 3 },       /* 25/8192 - 327.68s */
25 	{ 0, 6 },       /* 25/4096 - 163.84s */
26 	{ 0, 12 },      /* 25/2048 - 81.92s */
27 	{ 0, 24 },      /* 25/1024 - 40.96s */
28 	{ 0, 49 },      /* 25/512 - 20.48s */
29 	{ 0, 98 },      /* 25/256 - 10.24s */
30 	{ 0, 195 },     /* 25/128 - 5.12s */
31 	{ 0, 391 },     /* 25/64 - 2.56s */
32 	{ 0, 781 },     /* 25/32 - 1.28s */
33 	{ 1, 563 },     /* 25/16 - 640ms */
34 	{ 3, 125 },     /* 25/8 - 320ms */
35 	{ 6, 250 },     /* 25/4 - 160ms */
36 	{ 12, 500 },    /* 25/2 - 80ms */
37 	{ 25, 0 },      /* 25 - 40ms */
38 	{ 50, 0 },      /* 50 - 20ms */
39 	{ 100, 0 },     /* 100 - 10ms */
40 	{ 200, 0 },     /* 200 - 5ms */
41 };
42 #endif
43 
bmp388_bus_check(const struct device * dev)44 static inline int bmp388_bus_check(const struct device *dev)
45 {
46 	const struct bmp388_config *cfg = dev->config;
47 
48 	return cfg->bus_io->check(&cfg->bus);
49 }
50 
bmp388_reg_read(const struct device * dev,uint8_t start,uint8_t * buf,int size)51 static inline int bmp388_reg_read(const struct device *dev,
52 				  uint8_t start, uint8_t *buf, int size)
53 {
54 	const struct bmp388_config *cfg = dev->config;
55 
56 	return cfg->bus_io->read(&cfg->bus, start, buf, size);
57 }
58 
bmp388_reg_write(const struct device * dev,uint8_t reg,uint8_t val)59 static inline int bmp388_reg_write(const struct device *dev, uint8_t reg,
60 				   uint8_t val)
61 {
62 	const struct bmp388_config *cfg = dev->config;
63 
64 	return cfg->bus_io->write(&cfg->bus, reg, val);
65 }
66 
bmp388_reg_field_update(const struct device * dev,uint8_t reg,uint8_t mask,uint8_t val)67 int bmp388_reg_field_update(const struct device *dev,
68 			    uint8_t reg,
69 			    uint8_t mask,
70 			    uint8_t val)
71 {
72 	int rc = 0;
73 	uint8_t old_value, new_value;
74 	const struct bmp388_config *cfg = dev->config;
75 
76 	rc = cfg->bus_io->read(&cfg->bus, reg, &old_value, 1);
77 	if (rc != 0) {
78 		return rc;
79 	}
80 
81 	new_value = (old_value & ~mask) | (val & mask);
82 	if (new_value == old_value) {
83 		return 0;
84 	}
85 
86 	return cfg->bus_io->write(&cfg->bus, reg, new_value);
87 }
88 
89 #ifdef CONFIG_BMP388_ODR_RUNTIME
bmp388_freq_to_odr_val(uint16_t freq_int,uint16_t freq_milli)90 static int bmp388_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli)
91 {
92 	size_t i;
93 
94 	/* An ODR of 0 Hz is not allowed */
95 	if (freq_int == 0U && freq_milli == 0U) {
96 		return -EINVAL;
97 	}
98 
99 	for (i = 0; i < ARRAY_SIZE(bmp388_odr_map); i++) {
100 		if (freq_int < bmp388_odr_map[i].freq_int ||
101 		    (freq_int == bmp388_odr_map[i].freq_int &&
102 		     freq_milli <= bmp388_odr_map[i].freq_milli)) {
103 			return (ARRAY_SIZE(bmp388_odr_map) - 1) - i;
104 		}
105 	}
106 
107 	return -EINVAL;
108 }
109 
bmp388_attr_set_odr(const struct device * dev,uint16_t freq_int,uint16_t freq_milli)110 static int bmp388_attr_set_odr(const struct device *dev,
111 			       uint16_t freq_int,
112 			       uint16_t freq_milli)
113 {
114 	int err;
115 	struct bmp388_data *data = dev->data;
116 	int odr = bmp388_freq_to_odr_val(freq_int, freq_milli);
117 
118 	if (odr < 0) {
119 		return odr;
120 	}
121 
122 	err = bmp388_reg_field_update(dev,
123 				      BMP388_REG_ODR,
124 				      BMP388_ODR_MASK,
125 				      (uint8_t)odr);
126 	if (err == 0) {
127 		data->odr = odr;
128 	}
129 
130 	return err;
131 }
132 #endif
133 
134 #ifdef CONFIG_BMP388_OSR_RUNTIME
bmp388_attr_set_oversampling(const struct device * dev,enum sensor_channel chan,uint16_t val)135 static int bmp388_attr_set_oversampling(const struct device *dev,
136 					enum sensor_channel chan,
137 					uint16_t val)
138 {
139 	uint8_t reg_val = 0;
140 	uint32_t pos, mask;
141 	int err;
142 
143 	struct bmp388_data *data = dev->data;
144 
145 	/* Value must be a positive power of 2 <= 32. */
146 	if ((val <= 0) || (val > 32) || ((val & (val - 1)) != 0)) {
147 		return -EINVAL;
148 	}
149 
150 	if (chan == SENSOR_CHAN_PRESS) {
151 		pos = BMP388_OSR_PRESSURE_POS;
152 		mask = BMP388_OSR_PRESSURE_MASK;
153 	} else if ((chan == SENSOR_CHAN_AMBIENT_TEMP) ||
154 		   (chan == SENSOR_CHAN_DIE_TEMP)) {
155 		pos = BMP388_OSR_TEMP_POS;
156 		mask = BMP388_OSR_TEMP_MASK;
157 	} else {
158 		return -EINVAL;
159 	}
160 
161 	/* Determine exponent: this corresponds to register setting. */
162 	while ((val % 2) == 0) {
163 		val >>= 1;
164 		++reg_val;
165 	}
166 
167 	err = bmp388_reg_field_update(dev,
168 				      BMP388_REG_OSR,
169 				      mask,
170 				      reg_val << pos);
171 	if (err < 0) {
172 		return err;
173 	}
174 
175 	/* Store for future use in converting RAW values. */
176 	if (chan == SENSOR_CHAN_PRESS) {
177 		data->osr_pressure = reg_val;
178 	} else {
179 		data->osr_temp = reg_val;
180 	}
181 
182 	return err;
183 }
184 #endif
185 
bmp388_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)186 static int bmp388_attr_set(const struct device *dev,
187 			   enum sensor_channel chan,
188 			   enum sensor_attribute attr,
189 			   const struct sensor_value *val)
190 {
191 	int ret;
192 
193 #ifdef CONFIG_PM_DEVICE
194 	enum pm_device_state state;
195 
196 	(void)pm_device_state_get(dev, &state);
197 	if (state != PM_DEVICE_STATE_ACTIVE) {
198 		return -EBUSY;
199 	}
200 #endif
201 
202 	switch (attr) {
203 #ifdef CONFIG_BMP388_ODR_RUNTIME
204 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
205 		ret = bmp388_attr_set_odr(dev, val->val1, val->val2 / 1000);
206 		break;
207 #endif
208 
209 #ifdef CONFIG_BMP388_OSR_RUNTIME
210 	case SENSOR_ATTR_OVERSAMPLING:
211 		ret = bmp388_attr_set_oversampling(dev, chan, val->val1);
212 		break;
213 #endif
214 
215 	default:
216 		ret = -EINVAL;
217 	}
218 
219 	return ret;
220 }
221 
bmp388_sample_fetch(const struct device * dev,enum sensor_channel chan)222 static int bmp388_sample_fetch(const struct device *dev,
223 			       enum sensor_channel chan)
224 {
225 	struct bmp388_data *bmp388 = dev->data;
226 	uint8_t raw[BMP388_SAMPLE_BUFFER_SIZE];
227 	int ret = 0;
228 
229 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
230 
231 #ifdef CONFIG_PM_DEVICE
232 	enum pm_device_state state;
233 
234 	(void)pm_device_state_get(dev, &state);
235 	if (state != PM_DEVICE_STATE_ACTIVE) {
236 		return -EBUSY;
237 	}
238 #endif
239 
240 	pm_device_busy_set(dev);
241 
242 	/* Wait for status to indicate that data is ready. */
243 	raw[0] = 0U;
244 	while ((raw[0] & BMP388_STATUS_DRDY_PRESS) == 0U) {
245 		ret = bmp388_reg_read(dev, BMP388_REG_STATUS, raw, 1);
246 		if (ret < 0) {
247 			goto error;
248 		}
249 	}
250 
251 	ret = bmp388_reg_read(dev,
252 			  BMP388_REG_DATA0,
253 			  raw,
254 			  BMP388_SAMPLE_BUFFER_SIZE);
255 	if (ret < 0) {
256 		goto error;
257 	}
258 
259 	/* convert samples to 32bit values */
260 	bmp388->sample.press = (uint32_t)raw[0] |
261 			       ((uint32_t)raw[1] << 8) |
262 			       ((uint32_t)raw[2] << 16);
263 	bmp388->sample.raw_temp = (uint32_t)raw[3] |
264 				  ((uint32_t)raw[4] << 8) |
265 				  ((uint32_t)raw[5] << 16);
266 	bmp388->sample.comp_temp = 0;
267 
268 error:
269 	pm_device_busy_clear(dev);
270 	return ret;
271 }
272 
bmp388_compensate_temp(struct bmp388_data * data)273 static void bmp388_compensate_temp(struct bmp388_data *data)
274 {
275 	/* Adapted from:
276 	 * https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3.c
277 	 */
278 
279 	int64_t partial_data1;
280 	int64_t partial_data2;
281 	int64_t partial_data3;
282 	int64_t partial_data4;
283 	int64_t partial_data5;
284 
285 	struct bmp388_cal_data *cal = &data->cal;
286 
287 	partial_data1 = ((int64_t)data->sample.raw_temp - (256 * cal->t1));
288 	partial_data2 = cal->t2 * partial_data1;
289 	partial_data3 = (partial_data1 * partial_data1);
290 	partial_data4 = (int64_t)partial_data3 * cal->t3;
291 	partial_data5 = ((int64_t)(partial_data2 * 262144) + partial_data4);
292 
293 	/* Store for pressure calculation */
294 	data->sample.comp_temp = partial_data5 / 4294967296;
295 }
296 
bmp388_temp_channel_get(const struct device * dev,struct sensor_value * val)297 static int bmp388_temp_channel_get(const struct device *dev,
298 				   struct sensor_value *val)
299 {
300 	struct bmp388_data *data = dev->data;
301 
302 	if (data->sample.comp_temp == 0) {
303 		bmp388_compensate_temp(data);
304 	}
305 
306 	int64_t tmp = (data->sample.comp_temp * 250000) / 16384;
307 
308 	val->val1 = tmp / 1000000;
309 	val->val2 = tmp % 1000000;
310 
311 	return 0;
312 }
313 
bmp388_compensate_press(struct bmp388_data * data)314 static uint64_t bmp388_compensate_press(struct bmp388_data *data)
315 {
316 	/* Adapted from:
317 	 * https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3.c
318 	 */
319 
320 	int64_t partial_data1;
321 	int64_t partial_data2;
322 	int64_t partial_data3;
323 	int64_t partial_data4;
324 	int64_t partial_data5;
325 	int64_t partial_data6;
326 	int64_t offset;
327 	int64_t sensitivity;
328 	uint64_t comp_press;
329 
330 	struct bmp388_cal_data *cal = &data->cal;
331 
332 	int64_t t_lin = data->sample.comp_temp;
333 	uint32_t raw_pressure = data->sample.press;
334 
335 	partial_data1 = t_lin * t_lin;
336 	partial_data2 = partial_data1 / 64;
337 	partial_data3 = (partial_data2 * t_lin) / 256;
338 	partial_data4 = (cal->p8 * partial_data3) / 32;
339 	partial_data5 = (cal->p7 * partial_data1) * 16;
340 	partial_data6 = (cal->p6 * t_lin) * 4194304;
341 	offset = (cal->p5 * 140737488355328) + partial_data4 + partial_data5 +
342 		 partial_data6;
343 	partial_data2 = (cal->p4 * partial_data3) / 32;
344 	partial_data4 = (cal->p3 * partial_data1) * 4;
345 	partial_data5 = (cal->p2 - 16384) * t_lin * 2097152;
346 	sensitivity = ((cal->p1 - 16384) * 70368744177664) + partial_data2 +
347 		      partial_data4 + partial_data5;
348 	partial_data1 = (sensitivity / 16777216) * raw_pressure;
349 	partial_data2 = cal->p10 * t_lin;
350 	partial_data3 = partial_data2 + (65536 * cal->p9);
351 	partial_data4 = (partial_data3 * raw_pressure) / 8192;
352 	/* Dividing by 10 followed by multiplying by 10 to avoid overflow caused
353 	 * (raw_pressure * partial_data4)
354 	 */
355 	partial_data5 = (raw_pressure * (partial_data4 / 10)) / 512;
356 	partial_data5 = partial_data5 * 10;
357 	partial_data6 = ((int64_t)raw_pressure * (int64_t)raw_pressure);
358 	partial_data2 = (cal->p11 * partial_data6) / 65536;
359 	partial_data3 = (partial_data2 * raw_pressure) / 128;
360 	partial_data4 = (offset / 4) + partial_data1 + partial_data5 +
361 			partial_data3;
362 
363 	comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776);
364 
365 	/* returned value is in hundredths of Pa. */
366 	return comp_press;
367 }
368 
bmp388_press_channel_get(const struct device * dev,struct sensor_value * val)369 static int bmp388_press_channel_get(const struct device *dev,
370 				    struct sensor_value *val)
371 {
372 	struct bmp388_data *data = dev->data;
373 
374 	if (data->sample.comp_temp == 0) {
375 		bmp388_compensate_temp(data);
376 	}
377 
378 	uint64_t tmp = bmp388_compensate_press(data);
379 
380 	/* tmp is in hundredths of Pa. Convert to kPa as specified in sensor
381 	 * interface.
382 	 */
383 	val->val1 = tmp / 100000;
384 	val->val2 = (tmp % 100000) * 10;
385 
386 	return 0;
387 }
388 
bmp388_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)389 static int bmp388_channel_get(const struct device *dev,
390 			      enum sensor_channel chan,
391 			      struct sensor_value *val)
392 {
393 	switch (chan) {
394 	case SENSOR_CHAN_PRESS:
395 		bmp388_press_channel_get(dev, val);
396 		break;
397 
398 	case SENSOR_CHAN_DIE_TEMP:
399 	case SENSOR_CHAN_AMBIENT_TEMP:
400 		bmp388_temp_channel_get(dev, val);
401 		break;
402 
403 	default:
404 		LOG_DBG("Channel not supported.");
405 		return -ENOTSUP;
406 	}
407 
408 	return 0;
409 }
410 
bmp388_get_calibration_data(const struct device * dev)411 static int bmp388_get_calibration_data(const struct device *dev)
412 {
413 	struct bmp388_data *data = dev->data;
414 	struct bmp388_cal_data *cal = &data->cal;
415 
416 	if (bmp388_reg_read(dev, BMP388_REG_CALIB0, (uint8_t *)cal, sizeof(*cal)) < 0) {
417 		return -EIO;
418 	}
419 
420 	cal->t1 = sys_le16_to_cpu(cal->t1);
421 	cal->t2 = sys_le16_to_cpu(cal->t2);
422 	cal->p1 = sys_le16_to_cpu(cal->p1);
423 	cal->p2 = sys_le16_to_cpu(cal->p2);
424 	cal->p5 = sys_le16_to_cpu(cal->p5);
425 	cal->p6 = sys_le16_to_cpu(cal->p6);
426 	cal->p9 = sys_le16_to_cpu(cal->p9);
427 
428 	return 0;
429 }
430 
431 #ifdef CONFIG_PM_DEVICE
bmp388_pm_action(const struct device * dev,enum pm_device_action action)432 static int bmp388_pm_action(const struct device *dev,
433 			    enum pm_device_action action)
434 {
435 	uint8_t reg_val;
436 
437 	switch (action) {
438 	case PM_DEVICE_ACTION_RESUME:
439 		reg_val = BMP388_PWR_CTRL_MODE_NORMAL;
440 		break;
441 	case PM_DEVICE_ACTION_SUSPEND:
442 		reg_val = BMP388_PWR_CTRL_MODE_SLEEP;
443 		break;
444 	default:
445 		return -ENOTSUP;
446 	}
447 
448 	if (bmp388_reg_field_update(dev,
449 				    BMP388_REG_PWR_CTRL,
450 				    BMP388_PWR_CTRL_MODE_MASK,
451 				    reg_val) < 0) {
452 		LOG_DBG("Failed to set power mode.");
453 		return -EIO;
454 	}
455 
456 	return 0;
457 }
458 #endif /* CONFIG_PM_DEVICE */
459 
460 static const struct sensor_driver_api bmp388_api = {
461 	.attr_set = bmp388_attr_set,
462 #ifdef CONFIG_BMP388_TRIGGER
463 	.trigger_set = bmp388_trigger_set,
464 #endif
465 	.sample_fetch = bmp388_sample_fetch,
466 	.channel_get = bmp388_channel_get,
467 };
468 
bmp388_init(const struct device * dev)469 static int bmp388_init(const struct device *dev)
470 {
471 	struct bmp388_data *bmp388 = dev->data;
472 	const struct bmp388_config *cfg = dev->config;
473 	uint8_t val = 0U;
474 
475 	if (bmp388_bus_check(dev) < 0) {
476 		LOG_DBG("bus check failed");
477 		return -ENODEV;
478 	}
479 
480 	/* reboot the chip */
481 	if (bmp388_reg_write(dev, BMP388_REG_CMD, BMP388_CMD_SOFT_RESET) < 0) {
482 		LOG_ERR("Cannot reboot chip.");
483 		return -EIO;
484 	}
485 
486 	k_busy_wait(2000);
487 
488 	if (bmp388_reg_read(dev, BMP388_REG_CHIPID, &val, 1) < 0) {
489 		LOG_ERR("Failed to read chip id.");
490 		return -EIO;
491 	}
492 
493 	if (val != BMP388_CHIP_ID) {
494 		LOG_ERR("Unsupported chip detected (0x%x)!", val);
495 		return -ENODEV;
496 	}
497 
498 	/* Read calibration data */
499 	if (bmp388_get_calibration_data(dev) < 0) {
500 		LOG_ERR("Failed to read calibration data.");
501 		return -EIO;
502 	}
503 
504 	/* Set ODR */
505 	if (bmp388_reg_field_update(dev,
506 				    BMP388_REG_ODR,
507 				    BMP388_ODR_MASK,
508 				    bmp388->odr) < 0) {
509 		LOG_ERR("Failed to set ODR.");
510 		return -EIO;
511 	}
512 
513 	/* Set OSR */
514 	val = (bmp388->osr_pressure << BMP388_OSR_PRESSURE_POS);
515 	val |= (bmp388->osr_temp << BMP388_OSR_TEMP_POS);
516 	if (bmp388_reg_write(dev, BMP388_REG_OSR, val) < 0) {
517 		LOG_ERR("Failed to set OSR.");
518 		return -EIO;
519 	}
520 
521 	/* Set IIR filter coefficient */
522 	val = (cfg->iir_filter << BMP388_IIR_FILTER_POS) & BMP388_IIR_FILTER_MASK;
523 	if (bmp388_reg_write(dev, BMP388_REG_CONFIG, val) < 0) {
524 		LOG_ERR("Failed to set IIR coefficient.");
525 		return -EIO;
526 	}
527 
528 	/* Enable sensors and normal mode*/
529 	if (bmp388_reg_write(dev,
530 			     BMP388_REG_PWR_CTRL,
531 			     BMP388_PWR_CTRL_ON) < 0) {
532 		LOG_ERR("Failed to enable sensors.");
533 		return -EIO;
534 	}
535 
536 	/* Read error register */
537 	if (bmp388_reg_read(dev, BMP388_REG_ERR_REG, &val, 1) < 0) {
538 		LOG_ERR("Failed get sensors error register.");
539 		return -EIO;
540 	}
541 
542 	/* OSR and ODR config not proper */
543 	if (val & BMP388_STATUS_CONF_ERR) {
544 		LOG_ERR("OSR and ODR configuration is not proper");
545 		return -EINVAL;
546 	}
547 
548 #ifdef CONFIG_BMP388_TRIGGER
549 	if (cfg->gpio_int.port != NULL && bmp388_trigger_mode_init(dev) < 0) {
550 		LOG_ERR("Cannot set up trigger mode.");
551 		return -EINVAL;
552 	}
553 #endif
554 
555 	return 0;
556 }
557 
558 /* Initializes a struct bmp388_config for an instance on a SPI bus. */
559 #define BMP388_CONFIG_SPI(inst)				\
560 	.bus.spi = SPI_DT_SPEC_INST_GET(inst, BMP388_SPI_OPERATION, 0),	\
561 	.bus_io = &bmp388_bus_io_spi,
562 
563 /* Initializes a struct bmp388_config for an instance on an I2C bus. */
564 #define BMP388_CONFIG_I2C(inst)			       \
565 	.bus.i2c = I2C_DT_SPEC_INST_GET(inst),	       \
566 	.bus_io = &bmp388_bus_io_i2c,
567 
568 #define BMP388_BUS_CFG(inst)			\
569 	COND_CODE_1(DT_INST_ON_BUS(inst, i2c),	\
570 		    (BMP388_CONFIG_I2C(inst)),	\
571 		    (BMP388_CONFIG_SPI(inst)))
572 
573 #if defined(CONFIG_BMP388_TRIGGER)
574 #define BMP388_INT_CFG(inst) \
575 	.gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}),
576 #else
577 #define BMP388_INT_CFG(inst)
578 #endif
579 
580 #define BMP388_INST(inst)						   \
581 	static struct bmp388_data bmp388_data_##inst = {		   \
582 		.odr = DT_INST_ENUM_IDX(inst, odr),			   \
583 		.osr_pressure = DT_INST_ENUM_IDX(inst, osr_press),	   \
584 		.osr_temp = DT_INST_ENUM_IDX(inst, osr_temp),		   \
585 	};								   \
586 	static const struct bmp388_config bmp388_config_##inst = {	   \
587 		BMP388_BUS_CFG(inst)					   \
588 		BMP388_INT_CFG(inst)					   \
589 		.iir_filter = DT_INST_ENUM_IDX(inst, iir_filter),	   \
590 	};								   \
591 	PM_DEVICE_DT_INST_DEFINE(inst, bmp388_pm_action);		   \
592 	SENSOR_DEVICE_DT_INST_DEFINE(					   \
593 		inst,							   \
594 		bmp388_init,						   \
595 		PM_DEVICE_DT_INST_GET(inst),				   \
596 		&bmp388_data_##inst,					   \
597 		&bmp388_config_##inst,					   \
598 		POST_KERNEL,						   \
599 		CONFIG_SENSOR_INIT_PRIORITY,				   \
600 		&bmp388_api);
601 
602 DT_INST_FOREACH_STATUS_OKAY(BMP388_INST)
603