xref: /openbmc/linux/drivers/iio/temperature/max30208.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
19ee95ae4SRajat Khandelwal // SPDX-License-Identifier: GPL-2.0-only
29ee95ae4SRajat Khandelwal 
39ee95ae4SRajat Khandelwal /*
49ee95ae4SRajat Khandelwal  * Copyright (c) Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
59ee95ae4SRajat Khandelwal  *
69ee95ae4SRajat Khandelwal  * Maxim MAX30208 digital temperature sensor with 0.1°C accuracy
79ee95ae4SRajat Khandelwal  * (7-bit I2C slave address (0x50 - 0x53))
89ee95ae4SRajat Khandelwal  */
99ee95ae4SRajat Khandelwal 
109ee95ae4SRajat Khandelwal #include <linux/bitops.h>
119ee95ae4SRajat Khandelwal #include <linux/delay.h>
129ee95ae4SRajat Khandelwal #include <linux/iio/iio.h>
139ee95ae4SRajat Khandelwal #include <linux/i2c.h>
149ee95ae4SRajat Khandelwal #include <linux/module.h>
159ee95ae4SRajat Khandelwal #include <linux/types.h>
169ee95ae4SRajat Khandelwal 
179ee95ae4SRajat Khandelwal #define MAX30208_STATUS			0x00
189ee95ae4SRajat Khandelwal #define MAX30208_STATUS_TEMP_RDY	BIT(0)
199ee95ae4SRajat Khandelwal #define MAX30208_INT_ENABLE		0x01
209ee95ae4SRajat Khandelwal #define MAX30208_INT_ENABLE_TEMP_RDY	BIT(0)
219ee95ae4SRajat Khandelwal 
229ee95ae4SRajat Khandelwal #define MAX30208_FIFO_OVF_CNTR		0x06
239ee95ae4SRajat Khandelwal #define MAX30208_FIFO_DATA_CNTR		0x07
249ee95ae4SRajat Khandelwal #define MAX30208_FIFO_DATA		0x08
259ee95ae4SRajat Khandelwal 
269ee95ae4SRajat Khandelwal #define MAX30208_FIFO_CONFIG		0x0a
279ee95ae4SRajat Khandelwal #define MAX30208_FIFO_CONFIG_RO		BIT(1)
289ee95ae4SRajat Khandelwal 
299ee95ae4SRajat Khandelwal #define MAX30208_SYSTEM_CTRL		0x0c
309ee95ae4SRajat Khandelwal #define MAX30208_SYSTEM_CTRL_RESET	0x01
319ee95ae4SRajat Khandelwal 
329ee95ae4SRajat Khandelwal #define MAX30208_TEMP_SENSOR_SETUP	0x14
339ee95ae4SRajat Khandelwal #define MAX30208_TEMP_SENSOR_SETUP_CONV	BIT(0)
349ee95ae4SRajat Khandelwal 
359ee95ae4SRajat Khandelwal struct max30208_data {
369ee95ae4SRajat Khandelwal 	struct i2c_client *client;
379ee95ae4SRajat Khandelwal 	struct iio_dev *indio_dev;
389ee95ae4SRajat Khandelwal 	struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
399ee95ae4SRajat Khandelwal };
409ee95ae4SRajat Khandelwal 
419ee95ae4SRajat Khandelwal static const struct iio_chan_spec max30208_channels[] = {
429ee95ae4SRajat Khandelwal 	{
439ee95ae4SRajat Khandelwal 		.type = IIO_TEMP,
449ee95ae4SRajat Khandelwal 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
459ee95ae4SRajat Khandelwal 	},
469ee95ae4SRajat Khandelwal };
479ee95ae4SRajat Khandelwal 
489ee95ae4SRajat Khandelwal /**
499ee95ae4SRajat Khandelwal  * max30208_request() - Request a reading
509ee95ae4SRajat Khandelwal  * @data: Struct comprising member elements of the device
519ee95ae4SRajat Khandelwal  *
529ee95ae4SRajat Khandelwal  * Requests a reading from the device and waits until the conversion is ready.
539ee95ae4SRajat Khandelwal  */
max30208_request(struct max30208_data * data)549ee95ae4SRajat Khandelwal static int max30208_request(struct max30208_data *data)
559ee95ae4SRajat Khandelwal {
569ee95ae4SRajat Khandelwal 	/*
579ee95ae4SRajat Khandelwal 	 * Sensor can take up to 500 ms to respond so execute a total of
589ee95ae4SRajat Khandelwal 	 * 10 retries to give the device sufficient time.
599ee95ae4SRajat Khandelwal 	 */
609ee95ae4SRajat Khandelwal 	int retries = 10;
619ee95ae4SRajat Khandelwal 	u8 regval;
629ee95ae4SRajat Khandelwal 	int ret;
639ee95ae4SRajat Khandelwal 
649ee95ae4SRajat Khandelwal 	ret = i2c_smbus_read_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP);
659ee95ae4SRajat Khandelwal 	if (ret < 0)
669ee95ae4SRajat Khandelwal 		return ret;
679ee95ae4SRajat Khandelwal 
689ee95ae4SRajat Khandelwal 	regval = ret | MAX30208_TEMP_SENSOR_SETUP_CONV;
699ee95ae4SRajat Khandelwal 
709ee95ae4SRajat Khandelwal 	ret = i2c_smbus_write_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP, regval);
719ee95ae4SRajat Khandelwal 	if (ret)
729ee95ae4SRajat Khandelwal 		return ret;
739ee95ae4SRajat Khandelwal 
749ee95ae4SRajat Khandelwal 	while (retries--) {
759ee95ae4SRajat Khandelwal 		ret = i2c_smbus_read_byte_data(data->client, MAX30208_STATUS);
769ee95ae4SRajat Khandelwal 		if (ret < 0)
779ee95ae4SRajat Khandelwal 			return ret;
789ee95ae4SRajat Khandelwal 
799ee95ae4SRajat Khandelwal 		if (ret & MAX30208_STATUS_TEMP_RDY)
809ee95ae4SRajat Khandelwal 			return 0;
819ee95ae4SRajat Khandelwal 
829ee95ae4SRajat Khandelwal 		msleep(50);
839ee95ae4SRajat Khandelwal 	}
849ee95ae4SRajat Khandelwal 	dev_err(&data->client->dev, "Temperature conversion failed\n");
859ee95ae4SRajat Khandelwal 
869ee95ae4SRajat Khandelwal 	return -ETIMEDOUT;
879ee95ae4SRajat Khandelwal }
889ee95ae4SRajat Khandelwal 
max30208_update_temp(struct max30208_data * data)899ee95ae4SRajat Khandelwal static int max30208_update_temp(struct max30208_data *data)
909ee95ae4SRajat Khandelwal {
919ee95ae4SRajat Khandelwal 	u8 data_count;
929ee95ae4SRajat Khandelwal 	int ret;
939ee95ae4SRajat Khandelwal 
949ee95ae4SRajat Khandelwal 	mutex_lock(&data->lock);
959ee95ae4SRajat Khandelwal 
969ee95ae4SRajat Khandelwal 	ret = max30208_request(data);
979ee95ae4SRajat Khandelwal 	if (ret)
989ee95ae4SRajat Khandelwal 		goto unlock;
999ee95ae4SRajat Khandelwal 
1009ee95ae4SRajat Khandelwal 	ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_OVF_CNTR);
1019ee95ae4SRajat Khandelwal 	if (ret < 0)
1029ee95ae4SRajat Khandelwal 		goto unlock;
1039ee95ae4SRajat Khandelwal 	else if (!ret) {
1049ee95ae4SRajat Khandelwal 		ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_DATA_CNTR);
1059ee95ae4SRajat Khandelwal 		if (ret < 0)
1069ee95ae4SRajat Khandelwal 			goto unlock;
1079ee95ae4SRajat Khandelwal 
1089ee95ae4SRajat Khandelwal 		data_count = ret;
1099ee95ae4SRajat Khandelwal 	} else
1109ee95ae4SRajat Khandelwal 		data_count = 1;
1119ee95ae4SRajat Khandelwal 
1129ee95ae4SRajat Khandelwal 	while (data_count) {
1139ee95ae4SRajat Khandelwal 		ret = i2c_smbus_read_word_swapped(data->client, MAX30208_FIFO_DATA);
1149ee95ae4SRajat Khandelwal 		if (ret < 0)
1159ee95ae4SRajat Khandelwal 			goto unlock;
1169ee95ae4SRajat Khandelwal 
1179ee95ae4SRajat Khandelwal 		data_count--;
1189ee95ae4SRajat Khandelwal 	}
1199ee95ae4SRajat Khandelwal 
1209ee95ae4SRajat Khandelwal unlock:
1219ee95ae4SRajat Khandelwal 	mutex_unlock(&data->lock);
1229ee95ae4SRajat Khandelwal 	return ret;
1239ee95ae4SRajat Khandelwal }
1249ee95ae4SRajat Khandelwal 
1259ee95ae4SRajat Khandelwal /**
1269ee95ae4SRajat Khandelwal  * max30208_config_setup() - Set up FIFO configuration register
1279ee95ae4SRajat Khandelwal  * @data: Struct comprising member elements of the device
1289ee95ae4SRajat Khandelwal  *
1299ee95ae4SRajat Khandelwal  * Sets the rollover bit to '1' to enable overwriting FIFO during overflow.
1309ee95ae4SRajat Khandelwal  */
max30208_config_setup(struct max30208_data * data)1319ee95ae4SRajat Khandelwal static int max30208_config_setup(struct max30208_data *data)
1329ee95ae4SRajat Khandelwal {
1339ee95ae4SRajat Khandelwal 	u8 regval;
1349ee95ae4SRajat Khandelwal 	int ret;
1359ee95ae4SRajat Khandelwal 
1369ee95ae4SRajat Khandelwal 	ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_CONFIG);
1379ee95ae4SRajat Khandelwal 	if (ret < 0)
1389ee95ae4SRajat Khandelwal 		return ret;
1399ee95ae4SRajat Khandelwal 
1409ee95ae4SRajat Khandelwal 	regval = ret | MAX30208_FIFO_CONFIG_RO;
1419ee95ae4SRajat Khandelwal 
1429ee95ae4SRajat Khandelwal 	ret = i2c_smbus_write_byte_data(data->client, MAX30208_FIFO_CONFIG, regval);
1439ee95ae4SRajat Khandelwal 	if (ret)
1449ee95ae4SRajat Khandelwal 		return ret;
1459ee95ae4SRajat Khandelwal 
1469ee95ae4SRajat Khandelwal 	return 0;
1479ee95ae4SRajat Khandelwal }
1489ee95ae4SRajat Khandelwal 
max30208_read(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)1499ee95ae4SRajat Khandelwal static int max30208_read(struct iio_dev *indio_dev,
1509ee95ae4SRajat Khandelwal 			 struct iio_chan_spec const *chan,
1519ee95ae4SRajat Khandelwal 			 int *val, int *val2, long mask)
1529ee95ae4SRajat Khandelwal {
1539ee95ae4SRajat Khandelwal 	struct max30208_data *data = iio_priv(indio_dev);
1549ee95ae4SRajat Khandelwal 	int ret;
1559ee95ae4SRajat Khandelwal 
1569ee95ae4SRajat Khandelwal 	switch (mask) {
1579ee95ae4SRajat Khandelwal 	case IIO_CHAN_INFO_RAW:
1589ee95ae4SRajat Khandelwal 		ret = max30208_update_temp(data);
1599ee95ae4SRajat Khandelwal 		if (ret < 0)
1609ee95ae4SRajat Khandelwal 			return ret;
1619ee95ae4SRajat Khandelwal 
1629ee95ae4SRajat Khandelwal 		*val = sign_extend32(ret, 15);
1639ee95ae4SRajat Khandelwal 		return IIO_VAL_INT;
1649ee95ae4SRajat Khandelwal 
1659ee95ae4SRajat Khandelwal 	case IIO_CHAN_INFO_SCALE:
1669ee95ae4SRajat Khandelwal 		*val = 5;
1679ee95ae4SRajat Khandelwal 		return IIO_VAL_INT;
1689ee95ae4SRajat Khandelwal 
1699ee95ae4SRajat Khandelwal 	default:
1709ee95ae4SRajat Khandelwal 		return -EINVAL;
1719ee95ae4SRajat Khandelwal 	}
1729ee95ae4SRajat Khandelwal }
1739ee95ae4SRajat Khandelwal 
1749ee95ae4SRajat Khandelwal static const struct iio_info max30208_info = {
1759ee95ae4SRajat Khandelwal 	.read_raw = max30208_read,
1769ee95ae4SRajat Khandelwal };
1779ee95ae4SRajat Khandelwal 
max30208_probe(struct i2c_client * i2c)1789ee95ae4SRajat Khandelwal static int max30208_probe(struct i2c_client *i2c)
1799ee95ae4SRajat Khandelwal {
1809ee95ae4SRajat Khandelwal 	struct device *dev = &i2c->dev;
1819ee95ae4SRajat Khandelwal 	struct max30208_data *data;
1829ee95ae4SRajat Khandelwal 	struct iio_dev *indio_dev;
1839ee95ae4SRajat Khandelwal 	int ret;
1849ee95ae4SRajat Khandelwal 
1859ee95ae4SRajat Khandelwal 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
1869ee95ae4SRajat Khandelwal 	if (!indio_dev)
1879ee95ae4SRajat Khandelwal 		return -ENOMEM;
1889ee95ae4SRajat Khandelwal 
1899ee95ae4SRajat Khandelwal 	data = iio_priv(indio_dev);
1909ee95ae4SRajat Khandelwal 	data->client = i2c;
1919ee95ae4SRajat Khandelwal 	mutex_init(&data->lock);
1929ee95ae4SRajat Khandelwal 
1939ee95ae4SRajat Khandelwal 	indio_dev->name = "max30208";
1949ee95ae4SRajat Khandelwal 	indio_dev->channels = max30208_channels;
1959ee95ae4SRajat Khandelwal 	indio_dev->num_channels = ARRAY_SIZE(max30208_channels);
1969ee95ae4SRajat Khandelwal 	indio_dev->info = &max30208_info;
1979ee95ae4SRajat Khandelwal 	indio_dev->modes = INDIO_DIRECT_MODE;
1989ee95ae4SRajat Khandelwal 
1999ee95ae4SRajat Khandelwal 	ret = i2c_smbus_write_byte_data(data->client, MAX30208_SYSTEM_CTRL,
2009ee95ae4SRajat Khandelwal 					MAX30208_SYSTEM_CTRL_RESET);
2019ee95ae4SRajat Khandelwal 	if (ret) {
2029ee95ae4SRajat Khandelwal 		dev_err(dev, "Failure in performing reset\n");
2039ee95ae4SRajat Khandelwal 		return ret;
2049ee95ae4SRajat Khandelwal 	}
2059ee95ae4SRajat Khandelwal 
2069ee95ae4SRajat Khandelwal 	msleep(50);
2079ee95ae4SRajat Khandelwal 
2089ee95ae4SRajat Khandelwal 	ret = max30208_config_setup(data);
2099ee95ae4SRajat Khandelwal 	if (ret)
2109ee95ae4SRajat Khandelwal 		return ret;
2119ee95ae4SRajat Khandelwal 
2129ee95ae4SRajat Khandelwal 	ret = devm_iio_device_register(dev, indio_dev);
2139ee95ae4SRajat Khandelwal 	if (ret) {
2149ee95ae4SRajat Khandelwal 		dev_err(dev, "Failed to register IIO device\n");
2159ee95ae4SRajat Khandelwal 		return ret;
2169ee95ae4SRajat Khandelwal 	}
2179ee95ae4SRajat Khandelwal 
2189ee95ae4SRajat Khandelwal 	return 0;
2199ee95ae4SRajat Khandelwal }
2209ee95ae4SRajat Khandelwal 
2219ee95ae4SRajat Khandelwal static const struct i2c_device_id max30208_id_table[] = {
2229ee95ae4SRajat Khandelwal 	{ "max30208" },
2239ee95ae4SRajat Khandelwal 	{ }
2249ee95ae4SRajat Khandelwal };
2259ee95ae4SRajat Khandelwal MODULE_DEVICE_TABLE(i2c, max30208_id_table);
2269ee95ae4SRajat Khandelwal 
2279ee95ae4SRajat Khandelwal static const struct acpi_device_id max30208_acpi_match[] = {
2289ee95ae4SRajat Khandelwal 	{ "MAX30208" },
2299ee95ae4SRajat Khandelwal 	{ }
2309ee95ae4SRajat Khandelwal };
2319ee95ae4SRajat Khandelwal MODULE_DEVICE_TABLE(acpi, max30208_acpi_match);
2329ee95ae4SRajat Khandelwal 
2339ee95ae4SRajat Khandelwal static const struct of_device_id max30208_of_match[] = {
2349ee95ae4SRajat Khandelwal 	{ .compatible = "maxim,max30208" },
2359ee95ae4SRajat Khandelwal 	{ }
2369ee95ae4SRajat Khandelwal };
2379ee95ae4SRajat Khandelwal MODULE_DEVICE_TABLE(of, max30208_of_match);
2389ee95ae4SRajat Khandelwal 
2399ee95ae4SRajat Khandelwal static struct i2c_driver max30208_driver = {
2409ee95ae4SRajat Khandelwal 	.driver = {
2419ee95ae4SRajat Khandelwal 		.name = "max30208",
2429ee95ae4SRajat Khandelwal 		.of_match_table = max30208_of_match,
2439ee95ae4SRajat Khandelwal 		.acpi_match_table = max30208_acpi_match,
2449ee95ae4SRajat Khandelwal 	},
245*7cf15f42SUwe Kleine-König 	.probe = max30208_probe,
2469ee95ae4SRajat Khandelwal 	.id_table = max30208_id_table,
2479ee95ae4SRajat Khandelwal };
2489ee95ae4SRajat Khandelwal module_i2c_driver(max30208_driver);
2499ee95ae4SRajat Khandelwal 
2509ee95ae4SRajat Khandelwal MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>");
2519ee95ae4SRajat Khandelwal MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
2529ee95ae4SRajat Khandelwal MODULE_LICENSE("GPL");
253