ir35221.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. * Hardware monitoring driver for IR35221
  3. *
  4. * Copyright (C) IBM Corporation 2017.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/err.h>
  12. #include <linux/i2c.h>
  13. #include <linux/init.h>
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include "pmbus.h"
  17. #define IR35221_MFR_VIN_PEAK 0xc5
  18. #define IR35221_MFR_VOUT_PEAK 0xc6
  19. #define IR35221_MFR_IOUT_PEAK 0xc7
  20. #define IR35221_MFR_TEMP_PEAK 0xc8
  21. #define IR35221_MFR_VIN_VALLEY 0xc9
  22. #define IR35221_MFR_VOUT_VALLEY 0xca
  23. #define IR35221_MFR_IOUT_VALLEY 0xcb
  24. #define IR35221_MFR_TEMP_VALLEY 0xcc
  25. static long ir35221_reg2data(int data, enum pmbus_sensor_classes class)
  26. {
  27. s16 exponent;
  28. s32 mantissa;
  29. long val;
  30. /* We only modify LINEAR11 formats */
  31. exponent = ((s16)data) >> 11;
  32. mantissa = ((s16)((data & 0x7ff) << 5)) >> 5;
  33. val = mantissa * 1000L;
  34. /* scale result to micro-units for power sensors */
  35. if (class == PSC_POWER)
  36. val = val * 1000L;
  37. if (exponent >= 0)
  38. val <<= exponent;
  39. else
  40. val >>= -exponent;
  41. return val;
  42. }
  43. #define MAX_MANTISSA (1023 * 1000)
  44. #define MIN_MANTISSA (511 * 1000)
  45. static u16 ir35221_data2reg(long val, enum pmbus_sensor_classes class)
  46. {
  47. s16 exponent = 0, mantissa;
  48. bool negative = false;
  49. if (val == 0)
  50. return 0;
  51. if (val < 0) {
  52. negative = true;
  53. val = -val;
  54. }
  55. /* Power is in uW. Convert to mW before converting. */
  56. if (class == PSC_POWER)
  57. val = DIV_ROUND_CLOSEST(val, 1000L);
  58. /* Reduce large mantissa until it fits into 10 bit */
  59. while (val >= MAX_MANTISSA && exponent < 15) {
  60. exponent++;
  61. val >>= 1;
  62. }
  63. /* Increase small mantissa to improve precision */
  64. while (val < MIN_MANTISSA && exponent > -15) {
  65. exponent--;
  66. val <<= 1;
  67. }
  68. /* Convert mantissa from milli-units to units */
  69. mantissa = DIV_ROUND_CLOSEST(val, 1000);
  70. /* Ensure that resulting number is within range */
  71. if (mantissa > 0x3ff)
  72. mantissa = 0x3ff;
  73. /* restore sign */
  74. if (negative)
  75. mantissa = -mantissa;
  76. /* Convert to 5 bit exponent, 11 bit mantissa */
  77. return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
  78. }
  79. static u16 ir35221_scale_result(s16 data, int shift,
  80. enum pmbus_sensor_classes class)
  81. {
  82. long val;
  83. val = ir35221_reg2data(data, class);
  84. if (shift < 0)
  85. val >>= -shift;
  86. else
  87. val <<= shift;
  88. return ir35221_data2reg(val, class);
  89. }
  90. static int ir35221_read_word_data(struct i2c_client *client, int page, int reg)
  91. {
  92. int ret;
  93. switch (reg) {
  94. case PMBUS_IOUT_OC_FAULT_LIMIT:
  95. case PMBUS_IOUT_OC_WARN_LIMIT:
  96. ret = pmbus_read_word_data(client, page, reg);
  97. if (ret < 0)
  98. break;
  99. ret = ir35221_scale_result(ret, 1, PSC_CURRENT_OUT);
  100. break;
  101. case PMBUS_VIN_OV_FAULT_LIMIT:
  102. case PMBUS_VIN_OV_WARN_LIMIT:
  103. case PMBUS_VIN_UV_WARN_LIMIT:
  104. ret = pmbus_read_word_data(client, page, reg);
  105. ret = ir35221_scale_result(ret, -4, PSC_VOLTAGE_IN);
  106. break;
  107. case PMBUS_IIN_OC_WARN_LIMIT:
  108. ret = pmbus_read_word_data(client, page, reg);
  109. if (ret < 0)
  110. break;
  111. ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
  112. break;
  113. case PMBUS_READ_VIN:
  114. ret = pmbus_read_word_data(client, page, PMBUS_READ_VIN);
  115. if (ret < 0)
  116. break;
  117. ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
  118. break;
  119. case PMBUS_READ_IIN:
  120. ret = pmbus_read_word_data(client, page, PMBUS_READ_IIN);
  121. if (ret < 0)
  122. break;
  123. if (page == 0)
  124. ret = ir35221_scale_result(ret, -4, PSC_CURRENT_IN);
  125. else
  126. ret = ir35221_scale_result(ret, -5, PSC_CURRENT_IN);
  127. break;
  128. case PMBUS_READ_POUT:
  129. ret = pmbus_read_word_data(client, page, PMBUS_READ_POUT);
  130. if (ret < 0)
  131. break;
  132. ret = ir35221_scale_result(ret, -1, PSC_POWER);
  133. break;
  134. case PMBUS_READ_PIN:
  135. ret = pmbus_read_word_data(client, page, PMBUS_READ_PIN);
  136. if (ret < 0)
  137. break;
  138. ret = ir35221_scale_result(ret, -1, PSC_POWER);
  139. break;
  140. case PMBUS_READ_IOUT:
  141. ret = pmbus_read_word_data(client, page, PMBUS_READ_IOUT);
  142. if (ret < 0)
  143. break;
  144. if (page == 0)
  145. ret = ir35221_scale_result(ret, -1, PSC_CURRENT_OUT);
  146. else
  147. ret = ir35221_scale_result(ret, -2, PSC_CURRENT_OUT);
  148. break;
  149. case PMBUS_VIRT_READ_VIN_MAX:
  150. ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK);
  151. if (ret < 0)
  152. break;
  153. ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
  154. break;
  155. case PMBUS_VIRT_READ_VOUT_MAX:
  156. ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK);
  157. break;
  158. case PMBUS_VIRT_READ_IOUT_MAX:
  159. ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK);
  160. if (ret < 0)
  161. break;
  162. if (page == 0)
  163. ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
  164. else
  165. ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN);
  166. break;
  167. case PMBUS_VIRT_READ_TEMP_MAX:
  168. ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK);
  169. break;
  170. case PMBUS_VIRT_READ_VIN_MIN:
  171. ret = pmbus_read_word_data(client, page,
  172. IR35221_MFR_VIN_VALLEY);
  173. if (ret < 0)
  174. break;
  175. ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
  176. break;
  177. case PMBUS_VIRT_READ_VOUT_MIN:
  178. ret = pmbus_read_word_data(client, page,
  179. IR35221_MFR_VOUT_VALLEY);
  180. break;
  181. case PMBUS_VIRT_READ_IOUT_MIN:
  182. ret = pmbus_read_word_data(client, page,
  183. IR35221_MFR_IOUT_VALLEY);
  184. if (ret < 0)
  185. break;
  186. if (page == 0)
  187. ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
  188. else
  189. ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN);
  190. break;
  191. case PMBUS_VIRT_READ_TEMP_MIN:
  192. ret = pmbus_read_word_data(client, page,
  193. IR35221_MFR_TEMP_VALLEY);
  194. break;
  195. default:
  196. ret = -ENODATA;
  197. break;
  198. }
  199. return ret;
  200. }
  201. static int ir35221_write_word_data(struct i2c_client *client, int page, int reg,
  202. u16 word)
  203. {
  204. int ret;
  205. u16 val;
  206. switch (reg) {
  207. case PMBUS_IOUT_OC_FAULT_LIMIT:
  208. case PMBUS_IOUT_OC_WARN_LIMIT:
  209. val = ir35221_scale_result(word, -1, PSC_CURRENT_OUT);
  210. ret = pmbus_write_word_data(client, page, reg, val);
  211. break;
  212. case PMBUS_VIN_OV_FAULT_LIMIT:
  213. case PMBUS_VIN_OV_WARN_LIMIT:
  214. case PMBUS_VIN_UV_WARN_LIMIT:
  215. val = ir35221_scale_result(word, 4, PSC_VOLTAGE_IN);
  216. ret = pmbus_write_word_data(client, page, reg, val);
  217. break;
  218. case PMBUS_IIN_OC_WARN_LIMIT:
  219. val = ir35221_scale_result(word, 1, PSC_CURRENT_IN);
  220. ret = pmbus_write_word_data(client, page, reg, val);
  221. break;
  222. default:
  223. ret = -ENODATA;
  224. break;
  225. }
  226. return ret;
  227. }
  228. static int ir35221_probe(struct i2c_client *client,
  229. const struct i2c_device_id *id)
  230. {
  231. struct pmbus_driver_info *info;
  232. u8 buf[I2C_SMBUS_BLOCK_MAX];
  233. int ret;
  234. if (!i2c_check_functionality(client->adapter,
  235. I2C_FUNC_SMBUS_READ_BYTE_DATA
  236. | I2C_FUNC_SMBUS_READ_WORD_DATA
  237. | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
  238. return -ENODEV;
  239. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
  240. if (ret < 0) {
  241. dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
  242. return ret;
  243. }
  244. if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
  245. dev_err(&client->dev, "MFR_ID unrecognised\n");
  246. return -ENODEV;
  247. }
  248. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
  249. if (ret < 0) {
  250. dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
  251. return ret;
  252. }
  253. if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
  254. dev_err(&client->dev, "MFR_MODEL unrecognised\n");
  255. return -ENODEV;
  256. }
  257. info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
  258. GFP_KERNEL);
  259. if (!info)
  260. return -ENOMEM;
  261. info->write_word_data = ir35221_write_word_data;
  262. info->read_word_data = ir35221_read_word_data;
  263. info->pages = 2;
  264. info->format[PSC_VOLTAGE_IN] = linear;
  265. info->format[PSC_VOLTAGE_OUT] = linear;
  266. info->format[PSC_CURRENT_IN] = linear;
  267. info->format[PSC_CURRENT_OUT] = linear;
  268. info->format[PSC_POWER] = linear;
  269. info->format[PSC_TEMPERATURE] = linear;
  270. info->func[0] = PMBUS_HAVE_VIN
  271. | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
  272. | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
  273. | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
  274. | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
  275. | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
  276. info->func[1] = info->func[0];
  277. return pmbus_do_probe(client, id, info);
  278. }
  279. static const struct i2c_device_id ir35221_id[] = {
  280. {"ir35221", 0},
  281. {}
  282. };
  283. MODULE_DEVICE_TABLE(i2c, ir35221_id);
  284. static struct i2c_driver ir35221_driver = {
  285. .driver = {
  286. .name = "ir35221",
  287. },
  288. .probe = ir35221_probe,
  289. .remove = pmbus_do_remove,
  290. .id_table = ir35221_id,
  291. };
  292. module_i2c_driver(ir35221_driver);
  293. MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
  294. MODULE_DESCRIPTION("PMBus driver for IR35221");
  295. MODULE_LICENSE("GPL");