pxe1610.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Hardware monitoring driver for Infineon PXE1610
  4. *
  5. * Copyright (c) 2019 Facebook Inc
  6. *
  7. */
  8. #include <linux/err.h>
  9. #include <linux/i2c.h>
  10. #include <linux/init.h>
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include "pmbus.h"
  14. #define PXE1610_NUM_PAGES 3
  15. /* Identify chip parameters. */
  16. static int pxe1610_identify(struct i2c_client *client,
  17. struct pmbus_driver_info *info)
  18. {
  19. int i;
  20. for (i = 0; i < PXE1610_NUM_PAGES; i++) {
  21. if (pmbus_check_byte_register(client, i, PMBUS_VOUT_MODE)) {
  22. u8 vout_mode;
  23. int ret;
  24. /* Read the register with VOUT scaling value.*/
  25. ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
  26. if (ret < 0)
  27. return ret;
  28. vout_mode = ret & GENMASK(4, 0);
  29. switch (vout_mode) {
  30. case 1:
  31. info->vrm_version[i] = vr12;
  32. break;
  33. case 2:
  34. info->vrm_version[i] = vr13;
  35. break;
  36. default:
  37. /*
  38. * If prior pages are available limit operation
  39. * to them
  40. */
  41. if (i != 0) {
  42. info->pages = i;
  43. return 0;
  44. }
  45. return -ENODEV;
  46. }
  47. }
  48. }
  49. return 0;
  50. }
  51. static struct pmbus_driver_info pxe1610_info = {
  52. .pages = PXE1610_NUM_PAGES,
  53. .format[PSC_VOLTAGE_IN] = linear,
  54. .format[PSC_VOLTAGE_OUT] = vid,
  55. .format[PSC_CURRENT_IN] = linear,
  56. .format[PSC_CURRENT_OUT] = linear,
  57. .format[PSC_TEMPERATURE] = linear,
  58. .format[PSC_POWER] = linear,
  59. .func[0] = PMBUS_HAVE_VIN
  60. | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
  61. | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
  62. | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
  63. | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
  64. | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
  65. .func[1] = PMBUS_HAVE_VIN
  66. | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
  67. | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
  68. | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
  69. | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
  70. | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
  71. .func[2] = PMBUS_HAVE_VIN
  72. | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
  73. | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
  74. | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
  75. | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
  76. | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
  77. .identify = pxe1610_identify,
  78. };
  79. static int pxe1610_probe(struct i2c_client *client)
  80. {
  81. struct pmbus_driver_info *info;
  82. u8 buf[I2C_SMBUS_BLOCK_MAX];
  83. int ret;
  84. if (!i2c_check_functionality(
  85. client->adapter,
  86. I2C_FUNC_SMBUS_READ_BYTE_DATA
  87. | I2C_FUNC_SMBUS_READ_WORD_DATA
  88. | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
  89. return -ENODEV;
  90. /*
  91. * By default this device doesn't boot to page 0, so set page 0
  92. * to access all pmbus registers.
  93. */
  94. i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
  95. /* Read Manufacturer id */
  96. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
  97. if (ret < 0) {
  98. dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
  99. return ret;
  100. }
  101. if (ret != 2 || strncmp(buf, "XP", 2)) {
  102. dev_err(&client->dev, "MFR_ID unrecognized\n");
  103. return -ENODEV;
  104. }
  105. info = devm_kmemdup(&client->dev, &pxe1610_info,
  106. sizeof(struct pmbus_driver_info),
  107. GFP_KERNEL);
  108. if (!info)
  109. return -ENOMEM;
  110. return pmbus_do_probe(client, info);
  111. }
  112. static const struct i2c_device_id pxe1610_id[] = {
  113. {"pxe1610", 0},
  114. {"pxe1110", 0},
  115. {"pxm1310", 0},
  116. {}
  117. };
  118. MODULE_DEVICE_TABLE(i2c, pxe1610_id);
  119. static struct i2c_driver pxe1610_driver = {
  120. .driver = {
  121. .name = "pxe1610",
  122. },
  123. .probe_new = pxe1610_probe,
  124. .id_table = pxe1610_id,
  125. };
  126. module_i2c_driver(pxe1610_driver);
  127. MODULE_AUTHOR("Vijay Khemka <[email protected]>");
  128. MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");
  129. MODULE_LICENSE("GPL");
  130. MODULE_IMPORT_NS(PMBUS);