dps920ab.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Driver for Delta DPS920AB PSU
  4. *
  5. * Copyright (C) 2021 Delta Networks, Inc.
  6. * Copyright (C) 2021 Sartura Ltd.
  7. */
  8. #include <linux/debugfs.h>
  9. #include <linux/i2c.h>
  10. #include <linux/module.h>
  11. #include <linux/of_device.h>
  12. #include "pmbus.h"
  13. struct dps920ab_data {
  14. char *mfr_model;
  15. char *mfr_id;
  16. };
  17. static int dps920ab_read_word_data(struct i2c_client *client, int page, int phase, int reg)
  18. {
  19. /*
  20. * This masks commands which are not supported.
  21. * PSU advertises that all features are supported,
  22. * in reality that unfortunately is not true.
  23. * So enable only those that the datasheet confirms.
  24. */
  25. switch (reg) {
  26. case PMBUS_FAN_COMMAND_1:
  27. case PMBUS_IOUT_OC_WARN_LIMIT:
  28. case PMBUS_STATUS_WORD:
  29. case PMBUS_READ_VIN:
  30. case PMBUS_READ_IIN:
  31. case PMBUS_READ_VOUT:
  32. case PMBUS_READ_IOUT:
  33. case PMBUS_READ_TEMPERATURE_1:
  34. case PMBUS_READ_TEMPERATURE_2:
  35. case PMBUS_READ_TEMPERATURE_3:
  36. case PMBUS_READ_FAN_SPEED_1:
  37. case PMBUS_READ_POUT:
  38. case PMBUS_READ_PIN:
  39. case PMBUS_MFR_VOUT_MIN:
  40. case PMBUS_MFR_VOUT_MAX:
  41. case PMBUS_MFR_IOUT_MAX:
  42. case PMBUS_MFR_POUT_MAX:
  43. return pmbus_read_word_data(client, page, phase, reg);
  44. default:
  45. return -ENXIO;
  46. }
  47. }
  48. static int dps920ab_write_word_data(struct i2c_client *client, int page, int reg,
  49. u16 word)
  50. {
  51. /*
  52. * This masks commands which are not supported.
  53. * PSU only has one R/W register and that is
  54. * for the fan.
  55. */
  56. switch (reg) {
  57. case PMBUS_FAN_COMMAND_1:
  58. return pmbus_write_word_data(client, page, reg, word);
  59. default:
  60. return -EACCES;
  61. }
  62. }
  63. static struct pmbus_driver_info dps920ab_info = {
  64. .pages = 1,
  65. .format[PSC_VOLTAGE_IN] = linear,
  66. .format[PSC_VOLTAGE_OUT] = linear,
  67. .format[PSC_CURRENT_IN] = linear,
  68. .format[PSC_CURRENT_OUT] = linear,
  69. .format[PSC_POWER] = linear,
  70. .format[PSC_FAN] = linear,
  71. .format[PSC_TEMPERATURE] = linear,
  72. .func[0] =
  73. PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
  74. PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
  75. PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
  76. PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |
  77. PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
  78. PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
  79. .read_word_data = dps920ab_read_word_data,
  80. .write_word_data = dps920ab_write_word_data,
  81. };
  82. static int dps920ab_mfr_id_show(struct seq_file *s, void *data)
  83. {
  84. struct dps920ab_data *priv = s->private;
  85. seq_printf(s, "%s\n", priv->mfr_id);
  86. return 0;
  87. }
  88. DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_id);
  89. static int dps920ab_mfr_model_show(struct seq_file *s, void *data)
  90. {
  91. struct dps920ab_data *priv = s->private;
  92. seq_printf(s, "%s\n", priv->mfr_model);
  93. return 0;
  94. }
  95. DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_model);
  96. static void dps920ab_init_debugfs(struct dps920ab_data *data, struct i2c_client *client)
  97. {
  98. struct dentry *debugfs_dir;
  99. struct dentry *root;
  100. root = pmbus_get_debugfs_dir(client);
  101. if (!root)
  102. return;
  103. debugfs_dir = debugfs_create_dir(client->name, root);
  104. debugfs_create_file("mfr_id",
  105. 0400,
  106. debugfs_dir,
  107. data,
  108. &dps920ab_mfr_id_fops);
  109. debugfs_create_file("mfr_model",
  110. 0400,
  111. debugfs_dir,
  112. data,
  113. &dps920ab_mfr_model_fops);
  114. }
  115. static int dps920ab_probe(struct i2c_client *client)
  116. {
  117. u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
  118. struct dps920ab_data *data;
  119. int ret;
  120. data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
  121. if (!data)
  122. return -ENOMEM;
  123. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
  124. if (ret < 0) {
  125. dev_err(&client->dev, "Failed to read Manufacturer ID\n");
  126. return ret;
  127. }
  128. buf[ret] = '\0';
  129. if (ret != 5 || strncmp(buf, "DELTA", 5)) {
  130. buf[ret] = '\0';
  131. dev_err(&client->dev, "Unsupported Manufacturer ID '%s'\n", buf);
  132. return -ENODEV;
  133. }
  134. data->mfr_id = devm_kstrdup(&client->dev, buf, GFP_KERNEL);
  135. if (!data->mfr_id)
  136. return -ENOMEM;
  137. ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
  138. if (ret < 0) {
  139. dev_err(&client->dev, "Failed to read Manufacturer Model\n");
  140. return ret;
  141. }
  142. buf[ret] = '\0';
  143. if (ret != 11 || strncmp(buf, "DPS-920AB", 9)) {
  144. dev_err(&client->dev, "Unsupported Manufacturer Model '%s'\n", buf);
  145. return -ENODEV;
  146. }
  147. data->mfr_model = devm_kstrdup(&client->dev, buf, GFP_KERNEL);
  148. if (!data->mfr_model)
  149. return -ENOMEM;
  150. ret = pmbus_do_probe(client, &dps920ab_info);
  151. if (ret)
  152. return ret;
  153. dps920ab_init_debugfs(data, client);
  154. return 0;
  155. }
  156. static const struct of_device_id __maybe_unused dps920ab_of_match[] = {
  157. { .compatible = "delta,dps920ab", },
  158. {}
  159. };
  160. MODULE_DEVICE_TABLE(of, dps920ab_of_match);
  161. static struct i2c_driver dps920ab_driver = {
  162. .driver = {
  163. .name = "dps920ab",
  164. .of_match_table = of_match_ptr(dps920ab_of_match),
  165. },
  166. .probe_new = dps920ab_probe,
  167. };
  168. module_i2c_driver(dps920ab_driver);
  169. MODULE_AUTHOR("Robert Marko <[email protected]>");
  170. MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU");
  171. MODULE_LICENSE("GPL");
  172. MODULE_IMPORT_NS(PMBUS);