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 unsigned int regs[2] = {ADT7X10_T_HYST, ADT7X10_REG_TEMP[index]}; 174 int hyst, ret; 175 u16 regdata[2]; 176 177 ret = regmap_multi_reg_read(data->regmap, regs, regdata, 2); 178 if (ret) 179 return ret; 180 181 hyst = (regdata[0] & ADT7X10_T_HYST_MASK) * 1000; 182 183 /* 184 * hysteresis is stored as a 4 bit offset in the device, convert it 185 * to an absolute value 186 */ 187 /* min has positive offset, others have negative */ 188 if (index == adt7x10_t_alarm_low) 189 hyst = -hyst; 190 191 *val = ADT7X10_REG_TO_TEMP(data, regdata[1]) - hyst; 192 return 0; 193 } 194 195 static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst) 196 { 197 unsigned int regval; 198 int limit, ret; 199 200 mutex_lock(&data->update_lock); 201 202 /* convert absolute hysteresis value to a 4 bit delta value */ 203 ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, ®val); 204 if (ret < 0) 205 goto abort; 206 207 limit = ADT7X10_REG_TO_TEMP(data, regval); 208 209 hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX); 210 regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0, 211 ADT7X10_T_HYST_MASK); 212 ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval); 213 abort: 214 mutex_unlock(&data->update_lock); 215 return ret; 216 } 217 218 static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val) 219 { 220 unsigned int status; 221 int ret; 222 223 ret = regmap_read(data->regmap, ADT7X10_STATUS, &status); 224 if (ret < 0) 225 return ret; 226 227 *val = !!(status & index); 228 229 return 0; 230 } 231 232 static umode_t adt7x10_is_visible(const void *data, 233 enum hwmon_sensor_types type, 234 u32 attr, int channel) 235 { 236 switch (attr) { 237 case hwmon_temp_max: 238 case hwmon_temp_min: 239 case hwmon_temp_crit: 240 case hwmon_temp_max_hyst: 241 return 0644; 242 case hwmon_temp_input: 243 case hwmon_temp_min_alarm: 244 case hwmon_temp_max_alarm: 245 case hwmon_temp_crit_alarm: 246 case hwmon_temp_min_hyst: 247 case hwmon_temp_crit_hyst: 248 return 0444; 249 default: 250 break; 251 } 252 253 return 0; 254 } 255 256 static int adt7x10_read(struct device *dev, enum hwmon_sensor_types type, 257 u32 attr, int channel, long *val) 258 { 259 struct adt7x10_data *data = dev_get_drvdata(dev); 260 261 switch (attr) { 262 case hwmon_temp_input: 263 return adt7x10_temp_read(data, adt7x10_temperature, val); 264 case hwmon_temp_max: 265 return adt7x10_temp_read(data, adt7x10_t_alarm_high, val); 266 case hwmon_temp_min: 267 return adt7x10_temp_read(data, adt7x10_t_alarm_low, val); 268 case hwmon_temp_crit: 269 return adt7x10_temp_read(data, adt7x10_t_crit, val); 270 case hwmon_temp_max_hyst: 271 return adt7x10_hyst_read(data, adt7x10_t_alarm_high, val); 272 case hwmon_temp_min_hyst: 273 return adt7x10_hyst_read(data, adt7x10_t_alarm_low, val); 274 case hwmon_temp_crit_hyst: 275 return adt7x10_hyst_read(data, adt7x10_t_crit, val); 276 case hwmon_temp_min_alarm: 277 return adt7x10_alarm_read(data, ADT7X10_STAT_T_LOW, val); 278 case hwmon_temp_max_alarm: 279 return adt7x10_alarm_read(data, ADT7X10_STAT_T_HIGH, val); 280 case hwmon_temp_crit_alarm: 281 return adt7x10_alarm_read(data, ADT7X10_STAT_T_CRIT, val); 282 default: 283 return -EOPNOTSUPP; 284 } 285 } 286 287 static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type, 288 u32 attr, int channel, long val) 289 { 290 struct adt7x10_data *data = dev_get_drvdata(dev); 291 292 switch (attr) { 293 case hwmon_temp_max: 294 return adt7x10_temp_write(data, adt7x10_t_alarm_high, val); 295 case hwmon_temp_min: 296 return adt7x10_temp_write(data, adt7x10_t_alarm_low, val); 297 case hwmon_temp_crit: 298 return adt7x10_temp_write(data, adt7x10_t_crit, val); 299 case hwmon_temp_max_hyst: 300 return adt7x10_hyst_write(data, val); 301 default: 302 return -EOPNOTSUPP; 303 } 304 } 305 306 static const struct hwmon_channel_info * const adt7x10_info[] = { 307 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 308 HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST | 309 HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM | 310 HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM), 311 NULL, 312 }; 313 314 static const struct hwmon_ops adt7x10_hwmon_ops = { 315 .is_visible = adt7x10_is_visible, 316 .read = adt7x10_read, 317 .write = adt7x10_write, 318 }; 319 320 static const struct hwmon_chip_info adt7x10_chip_info = { 321 .ops = &adt7x10_hwmon_ops, 322 .info = adt7x10_info, 323 }; 324 325 static void adt7x10_restore_config(void *private) 326 { 327 struct adt7x10_data *data = private; 328 329 regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig); 330 } 331 332 int adt7x10_probe(struct device *dev, const char *name, int irq, 333 struct regmap *regmap) 334 { 335 struct adt7x10_data *data; 336 unsigned int config; 337 struct device *hdev; 338 int ret; 339 340 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 341 if (!data) 342 return -ENOMEM; 343 344 data->regmap = regmap; 345 346 dev_set_drvdata(dev, data); 347 mutex_init(&data->update_lock); 348 349 /* configure as specified */ 350 ret = regmap_read(regmap, ADT7X10_CONFIG, &config); 351 if (ret < 0) { 352 dev_dbg(dev, "Can't read config? %d\n", ret); 353 return ret; 354 } 355 data->oldconfig = config; 356 357 /* 358 * Set to 16 bit resolution, continous conversion and comparator mode. 359 */ 360 data->config = data->oldconfig; 361 data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY | 362 ADT7X10_INT_POLARITY); 363 data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE; 364 365 if (data->config != data->oldconfig) { 366 ret = regmap_write(regmap, ADT7X10_CONFIG, data->config); 367 if (ret) 368 return ret; 369 ret = devm_add_action_or_reset(dev, adt7x10_restore_config, data); 370 if (ret) 371 return ret; 372 } 373 dev_dbg(dev, "Config %02x\n", data->config); 374 375 hdev = devm_hwmon_device_register_with_info(dev, name, data, 376 &adt7x10_chip_info, NULL); 377 if (IS_ERR(hdev)) 378 return PTR_ERR(hdev); 379 380 if (irq > 0) { 381 ret = devm_request_threaded_irq(dev, irq, NULL, 382 adt7x10_irq_handler, 383 IRQF_TRIGGER_FALLING | 384 IRQF_ONESHOT, 385 dev_name(dev), hdev); 386 if (ret) 387 return ret; 388 } 389 390 return 0; 391 } 392 EXPORT_SYMBOL_GPL(adt7x10_probe); 393 394 static int adt7x10_suspend(struct device *dev) 395 { 396 struct adt7x10_data *data = dev_get_drvdata(dev); 397 398 return regmap_write(data->regmap, ADT7X10_CONFIG, 399 data->config | ADT7X10_PD); 400 } 401 402 static int adt7x10_resume(struct device *dev) 403 { 404 struct adt7x10_data *data = dev_get_drvdata(dev); 405 406 return regmap_write(data->regmap, ADT7X10_CONFIG, data->config); 407 } 408 409 EXPORT_SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume); 410 411 MODULE_AUTHOR("Hartmut Knaack"); 412 MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code"); 413 MODULE_LICENSE("GPL"); 414