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

hwmon: Driver for MAX31730

MAX31730 is a 3-Channel Remote Temperature Sensor.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>

+497 -1
+1
Documentation/hwmon/index.rst
··· 108 108 max197 109 109 max20751 110 110 max31722 111 + max31730 111 112 max31785 112 113 max31790 113 114 max34440
+44
Documentation/hwmon/max31730.rst
··· 1 + Kernel driver max31790 2 + ====================== 3 + 4 + Supported chips: 5 + 6 + * Maxim MAX31730 7 + 8 + Prefix: 'max31730' 9 + 10 + Addresses scanned: 0x1c, 0x1d, 0x1e, 0x1f, 0x4c, 0x4d, 0x4e, 0x4f 11 + 12 + Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31730.pdf 13 + 14 + Author: Guenter Roeck <linux@roeck-us.net> 15 + 16 + 17 + Description 18 + ----------- 19 + 20 + This driver implements support for Maxim MAX31730. 21 + 22 + The MAX31730 temperature sensor monitors its own temperature and the 23 + temperatures of three external diode-connected transistors. The operating 24 + supply voltage is from 3.0V to 3.6V. Resistance cancellation compensates 25 + for high series resistance in circuit-board traces and the external thermal 26 + diode, while beta compensation corrects for temperature-measurement 27 + errors due to low-beta sensing transistors. 28 + 29 + 30 + Sysfs entries 31 + ------------- 32 + 33 + =================== == ======================================================= 34 + temp[1-4]_enable RW Temperature enable/disable 35 + Set to 0 to enable channel, 0 to disable 36 + temp[1-4]_input RO Temperature input 37 + temp[2-4]_fault RO Fault indicator for remote channels 38 + temp[1-4]_max RW Maximum temperature 39 + temp[1-4]_max_alarm RW Maximum temperature alarm 40 + temp[1-4]_min RW Minimum temperature. Common for all channels. 41 + Only temp1_min is writeable. 42 + temp[1-4]_min_alarm RO Minimum temperature alarm 43 + temp[2-4]_offset RW Temperature offset for remote channels 44 + =================== == =======================================================
+11 -1
drivers/hwmon/Kconfig
··· 889 889 will be called max197. 890 890 891 891 config SENSORS_MAX31722 892 - tristate "MAX31722 temperature sensor" 892 + tristate "MAX31722 temperature sensor" 893 893 depends on SPI 894 894 help 895 895 Support for the Maxim Integrated MAX31722/MAX31723 digital ··· 897 897 898 898 This driver can also be built as a module. If so, the module 899 899 will be called max31722. 900 + 901 + config SENSORS_MAX31730 902 + tristate "MAX31730 temperature sensor" 903 + depends on I2C 904 + help 905 + Support for the Maxim Integrated MAX31730 3-Channel Remote 906 + Temperature Sensor. 907 + 908 + This driver can also be built as a module. If so, the module 909 + will be called max31730. 900 910 901 911 config SENSORS_MAX6621 902 912 tristate "Maxim MAX6621 sensor chip"
+1
drivers/hwmon/Makefile
··· 123 123 obj-$(CONFIG_SENSORS_MAX1668) += max1668.o 124 124 obj-$(CONFIG_SENSORS_MAX197) += max197.o 125 125 obj-$(CONFIG_SENSORS_MAX31722) += max31722.o 126 + obj-$(CONFIG_SENSORS_MAX31730) += max31730.o 126 127 obj-$(CONFIG_SENSORS_MAX6621) += max6621.o 127 128 obj-$(CONFIG_SENSORS_MAX6639) += max6639.o 128 129 obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
+440
drivers/hwmon/max31730.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Driver for MAX31730 3-Channel Remote Temperature Sensor 4 + * 5 + * Copyright (c) 2019 Guenter Roeck <linux@roeck-us.net> 6 + */ 7 + 8 + #include <linux/bits.h> 9 + #include <linux/err.h> 10 + #include <linux/i2c.h> 11 + #include <linux/init.h> 12 + #include <linux/hwmon.h> 13 + #include <linux/module.h> 14 + #include <linux/of_device.h> 15 + #include <linux/of.h> 16 + #include <linux/slab.h> 17 + 18 + /* Addresses scanned */ 19 + static const unsigned short normal_i2c[] = { 0x1c, 0x1d, 0x1e, 0x1f, 0x4c, 20 + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; 21 + 22 + /* The MAX31730 registers */ 23 + #define MAX31730_REG_TEMP 0x00 24 + #define MAX31730_REG_CONF 0x13 25 + #define MAX31730_STOP BIT(7) 26 + #define MAX31730_EXTRANGE BIT(1) 27 + #define MAX31730_REG_TEMP_OFFSET 0x16 28 + #define MAX31730_TEMP_OFFSET_BASELINE 0x77 29 + #define MAX31730_REG_OFFSET_ENABLE 0x17 30 + #define MAX31730_REG_TEMP_MAX 0x20 31 + #define MAX31730_REG_TEMP_MIN 0x30 32 + #define MAX31730_REG_STATUS_HIGH 0x32 33 + #define MAX31730_REG_STATUS_LOW 0x33 34 + #define MAX31730_REG_CHANNEL_ENABLE 0x35 35 + #define MAX31730_REG_TEMP_FAULT 0x36 36 + 37 + #define MAX31730_REG_MFG_ID 0x50 38 + #define MAX31730_MFG_ID 0x4d 39 + #define MAX31730_REG_MFG_REV 0x51 40 + #define MAX31730_MFG_REV 0x01 41 + 42 + #define MAX31730_TEMP_MIN (-128000) 43 + #define MAX31730_TEMP_MAX 127937 44 + 45 + /* Each client has this additional data */ 46 + struct max31730_data { 47 + struct i2c_client *client; 48 + u8 orig_conf; 49 + u8 current_conf; 50 + u8 offset_enable; 51 + u8 channel_enable; 52 + }; 53 + 54 + /*-----------------------------------------------------------------------*/ 55 + 56 + static inline long max31730_reg_to_mc(s16 temp) 57 + { 58 + return DIV_ROUND_CLOSEST((temp >> 4) * 1000, 16); 59 + } 60 + 61 + static int max31730_write_config(struct max31730_data *data, u8 set_mask, 62 + u8 clr_mask) 63 + { 64 + u8 value; 65 + 66 + clr_mask |= MAX31730_EXTRANGE; 67 + value = data->current_conf & ~clr_mask; 68 + value |= set_mask; 69 + 70 + if (data->current_conf != value) { 71 + s32 err; 72 + 73 + err = i2c_smbus_write_byte_data(data->client, MAX31730_REG_CONF, 74 + value); 75 + if (err) 76 + return err; 77 + data->current_conf = value; 78 + } 79 + return 0; 80 + } 81 + 82 + static int max31730_set_enable(struct i2c_client *client, int reg, 83 + u8 *confdata, int channel, bool enable) 84 + { 85 + u8 regval = *confdata; 86 + int err; 87 + 88 + if (enable) 89 + regval |= BIT(channel); 90 + else 91 + regval &= ~BIT(channel); 92 + 93 + if (regval != *confdata) { 94 + err = i2c_smbus_write_byte_data(client, reg, regval); 95 + if (err) 96 + return err; 97 + *confdata = regval; 98 + } 99 + return 0; 100 + } 101 + 102 + static int max31730_set_offset_enable(struct max31730_data *data, int channel, 103 + bool enable) 104 + { 105 + return max31730_set_enable(data->client, MAX31730_REG_OFFSET_ENABLE, 106 + &data->offset_enable, channel, enable); 107 + } 108 + 109 + static int max31730_set_channel_enable(struct max31730_data *data, int channel, 110 + bool enable) 111 + { 112 + return max31730_set_enable(data->client, MAX31730_REG_CHANNEL_ENABLE, 113 + &data->channel_enable, channel, enable); 114 + } 115 + 116 + static int max31730_read(struct device *dev, enum hwmon_sensor_types type, 117 + u32 attr, int channel, long *val) 118 + { 119 + struct max31730_data *data = dev_get_drvdata(dev); 120 + int regval, reg, offset; 121 + 122 + if (type != hwmon_temp) 123 + return -EINVAL; 124 + 125 + switch (attr) { 126 + case hwmon_temp_input: 127 + if (!(data->channel_enable & BIT(channel))) 128 + return -ENODATA; 129 + reg = MAX31730_REG_TEMP + (channel * 2); 130 + break; 131 + case hwmon_temp_max: 132 + reg = MAX31730_REG_TEMP_MAX + (channel * 2); 133 + break; 134 + case hwmon_temp_min: 135 + reg = MAX31730_REG_TEMP_MIN; 136 + break; 137 + case hwmon_temp_enable: 138 + *val = !!(data->channel_enable & BIT(channel)); 139 + return 0; 140 + case hwmon_temp_offset: 141 + if (!channel) 142 + return -EINVAL; 143 + if (!(data->offset_enable & BIT(channel))) { 144 + *val = 0; 145 + return 0; 146 + } 147 + offset = i2c_smbus_read_byte_data(data->client, 148 + MAX31730_REG_TEMP_OFFSET); 149 + if (offset < 0) 150 + return offset; 151 + *val = (offset - MAX31730_TEMP_OFFSET_BASELINE) * 125; 152 + return 0; 153 + case hwmon_temp_fault: 154 + regval = i2c_smbus_read_byte_data(data->client, 155 + MAX31730_REG_TEMP_FAULT); 156 + if (regval < 0) 157 + return regval; 158 + *val = !!(regval & BIT(channel)); 159 + return 0; 160 + case hwmon_temp_min_alarm: 161 + regval = i2c_smbus_read_byte_data(data->client, 162 + MAX31730_REG_STATUS_LOW); 163 + if (regval < 0) 164 + return regval; 165 + *val = !!(regval & BIT(channel)); 166 + return 0; 167 + case hwmon_temp_max_alarm: 168 + regval = i2c_smbus_read_byte_data(data->client, 169 + MAX31730_REG_STATUS_HIGH); 170 + if (regval < 0) 171 + return regval; 172 + *val = !!(regval & BIT(channel)); 173 + return 0; 174 + default: 175 + return -EINVAL; 176 + } 177 + regval = i2c_smbus_read_word_swapped(data->client, reg); 178 + if (regval < 0) 179 + return regval; 180 + 181 + *val = max31730_reg_to_mc(regval); 182 + 183 + return 0; 184 + } 185 + 186 + static int max31730_write(struct device *dev, enum hwmon_sensor_types type, 187 + u32 attr, int channel, long val) 188 + { 189 + struct max31730_data *data = dev_get_drvdata(dev); 190 + int reg, err; 191 + 192 + if (type != hwmon_temp) 193 + return -EINVAL; 194 + 195 + switch (attr) { 196 + case hwmon_temp_max: 197 + reg = MAX31730_REG_TEMP_MAX + channel * 2; 198 + break; 199 + case hwmon_temp_min: 200 + reg = MAX31730_REG_TEMP_MIN; 201 + break; 202 + case hwmon_temp_enable: 203 + if (val != 0 && val != 1) 204 + return -EINVAL; 205 + return max31730_set_channel_enable(data, channel, val); 206 + case hwmon_temp_offset: 207 + val = clamp_val(val, -14875, 17000) + 14875; 208 + val = DIV_ROUND_CLOSEST(val, 125); 209 + err = max31730_set_offset_enable(data, channel, 210 + val != MAX31730_TEMP_OFFSET_BASELINE); 211 + if (err) 212 + return err; 213 + return i2c_smbus_write_byte_data(data->client, 214 + MAX31730_REG_TEMP_OFFSET, val); 215 + default: 216 + return -EINVAL; 217 + } 218 + 219 + val = clamp_val(val, MAX31730_TEMP_MIN, MAX31730_TEMP_MAX); 220 + val = DIV_ROUND_CLOSEST(val << 4, 1000) << 4; 221 + 222 + return i2c_smbus_write_word_swapped(data->client, reg, (u16)val); 223 + } 224 + 225 + static umode_t max31730_is_visible(const void *data, 226 + enum hwmon_sensor_types type, 227 + u32 attr, int channel) 228 + { 229 + switch (type) { 230 + case hwmon_temp: 231 + switch (attr) { 232 + case hwmon_temp_input: 233 + case hwmon_temp_min_alarm: 234 + case hwmon_temp_max_alarm: 235 + case hwmon_temp_fault: 236 + return 0444; 237 + case hwmon_temp_min: 238 + return channel ? 0444 : 0644; 239 + case hwmon_temp_offset: 240 + case hwmon_temp_enable: 241 + case hwmon_temp_max: 242 + return 0644; 243 + } 244 + break; 245 + default: 246 + break; 247 + } 248 + return 0; 249 + } 250 + 251 + static const struct hwmon_channel_info *max31730_info[] = { 252 + HWMON_CHANNEL_INFO(chip, 253 + HWMON_C_REGISTER_TZ), 254 + HWMON_CHANNEL_INFO(temp, 255 + HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | 256 + HWMON_T_ENABLE | 257 + HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM, 258 + HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | 259 + HWMON_T_OFFSET | HWMON_T_ENABLE | 260 + HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | 261 + HWMON_T_FAULT, 262 + HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | 263 + HWMON_T_OFFSET | HWMON_T_ENABLE | 264 + HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | 265 + HWMON_T_FAULT, 266 + HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | 267 + HWMON_T_OFFSET | HWMON_T_ENABLE | 268 + HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | 269 + HWMON_T_FAULT 270 + ), 271 + NULL 272 + }; 273 + 274 + static const struct hwmon_ops max31730_hwmon_ops = { 275 + .is_visible = max31730_is_visible, 276 + .read = max31730_read, 277 + .write = max31730_write, 278 + }; 279 + 280 + static const struct hwmon_chip_info max31730_chip_info = { 281 + .ops = &max31730_hwmon_ops, 282 + .info = max31730_info, 283 + }; 284 + 285 + static void max31730_remove(void *data) 286 + { 287 + struct max31730_data *max31730 = data; 288 + struct i2c_client *client = max31730->client; 289 + 290 + i2c_smbus_write_byte_data(client, MAX31730_REG_CONF, 291 + max31730->orig_conf); 292 + } 293 + 294 + static int 295 + max31730_probe(struct i2c_client *client, const struct i2c_device_id *id) 296 + { 297 + struct device *dev = &client->dev; 298 + struct device *hwmon_dev; 299 + struct max31730_data *data; 300 + int status, err; 301 + 302 + if (!i2c_check_functionality(client->adapter, 303 + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) 304 + return -EIO; 305 + 306 + data = devm_kzalloc(dev, sizeof(struct max31730_data), GFP_KERNEL); 307 + if (!data) 308 + return -ENOMEM; 309 + 310 + data->client = client; 311 + 312 + /* Cache original configuration and enable status */ 313 + status = i2c_smbus_read_byte_data(client, MAX31730_REG_CHANNEL_ENABLE); 314 + if (status < 0) 315 + return status; 316 + data->channel_enable = status; 317 + 318 + status = i2c_smbus_read_byte_data(client, MAX31730_REG_OFFSET_ENABLE); 319 + if (status < 0) 320 + return status; 321 + data->offset_enable = status; 322 + 323 + status = i2c_smbus_read_byte_data(client, MAX31730_REG_CONF); 324 + if (status < 0) 325 + return status; 326 + data->orig_conf = status; 327 + data->current_conf = status; 328 + 329 + err = max31730_write_config(data, 330 + data->channel_enable ? 0 : MAX31730_STOP, 331 + data->channel_enable ? MAX31730_STOP : 0); 332 + if (err) 333 + return err; 334 + 335 + dev_set_drvdata(dev, data); 336 + 337 + err = devm_add_action_or_reset(dev, max31730_remove, data); 338 + if (err) 339 + return err; 340 + 341 + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 342 + data, 343 + &max31730_chip_info, 344 + NULL); 345 + return PTR_ERR_OR_ZERO(hwmon_dev); 346 + } 347 + 348 + static const struct i2c_device_id max31730_ids[] = { 349 + { "max31730", 0, }, 350 + { } 351 + }; 352 + MODULE_DEVICE_TABLE(i2c, max31730_ids); 353 + 354 + static const struct of_device_id __maybe_unused max31730_of_match[] = { 355 + { 356 + .compatible = "maxim,max31730", 357 + }, 358 + { }, 359 + }; 360 + MODULE_DEVICE_TABLE(of, max31730_of_match); 361 + 362 + static bool max31730_check_reg_temp(struct i2c_client *client, 363 + int reg) 364 + { 365 + int regval; 366 + 367 + regval = i2c_smbus_read_byte_data(client, reg + 1); 368 + return regval < 0 || (regval & 0x0f); 369 + } 370 + 371 + /* Return 0 if detection is successful, -ENODEV otherwise */ 372 + static int max31730_detect(struct i2c_client *client, 373 + struct i2c_board_info *info) 374 + { 375 + struct i2c_adapter *adapter = client->adapter; 376 + int regval; 377 + int i; 378 + 379 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | 380 + I2C_FUNC_SMBUS_WORD_DATA)) 381 + return -ENODEV; 382 + 383 + regval = i2c_smbus_read_byte_data(client, MAX31730_REG_MFG_ID); 384 + if (regval != MAX31730_MFG_ID) 385 + return -ENODEV; 386 + regval = i2c_smbus_read_byte_data(client, MAX31730_REG_MFG_REV); 387 + if (regval != MAX31730_MFG_REV) 388 + return -ENODEV; 389 + 390 + /* lower 4 bit of temperature and limit registers must be 0 */ 391 + if (max31730_check_reg_temp(client, MAX31730_REG_TEMP_MIN)) 392 + return -ENODEV; 393 + 394 + for (i = 0; i < 4; i++) { 395 + if (max31730_check_reg_temp(client, MAX31730_REG_TEMP + i * 2)) 396 + return -ENODEV; 397 + if (max31730_check_reg_temp(client, 398 + MAX31730_REG_TEMP_MAX + i * 2)) 399 + return -ENODEV; 400 + } 401 + 402 + strlcpy(info->type, "max31730", I2C_NAME_SIZE); 403 + 404 + return 0; 405 + } 406 + 407 + static int __maybe_unused max31730_suspend(struct device *dev) 408 + { 409 + struct max31730_data *data = dev_get_drvdata(dev); 410 + 411 + return max31730_write_config(data, MAX31730_STOP, 0); 412 + } 413 + 414 + static int __maybe_unused max31730_resume(struct device *dev) 415 + { 416 + struct max31730_data *data = dev_get_drvdata(dev); 417 + 418 + return max31730_write_config(data, 0, MAX31730_STOP); 419 + } 420 + 421 + static SIMPLE_DEV_PM_OPS(max31730_pm_ops, max31730_suspend, max31730_resume); 422 + 423 + static struct i2c_driver max31730_driver = { 424 + .class = I2C_CLASS_HWMON, 425 + .driver = { 426 + .name = "max31730", 427 + .of_match_table = of_match_ptr(max31730_of_match), 428 + .pm = &max31730_pm_ops, 429 + }, 430 + .probe = max31730_probe, 431 + .id_table = max31730_ids, 432 + .detect = max31730_detect, 433 + .address_list = normal_i2c, 434 + }; 435 + 436 + module_i2c_driver(max31730_driver); 437 + 438 + MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); 439 + MODULE_DESCRIPTION("MAX31730 driver"); 440 + MODULE_LICENSE("GPL");