ltc3815.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Hardware monitoring driver for LTC3815
  4. *
  5. * Copyright (c) 2015 Linear Technology
  6. * Copyright (c) 2015 Guenter Roeck
  7. */
  8. #include <linux/err.h>
  9. #include <linux/i2c.h>
  10. #include <linux/init.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include "pmbus.h"
  15. #define LTC3815_MFR_IOUT_PEAK 0xd7
  16. #define LTC3815_MFR_VOUT_PEAK 0xdd
  17. #define LTC3815_MFR_VIN_PEAK 0xde
  18. #define LTC3815_MFR_TEMP_PEAK 0xdf
  19. #define LTC3815_MFR_IIN_PEAK 0xe1
  20. #define LTC3815_MFR_SPECIAL_ID 0xe7
  21. #define LTC3815_ID 0x8000
  22. #define LTC3815_ID_MASK 0xff00
  23. static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
  24. {
  25. int ret;
  26. switch (reg) {
  27. case PMBUS_VOUT_MODE:
  28. /*
  29. * The chip returns 0x3e, suggesting VID mode with manufacturer
  30. * specific VID codes. Since the output voltage is reported
  31. * with a LSB of 0.5mV, override and report direct mode with
  32. * appropriate coefficients.
  33. */
  34. ret = 0x40;
  35. break;
  36. default:
  37. ret = -ENODATA;
  38. break;
  39. }
  40. return ret;
  41. }
  42. static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
  43. {
  44. int ret;
  45. switch (reg) {
  46. case PMBUS_CLEAR_FAULTS:
  47. /*
  48. * LTC3815 does not support the CLEAR_FAULTS command.
  49. * Emulate it by clearing the status register.
  50. */
  51. ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_WORD);
  52. if (ret > 0) {
  53. pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
  54. ret);
  55. ret = 0;
  56. }
  57. break;
  58. default:
  59. ret = -ENODATA;
  60. break;
  61. }
  62. return ret;
  63. }
  64. static int ltc3815_read_word_data(struct i2c_client *client, int page,
  65. int phase, int reg)
  66. {
  67. int ret;
  68. switch (reg) {
  69. case PMBUS_VIRT_READ_VIN_MAX:
  70. ret = pmbus_read_word_data(client, page, phase,
  71. LTC3815_MFR_VIN_PEAK);
  72. break;
  73. case PMBUS_VIRT_READ_VOUT_MAX:
  74. ret = pmbus_read_word_data(client, page, phase,
  75. LTC3815_MFR_VOUT_PEAK);
  76. break;
  77. case PMBUS_VIRT_READ_TEMP_MAX:
  78. ret = pmbus_read_word_data(client, page, phase,
  79. LTC3815_MFR_TEMP_PEAK);
  80. break;
  81. case PMBUS_VIRT_READ_IOUT_MAX:
  82. ret = pmbus_read_word_data(client, page, phase,
  83. LTC3815_MFR_IOUT_PEAK);
  84. break;
  85. case PMBUS_VIRT_READ_IIN_MAX:
  86. ret = pmbus_read_word_data(client, page, phase,
  87. LTC3815_MFR_IIN_PEAK);
  88. break;
  89. case PMBUS_VIRT_RESET_VOUT_HISTORY:
  90. case PMBUS_VIRT_RESET_VIN_HISTORY:
  91. case PMBUS_VIRT_RESET_TEMP_HISTORY:
  92. case PMBUS_VIRT_RESET_IOUT_HISTORY:
  93. case PMBUS_VIRT_RESET_IIN_HISTORY:
  94. ret = 0;
  95. break;
  96. default:
  97. ret = -ENODATA;
  98. break;
  99. }
  100. return ret;
  101. }
  102. static int ltc3815_write_word_data(struct i2c_client *client, int page,
  103. int reg, u16 word)
  104. {
  105. int ret;
  106. switch (reg) {
  107. case PMBUS_VIRT_RESET_IIN_HISTORY:
  108. ret = pmbus_write_word_data(client, page,
  109. LTC3815_MFR_IIN_PEAK, 0);
  110. break;
  111. case PMBUS_VIRT_RESET_IOUT_HISTORY:
  112. ret = pmbus_write_word_data(client, page,
  113. LTC3815_MFR_IOUT_PEAK, 0);
  114. break;
  115. case PMBUS_VIRT_RESET_VOUT_HISTORY:
  116. ret = pmbus_write_word_data(client, page,
  117. LTC3815_MFR_VOUT_PEAK, 0);
  118. break;
  119. case PMBUS_VIRT_RESET_VIN_HISTORY:
  120. ret = pmbus_write_word_data(client, page,
  121. LTC3815_MFR_VIN_PEAK, 0);
  122. break;
  123. case PMBUS_VIRT_RESET_TEMP_HISTORY:
  124. ret = pmbus_write_word_data(client, page,
  125. LTC3815_MFR_TEMP_PEAK, 0);
  126. break;
  127. default:
  128. ret = -ENODATA;
  129. break;
  130. }
  131. return ret;
  132. }
  133. static const struct i2c_device_id ltc3815_id[] = {
  134. {"ltc3815", 0},
  135. { }
  136. };
  137. MODULE_DEVICE_TABLE(i2c, ltc3815_id);
  138. static struct pmbus_driver_info ltc3815_info = {
  139. .pages = 1,
  140. .format[PSC_VOLTAGE_IN] = direct,
  141. .format[PSC_VOLTAGE_OUT] = direct,
  142. .format[PSC_CURRENT_IN] = direct,
  143. .format[PSC_CURRENT_OUT] = direct,
  144. .format[PSC_TEMPERATURE] = direct,
  145. .m[PSC_VOLTAGE_IN] = 250,
  146. .b[PSC_VOLTAGE_IN] = 0,
  147. .R[PSC_VOLTAGE_IN] = 0,
  148. .m[PSC_VOLTAGE_OUT] = 2,
  149. .b[PSC_VOLTAGE_OUT] = 0,
  150. .R[PSC_VOLTAGE_OUT] = 3,
  151. .m[PSC_CURRENT_IN] = 1,
  152. .b[PSC_CURRENT_IN] = 0,
  153. .R[PSC_CURRENT_IN] = 2,
  154. .m[PSC_CURRENT_OUT] = 1,
  155. .b[PSC_CURRENT_OUT] = 0,
  156. .R[PSC_CURRENT_OUT] = 2,
  157. .m[PSC_TEMPERATURE] = 1,
  158. .b[PSC_TEMPERATURE] = 0,
  159. .R[PSC_TEMPERATURE] = 0,
  160. .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
  161. PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
  162. .read_byte_data = ltc3815_read_byte_data,
  163. .read_word_data = ltc3815_read_word_data,
  164. .write_byte = ltc3815_write_byte,
  165. .write_word_data = ltc3815_write_word_data,
  166. };
  167. static int ltc3815_probe(struct i2c_client *client)
  168. {
  169. int chip_id;
  170. if (!i2c_check_functionality(client->adapter,
  171. I2C_FUNC_SMBUS_READ_WORD_DATA))
  172. return -ENODEV;
  173. chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
  174. if (chip_id < 0)
  175. return chip_id;
  176. if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
  177. return -ENODEV;
  178. return pmbus_do_probe(client, &ltc3815_info);
  179. }
  180. static struct i2c_driver ltc3815_driver = {
  181. .driver = {
  182. .name = "ltc3815",
  183. },
  184. .probe_new = ltc3815_probe,
  185. .id_table = ltc3815_id,
  186. };
  187. module_i2c_driver(ltc3815_driver);
  188. MODULE_AUTHOR("Guenter Roeck");
  189. MODULE_DESCRIPTION("PMBus driver for LTC3815");
  190. MODULE_LICENSE("GPL");
  191. MODULE_IMPORT_NS(PMBUS);