ltc4286.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <linux/err.h>
  3. #include <linux/i2c.h>
  4. #include <linux/init.h>
  5. #include <linux/kernel.h>
  6. #include <linux/module.h>
  7. #include <linux/pmbus.h>
  8. #include "pmbus.h"
  9. /* LTC4286 register */
  10. #define LTC4286_MFR_CONFIG1 0xF2
  11. /* LTC4286 configuration */
  12. #define VRANGE_SELECT_BIT BIT(1)
  13. #define LTC4286_MFR_ID_SIZE 3
  14. /*
  15. * Initialize the MBR as default settings which is referred to LTC4286 datasheet
  16. * (March 22, 2022 version) table 3 page 16
  17. */
  18. static struct pmbus_driver_info ltc4286_info = {
  19. .pages = 1,
  20. .format[PSC_VOLTAGE_IN] = direct,
  21. .format[PSC_VOLTAGE_OUT] = direct,
  22. .format[PSC_CURRENT_OUT] = direct,
  23. .format[PSC_POWER] = direct,
  24. .format[PSC_TEMPERATURE] = direct,
  25. .m[PSC_VOLTAGE_IN] = 32,
  26. .b[PSC_VOLTAGE_IN] = 0,
  27. .R[PSC_VOLTAGE_IN] = 1,
  28. .m[PSC_VOLTAGE_OUT] = 32,
  29. .b[PSC_VOLTAGE_OUT] = 0,
  30. .R[PSC_VOLTAGE_OUT] = 1,
  31. .m[PSC_CURRENT_OUT] = 1024,
  32. .b[PSC_CURRENT_OUT] = 0,
  33. /*
  34. * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit.
  35. * However, the rsense value that user input is micro ohm.
  36. * Thus, the MBR setting which involves rsense should be shifted by 6 digits.
  37. */
  38. .R[PSC_CURRENT_OUT] = 3 - 6,
  39. .m[PSC_POWER] = 1,
  40. .b[PSC_POWER] = 0,
  41. /*
  42. * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit.
  43. * However, the rsense value that user input is micro ohm.
  44. * Thus, the MBR setting which involves rsense should be shifted by 6 digits.
  45. */
  46. .R[PSC_POWER] = 4 - 6,
  47. .m[PSC_TEMPERATURE] = 1,
  48. .b[PSC_TEMPERATURE] = 273,
  49. .R[PSC_TEMPERATURE] = 0,
  50. .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
  51. PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT |
  52. PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP,
  53. };
  54. static const struct i2c_device_id ltc4286_id[] = {
  55. { "ltc4286", },
  56. { "ltc4287", },
  57. {}
  58. };
  59. MODULE_DEVICE_TABLE(i2c, ltc4286_id);
  60. static int ltc4286_probe(struct i2c_client *client)
  61. {
  62. int ret;
  63. const struct i2c_device_id *mid;
  64. u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
  65. struct pmbus_driver_info *info;
  66. u32 rsense;
  67. int vrange_nval, vrange_oval;
  68. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
  69. if (ret < 0) {
  70. return dev_err_probe(&client->dev, ret,
  71. "Failed to read manufacturer id\n");
  72. }
  73. /*
  74. * Refer to ltc4286 datasheet page 20
  75. * the manufacturer id is LTC
  76. */
  77. if (ret != LTC4286_MFR_ID_SIZE ||
  78. strncmp(block_buffer, "LTC", LTC4286_MFR_ID_SIZE)) {
  79. return dev_err_probe(&client->dev, -ENODEV,
  80. "Manufacturer id mismatch\n");
  81. }
  82. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
  83. if (ret < 0) {
  84. return dev_err_probe(&client->dev, ret,
  85. "Failed to read manufacturer model\n");
  86. }
  87. for (mid = ltc4286_id; mid->name[0]; mid++) {
  88. if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
  89. break;
  90. }
  91. if (!mid->name[0])
  92. return dev_err_probe(&client->dev, -ENODEV,
  93. "Unsupported device\n");
  94. if (of_property_read_u32(client->dev.of_node,
  95. "shunt-resistor-micro-ohms", &rsense))
  96. rsense = 300; /* 0.3 mOhm if not set via DT */
  97. if (rsense == 0)
  98. return -EINVAL;
  99. /* Check for the latter MBR value won't overflow */
  100. if (rsense > (INT_MAX / 1024))
  101. return -EINVAL;
  102. info = devm_kmemdup(&client->dev, &ltc4286_info, sizeof(*info),
  103. GFP_KERNEL);
  104. if (!info)
  105. return -ENOMEM;
  106. /* Check MFR1 CONFIG register bit 1 VRANGE_SELECT before driver loading */
  107. vrange_oval = i2c_smbus_read_word_data(client, LTC4286_MFR_CONFIG1);
  108. if (vrange_oval < 0)
  109. return dev_err_probe(&client->dev, vrange_oval,
  110. "Failed to read manufacturer configuration one\n");
  111. vrange_nval = vrange_oval;
  112. if (device_property_read_bool(&client->dev, "adi,vrange-low-enable")) {
  113. vrange_nval &=
  114. ~VRANGE_SELECT_BIT; /* VRANGE_SELECT = 0, 25.6 volts */
  115. info->m[PSC_VOLTAGE_IN] = 128;
  116. info->m[PSC_VOLTAGE_OUT] = 128;
  117. info->m[PSC_POWER] = 4 * rsense;
  118. } else {
  119. vrange_nval |=
  120. VRANGE_SELECT_BIT; /* VRANGE_SELECT = 1, 102.4 volts */
  121. info->m[PSC_POWER] = rsense;
  122. }
  123. if (vrange_nval != vrange_oval) {
  124. /* Set MFR1 CONFIG register bit 1 VRANGE_SELECT */
  125. ret = i2c_smbus_write_word_data(client, LTC4286_MFR_CONFIG1,
  126. vrange_nval);
  127. if (ret < 0)
  128. return dev_err_probe(&client->dev, ret,
  129. "Failed to set vrange\n");
  130. }
  131. info->m[PSC_CURRENT_OUT] = 1024 * rsense;
  132. return pmbus_do_probe(client, info);
  133. }
  134. static const struct of_device_id ltc4286_of_match[] = {
  135. { .compatible = "lltc,ltc4286" },
  136. { .compatible = "lltc,ltc4287" },
  137. {}
  138. };
  139. static struct i2c_driver ltc4286_driver = {
  140. .driver = {
  141. .name = "ltc4286",
  142. .of_match_table = ltc4286_of_match,
  143. },
  144. .probe = ltc4286_probe,
  145. .id_table = ltc4286_id,
  146. };
  147. module_i2c_driver(ltc4286_driver);
  148. MODULE_AUTHOR("Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>");
  149. MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles");
  150. MODULE_LICENSE("GPL");
  151. MODULE_IMPORT_NS("PMBUS");