max77705-hwmon.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * MAX77705 voltage and current hwmon driver.
  4. *
  5. * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com>
  6. */
  7. #include <linux/err.h>
  8. #include <linux/hwmon-sysfs.h>
  9. #include <linux/hwmon.h>
  10. #include <linux/kernel.h>
  11. #include <linux/mfd/max77705-private.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/regmap.h>
  14. struct channel_desc {
  15. u8 reg;
  16. u8 avg_reg;
  17. const char *const label;
  18. // register resolution. nano Volts for voltage, nano Amperes for current
  19. u32 resolution;
  20. };
  21. static const struct channel_desc current_channel_desc[] = {
  22. {
  23. .reg = IIN_REG,
  24. .label = "IIN_REG",
  25. .resolution = 125000
  26. },
  27. {
  28. .reg = ISYS_REG,
  29. .avg_reg = AVGISYS_REG,
  30. .label = "ISYS_REG",
  31. .resolution = 312500
  32. }
  33. };
  34. static const struct channel_desc voltage_channel_desc[] = {
  35. {
  36. .reg = VBYP_REG,
  37. .label = "VBYP_REG",
  38. .resolution = 427246
  39. },
  40. {
  41. .reg = VSYS_REG,
  42. .label = "VSYS_REG",
  43. .resolution = 156250
  44. }
  45. };
  46. static int max77705_read_and_convert(struct regmap *regmap, u8 reg, u32 res,
  47. bool is_signed, long *val)
  48. {
  49. int ret;
  50. u32 regval;
  51. ret = regmap_read(regmap, reg, &regval);
  52. if (ret < 0)
  53. return ret;
  54. if (is_signed)
  55. *val = mult_frac((long)sign_extend32(regval, 15), res, 1000000);
  56. else
  57. *val = mult_frac((long)regval, res, 1000000);
  58. return 0;
  59. }
  60. static umode_t max77705_is_visible(const void *data,
  61. enum hwmon_sensor_types type,
  62. u32 attr, int channel)
  63. {
  64. switch (type) {
  65. case hwmon_in:
  66. switch (attr) {
  67. case hwmon_in_input:
  68. case hwmon_in_label:
  69. return 0444;
  70. default:
  71. break;
  72. }
  73. break;
  74. case hwmon_curr:
  75. switch (attr) {
  76. case hwmon_curr_input:
  77. case hwmon_in_label:
  78. return 0444;
  79. case hwmon_curr_average:
  80. if (current_channel_desc[channel].avg_reg)
  81. return 0444;
  82. break;
  83. default:
  84. break;
  85. }
  86. break;
  87. default:
  88. break;
  89. }
  90. return 0;
  91. }
  92. static int max77705_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
  93. int channel, const char **buf)
  94. {
  95. switch (type) {
  96. case hwmon_curr:
  97. switch (attr) {
  98. case hwmon_in_label:
  99. *buf = current_channel_desc[channel].label;
  100. return 0;
  101. default:
  102. return -EOPNOTSUPP;
  103. }
  104. case hwmon_in:
  105. switch (attr) {
  106. case hwmon_in_label:
  107. *buf = voltage_channel_desc[channel].label;
  108. return 0;
  109. default:
  110. return -EOPNOTSUPP;
  111. }
  112. default:
  113. return -EOPNOTSUPP;
  114. }
  115. }
  116. static int max77705_read(struct device *dev, enum hwmon_sensor_types type,
  117. u32 attr, int channel, long *val)
  118. {
  119. struct regmap *regmap = dev_get_drvdata(dev);
  120. u8 reg;
  121. u32 res;
  122. switch (type) {
  123. case hwmon_curr:
  124. switch (attr) {
  125. case hwmon_curr_input:
  126. reg = current_channel_desc[channel].reg;
  127. res = current_channel_desc[channel].resolution;
  128. return max77705_read_and_convert(regmap, reg, res, true, val);
  129. case hwmon_curr_average:
  130. reg = current_channel_desc[channel].avg_reg;
  131. res = current_channel_desc[channel].resolution;
  132. return max77705_read_and_convert(regmap, reg, res, true, val);
  133. default:
  134. return -EOPNOTSUPP;
  135. }
  136. case hwmon_in:
  137. switch (attr) {
  138. case hwmon_in_input:
  139. reg = voltage_channel_desc[channel].reg;
  140. res = voltage_channel_desc[channel].resolution;
  141. return max77705_read_and_convert(regmap, reg, res, false, val);
  142. default:
  143. return -EOPNOTSUPP;
  144. }
  145. default:
  146. return -EOPNOTSUPP;
  147. }
  148. return 0;
  149. }
  150. static const struct hwmon_ops max77705_hwmon_ops = {
  151. .is_visible = max77705_is_visible,
  152. .read = max77705_read,
  153. .read_string = max77705_read_string,
  154. };
  155. static const struct hwmon_channel_info *max77705_info[] = {
  156. HWMON_CHANNEL_INFO(in,
  157. HWMON_I_INPUT | HWMON_I_LABEL,
  158. HWMON_I_INPUT | HWMON_I_LABEL
  159. ),
  160. HWMON_CHANNEL_INFO(curr,
  161. HWMON_C_INPUT | HWMON_C_LABEL,
  162. HWMON_C_INPUT | HWMON_C_AVERAGE | HWMON_C_LABEL
  163. ),
  164. NULL
  165. };
  166. static const struct hwmon_chip_info max77705_chip_info = {
  167. .ops = &max77705_hwmon_ops,
  168. .info = max77705_info,
  169. };
  170. static int max77705_hwmon_probe(struct platform_device *pdev)
  171. {
  172. struct device *hwmon_dev;
  173. struct regmap *regmap;
  174. regmap = dev_get_regmap(pdev->dev.parent, NULL);
  175. if (!regmap)
  176. return -ENODEV;
  177. hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "max77705", regmap,
  178. &max77705_chip_info, NULL);
  179. if (IS_ERR(hwmon_dev))
  180. return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev),
  181. "Unable to register hwmon device\n");
  182. return 0;
  183. };
  184. static struct platform_driver max77705_hwmon_driver = {
  185. .driver = {
  186. .name = "max77705-hwmon",
  187. },
  188. .probe = max77705_hwmon_probe,
  189. };
  190. module_platform_driver(max77705_hwmon_driver);
  191. MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
  192. MODULE_DESCRIPTION("MAX77705 monitor driver");
  193. MODULE_LICENSE("GPL");