Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: temperature: Add driver support for Maxim MAX30208

Maxim MAX30208 is a digital temperature sensor with 0.1°C accuracy.

Add support for max30208 driver in iio subsystem.

Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX30208.pdf
Signed-off-by: Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
Link: https://lore.kernel.org/r/20221122175300.800956-1-rajat.khandelwal@linux.intel.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Rajat Khandelwal and committed by
Jonathan Cameron
9ee95ae4 9fe1614f

+269
+6
MAINTAINERS
··· 12518 12518 F: Documentation/devicetree/bindings/regulator/maxim,max20086.yaml 12519 12519 F: drivers/regulator/max20086-regulator.c 12520 12520 12521 + MAXIM MAX30208 TEMPERATURE SENSOR DRIVER 12522 + M: Rajat Khandelwal <rajat.khandelwal@linux.intel.com> 12523 + L: linux-iio@vger.kernel.org 12524 + S: Maintained 12525 + F: drivers/iio/temperature/max30208.c 12526 + 12521 12527 MAXIM MAX77650 PMIC MFD DRIVER 12522 12528 M: Bartosz Golaszewski <brgl@bgdev.pl> 12523 12529 L: linux-kernel@vger.kernel.org
+10
drivers/iio/temperature/Kconfig
··· 128 128 This driver can also be built as a module. If so, the module will 129 129 be called tsys02d. 130 130 131 + config MAX30208 132 + tristate "Maxim MAX30208 digital temperature sensor" 133 + depends on I2C 134 + help 135 + If you say yes here you get support for Maxim MAX30208 136 + digital temperature sensor connected via I2C. 137 + 138 + This driver can also be built as a module. If so, the module 139 + will be called max30208. 140 + 131 141 config MAX31856 132 142 tristate "MAX31856 thermocouple sensor" 133 143 depends on SPI
+1
drivers/iio/temperature/Makefile
··· 7 7 obj-$(CONFIG_LTC2983) += ltc2983.o 8 8 obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o 9 9 obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o 10 + obj-$(CONFIG_MAX30208) += max30208.o 10 11 obj-$(CONFIG_MAX31856) += max31856.o 11 12 obj-$(CONFIG_MAX31865) += max31865.o 12 13 obj-$(CONFIG_MLX90614) += mlx90614.o
+252
drivers/iio/temperature/max30208.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + /* 4 + * Copyright (c) Rajat Khandelwal <rajat.khandelwal@linux.intel.com> 5 + * 6 + * Maxim MAX30208 digital temperature sensor with 0.1°C accuracy 7 + * (7-bit I2C slave address (0x50 - 0x53)) 8 + */ 9 + 10 + #include <linux/bitops.h> 11 + #include <linux/delay.h> 12 + #include <linux/iio/iio.h> 13 + #include <linux/i2c.h> 14 + #include <linux/module.h> 15 + #include <linux/types.h> 16 + 17 + #define MAX30208_STATUS 0x00 18 + #define MAX30208_STATUS_TEMP_RDY BIT(0) 19 + #define MAX30208_INT_ENABLE 0x01 20 + #define MAX30208_INT_ENABLE_TEMP_RDY BIT(0) 21 + 22 + #define MAX30208_FIFO_OVF_CNTR 0x06 23 + #define MAX30208_FIFO_DATA_CNTR 0x07 24 + #define MAX30208_FIFO_DATA 0x08 25 + 26 + #define MAX30208_FIFO_CONFIG 0x0a 27 + #define MAX30208_FIFO_CONFIG_RO BIT(1) 28 + 29 + #define MAX30208_SYSTEM_CTRL 0x0c 30 + #define MAX30208_SYSTEM_CTRL_RESET 0x01 31 + 32 + #define MAX30208_TEMP_SENSOR_SETUP 0x14 33 + #define MAX30208_TEMP_SENSOR_SETUP_CONV BIT(0) 34 + 35 + struct max30208_data { 36 + struct i2c_client *client; 37 + struct iio_dev *indio_dev; 38 + struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */ 39 + }; 40 + 41 + static const struct iio_chan_spec max30208_channels[] = { 42 + { 43 + .type = IIO_TEMP, 44 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 45 + }, 46 + }; 47 + 48 + /** 49 + * max30208_request() - Request a reading 50 + * @data: Struct comprising member elements of the device 51 + * 52 + * Requests a reading from the device and waits until the conversion is ready. 53 + */ 54 + static int max30208_request(struct max30208_data *data) 55 + { 56 + /* 57 + * Sensor can take up to 500 ms to respond so execute a total of 58 + * 10 retries to give the device sufficient time. 59 + */ 60 + int retries = 10; 61 + u8 regval; 62 + int ret; 63 + 64 + ret = i2c_smbus_read_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP); 65 + if (ret < 0) 66 + return ret; 67 + 68 + regval = ret | MAX30208_TEMP_SENSOR_SETUP_CONV; 69 + 70 + ret = i2c_smbus_write_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP, regval); 71 + if (ret) 72 + return ret; 73 + 74 + while (retries--) { 75 + ret = i2c_smbus_read_byte_data(data->client, MAX30208_STATUS); 76 + if (ret < 0) 77 + return ret; 78 + 79 + if (ret & MAX30208_STATUS_TEMP_RDY) 80 + return 0; 81 + 82 + msleep(50); 83 + } 84 + dev_err(&data->client->dev, "Temperature conversion failed\n"); 85 + 86 + return -ETIMEDOUT; 87 + } 88 + 89 + static int max30208_update_temp(struct max30208_data *data) 90 + { 91 + u8 data_count; 92 + int ret; 93 + 94 + mutex_lock(&data->lock); 95 + 96 + ret = max30208_request(data); 97 + if (ret) 98 + goto unlock; 99 + 100 + ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_OVF_CNTR); 101 + if (ret < 0) 102 + goto unlock; 103 + else if (!ret) { 104 + ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_DATA_CNTR); 105 + if (ret < 0) 106 + goto unlock; 107 + 108 + data_count = ret; 109 + } else 110 + data_count = 1; 111 + 112 + while (data_count) { 113 + ret = i2c_smbus_read_word_swapped(data->client, MAX30208_FIFO_DATA); 114 + if (ret < 0) 115 + goto unlock; 116 + 117 + data_count--; 118 + } 119 + 120 + unlock: 121 + mutex_unlock(&data->lock); 122 + return ret; 123 + } 124 + 125 + /** 126 + * max30208_config_setup() - Set up FIFO configuration register 127 + * @data: Struct comprising member elements of the device 128 + * 129 + * Sets the rollover bit to '1' to enable overwriting FIFO during overflow. 130 + */ 131 + static int max30208_config_setup(struct max30208_data *data) 132 + { 133 + u8 regval; 134 + int ret; 135 + 136 + ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_CONFIG); 137 + if (ret < 0) 138 + return ret; 139 + 140 + regval = ret | MAX30208_FIFO_CONFIG_RO; 141 + 142 + ret = i2c_smbus_write_byte_data(data->client, MAX30208_FIFO_CONFIG, regval); 143 + if (ret) 144 + return ret; 145 + 146 + return 0; 147 + } 148 + 149 + static int max30208_read(struct iio_dev *indio_dev, 150 + struct iio_chan_spec const *chan, 151 + int *val, int *val2, long mask) 152 + { 153 + struct max30208_data *data = iio_priv(indio_dev); 154 + int ret; 155 + 156 + switch (mask) { 157 + case IIO_CHAN_INFO_RAW: 158 + ret = max30208_update_temp(data); 159 + if (ret < 0) 160 + return ret; 161 + 162 + *val = sign_extend32(ret, 15); 163 + return IIO_VAL_INT; 164 + 165 + case IIO_CHAN_INFO_SCALE: 166 + *val = 5; 167 + return IIO_VAL_INT; 168 + 169 + default: 170 + return -EINVAL; 171 + } 172 + } 173 + 174 + static const struct iio_info max30208_info = { 175 + .read_raw = max30208_read, 176 + }; 177 + 178 + static int max30208_probe(struct i2c_client *i2c) 179 + { 180 + struct device *dev = &i2c->dev; 181 + struct max30208_data *data; 182 + struct iio_dev *indio_dev; 183 + int ret; 184 + 185 + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 186 + if (!indio_dev) 187 + return -ENOMEM; 188 + 189 + data = iio_priv(indio_dev); 190 + data->client = i2c; 191 + mutex_init(&data->lock); 192 + 193 + indio_dev->name = "max30208"; 194 + indio_dev->channels = max30208_channels; 195 + indio_dev->num_channels = ARRAY_SIZE(max30208_channels); 196 + indio_dev->info = &max30208_info; 197 + indio_dev->modes = INDIO_DIRECT_MODE; 198 + 199 + ret = i2c_smbus_write_byte_data(data->client, MAX30208_SYSTEM_CTRL, 200 + MAX30208_SYSTEM_CTRL_RESET); 201 + if (ret) { 202 + dev_err(dev, "Failure in performing reset\n"); 203 + return ret; 204 + } 205 + 206 + msleep(50); 207 + 208 + ret = max30208_config_setup(data); 209 + if (ret) 210 + return ret; 211 + 212 + ret = devm_iio_device_register(dev, indio_dev); 213 + if (ret) { 214 + dev_err(dev, "Failed to register IIO device\n"); 215 + return ret; 216 + } 217 + 218 + return 0; 219 + } 220 + 221 + static const struct i2c_device_id max30208_id_table[] = { 222 + { "max30208" }, 223 + { } 224 + }; 225 + MODULE_DEVICE_TABLE(i2c, max30208_id_table); 226 + 227 + static const struct acpi_device_id max30208_acpi_match[] = { 228 + { "MAX30208" }, 229 + { } 230 + }; 231 + MODULE_DEVICE_TABLE(acpi, max30208_acpi_match); 232 + 233 + static const struct of_device_id max30208_of_match[] = { 234 + { .compatible = "maxim,max30208" }, 235 + { } 236 + }; 237 + MODULE_DEVICE_TABLE(of, max30208_of_match); 238 + 239 + static struct i2c_driver max30208_driver = { 240 + .driver = { 241 + .name = "max30208", 242 + .of_match_table = max30208_of_match, 243 + .acpi_match_table = max30208_acpi_match, 244 + }, 245 + .probe_new = max30208_probe, 246 + .id_table = max30208_id_table, 247 + }; 248 + module_i2c_driver(max30208_driver); 249 + 250 + MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>"); 251 + MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor"); 252 + MODULE_LICENSE("GPL");