1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware 4 * monitoring 5 * This driver handles the ADT7410 and compatible digital temperature sensors. 6 * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22 7 * based on lm75.c by Frodo Looijaard <frodol@dds.nl> 8 * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com> 9 */ 10 11 #include <linux/device.h> 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/slab.h> 15 #include <linux/jiffies.h> 16 #include <linux/hwmon.h> 17 #include <linux/err.h> 18 #include <linux/mutex.h> 19 #include <linux/delay.h> 20 #include <linux/interrupt.h> 21 #include <linux/regmap.h> 22 23 #include "adt7x10.h" 24 25 /* 26 * ADT7X10 status 27 */ 28 #define ADT7X10_STAT_T_LOW (1 << 4) 29 #define ADT7X10_STAT_T_HIGH (1 << 5) 30 #define ADT7X10_STAT_T_CRIT (1 << 6) 31 #define ADT7X10_STAT_NOT_RDY (1 << 7) 32 33 /* 34 * ADT7X10 config 35 */ 36 #define ADT7X10_FAULT_QUEUE_MASK (1 << 0 | 1 << 1) 37 #define ADT7X10_CT_POLARITY (1 << 2) 38 #define ADT7X10_INT_POLARITY (1 << 3) 39 #define ADT7X10_EVENT_MODE (1 << 4) 40 #define ADT7X10_MODE_MASK (1 << 5 | 1 << 6) 41 #define ADT7X10_FULL (0 << 5 | 0 << 6) 42 #define ADT7X10_PD (1 << 5 | 1 << 6) 43 #define ADT7X10_RESOLUTION (1 << 7) 44 45 /* 46 * ADT7X10 masks 47 */ 48 #define ADT7X10_T13_VALUE_MASK 0xFFF8 49 #define ADT7X10_T_HYST_MASK 0xF 50 51 /* straight from the datasheet */ 52 #define ADT7X10_TEMP_MIN (-55000) 53 #define ADT7X10_TEMP_MAX 150000 54 55 /* Each client has this additional data */ 56 struct adt7x10_data { 57 struct regmap *regmap; 58 struct mutex update_lock; 59 u8 config; 60 u8 oldconfig; 61 bool valid; /* true if temperature valid */ 62 }; 63 64 enum { 65 adt7x10_temperature = 0, 66 adt7x10_t_alarm_high, 67 adt7x10_t_alarm_low, 68 adt7x10_t_crit, 69 }; 70 71 static const u8 ADT7X10_REG_TEMP[] = { 72 [adt7x10_temperature] = ADT7X10_TEMPERATURE, /* input */ 73 [adt7x10_t_alarm_high] = ADT7X10_T_ALARM_HIGH, /* high */ 74 [adt7x10_t_alarm_low] = ADT7X10_T_ALARM_LOW, /* low */ 75 [adt7x10_t_crit] = ADT7X10_T_CRIT, /* critical */ 76 }; 77 78 static irqreturn_t adt7x10_irq_handler(int irq, void *private) 79 { 80 struct device *dev = private; 81 struct adt7x10_data *d = dev_get_drvdata(dev); 82 unsigned int status; 83 int ret; 84 85 ret = regmap_read(d->regmap, ADT7X10_STATUS, &status); 86 if (ret < 0) 87 return IRQ_HANDLED; 88 89 if (status & ADT7X10_STAT_T_HIGH) 90 hwmon_notify_event(dev, hwmon_temp, hwmon_temp_max_alarm, 0); 91 if (status & ADT7X10_STAT_T_LOW) 92 hwmon_notify_event(dev, hwmon_temp, hwmon_temp_min_alarm, 0); 93 if (status & ADT7X10_STAT_T_CRIT) 94 hwmon_notify_event(dev, hwmon_temp, hwmon_temp_crit_alarm, 0); 95 96 return IRQ_HANDLED; 97 } 98 99 static int adt7x10_temp_ready(struct regmap *regmap) 100 { 101 unsigned int status; 102 int i, ret; 103 104 for (i = 0; i < 6; i++) { 105 ret = regmap_read(regmap, ADT7X10_STATUS, &status); 106 if (ret < 0) 107 return ret; 108 if (!(status & ADT7X10_STAT_NOT_RDY)) 109 return 0; 110 msleep(60); 111 } 112 return -ETIMEDOUT; 113 } 114 115 static s16 ADT7X10_TEMP_TO_REG(long temp) 116 { 117 return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN, 118 ADT7X10_TEMP_MAX) * 128, 1000); 119 } 120 121 static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg) 122 { 123 /* in 13 bit mode, bits 0-2 are status flags - mask them out */ 124 if (!(data->config & ADT7X10_RESOLUTION)) 125 reg &= ADT7X10_T13_VALUE_MASK; 126 /* 127 * temperature is stored in twos complement format, in steps of 128 * 1/128°C 129 */ 130 return DIV_ROUND_CLOSEST(reg * 1000, 128); 131 } 132 133 /*-----------------------------------------------------------------------*/ 134 135 static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val) 136 { 137 unsigned int regval; 138 int ret; 139 140 mutex_lock(&data->update_lock); 141 if (index == adt7x10_temperature && !data->valid) { 142 /* wait for valid temperature */ 143 ret = adt7x10_temp_ready(data->regmap); 144 if (ret) { 145 mutex_unlock(&data->update_lock); 146 return ret; 147 } 148 data->valid = true; 149 } 150 mutex_unlock(&data->update_lock); 151 152 ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], ®val); 153 if (ret) 154 return ret; 155 156 *val = ADT7X10_REG_TO_TEMP(data, regval); 157 return 0; 158 } 159 160 static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp) 161 { 162 int ret; 163 164 mutex_lock(&data->update_lock); 165 ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[index], 166 ADT7X10_TEMP_TO_REG(temp)); 167 mutex_unlock(&data->update_lock); 168 return ret; 169 } 170 171 static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val) 172 { 173 int hyst, temp, ret; 174 175 mutex_lock(&data->update_lock); 176 ret = regmap_read(data->regmap, ADT7X10_T_HYST, &hyst); 177 if (ret) { 178 mutex_unlock(&data->update_lock); 179 return ret; 180 } 181 182 ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &temp); 183 mutex_unlock(&data->update_lock); 184 if (ret) 185 return ret; 186 187 hyst = (hyst & ADT7X10_T_HYST_MASK) * 1000; 188 189 /* 190 * hysteresis is stored as a 4 bit offset in the device, convert it 191 * to an absolute value 192 */ 193 /* min has positive offset, others have negative */ 194 if (index == adt7x10_t_alarm_low) 195 hyst = -hyst; 196 197 *val = ADT7X10_REG_TO_TEMP(data, temp) - hyst; 198 return 0; 199 } 200 201 static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst) 202 { 203 unsigned int regval; 204 int limit, ret; 205 206 mutex_lock(&data->update_lock); 207 208 /* convert absolute hysteresis value to a 4 bit delta value */ 209 ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, ®val); 210 if (ret < 0) 211 goto abort; 212 213 limit = ADT7X10_REG_TO_TEMP(data, regval); 214 215 hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX); 216 regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0, 217 ADT7X10_T_HYST_MASK); 218 ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval); 219 abort: 220 mutex_unlock(&data->update_lock); 221 return ret; 222 } 223 224 static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val) 225 { 226 unsigned int status; 227 int ret; 228 229 ret = regmap_read(data->regmap, ADT7X10_STATUS, &status); 230 if (ret < 0) 231 return ret; 232 233 *val = !!(status & index); 234 235 return 0; 236 } 237 238 static umode_t adt7x10_is_visible(const void *data, 239 enum hwmon_sensor_types type, 240 u32 attr, int channel) 241 { 242 switch (attr) { 243 case hwmon_temp_max: 244 case hwmon_temp_min: 245 case hwmon_temp_crit: 246 case hwmon_temp_max_hyst: 247 return 0644; 248 case hwmon_temp_input: 249 case hwmon_temp_min_alarm: 250 case hwmon_temp_max_alarm: 251 case hwmon_temp_crit_alarm: 252 case hwmon_temp_min_hyst: 253 case hwmon_temp_crit_hyst: 254 return 0444; 255 default: 256 break; 257 } 258 259 return 0; 260 } 261 262 static int adt7x10_read(struct device *dev, enum hwmon_sensor_types type, 263 u32 attr, int channel, long *val) 264 { 265 struct adt7x10_data *data = dev_get_drvdata(dev); 266 267 switch (attr) { 268 case hwmon_temp_input: 269 return adt7x10_temp_read(data, adt7x10_temperature, val); 270 case hwmon_temp_max: 271 return adt7x10_temp_read(data, adt7x10_t_alarm_high, val); 272 case hwmon_temp_min: 273 return adt7x10_temp_read(data, adt7x10_t_alarm_low, val); 274 case hwmon_temp_crit: 275 return adt7x10_temp_read(data, adt7x10_t_crit, val); 276 case hwmon_temp_max_hyst: 277 return adt7x10_hyst_read(data, adt7x10_t_alarm_high, val); 278 case hwmon_temp_min_hyst: 279 return adt7x10_hyst_read(data, adt7x10_t_alarm_low, val); 280 case hwmon_temp_crit_hyst: 281 return adt7x10_hyst_read(data, adt7x10_t_crit, val); 282 case hwmon_temp_min_alarm: 283 return adt7x10_alarm_read(data, ADT7X10_STAT_T_LOW, val); 284 case hwmon_temp_max_alarm: 285 return adt7x10_alarm_read(data, ADT7X10_STAT_T_HIGH, val); 286 case hwmon_temp_crit_alarm: 287 return adt7x10_alarm_read(data, ADT7X10_STAT_T_CRIT, val); 288 default: 289 return -EOPNOTSUPP; 290 } 291 } 292 293 static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type, 294 u32 attr, int channel, long val) 295 { 296 struct adt7x10_data *data = dev_get_drvdata(dev); 297 298 switch (attr) { 299 case hwmon_temp_max: 300 return adt7x10_temp_write(data, adt7x10_t_alarm_high, val); 301 case hwmon_temp_min: 302 return adt7x10_temp_write(data, adt7x10_t_alarm_low, val); 303 case hwmon_temp_crit: 304 return adt7x10_temp_write(data, adt7x10_t_crit, val); 305 case hwmon_temp_max_hyst: 306 return adt7x10_hyst_write(data, val); 307 default: 308 return -EOPNOTSUPP; 309 } 310 } 311 312 static const struct hwmon_channel_info *adt7x10_info[] = { 313 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 314 HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST | 315 HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM | 316 HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM), 317 NULL, 318 }; 319 320 static const struct hwmon_ops adt7x10_hwmon_ops = { 321 .is_visible = adt7x10_is_visible, 322 .read = adt7x10_read, 323 .write = adt7x10_write, 324 }; 325 326 static const struct hwmon_chip_info adt7x10_chip_info = { 327 .ops = &adt7x10_hwmon_ops, 328 .info = adt7x10_info, 329 }; 330 331 static void adt7x10_restore_config(void *private) 332 { 333 struct adt7x10_data *data = private; 334 335 regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig); 336 } 337 338 int adt7x10_probe(struct device *dev, const char *name, int irq, 339 struct regmap *regmap) 340 { 341 struct adt7x10_data *data; 342 unsigned int config; 343 struct device *hdev; 344 int ret; 345 346 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 347 if (!data) 348 return -ENOMEM; 349 350 data->regmap = regmap; 351 352 dev_set_drvdata(dev, data); 353 mutex_init(&data->update_lock); 354 355 /* configure as specified */ 356 ret = regmap_read(regmap, ADT7X10_CONFIG, &config); 357 if (ret < 0) { 358 dev_dbg(dev, "Can't read config? %d\n", ret); 359 return ret; 360 } 361 data->oldconfig = config; 362 363 /* 364 * Set to 16 bit resolution, continous conversion and comparator mode. 365 */ 366 data->config = data->oldconfig; 367 data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY | 368 ADT7X10_INT_POLARITY); 369 data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE; 370 371 if (data->config != data->oldconfig) { 372 ret = regmap_write(regmap, ADT7X10_CONFIG, data->config); 373 if (ret) 374 return ret; 375 ret = devm_add_action_or_reset(dev, adt7x10_restore_config, data); 376 if (ret) 377 return ret; 378 } 379 dev_dbg(dev, "Config %02x\n", data->config); 380 381 hdev = devm_hwmon_device_register_with_info(dev, name, data, 382 &adt7x10_chip_info, NULL); 383 if (IS_ERR(hdev)) 384 return PTR_ERR(hdev); 385 386 if (irq > 0) { 387 ret = devm_request_threaded_irq(dev, irq, NULL, 388 adt7x10_irq_handler, 389 IRQF_TRIGGER_FALLING | 390 IRQF_ONESHOT, 391 dev_name(dev), hdev); 392 if (ret) 393 return ret; 394 } 395 396 return 0; 397 } 398 EXPORT_SYMBOL_GPL(adt7x10_probe); 399 400 static int adt7x10_suspend(struct device *dev) 401 { 402 struct adt7x10_data *data = dev_get_drvdata(dev); 403 404 return regmap_write(data->regmap, ADT7X10_CONFIG, 405 data->config | ADT7X10_PD); 406 } 407 408 static int adt7x10_resume(struct device *dev) 409 { 410 struct adt7x10_data *data = dev_get_drvdata(dev); 411 412 return regmap_write(data->regmap, ADT7X10_CONFIG, data->config); 413 } 414 415 EXPORT_SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume); 416 417 MODULE_AUTHOR("Hartmut Knaack"); 418 MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code"); 419 MODULE_LICENSE("GPL"); 420