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