xdpe12284.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers
  4. *
  5. * Copyright (c) 2020 Mellanox Technologies. All rights reserved.
  6. */
  7. #include <linux/err.h>
  8. #include <linux/i2c.h>
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/regulator/driver.h>
  13. #include "pmbus.h"
  14. #define XDPE122_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
  15. #define XDPE122_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
  16. #define XDPE122_PROT_IMVP9_10MV 0x03 /* IMVP9 mode, 10-mV DAC */
  17. #define XDPE122_AMD_625MV 0x10 /* AMD mode 6.25mV */
  18. #define XDPE122_PAGE_NUM 2
  19. static int xdpe122_read_word_data(struct i2c_client *client, int page,
  20. int phase, int reg)
  21. {
  22. const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
  23. long val;
  24. s16 exponent;
  25. s32 mantissa;
  26. int ret;
  27. switch (reg) {
  28. case PMBUS_VOUT_OV_FAULT_LIMIT:
  29. case PMBUS_VOUT_UV_FAULT_LIMIT:
  30. ret = pmbus_read_word_data(client, page, phase, reg);
  31. if (ret < 0)
  32. return ret;
  33. /* Convert register value to LINEAR11 data. */
  34. exponent = ((s16)ret) >> 11;
  35. mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5;
  36. val = mantissa * 1000L;
  37. if (exponent >= 0)
  38. val <<= exponent;
  39. else
  40. val >>= -exponent;
  41. /* Convert data to VID register. */
  42. switch (info->vrm_version[page]) {
  43. case vr13:
  44. if (val >= 500)
  45. return 1 + DIV_ROUND_CLOSEST(val - 500, 10);
  46. return 0;
  47. case vr12:
  48. if (val >= 250)
  49. return 1 + DIV_ROUND_CLOSEST(val - 250, 5);
  50. return 0;
  51. case imvp9:
  52. if (val >= 200)
  53. return 1 + DIV_ROUND_CLOSEST(val - 200, 10);
  54. return 0;
  55. case amd625mv:
  56. if (val >= 200 && val <= 1550)
  57. return DIV_ROUND_CLOSEST((1550 - val) * 100,
  58. 625);
  59. return 0;
  60. default:
  61. return -EINVAL;
  62. }
  63. default:
  64. return -ENODATA;
  65. }
  66. return 0;
  67. }
  68. static int xdpe122_identify(struct i2c_client *client,
  69. struct pmbus_driver_info *info)
  70. {
  71. u8 vout_params;
  72. int i, ret, vout_mode;
  73. vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
  74. if (vout_mode >= 0 && vout_mode != 0xff) {
  75. switch (vout_mode >> 5) {
  76. case 0:
  77. info->format[PSC_VOLTAGE_OUT] = linear;
  78. return 0;
  79. case 1:
  80. info->format[PSC_VOLTAGE_OUT] = vid;
  81. info->read_word_data = xdpe122_read_word_data;
  82. break;
  83. default:
  84. return -ENODEV;
  85. }
  86. }
  87. for (i = 0; i < XDPE122_PAGE_NUM; i++) {
  88. /* Read the register with VOUT scaling value.*/
  89. ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
  90. if (ret < 0)
  91. return ret;
  92. vout_params = ret & GENMASK(4, 0);
  93. switch (vout_params) {
  94. case XDPE122_PROT_VR12_5_10MV:
  95. info->vrm_version[i] = vr13;
  96. break;
  97. case XDPE122_PROT_VR12_5MV:
  98. info->vrm_version[i] = vr12;
  99. break;
  100. case XDPE122_PROT_IMVP9_10MV:
  101. info->vrm_version[i] = imvp9;
  102. break;
  103. case XDPE122_AMD_625MV:
  104. info->vrm_version[i] = amd625mv;
  105. break;
  106. default:
  107. return -EINVAL;
  108. }
  109. }
  110. return 0;
  111. }
  112. static const struct regulator_desc __maybe_unused xdpe122_reg_desc[] = {
  113. PMBUS_REGULATOR("vout", 0),
  114. PMBUS_REGULATOR("vout", 1),
  115. };
  116. static struct pmbus_driver_info xdpe122_info = {
  117. .pages = XDPE122_PAGE_NUM,
  118. .format[PSC_VOLTAGE_IN] = linear,
  119. .format[PSC_TEMPERATURE] = linear,
  120. .format[PSC_CURRENT_IN] = linear,
  121. .format[PSC_CURRENT_OUT] = linear,
  122. .format[PSC_POWER] = linear,
  123. .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
  124. PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
  125. PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
  126. PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
  127. .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
  128. PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
  129. PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
  130. PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
  131. .identify = xdpe122_identify,
  132. #if IS_ENABLED(CONFIG_SENSORS_XDPE122_REGULATOR)
  133. .num_regulators = 2,
  134. .reg_desc = xdpe122_reg_desc,
  135. #endif
  136. };
  137. static int xdpe122_probe(struct i2c_client *client)
  138. {
  139. struct pmbus_driver_info *info;
  140. info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info),
  141. GFP_KERNEL);
  142. if (!info)
  143. return -ENOMEM;
  144. return pmbus_do_probe(client, info);
  145. }
  146. static const struct i2c_device_id xdpe122_id[] = {
  147. {"xdpe11280", 0},
  148. {"xdpe12254", 0},
  149. {"xdpe12284", 0},
  150. {}
  151. };
  152. MODULE_DEVICE_TABLE(i2c, xdpe122_id);
  153. static const struct of_device_id __maybe_unused xdpe122_of_match[] = {
  154. {.compatible = "infineon,xdpe11280"},
  155. {.compatible = "infineon,xdpe12254"},
  156. {.compatible = "infineon,xdpe12284"},
  157. {}
  158. };
  159. MODULE_DEVICE_TABLE(of, xdpe122_of_match);
  160. static struct i2c_driver xdpe122_driver = {
  161. .driver = {
  162. .name = "xdpe12284",
  163. .of_match_table = of_match_ptr(xdpe122_of_match),
  164. },
  165. .probe_new = xdpe122_probe,
  166. .id_table = xdpe122_id,
  167. };
  168. module_i2c_driver(xdpe122_driver);
  169. MODULE_AUTHOR("Vadim Pasternak <[email protected]>");
  170. MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family");
  171. MODULE_LICENSE("GPL");
  172. MODULE_IMPORT_NS(PMBUS);