adt7x10.c 9.9 KB

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