delta-ahe50dc-fan.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Delta AHE-50DC power shelf fan control module driver
  4. *
  5. * Copyright 2021 Zev Weiss <[email protected]>
  6. */
  7. #include <linux/i2c.h>
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/pmbus.h>
  11. #include "pmbus.h"
  12. #define AHE50DC_PMBUS_READ_TEMP4 0xd0
  13. static int ahe50dc_fan_write_byte(struct i2c_client *client, int page, u8 value)
  14. {
  15. /*
  16. * The CLEAR_FAULTS operation seems to sometimes (unpredictably, perhaps
  17. * 5% of the time or so) trigger a problematic phenomenon in which the
  18. * fan speeds surge momentarily and at least some (perhaps all?) of the
  19. * system's power outputs experience a glitch.
  20. *
  21. * However, according to Delta it should be OK to simply not send any
  22. * CLEAR_FAULTS commands (the device doesn't seem to be capable of
  23. * reporting any faults anyway), so just blackhole them unconditionally.
  24. */
  25. return value == PMBUS_CLEAR_FAULTS ? -EOPNOTSUPP : -ENODATA;
  26. }
  27. static int ahe50dc_fan_read_word_data(struct i2c_client *client, int page, int phase, int reg)
  28. {
  29. /* temp1 in (virtual) page 1 is remapped to mfr-specific temp4 */
  30. if (page == 1) {
  31. if (reg == PMBUS_READ_TEMPERATURE_1)
  32. return i2c_smbus_read_word_data(client, AHE50DC_PMBUS_READ_TEMP4);
  33. return -EOPNOTSUPP;
  34. }
  35. /*
  36. * There's a fairly limited set of commands this device actually
  37. * supports, so here we block attempts to read anything else (which
  38. * return 0xffff and would cause confusion elsewhere).
  39. */
  40. switch (reg) {
  41. case PMBUS_STATUS_WORD:
  42. case PMBUS_FAN_COMMAND_1:
  43. case PMBUS_FAN_COMMAND_2:
  44. case PMBUS_FAN_COMMAND_3:
  45. case PMBUS_FAN_COMMAND_4:
  46. case PMBUS_STATUS_FAN_12:
  47. case PMBUS_STATUS_FAN_34:
  48. case PMBUS_READ_VIN:
  49. case PMBUS_READ_TEMPERATURE_1:
  50. case PMBUS_READ_TEMPERATURE_2:
  51. case PMBUS_READ_TEMPERATURE_3:
  52. case PMBUS_READ_FAN_SPEED_1:
  53. case PMBUS_READ_FAN_SPEED_2:
  54. case PMBUS_READ_FAN_SPEED_3:
  55. case PMBUS_READ_FAN_SPEED_4:
  56. return -ENODATA;
  57. default:
  58. return -EOPNOTSUPP;
  59. }
  60. }
  61. static struct pmbus_driver_info ahe50dc_fan_info = {
  62. .pages = 2,
  63. .format[PSC_FAN] = direct,
  64. .format[PSC_TEMPERATURE] = direct,
  65. .format[PSC_VOLTAGE_IN] = direct,
  66. .m[PSC_FAN] = 1,
  67. .b[PSC_FAN] = 0,
  68. .R[PSC_FAN] = 0,
  69. .m[PSC_TEMPERATURE] = 1,
  70. .b[PSC_TEMPERATURE] = 0,
  71. .R[PSC_TEMPERATURE] = 1,
  72. .m[PSC_VOLTAGE_IN] = 1,
  73. .b[PSC_VOLTAGE_IN] = 0,
  74. .R[PSC_VOLTAGE_IN] = 3,
  75. .func[0] = PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
  76. PMBUS_HAVE_VIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_FAN34 |
  77. PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_STATUS_FAN34 | PMBUS_PAGE_VIRTUAL,
  78. .func[1] = PMBUS_HAVE_TEMP | PMBUS_PAGE_VIRTUAL,
  79. .write_byte = ahe50dc_fan_write_byte,
  80. .read_word_data = ahe50dc_fan_read_word_data,
  81. };
  82. /*
  83. * CAPABILITY returns 0xff, which appears to be this device's way indicating
  84. * it doesn't support something (and if we enable I2C_CLIENT_PEC on seeing bit
  85. * 7 being set it generates bad PECs, so let's not go there).
  86. */
  87. static struct pmbus_platform_data ahe50dc_fan_data = {
  88. .flags = PMBUS_NO_CAPABILITY,
  89. };
  90. static int ahe50dc_fan_probe(struct i2c_client *client)
  91. {
  92. client->dev.platform_data = &ahe50dc_fan_data;
  93. return pmbus_do_probe(client, &ahe50dc_fan_info);
  94. }
  95. static const struct i2c_device_id ahe50dc_fan_id[] = {
  96. { "ahe50dc_fan" },
  97. { }
  98. };
  99. MODULE_DEVICE_TABLE(i2c, ahe50dc_fan_id);
  100. static const struct of_device_id __maybe_unused ahe50dc_fan_of_match[] = {
  101. { .compatible = "delta,ahe50dc-fan" },
  102. { }
  103. };
  104. MODULE_DEVICE_TABLE(of, ahe50dc_fan_of_match);
  105. static struct i2c_driver ahe50dc_fan_driver = {
  106. .driver = {
  107. .name = "ahe50dc_fan",
  108. .of_match_table = of_match_ptr(ahe50dc_fan_of_match),
  109. },
  110. .probe_new = ahe50dc_fan_probe,
  111. .id_table = ahe50dc_fan_id,
  112. };
  113. module_i2c_driver(ahe50dc_fan_driver);
  114. MODULE_AUTHOR("Zev Weiss <[email protected]>");
  115. MODULE_DESCRIPTION("Driver for Delta AHE-50DC power shelf fan control module");
  116. MODULE_LICENSE("GPL");
  117. MODULE_IMPORT_NS(PMBUS);