xref: /linux/drivers/iio/chemical/bme680_core.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
11b3bd859SHimanshu Jha // SPDX-License-Identifier: GPL-2.0
21b3bd859SHimanshu Jha /*
31b3bd859SHimanshu Jha  * Bosch BME680 - Temperature, Pressure, Humidity & Gas Sensor
41b3bd859SHimanshu Jha  *
51b3bd859SHimanshu Jha  * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
61b3bd859SHimanshu Jha  * Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
71b3bd859SHimanshu Jha  *
81b3bd859SHimanshu Jha  * Datasheet:
91b3bd859SHimanshu Jha  * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME680-DS001-00.pdf
101b3bd859SHimanshu Jha  */
111b3bd859SHimanshu Jha #include <linux/acpi.h>
121b3bd859SHimanshu Jha #include <linux/bitfield.h>
131b3bd859SHimanshu Jha #include <linux/device.h>
141b3bd859SHimanshu Jha #include <linux/module.h>
151b3bd859SHimanshu Jha #include <linux/log2.h>
161b3bd859SHimanshu Jha #include <linux/regmap.h>
171b3bd859SHimanshu Jha #include <linux/iio/iio.h>
181b3bd859SHimanshu Jha #include <linux/iio/sysfs.h>
191b3bd859SHimanshu Jha 
201b3bd859SHimanshu Jha #include "bme680.h"
211b3bd859SHimanshu Jha 
221b3bd859SHimanshu Jha struct bme680_calib {
231b3bd859SHimanshu Jha 	u16 par_t1;
241b3bd859SHimanshu Jha 	s16 par_t2;
251b3bd859SHimanshu Jha 	s8  par_t3;
261b3bd859SHimanshu Jha 	u16 par_p1;
271b3bd859SHimanshu Jha 	s16 par_p2;
281b3bd859SHimanshu Jha 	s8  par_p3;
291b3bd859SHimanshu Jha 	s16 par_p4;
301b3bd859SHimanshu Jha 	s16 par_p5;
311b3bd859SHimanshu Jha 	s8  par_p6;
321b3bd859SHimanshu Jha 	s8  par_p7;
331b3bd859SHimanshu Jha 	s16 par_p8;
341b3bd859SHimanshu Jha 	s16 par_p9;
351b3bd859SHimanshu Jha 	u8  par_p10;
361b3bd859SHimanshu Jha 	u16 par_h1;
371b3bd859SHimanshu Jha 	u16 par_h2;
381b3bd859SHimanshu Jha 	s8  par_h3;
391b3bd859SHimanshu Jha 	s8  par_h4;
401b3bd859SHimanshu Jha 	s8  par_h5;
411b3bd859SHimanshu Jha 	s8  par_h6;
421b3bd859SHimanshu Jha 	s8  par_h7;
431b3bd859SHimanshu Jha 	s8  par_gh1;
441b3bd859SHimanshu Jha 	s16 par_gh2;
451b3bd859SHimanshu Jha 	s8  par_gh3;
461b3bd859SHimanshu Jha 	u8  res_heat_range;
471b3bd859SHimanshu Jha 	s8  res_heat_val;
481b3bd859SHimanshu Jha 	s8  range_sw_err;
491b3bd859SHimanshu Jha };
501b3bd859SHimanshu Jha 
511b3bd859SHimanshu Jha struct bme680_data {
521b3bd859SHimanshu Jha 	struct regmap *regmap;
531b3bd859SHimanshu Jha 	struct bme680_calib bme680;
541b3bd859SHimanshu Jha 	u8 oversampling_temp;
551b3bd859SHimanshu Jha 	u8 oversampling_press;
561b3bd859SHimanshu Jha 	u8 oversampling_humid;
571b3bd859SHimanshu Jha 	u16 heater_dur;
581b3bd859SHimanshu Jha 	u16 heater_temp;
591b3bd859SHimanshu Jha 	/*
601b3bd859SHimanshu Jha 	 * Carryover value from temperature conversion, used in pressure
611b3bd859SHimanshu Jha 	 * and humidity compensation calculations.
621b3bd859SHimanshu Jha 	 */
631b3bd859SHimanshu Jha 	s32 t_fine;
641b3bd859SHimanshu Jha };
651b3bd859SHimanshu Jha 
6673f3bc6dSMike Looijmans static const struct regmap_range bme680_volatile_ranges[] = {
6773f3bc6dSMike Looijmans 	regmap_reg_range(BME680_REG_MEAS_STAT_0, BME680_REG_GAS_R_LSB),
6873f3bc6dSMike Looijmans 	regmap_reg_range(BME680_REG_STATUS, BME680_REG_STATUS),
6973f3bc6dSMike Looijmans 	regmap_reg_range(BME680_T2_LSB_REG, BME680_GH3_REG),
7073f3bc6dSMike Looijmans };
7173f3bc6dSMike Looijmans 
7273f3bc6dSMike Looijmans static const struct regmap_access_table bme680_volatile_table = {
7373f3bc6dSMike Looijmans 	.yes_ranges	= bme680_volatile_ranges,
7473f3bc6dSMike Looijmans 	.n_yes_ranges	= ARRAY_SIZE(bme680_volatile_ranges),
7573f3bc6dSMike Looijmans };
7673f3bc6dSMike Looijmans 
771b3bd859SHimanshu Jha const struct regmap_config bme680_regmap_config = {
781b3bd859SHimanshu Jha 	.reg_bits = 8,
791b3bd859SHimanshu Jha 	.val_bits = 8,
8073f3bc6dSMike Looijmans 	.max_register = 0xef,
8173f3bc6dSMike Looijmans 	.volatile_table = &bme680_volatile_table,
8273f3bc6dSMike Looijmans 	.cache_type = REGCACHE_RBTREE,
831b3bd859SHimanshu Jha };
841b3bd859SHimanshu Jha EXPORT_SYMBOL(bme680_regmap_config);
851b3bd859SHimanshu Jha 
861b3bd859SHimanshu Jha static const struct iio_chan_spec bme680_channels[] = {
871b3bd859SHimanshu Jha 	{
881b3bd859SHimanshu Jha 		.type = IIO_TEMP,
891b3bd859SHimanshu Jha 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
901b3bd859SHimanshu Jha 				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
911b3bd859SHimanshu Jha 	},
921b3bd859SHimanshu Jha 	{
931b3bd859SHimanshu Jha 		.type = IIO_PRESSURE,
941b3bd859SHimanshu Jha 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
951b3bd859SHimanshu Jha 				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
961b3bd859SHimanshu Jha 	},
971b3bd859SHimanshu Jha 	{
981b3bd859SHimanshu Jha 		.type = IIO_HUMIDITYRELATIVE,
991b3bd859SHimanshu Jha 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
1001b3bd859SHimanshu Jha 				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
1011b3bd859SHimanshu Jha 	},
1021b3bd859SHimanshu Jha 	{
1031b3bd859SHimanshu Jha 		.type = IIO_RESISTANCE,
1041b3bd859SHimanshu Jha 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
1051b3bd859SHimanshu Jha 	},
1061b3bd859SHimanshu Jha };
1071b3bd859SHimanshu Jha 
1081b3bd859SHimanshu Jha static int bme680_read_calib(struct bme680_data *data,
1091b3bd859SHimanshu Jha 			     struct bme680_calib *calib)
1101b3bd859SHimanshu Jha {
1111b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
1121b3bd859SHimanshu Jha 	unsigned int tmp, tmp_msb, tmp_lsb;
1131b3bd859SHimanshu Jha 	int ret;
1141b3bd859SHimanshu Jha 	__le16 buf;
1151b3bd859SHimanshu Jha 
1161b3bd859SHimanshu Jha 	/* Temperature related coefficients */
117ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG,
118ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1191b3bd859SHimanshu Jha 	if (ret < 0) {
1201b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_T1_LSB_REG\n");
1211b3bd859SHimanshu Jha 		return ret;
1221b3bd859SHimanshu Jha 	}
1231b3bd859SHimanshu Jha 	calib->par_t1 = le16_to_cpu(buf);
1241b3bd859SHimanshu Jha 
125ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG,
126ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1271b3bd859SHimanshu Jha 	if (ret < 0) {
1281b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_T2_LSB_REG\n");
1291b3bd859SHimanshu Jha 		return ret;
1301b3bd859SHimanshu Jha 	}
1311b3bd859SHimanshu Jha 	calib->par_t2 = le16_to_cpu(buf);
1321b3bd859SHimanshu Jha 
1331b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_T3_REG, &tmp);
1341b3bd859SHimanshu Jha 	if (ret < 0) {
1351b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_T3_REG\n");
1361b3bd859SHimanshu Jha 		return ret;
1371b3bd859SHimanshu Jha 	}
1381b3bd859SHimanshu Jha 	calib->par_t3 = tmp;
1391b3bd859SHimanshu Jha 
1401b3bd859SHimanshu Jha 	/* Pressure related coefficients */
141ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG,
142ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1431b3bd859SHimanshu Jha 	if (ret < 0) {
1441b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P1_LSB_REG\n");
1451b3bd859SHimanshu Jha 		return ret;
1461b3bd859SHimanshu Jha 	}
1471b3bd859SHimanshu Jha 	calib->par_p1 = le16_to_cpu(buf);
1481b3bd859SHimanshu Jha 
149ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG,
150ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1511b3bd859SHimanshu Jha 	if (ret < 0) {
1521b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P2_LSB_REG\n");
1531b3bd859SHimanshu Jha 		return ret;
1541b3bd859SHimanshu Jha 	}
1551b3bd859SHimanshu Jha 	calib->par_p2 = le16_to_cpu(buf);
1561b3bd859SHimanshu Jha 
1571b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_P3_REG, &tmp);
1581b3bd859SHimanshu Jha 	if (ret < 0) {
1591b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P3_REG\n");
1601b3bd859SHimanshu Jha 		return ret;
1611b3bd859SHimanshu Jha 	}
1621b3bd859SHimanshu Jha 	calib->par_p3 = tmp;
1631b3bd859SHimanshu Jha 
164ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG,
165ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1661b3bd859SHimanshu Jha 	if (ret < 0) {
1671b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P4_LSB_REG\n");
1681b3bd859SHimanshu Jha 		return ret;
1691b3bd859SHimanshu Jha 	}
1701b3bd859SHimanshu Jha 	calib->par_p4 = le16_to_cpu(buf);
1711b3bd859SHimanshu Jha 
172ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG,
173ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1741b3bd859SHimanshu Jha 	if (ret < 0) {
1751b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P5_LSB_REG\n");
1761b3bd859SHimanshu Jha 		return ret;
1771b3bd859SHimanshu Jha 	}
1781b3bd859SHimanshu Jha 	calib->par_p5 = le16_to_cpu(buf);
1791b3bd859SHimanshu Jha 
1801b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_P6_REG, &tmp);
1811b3bd859SHimanshu Jha 	if (ret < 0) {
1821b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P6_REG\n");
1831b3bd859SHimanshu Jha 		return ret;
1841b3bd859SHimanshu Jha 	}
1851b3bd859SHimanshu Jha 	calib->par_p6 = tmp;
1861b3bd859SHimanshu Jha 
1871b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_P7_REG, &tmp);
1881b3bd859SHimanshu Jha 	if (ret < 0) {
1891b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P7_REG\n");
1901b3bd859SHimanshu Jha 		return ret;
1911b3bd859SHimanshu Jha 	}
1921b3bd859SHimanshu Jha 	calib->par_p7 = tmp;
1931b3bd859SHimanshu Jha 
194ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG,
195ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
1961b3bd859SHimanshu Jha 	if (ret < 0) {
1971b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P8_LSB_REG\n");
1981b3bd859SHimanshu Jha 		return ret;
1991b3bd859SHimanshu Jha 	}
2001b3bd859SHimanshu Jha 	calib->par_p8 = le16_to_cpu(buf);
2011b3bd859SHimanshu Jha 
202ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG,
203ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
2041b3bd859SHimanshu Jha 	if (ret < 0) {
2051b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P9_LSB_REG\n");
2061b3bd859SHimanshu Jha 		return ret;
2071b3bd859SHimanshu Jha 	}
2081b3bd859SHimanshu Jha 	calib->par_p9 = le16_to_cpu(buf);
2091b3bd859SHimanshu Jha 
2101b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_P10_REG, &tmp);
2111b3bd859SHimanshu Jha 	if (ret < 0) {
2121b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_P10_REG\n");
2131b3bd859SHimanshu Jha 		return ret;
2141b3bd859SHimanshu Jha 	}
2151b3bd859SHimanshu Jha 	calib->par_p10 = tmp;
2161b3bd859SHimanshu Jha 
2171b3bd859SHimanshu Jha 	/* Humidity related coefficients */
2181b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H1_MSB_REG, &tmp_msb);
2191b3bd859SHimanshu Jha 	if (ret < 0) {
2201b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H1_MSB_REG\n");
2211b3bd859SHimanshu Jha 		return ret;
2221b3bd859SHimanshu Jha 	}
2231b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H1_LSB_REG, &tmp_lsb);
2241b3bd859SHimanshu Jha 	if (ret < 0) {
2251b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H1_LSB_REG\n");
2261b3bd859SHimanshu Jha 		return ret;
2271b3bd859SHimanshu Jha 	}
2281b3bd859SHimanshu Jha 	calib->par_h1 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
229a24b4d70SDavid Frey 			(tmp_lsb & BME680_BIT_H1_DATA_MASK);
2301b3bd859SHimanshu Jha 
2311b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H2_MSB_REG, &tmp_msb);
2321b3bd859SHimanshu Jha 	if (ret < 0) {
2331b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H2_MSB_REG\n");
2341b3bd859SHimanshu Jha 		return ret;
2351b3bd859SHimanshu Jha 	}
2361b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H2_LSB_REG, &tmp_lsb);
2371b3bd859SHimanshu Jha 	if (ret < 0) {
2381b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H2_LSB_REG\n");
2391b3bd859SHimanshu Jha 		return ret;
2401b3bd859SHimanshu Jha 	}
2411b3bd859SHimanshu Jha 	calib->par_h2 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
2421b3bd859SHimanshu Jha 			(tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
2431b3bd859SHimanshu Jha 
2441b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H3_REG, &tmp);
2451b3bd859SHimanshu Jha 	if (ret < 0) {
2461b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H3_REG\n");
2471b3bd859SHimanshu Jha 		return ret;
2481b3bd859SHimanshu Jha 	}
2491b3bd859SHimanshu Jha 	calib->par_h3 = tmp;
2501b3bd859SHimanshu Jha 
2511b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H4_REG, &tmp);
2521b3bd859SHimanshu Jha 	if (ret < 0) {
2531b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H4_REG\n");
2541b3bd859SHimanshu Jha 		return ret;
2551b3bd859SHimanshu Jha 	}
2561b3bd859SHimanshu Jha 	calib->par_h4 = tmp;
2571b3bd859SHimanshu Jha 
2581b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H5_REG, &tmp);
2591b3bd859SHimanshu Jha 	if (ret < 0) {
2601b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H5_REG\n");
2611b3bd859SHimanshu Jha 		return ret;
2621b3bd859SHimanshu Jha 	}
2631b3bd859SHimanshu Jha 	calib->par_h5 = tmp;
2641b3bd859SHimanshu Jha 
2651b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H6_REG, &tmp);
2661b3bd859SHimanshu Jha 	if (ret < 0) {
2671b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H6_REG\n");
2681b3bd859SHimanshu Jha 		return ret;
2691b3bd859SHimanshu Jha 	}
2701b3bd859SHimanshu Jha 	calib->par_h6 = tmp;
2711b3bd859SHimanshu Jha 
2721b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_H7_REG, &tmp);
2731b3bd859SHimanshu Jha 	if (ret < 0) {
2741b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_H7_REG\n");
2751b3bd859SHimanshu Jha 		return ret;
2761b3bd859SHimanshu Jha 	}
2771b3bd859SHimanshu Jha 	calib->par_h7 = tmp;
2781b3bd859SHimanshu Jha 
2791b3bd859SHimanshu Jha 	/* Gas heater related coefficients */
2801b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_GH1_REG, &tmp);
2811b3bd859SHimanshu Jha 	if (ret < 0) {
2821b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_GH1_REG\n");
2831b3bd859SHimanshu Jha 		return ret;
2841b3bd859SHimanshu Jha 	}
2851b3bd859SHimanshu Jha 	calib->par_gh1 = tmp;
2861b3bd859SHimanshu Jha 
287ce968fb6SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG,
288ce968fb6SJonathan Cameron 			       &buf, sizeof(buf));
2891b3bd859SHimanshu Jha 	if (ret < 0) {
2901b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_GH2_LSB_REG\n");
2911b3bd859SHimanshu Jha 		return ret;
2921b3bd859SHimanshu Jha 	}
2931b3bd859SHimanshu Jha 	calib->par_gh2 = le16_to_cpu(buf);
2941b3bd859SHimanshu Jha 
2951b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_GH3_REG, &tmp);
2961b3bd859SHimanshu Jha 	if (ret < 0) {
2971b3bd859SHimanshu Jha 		dev_err(dev, "failed to read BME680_GH3_REG\n");
2981b3bd859SHimanshu Jha 		return ret;
2991b3bd859SHimanshu Jha 	}
3001b3bd859SHimanshu Jha 	calib->par_gh3 = tmp;
3011b3bd859SHimanshu Jha 
3021b3bd859SHimanshu Jha 	/* Other coefficients */
3031b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_RANGE, &tmp);
3041b3bd859SHimanshu Jha 	if (ret < 0) {
3051b3bd859SHimanshu Jha 		dev_err(dev, "failed to read resistance heat range\n");
3061b3bd859SHimanshu Jha 		return ret;
3071b3bd859SHimanshu Jha 	}
3083dcb60cdSDavid Frey 	calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, tmp);
3091b3bd859SHimanshu Jha 
3101b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_VAL, &tmp);
3111b3bd859SHimanshu Jha 	if (ret < 0) {
3121b3bd859SHimanshu Jha 		dev_err(dev, "failed to read resistance heat value\n");
3131b3bd859SHimanshu Jha 		return ret;
3141b3bd859SHimanshu Jha 	}
3151b3bd859SHimanshu Jha 	calib->res_heat_val = tmp;
3161b3bd859SHimanshu Jha 
3171b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_REG_RANGE_SW_ERR, &tmp);
3181b3bd859SHimanshu Jha 	if (ret < 0) {
3191b3bd859SHimanshu Jha 		dev_err(dev, "failed to read range software error\n");
3201b3bd859SHimanshu Jha 		return ret;
3211b3bd859SHimanshu Jha 	}
3223dcb60cdSDavid Frey 	calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, tmp);
3231b3bd859SHimanshu Jha 
3241b3bd859SHimanshu Jha 	return 0;
3251b3bd859SHimanshu Jha }
3261b3bd859SHimanshu Jha 
3271b3bd859SHimanshu Jha /*
3281b3bd859SHimanshu Jha  * Taken from Bosch BME680 API:
3291b3bd859SHimanshu Jha  * https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L876
3301b3bd859SHimanshu Jha  *
3311b3bd859SHimanshu Jha  * Returns temperature measurement in DegC, resolutions is 0.01 DegC. Therefore,
3321b3bd859SHimanshu Jha  * output value of "3233" represents 32.33 DegC.
3331b3bd859SHimanshu Jha  */
3341b3bd859SHimanshu Jha static s16 bme680_compensate_temp(struct bme680_data *data,
3351b3bd859SHimanshu Jha 				  s32 adc_temp)
3361b3bd859SHimanshu Jha {
3371b3bd859SHimanshu Jha 	struct bme680_calib *calib = &data->bme680;
3381b3bd859SHimanshu Jha 	s64 var1, var2, var3;
3391b3bd859SHimanshu Jha 	s16 calc_temp;
3401b3bd859SHimanshu Jha 
34173f3bc6dSMike Looijmans 	/* If the calibration is invalid, attempt to reload it */
34273f3bc6dSMike Looijmans 	if (!calib->par_t2)
34373f3bc6dSMike Looijmans 		bme680_read_calib(data, calib);
34473f3bc6dSMike Looijmans 
3451b3bd859SHimanshu Jha 	var1 = (adc_temp >> 3) - (calib->par_t1 << 1);
3461b3bd859SHimanshu Jha 	var2 = (var1 * calib->par_t2) >> 11;
3471b3bd859SHimanshu Jha 	var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
3481b3bd859SHimanshu Jha 	var3 = (var3 * (calib->par_t3 << 4)) >> 14;
3491b3bd859SHimanshu Jha 	data->t_fine = var2 + var3;
3501b3bd859SHimanshu Jha 	calc_temp = (data->t_fine * 5 + 128) >> 8;
3511b3bd859SHimanshu Jha 
3521b3bd859SHimanshu Jha 	return calc_temp;
3531b3bd859SHimanshu Jha }
3541b3bd859SHimanshu Jha 
3551b3bd859SHimanshu Jha /*
3561b3bd859SHimanshu Jha  * Taken from Bosch BME680 API:
3571b3bd859SHimanshu Jha  * https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L896
3581b3bd859SHimanshu Jha  *
3591b3bd859SHimanshu Jha  * Returns pressure measurement in Pa. Output value of "97356" represents
3601b3bd859SHimanshu Jha  * 97356 Pa = 973.56 hPa.
3611b3bd859SHimanshu Jha  */
3621b3bd859SHimanshu Jha static u32 bme680_compensate_press(struct bme680_data *data,
3631b3bd859SHimanshu Jha 				   u32 adc_press)
3641b3bd859SHimanshu Jha {
3651b3bd859SHimanshu Jha 	struct bme680_calib *calib = &data->bme680;
3661b3bd859SHimanshu Jha 	s32 var1, var2, var3, press_comp;
3671b3bd859SHimanshu Jha 
3681b3bd859SHimanshu Jha 	var1 = (data->t_fine >> 1) - 64000;
3691b3bd859SHimanshu Jha 	var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * calib->par_p6) >> 2;
3701b3bd859SHimanshu Jha 	var2 = var2 + (var1 * calib->par_p5 << 1);
3711b3bd859SHimanshu Jha 	var2 = (var2 >> 2) + (calib->par_p4 << 16);
3721b3bd859SHimanshu Jha 	var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
3731b3bd859SHimanshu Jha 			(calib->par_p3 << 5)) >> 3) +
3741b3bd859SHimanshu Jha 			((calib->par_p2 * var1) >> 1);
3751b3bd859SHimanshu Jha 	var1 = var1 >> 18;
3761b3bd859SHimanshu Jha 	var1 = ((32768 + var1) * calib->par_p1) >> 15;
3771b3bd859SHimanshu Jha 	press_comp = 1048576 - adc_press;
3781b3bd859SHimanshu Jha 	press_comp = ((press_comp - (var2 >> 12)) * 3125);
3791b3bd859SHimanshu Jha 
3801b3bd859SHimanshu Jha 	if (press_comp >= BME680_MAX_OVERFLOW_VAL)
3811b3bd859SHimanshu Jha 		press_comp = ((press_comp / (u32)var1) << 1);
3821b3bd859SHimanshu Jha 	else
3831b3bd859SHimanshu Jha 		press_comp = ((press_comp << 1) / (u32)var1);
3841b3bd859SHimanshu Jha 
3851b3bd859SHimanshu Jha 	var1 = (calib->par_p9 * (((press_comp >> 3) *
3861b3bd859SHimanshu Jha 			(press_comp >> 3)) >> 13)) >> 12;
3871b3bd859SHimanshu Jha 	var2 = ((press_comp >> 2) * calib->par_p8) >> 13;
3881b3bd859SHimanshu Jha 	var3 = ((press_comp >> 8) * (press_comp >> 8) *
3891b3bd859SHimanshu Jha 			(press_comp >> 8) * calib->par_p10) >> 17;
3901b3bd859SHimanshu Jha 
3911b3bd859SHimanshu Jha 	press_comp += (var1 + var2 + var3 + (calib->par_p7 << 7)) >> 4;
3921b3bd859SHimanshu Jha 
3931b3bd859SHimanshu Jha 	return press_comp;
3941b3bd859SHimanshu Jha }
3951b3bd859SHimanshu Jha 
3961b3bd859SHimanshu Jha /*
3971b3bd859SHimanshu Jha  * Taken from Bosch BME680 API:
3981b3bd859SHimanshu Jha  * https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L937
3991b3bd859SHimanshu Jha  *
4001b3bd859SHimanshu Jha  * Returns humidity measurement in percent, resolution is 0.001 percent. Output
4011b3bd859SHimanshu Jha  * value of "43215" represents 43.215 %rH.
4021b3bd859SHimanshu Jha  */
4031b3bd859SHimanshu Jha static u32 bme680_compensate_humid(struct bme680_data *data,
4041b3bd859SHimanshu Jha 				   u16 adc_humid)
4051b3bd859SHimanshu Jha {
4061b3bd859SHimanshu Jha 	struct bme680_calib *calib = &data->bme680;
4071b3bd859SHimanshu Jha 	s32 var1, var2, var3, var4, var5, var6, temp_scaled, calc_hum;
4081b3bd859SHimanshu Jha 
4091b3bd859SHimanshu Jha 	temp_scaled = (data->t_fine * 5 + 128) >> 8;
4101b3bd859SHimanshu Jha 	var1 = (adc_humid - ((s32) ((s32) calib->par_h1 * 16))) -
4111b3bd859SHimanshu Jha 		(((temp_scaled * (s32) calib->par_h3) / 100) >> 1);
4121b3bd859SHimanshu Jha 	var2 = ((s32) calib->par_h2 *
4131b3bd859SHimanshu Jha 		(((temp_scaled * calib->par_h4) / 100) +
4141b3bd859SHimanshu Jha 		 (((temp_scaled * ((temp_scaled * calib->par_h5) / 100))
4151b3bd859SHimanshu Jha 		   >> 6) / 100) + (1 << 14))) >> 10;
4161b3bd859SHimanshu Jha 	var3 = var1 * var2;
4171b3bd859SHimanshu Jha 	var4 = calib->par_h6 << 7;
4181b3bd859SHimanshu Jha 	var4 = (var4 + ((temp_scaled * calib->par_h7) / 100)) >> 4;
4191b3bd859SHimanshu Jha 	var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
4201b3bd859SHimanshu Jha 	var6 = (var4 * var5) >> 1;
4211b3bd859SHimanshu Jha 	calc_hum = (((var3 + var6) >> 10) * 1000) >> 12;
4221b3bd859SHimanshu Jha 
4238a0ae7d8SDavid Frey 	calc_hum = clamp(calc_hum, 0, 100000); /* clamp between 0-100 %rH */
4241b3bd859SHimanshu Jha 
4251b3bd859SHimanshu Jha 	return calc_hum;
4261b3bd859SHimanshu Jha }
4271b3bd859SHimanshu Jha 
4281b3bd859SHimanshu Jha /*
4291b3bd859SHimanshu Jha  * Taken from Bosch BME680 API:
4301b3bd859SHimanshu Jha  * https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L973
4311b3bd859SHimanshu Jha  *
4321b3bd859SHimanshu Jha  * Returns gas measurement in Ohm. Output value of "82986" represent 82986 ohms.
4331b3bd859SHimanshu Jha  */
4341b3bd859SHimanshu Jha static u32 bme680_compensate_gas(struct bme680_data *data, u16 gas_res_adc,
4351b3bd859SHimanshu Jha 				 u8 gas_range)
4361b3bd859SHimanshu Jha {
4371b3bd859SHimanshu Jha 	struct bme680_calib *calib = &data->bme680;
4381b3bd859SHimanshu Jha 	s64 var1;
4391b3bd859SHimanshu Jha 	u64 var2;
4401b3bd859SHimanshu Jha 	s64 var3;
4411b3bd859SHimanshu Jha 	u32 calc_gas_res;
4421b3bd859SHimanshu Jha 
4431b3bd859SHimanshu Jha 	/* Look up table for the possible gas range values */
4441b3bd859SHimanshu Jha 	const u32 lookupTable[16] = {2147483647u, 2147483647u,
4451b3bd859SHimanshu Jha 				2147483647u, 2147483647u, 2147483647u,
4461b3bd859SHimanshu Jha 				2126008810u, 2147483647u, 2130303777u,
4471b3bd859SHimanshu Jha 				2147483647u, 2147483647u, 2143188679u,
4481b3bd859SHimanshu Jha 				2136746228u, 2147483647u, 2126008810u,
4491b3bd859SHimanshu Jha 				2147483647u, 2147483647u};
4501b3bd859SHimanshu Jha 
4511b3bd859SHimanshu Jha 	var1 = ((1340 + (5 * (s64) calib->range_sw_err)) *
4521b3bd859SHimanshu Jha 			((s64) lookupTable[gas_range])) >> 16;
4531b3bd859SHimanshu Jha 	var2 = ((gas_res_adc << 15) - 16777216) + var1;
4541b3bd859SHimanshu Jha 	var3 = ((125000 << (15 - gas_range)) * var1) >> 9;
4551b3bd859SHimanshu Jha 	var3 += (var2 >> 1);
4561b3bd859SHimanshu Jha 	calc_gas_res = div64_s64(var3, (s64) var2);
4571b3bd859SHimanshu Jha 
4581b3bd859SHimanshu Jha 	return calc_gas_res;
4591b3bd859SHimanshu Jha }
4601b3bd859SHimanshu Jha 
4611b3bd859SHimanshu Jha /*
4621b3bd859SHimanshu Jha  * Taken from Bosch BME680 API:
4631b3bd859SHimanshu Jha  * https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L1002
4641b3bd859SHimanshu Jha  */
4651b3bd859SHimanshu Jha static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp)
4661b3bd859SHimanshu Jha {
4671b3bd859SHimanshu Jha 	struct bme680_calib *calib = &data->bme680;
4681b3bd859SHimanshu Jha 	s32 var1, var2, var3, var4, var5, heatr_res_x100;
4691b3bd859SHimanshu Jha 	u8 heatr_res;
4701b3bd859SHimanshu Jha 
4711b3bd859SHimanshu Jha 	if (temp > 400) /* Cap temperature */
4721b3bd859SHimanshu Jha 		temp = 400;
4731b3bd859SHimanshu Jha 
4741b3bd859SHimanshu Jha 	var1 = (((s32) BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256;
4751b3bd859SHimanshu Jha 	var2 = (calib->par_gh1 + 784) * (((((calib->par_gh2 + 154009) *
4761b3bd859SHimanshu Jha 						temp * 5) / 100)
4771b3bd859SHimanshu Jha 						+ 3276800) / 10);
4781b3bd859SHimanshu Jha 	var3 = var1 + (var2 / 2);
4791b3bd859SHimanshu Jha 	var4 = (var3 / (calib->res_heat_range + 4));
4801b3bd859SHimanshu Jha 	var5 = 131 * calib->res_heat_val + 65536;
4811b3bd859SHimanshu Jha 	heatr_res_x100 = ((var4 / var5) - 250) * 34;
482*166549bbSLars-Peter Clausen 	heatr_res = DIV_ROUND_CLOSEST(heatr_res_x100, 100);
4831b3bd859SHimanshu Jha 
4841b3bd859SHimanshu Jha 	return heatr_res;
4851b3bd859SHimanshu Jha }
4861b3bd859SHimanshu Jha 
4871b3bd859SHimanshu Jha /*
4881b3bd859SHimanshu Jha  * Taken from Bosch BME680 API:
4891b3bd859SHimanshu Jha  * https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L1188
4901b3bd859SHimanshu Jha  */
4911b3bd859SHimanshu Jha static u8 bme680_calc_heater_dur(u16 dur)
4921b3bd859SHimanshu Jha {
4931b3bd859SHimanshu Jha 	u8 durval, factor = 0;
4941b3bd859SHimanshu Jha 
4951b3bd859SHimanshu Jha 	if (dur >= 0xfc0) {
4961b3bd859SHimanshu Jha 		durval = 0xff; /* Max duration */
4971b3bd859SHimanshu Jha 	} else {
4981b3bd859SHimanshu Jha 		while (dur > 0x3F) {
4991b3bd859SHimanshu Jha 			dur = dur / 4;
5001b3bd859SHimanshu Jha 			factor += 1;
5011b3bd859SHimanshu Jha 		}
5021b3bd859SHimanshu Jha 		durval = dur + (factor * 64);
5031b3bd859SHimanshu Jha 	}
5041b3bd859SHimanshu Jha 
5051b3bd859SHimanshu Jha 	return durval;
5061b3bd859SHimanshu Jha }
5071b3bd859SHimanshu Jha 
5081b3bd859SHimanshu Jha static int bme680_set_mode(struct bme680_data *data, bool mode)
5091b3bd859SHimanshu Jha {
5101b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
5111b3bd859SHimanshu Jha 	int ret;
5121b3bd859SHimanshu Jha 
5131b3bd859SHimanshu Jha 	if (mode) {
5141b3bd859SHimanshu Jha 		ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
5151b3bd859SHimanshu Jha 					BME680_MODE_MASK, BME680_MODE_FORCED);
5161b3bd859SHimanshu Jha 		if (ret < 0)
5171b3bd859SHimanshu Jha 			dev_err(dev, "failed to set forced mode\n");
5181b3bd859SHimanshu Jha 
5191b3bd859SHimanshu Jha 	} else {
5201b3bd859SHimanshu Jha 		ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
5211b3bd859SHimanshu Jha 					BME680_MODE_MASK, BME680_MODE_SLEEP);
5221b3bd859SHimanshu Jha 		if (ret < 0)
5231b3bd859SHimanshu Jha 			dev_err(dev, "failed to set sleep mode\n");
5241b3bd859SHimanshu Jha 
5251b3bd859SHimanshu Jha 	}
5261b3bd859SHimanshu Jha 
5271b3bd859SHimanshu Jha 	return ret;
5281b3bd859SHimanshu Jha }
5291b3bd859SHimanshu Jha 
53079fd571bSDavid Frey static u8 bme680_oversampling_to_reg(u8 val)
53179fd571bSDavid Frey {
53279fd571bSDavid Frey 	return ilog2(val) + 1;
53379fd571bSDavid Frey }
53479fd571bSDavid Frey 
5351b3bd859SHimanshu Jha static int bme680_chip_config(struct bme680_data *data)
5361b3bd859SHimanshu Jha {
5371b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
5381b3bd859SHimanshu Jha 	int ret;
53979fd571bSDavid Frey 	u8 osrs;
54079fd571bSDavid Frey 
54179fd571bSDavid Frey 	osrs = FIELD_PREP(
54279fd571bSDavid Frey 		BME680_OSRS_HUMIDITY_MASK,
54379fd571bSDavid Frey 		bme680_oversampling_to_reg(data->oversampling_humid));
5441b3bd859SHimanshu Jha 	/*
5451b3bd859SHimanshu Jha 	 * Highly recommended to set oversampling of humidity before
5461b3bd859SHimanshu Jha 	 * temperature/pressure oversampling.
5471b3bd859SHimanshu Jha 	 */
5481b3bd859SHimanshu Jha 	ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_HUMIDITY,
5491b3bd859SHimanshu Jha 				 BME680_OSRS_HUMIDITY_MASK, osrs);
5501b3bd859SHimanshu Jha 	if (ret < 0) {
5511b3bd859SHimanshu Jha 		dev_err(dev, "failed to write ctrl_hum register\n");
5521b3bd859SHimanshu Jha 		return ret;
5531b3bd859SHimanshu Jha 	}
5541b3bd859SHimanshu Jha 
5551b3bd859SHimanshu Jha 	/* IIR filter settings */
5561b3bd859SHimanshu Jha 	ret = regmap_update_bits(data->regmap, BME680_REG_CONFIG,
5571b3bd859SHimanshu Jha 				 BME680_FILTER_MASK,
5581b3bd859SHimanshu Jha 				 BME680_FILTER_COEFF_VAL);
5591b3bd859SHimanshu Jha 	if (ret < 0) {
5601b3bd859SHimanshu Jha 		dev_err(dev, "failed to write config register\n");
5611b3bd859SHimanshu Jha 		return ret;
5621b3bd859SHimanshu Jha 	}
5631b3bd859SHimanshu Jha 
56479fd571bSDavid Frey 	osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK,
56579fd571bSDavid Frey 			  bme680_oversampling_to_reg(data->oversampling_temp)) |
56679fd571bSDavid Frey 	       FIELD_PREP(BME680_OSRS_PRESS_MASK,
56779fd571bSDavid Frey 			  bme680_oversampling_to_reg(data->oversampling_press));
5681b3bd859SHimanshu Jha 	ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
56979fd571bSDavid Frey 				BME680_OSRS_TEMP_MASK | BME680_OSRS_PRESS_MASK,
5701b3bd859SHimanshu Jha 				osrs);
5711b3bd859SHimanshu Jha 	if (ret < 0)
5721b3bd859SHimanshu Jha 		dev_err(dev, "failed to write ctrl_meas register\n");
5731b3bd859SHimanshu Jha 
5741b3bd859SHimanshu Jha 	return ret;
5751b3bd859SHimanshu Jha }
5761b3bd859SHimanshu Jha 
5771b3bd859SHimanshu Jha static int bme680_gas_config(struct bme680_data *data)
5781b3bd859SHimanshu Jha {
5791b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
5801b3bd859SHimanshu Jha 	int ret;
5811b3bd859SHimanshu Jha 	u8 heatr_res, heatr_dur;
5821b3bd859SHimanshu Jha 
5831b3bd859SHimanshu Jha 	heatr_res = bme680_calc_heater_res(data, data->heater_temp);
5841b3bd859SHimanshu Jha 
5851b3bd859SHimanshu Jha 	/* set target heater temperature */
5861b3bd859SHimanshu Jha 	ret = regmap_write(data->regmap, BME680_REG_RES_HEAT_0, heatr_res);
5871b3bd859SHimanshu Jha 	if (ret < 0) {
5881b3bd859SHimanshu Jha 		dev_err(dev, "failed to write res_heat_0 register\n");
5891b3bd859SHimanshu Jha 		return ret;
5901b3bd859SHimanshu Jha 	}
5911b3bd859SHimanshu Jha 
5921b3bd859SHimanshu Jha 	heatr_dur = bme680_calc_heater_dur(data->heater_dur);
5931b3bd859SHimanshu Jha 
5941b3bd859SHimanshu Jha 	/* set target heating duration */
5951b3bd859SHimanshu Jha 	ret = regmap_write(data->regmap, BME680_REG_GAS_WAIT_0, heatr_dur);
5961b3bd859SHimanshu Jha 	if (ret < 0) {
5975e457296SColin Ian King 		dev_err(dev, "failed to write gas_wait_0 register\n");
5981b3bd859SHimanshu Jha 		return ret;
5991b3bd859SHimanshu Jha 	}
6001b3bd859SHimanshu Jha 
6011691d4caSDavid Frey 	/* Enable the gas sensor and select heater profile set-point 0 */
6021b3bd859SHimanshu Jha 	ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1,
6031b3bd859SHimanshu Jha 				 BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK,
6041691d4caSDavid Frey 				 FIELD_PREP(BME680_RUN_GAS_MASK, 1) |
6051691d4caSDavid Frey 				 FIELD_PREP(BME680_NB_CONV_MASK, 0));
6061b3bd859SHimanshu Jha 	if (ret < 0)
6071b3bd859SHimanshu Jha 		dev_err(dev, "failed to write ctrl_gas_1 register\n");
6081b3bd859SHimanshu Jha 
6091b3bd859SHimanshu Jha 	return ret;
6101b3bd859SHimanshu Jha }
6111b3bd859SHimanshu Jha 
6129436f45dSMike Looijmans static int bme680_read_temp(struct bme680_data *data, int *val)
6131b3bd859SHimanshu Jha {
6141b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
6151b3bd859SHimanshu Jha 	int ret;
6161b3bd859SHimanshu Jha 	__be32 tmp = 0;
6171b3bd859SHimanshu Jha 	s32 adc_temp;
6181b3bd859SHimanshu Jha 	s16 comp_temp;
6191b3bd859SHimanshu Jha 
6201b3bd859SHimanshu Jha 	/* set forced mode to trigger measurement */
6211b3bd859SHimanshu Jha 	ret = bme680_set_mode(data, true);
6221b3bd859SHimanshu Jha 	if (ret < 0)
6231b3bd859SHimanshu Jha 		return ret;
6241b3bd859SHimanshu Jha 
6251b3bd859SHimanshu Jha 	ret = regmap_bulk_read(data->regmap, BME680_REG_TEMP_MSB,
626ce968fb6SJonathan Cameron 			       &tmp, 3);
6271b3bd859SHimanshu Jha 	if (ret < 0) {
6281b3bd859SHimanshu Jha 		dev_err(dev, "failed to read temperature\n");
6291b3bd859SHimanshu Jha 		return ret;
6301b3bd859SHimanshu Jha 	}
6311b3bd859SHimanshu Jha 
6321b3bd859SHimanshu Jha 	adc_temp = be32_to_cpu(tmp) >> 12;
6331b3bd859SHimanshu Jha 	if (adc_temp == BME680_MEAS_SKIPPED) {
6341b3bd859SHimanshu Jha 		/* reading was skipped */
6351b3bd859SHimanshu Jha 		dev_err(dev, "reading temperature skipped\n");
6361b3bd859SHimanshu Jha 		return -EINVAL;
6371b3bd859SHimanshu Jha 	}
6381b3bd859SHimanshu Jha 	comp_temp = bme680_compensate_temp(data, adc_temp);
6391b3bd859SHimanshu Jha 	/*
6401b3bd859SHimanshu Jha 	 * val might be NULL if we're called by the read_press/read_humid
6411b3bd859SHimanshu Jha 	 * routine which is callled to get t_fine value used in
6421b3bd859SHimanshu Jha 	 * compensate_press/compensate_humid to get compensated
6431b3bd859SHimanshu Jha 	 * pressure/humidity readings.
6441b3bd859SHimanshu Jha 	 */
6459436f45dSMike Looijmans 	if (val) {
6469436f45dSMike Looijmans 		*val = comp_temp * 10; /* Centidegrees to millidegrees */
6479436f45dSMike Looijmans 		return IIO_VAL_INT;
6481b3bd859SHimanshu Jha 	}
6491b3bd859SHimanshu Jha 
6501b3bd859SHimanshu Jha 	return ret;
6511b3bd859SHimanshu Jha }
6521b3bd859SHimanshu Jha 
6531b3bd859SHimanshu Jha static int bme680_read_press(struct bme680_data *data,
6541b3bd859SHimanshu Jha 			     int *val, int *val2)
6551b3bd859SHimanshu Jha {
6561b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
6571b3bd859SHimanshu Jha 	int ret;
6581b3bd859SHimanshu Jha 	__be32 tmp = 0;
6591b3bd859SHimanshu Jha 	s32 adc_press;
6601b3bd859SHimanshu Jha 
6611b3bd859SHimanshu Jha 	/* Read and compensate temperature to get a reading of t_fine */
6629436f45dSMike Looijmans 	ret = bme680_read_temp(data, NULL);
6631b3bd859SHimanshu Jha 	if (ret < 0)
6641b3bd859SHimanshu Jha 		return ret;
6651b3bd859SHimanshu Jha 
6661b3bd859SHimanshu Jha 	ret = regmap_bulk_read(data->regmap, BME680_REG_PRESS_MSB,
667ce968fb6SJonathan Cameron 			       &tmp, 3);
6681b3bd859SHimanshu Jha 	if (ret < 0) {
6691b3bd859SHimanshu Jha 		dev_err(dev, "failed to read pressure\n");
6701b3bd859SHimanshu Jha 		return ret;
6711b3bd859SHimanshu Jha 	}
6721b3bd859SHimanshu Jha 
6731b3bd859SHimanshu Jha 	adc_press = be32_to_cpu(tmp) >> 12;
6741b3bd859SHimanshu Jha 	if (adc_press == BME680_MEAS_SKIPPED) {
6751b3bd859SHimanshu Jha 		/* reading was skipped */
6761b3bd859SHimanshu Jha 		dev_err(dev, "reading pressure skipped\n");
6771b3bd859SHimanshu Jha 		return -EINVAL;
6781b3bd859SHimanshu Jha 	}
6791b3bd859SHimanshu Jha 
6801b3bd859SHimanshu Jha 	*val = bme680_compensate_press(data, adc_press);
6811b3bd859SHimanshu Jha 	*val2 = 100;
6821b3bd859SHimanshu Jha 	return IIO_VAL_FRACTIONAL;
6831b3bd859SHimanshu Jha }
6841b3bd859SHimanshu Jha 
6851b3bd859SHimanshu Jha static int bme680_read_humid(struct bme680_data *data,
6861b3bd859SHimanshu Jha 			     int *val, int *val2)
6871b3bd859SHimanshu Jha {
6881b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
6891b3bd859SHimanshu Jha 	int ret;
6901b3bd859SHimanshu Jha 	__be16 tmp = 0;
6911b3bd859SHimanshu Jha 	s32 adc_humidity;
6921b3bd859SHimanshu Jha 	u32 comp_humidity;
6931b3bd859SHimanshu Jha 
6941b3bd859SHimanshu Jha 	/* Read and compensate temperature to get a reading of t_fine */
6959436f45dSMike Looijmans 	ret = bme680_read_temp(data, NULL);
6961b3bd859SHimanshu Jha 	if (ret < 0)
6971b3bd859SHimanshu Jha 		return ret;
6981b3bd859SHimanshu Jha 
6991b3bd859SHimanshu Jha 	ret = regmap_bulk_read(data->regmap, BM6880_REG_HUMIDITY_MSB,
700ce968fb6SJonathan Cameron 			       &tmp, sizeof(tmp));
7011b3bd859SHimanshu Jha 	if (ret < 0) {
7021b3bd859SHimanshu Jha 		dev_err(dev, "failed to read humidity\n");
7031b3bd859SHimanshu Jha 		return ret;
7041b3bd859SHimanshu Jha 	}
7051b3bd859SHimanshu Jha 
7061b3bd859SHimanshu Jha 	adc_humidity = be16_to_cpu(tmp);
7071b3bd859SHimanshu Jha 	if (adc_humidity == BME680_MEAS_SKIPPED) {
7081b3bd859SHimanshu Jha 		/* reading was skipped */
7091b3bd859SHimanshu Jha 		dev_err(dev, "reading humidity skipped\n");
7101b3bd859SHimanshu Jha 		return -EINVAL;
7111b3bd859SHimanshu Jha 	}
7121b3bd859SHimanshu Jha 	comp_humidity = bme680_compensate_humid(data, adc_humidity);
7131b3bd859SHimanshu Jha 
7141b3bd859SHimanshu Jha 	*val = comp_humidity;
7151b3bd859SHimanshu Jha 	*val2 = 1000;
7161b3bd859SHimanshu Jha 	return IIO_VAL_FRACTIONAL;
7171b3bd859SHimanshu Jha }
7181b3bd859SHimanshu Jha 
7191b3bd859SHimanshu Jha static int bme680_read_gas(struct bme680_data *data,
7201b3bd859SHimanshu Jha 			   int *val)
7211b3bd859SHimanshu Jha {
7221b3bd859SHimanshu Jha 	struct device *dev = regmap_get_device(data->regmap);
7231b3bd859SHimanshu Jha 	int ret;
7241b3bd859SHimanshu Jha 	__be16 tmp = 0;
7251b3bd859SHimanshu Jha 	unsigned int check;
7261b3bd859SHimanshu Jha 	u16 adc_gas_res;
7271b3bd859SHimanshu Jha 	u8 gas_range;
7281b3bd859SHimanshu Jha 
7291b3bd859SHimanshu Jha 	/* Set heater settings */
7301b3bd859SHimanshu Jha 	ret = bme680_gas_config(data);
7311b3bd859SHimanshu Jha 	if (ret < 0) {
7321b3bd859SHimanshu Jha 		dev_err(dev, "failed to set gas config\n");
7331b3bd859SHimanshu Jha 		return ret;
7341b3bd859SHimanshu Jha 	}
7351b3bd859SHimanshu Jha 
7361b3bd859SHimanshu Jha 	/* set forced mode to trigger measurement */
7371b3bd859SHimanshu Jha 	ret = bme680_set_mode(data, true);
7381b3bd859SHimanshu Jha 	if (ret < 0)
7391b3bd859SHimanshu Jha 		return ret;
7401b3bd859SHimanshu Jha 
7411b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &check);
7421b3bd859SHimanshu Jha 	if (check & BME680_GAS_MEAS_BIT) {
7431b3bd859SHimanshu Jha 		dev_err(dev, "gas measurement incomplete\n");
7441b3bd859SHimanshu Jha 		return -EBUSY;
7451b3bd859SHimanshu Jha 	}
7461b3bd859SHimanshu Jha 
7471b3bd859SHimanshu Jha 	ret = regmap_read(data->regmap, BME680_REG_GAS_R_LSB, &check);
7481b3bd859SHimanshu Jha 	if (ret < 0) {
7491b3bd859SHimanshu Jha 		dev_err(dev, "failed to read gas_r_lsb register\n");
7501b3bd859SHimanshu Jha 		return ret;
7511b3bd859SHimanshu Jha 	}
7521b3bd859SHimanshu Jha 
7531b3bd859SHimanshu Jha 	/*
7541b3bd859SHimanshu Jha 	 * occurs if either the gas heating duration was insuffient
7551b3bd859SHimanshu Jha 	 * to reach the target heater temperature or the target
7561b3bd859SHimanshu Jha 	 * heater temperature was too high for the heater sink to
7571b3bd859SHimanshu Jha 	 * reach.
7581b3bd859SHimanshu Jha 	 */
7591b3bd859SHimanshu Jha 	if ((check & BME680_GAS_STAB_BIT) == 0) {
7601b3bd859SHimanshu Jha 		dev_err(dev, "heater failed to reach the target temperature\n");
7611b3bd859SHimanshu Jha 		return -EINVAL;
7621b3bd859SHimanshu Jha 	}
7631b3bd859SHimanshu Jha 
7641b3bd859SHimanshu Jha 	ret = regmap_bulk_read(data->regmap, BME680_REG_GAS_MSB,
765ce968fb6SJonathan Cameron 			       &tmp, sizeof(tmp));
7661b3bd859SHimanshu Jha 	if (ret < 0) {
7671b3bd859SHimanshu Jha 		dev_err(dev, "failed to read gas resistance\n");
7681b3bd859SHimanshu Jha 		return ret;
7691b3bd859SHimanshu Jha 	}
7701b3bd859SHimanshu Jha 
7711b3bd859SHimanshu Jha 	gas_range = check & BME680_GAS_RANGE_MASK;
7721b3bd859SHimanshu Jha 	adc_gas_res = be16_to_cpu(tmp) >> BME680_ADC_GAS_RES_SHIFT;
7731b3bd859SHimanshu Jha 
7741b3bd859SHimanshu Jha 	*val = bme680_compensate_gas(data, adc_gas_res, gas_range);
7751b3bd859SHimanshu Jha 	return IIO_VAL_INT;
7761b3bd859SHimanshu Jha }
7771b3bd859SHimanshu Jha 
7781b3bd859SHimanshu Jha static int bme680_read_raw(struct iio_dev *indio_dev,
7791b3bd859SHimanshu Jha 			   struct iio_chan_spec const *chan,
7801b3bd859SHimanshu Jha 			   int *val, int *val2, long mask)
7811b3bd859SHimanshu Jha {
7821b3bd859SHimanshu Jha 	struct bme680_data *data = iio_priv(indio_dev);
7831b3bd859SHimanshu Jha 
7841b3bd859SHimanshu Jha 	switch (mask) {
7851b3bd859SHimanshu Jha 	case IIO_CHAN_INFO_PROCESSED:
7861b3bd859SHimanshu Jha 		switch (chan->type) {
7871b3bd859SHimanshu Jha 		case IIO_TEMP:
7889436f45dSMike Looijmans 			return bme680_read_temp(data, val);
7891b3bd859SHimanshu Jha 		case IIO_PRESSURE:
7901b3bd859SHimanshu Jha 			return bme680_read_press(data, val, val2);
7911b3bd859SHimanshu Jha 		case IIO_HUMIDITYRELATIVE:
7921b3bd859SHimanshu Jha 			return bme680_read_humid(data, val, val2);
7931b3bd859SHimanshu Jha 		case IIO_RESISTANCE:
7941b3bd859SHimanshu Jha 			return bme680_read_gas(data, val);
7951b3bd859SHimanshu Jha 		default:
7961b3bd859SHimanshu Jha 			return -EINVAL;
7971b3bd859SHimanshu Jha 		}
7981b3bd859SHimanshu Jha 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
7991b3bd859SHimanshu Jha 		switch (chan->type) {
8001b3bd859SHimanshu Jha 		case IIO_TEMP:
80179fd571bSDavid Frey 			*val = data->oversampling_temp;
8021b3bd859SHimanshu Jha 			return IIO_VAL_INT;
8031b3bd859SHimanshu Jha 		case IIO_PRESSURE:
80479fd571bSDavid Frey 			*val = data->oversampling_press;
8051b3bd859SHimanshu Jha 			return IIO_VAL_INT;
8061b3bd859SHimanshu Jha 		case IIO_HUMIDITYRELATIVE:
80779fd571bSDavid Frey 			*val = data->oversampling_humid;
8081b3bd859SHimanshu Jha 			return IIO_VAL_INT;
8091b3bd859SHimanshu Jha 		default:
8101b3bd859SHimanshu Jha 			return -EINVAL;
8111b3bd859SHimanshu Jha 		}
8121b3bd859SHimanshu Jha 	default:
8131b3bd859SHimanshu Jha 		return -EINVAL;
8141b3bd859SHimanshu Jha 	}
8151b3bd859SHimanshu Jha }
8161b3bd859SHimanshu Jha 
81779fd571bSDavid Frey static bool bme680_is_valid_oversampling(int rate)
8181b3bd859SHimanshu Jha {
81979fd571bSDavid Frey 	return (rate > 0 && rate <= 16 && is_power_of_2(rate));
8201b3bd859SHimanshu Jha }
8211b3bd859SHimanshu Jha 
8221b3bd859SHimanshu Jha static int bme680_write_raw(struct iio_dev *indio_dev,
8231b3bd859SHimanshu Jha 			    struct iio_chan_spec const *chan,
8241b3bd859SHimanshu Jha 			    int val, int val2, long mask)
8251b3bd859SHimanshu Jha {
8261b3bd859SHimanshu Jha 	struct bme680_data *data = iio_priv(indio_dev);
8271b3bd859SHimanshu Jha 
828892e62faSHimanshu Jha 	if (val2 != 0)
829892e62faSHimanshu Jha 		return -EINVAL;
830892e62faSHimanshu Jha 
8311b3bd859SHimanshu Jha 	switch (mask) {
8321b3bd859SHimanshu Jha 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
83379fd571bSDavid Frey 	{
83479fd571bSDavid Frey 		if (!bme680_is_valid_oversampling(val))
83579fd571bSDavid Frey 			return -EINVAL;
83679fd571bSDavid Frey 
8371b3bd859SHimanshu Jha 		switch (chan->type) {
8381b3bd859SHimanshu Jha 		case IIO_TEMP:
83979fd571bSDavid Frey 			data->oversampling_temp = val;
84079fd571bSDavid Frey 			break;
8411b3bd859SHimanshu Jha 		case IIO_PRESSURE:
84279fd571bSDavid Frey 			data->oversampling_press = val;
84379fd571bSDavid Frey 			break;
8441b3bd859SHimanshu Jha 		case IIO_HUMIDITYRELATIVE:
84579fd571bSDavid Frey 			data->oversampling_humid = val;
84679fd571bSDavid Frey 			break;
8471b3bd859SHimanshu Jha 		default:
8481b3bd859SHimanshu Jha 			return -EINVAL;
8491b3bd859SHimanshu Jha 		}
85079fd571bSDavid Frey 
85179fd571bSDavid Frey 		return bme680_chip_config(data);
85279fd571bSDavid Frey 	}
8531b3bd859SHimanshu Jha 	default:
8541b3bd859SHimanshu Jha 		return -EINVAL;
8551b3bd859SHimanshu Jha 	}
8561b3bd859SHimanshu Jha }
8571b3bd859SHimanshu Jha 
8581b3bd859SHimanshu Jha static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16";
8591b3bd859SHimanshu Jha 
8601b3bd859SHimanshu Jha static IIO_CONST_ATTR(oversampling_ratio_available,
8611b3bd859SHimanshu Jha 		      bme680_oversampling_ratio_show);
8621b3bd859SHimanshu Jha 
8631b3bd859SHimanshu Jha static struct attribute *bme680_attributes[] = {
8641b3bd859SHimanshu Jha 	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
8651b3bd859SHimanshu Jha 	NULL,
8661b3bd859SHimanshu Jha };
8671b3bd859SHimanshu Jha 
8681b3bd859SHimanshu Jha static const struct attribute_group bme680_attribute_group = {
8691b3bd859SHimanshu Jha 	.attrs = bme680_attributes,
8701b3bd859SHimanshu Jha };
8711b3bd859SHimanshu Jha 
8721b3bd859SHimanshu Jha static const struct iio_info bme680_info = {
8731b3bd859SHimanshu Jha 	.read_raw = &bme680_read_raw,
8741b3bd859SHimanshu Jha 	.write_raw = &bme680_write_raw,
8751b3bd859SHimanshu Jha 	.attrs = &bme680_attribute_group,
8761b3bd859SHimanshu Jha };
8771b3bd859SHimanshu Jha 
8781b3bd859SHimanshu Jha static const char *bme680_match_acpi_device(struct device *dev)
8791b3bd859SHimanshu Jha {
8801b3bd859SHimanshu Jha 	const struct acpi_device_id *id;
8811b3bd859SHimanshu Jha 
8821b3bd859SHimanshu Jha 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
8831b3bd859SHimanshu Jha 	if (!id)
8841b3bd859SHimanshu Jha 		return NULL;
8851b3bd859SHimanshu Jha 
8861b3bd859SHimanshu Jha 	return dev_name(dev);
8871b3bd859SHimanshu Jha }
8881b3bd859SHimanshu Jha 
8891b3bd859SHimanshu Jha int bme680_core_probe(struct device *dev, struct regmap *regmap,
8901b3bd859SHimanshu Jha 		      const char *name)
8911b3bd859SHimanshu Jha {
8921b3bd859SHimanshu Jha 	struct iio_dev *indio_dev;
8931b3bd859SHimanshu Jha 	struct bme680_data *data;
89473f3bc6dSMike Looijmans 	unsigned int val;
8951b3bd859SHimanshu Jha 	int ret;
8961b3bd859SHimanshu Jha 
89773f3bc6dSMike Looijmans 	ret = regmap_write(regmap, BME680_REG_SOFT_RESET,
89873f3bc6dSMike Looijmans 			   BME680_CMD_SOFTRESET);
89973f3bc6dSMike Looijmans 	if (ret < 0) {
90073f3bc6dSMike Looijmans 		dev_err(dev, "Failed to reset chip\n");
90173f3bc6dSMike Looijmans 		return ret;
90273f3bc6dSMike Looijmans 	}
90373f3bc6dSMike Looijmans 
90473f3bc6dSMike Looijmans 	ret = regmap_read(regmap, BME680_REG_CHIP_ID, &val);
90573f3bc6dSMike Looijmans 	if (ret < 0) {
90673f3bc6dSMike Looijmans 		dev_err(dev, "Error reading chip ID\n");
90773f3bc6dSMike Looijmans 		return ret;
90873f3bc6dSMike Looijmans 	}
90973f3bc6dSMike Looijmans 
91073f3bc6dSMike Looijmans 	if (val != BME680_CHIP_ID_VAL) {
91173f3bc6dSMike Looijmans 		dev_err(dev, "Wrong chip ID, got %x expected %x\n",
91273f3bc6dSMike Looijmans 				val, BME680_CHIP_ID_VAL);
91373f3bc6dSMike Looijmans 		return -ENODEV;
91473f3bc6dSMike Looijmans 	}
91573f3bc6dSMike Looijmans 
9161b3bd859SHimanshu Jha 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
9171b3bd859SHimanshu Jha 	if (!indio_dev)
9181b3bd859SHimanshu Jha 		return -ENOMEM;
9191b3bd859SHimanshu Jha 
9201b3bd859SHimanshu Jha 	if (!name && ACPI_HANDLE(dev))
9211b3bd859SHimanshu Jha 		name = bme680_match_acpi_device(dev);
9221b3bd859SHimanshu Jha 
9231b3bd859SHimanshu Jha 	data = iio_priv(indio_dev);
9241b3bd859SHimanshu Jha 	dev_set_drvdata(dev, indio_dev);
9251b3bd859SHimanshu Jha 	data->regmap = regmap;
9261b3bd859SHimanshu Jha 	indio_dev->name = name;
9271b3bd859SHimanshu Jha 	indio_dev->channels = bme680_channels;
9281b3bd859SHimanshu Jha 	indio_dev->num_channels = ARRAY_SIZE(bme680_channels);
9291b3bd859SHimanshu Jha 	indio_dev->info = &bme680_info;
9301b3bd859SHimanshu Jha 	indio_dev->modes = INDIO_DIRECT_MODE;
9311b3bd859SHimanshu Jha 
9321b3bd859SHimanshu Jha 	/* default values for the sensor */
93379fd571bSDavid Frey 	data->oversampling_humid = 2; /* 2X oversampling rate */
93479fd571bSDavid Frey 	data->oversampling_press = 4; /* 4X oversampling rate */
93579fd571bSDavid Frey 	data->oversampling_temp = 8;  /* 8X oversampling rate */
9361b3bd859SHimanshu Jha 	data->heater_temp = 320; /* degree Celsius */
9371b3bd859SHimanshu Jha 	data->heater_dur = 150;  /* milliseconds */
9381b3bd859SHimanshu Jha 
9391b3bd859SHimanshu Jha 	ret = bme680_chip_config(data);
9401b3bd859SHimanshu Jha 	if (ret < 0) {
9411b3bd859SHimanshu Jha 		dev_err(dev, "failed to set chip_config data\n");
9421b3bd859SHimanshu Jha 		return ret;
9431b3bd859SHimanshu Jha 	}
9441b3bd859SHimanshu Jha 
9451b3bd859SHimanshu Jha 	ret = bme680_gas_config(data);
9461b3bd859SHimanshu Jha 	if (ret < 0) {
9471b3bd859SHimanshu Jha 		dev_err(dev, "failed to set gas config data\n");
9481b3bd859SHimanshu Jha 		return ret;
9491b3bd859SHimanshu Jha 	}
9501b3bd859SHimanshu Jha 
9511b3bd859SHimanshu Jha 	ret = bme680_read_calib(data, &data->bme680);
9521b3bd859SHimanshu Jha 	if (ret < 0) {
9531b3bd859SHimanshu Jha 		dev_err(dev,
9541b3bd859SHimanshu Jha 			"failed to read calibration coefficients at probe\n");
9551b3bd859SHimanshu Jha 		return ret;
9561b3bd859SHimanshu Jha 	}
9571b3bd859SHimanshu Jha 
9581b3bd859SHimanshu Jha 	return devm_iio_device_register(dev, indio_dev);
9591b3bd859SHimanshu Jha }
9601b3bd859SHimanshu Jha EXPORT_SYMBOL_GPL(bme680_core_probe);
9611b3bd859SHimanshu Jha 
9621b3bd859SHimanshu Jha MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
9631b3bd859SHimanshu Jha MODULE_DESCRIPTION("Bosch BME680 Driver");
9641b3bd859SHimanshu Jha MODULE_LICENSE("GPL v2");
965