pim4328.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Hardware monitoring driver for PIM4006, PIM4328 and PIM4820
  4. *
  5. * Copyright (c) 2021 Flextronics International Sweden AB
  6. */
  7. #include <linux/err.h>
  8. #include <linux/i2c.h>
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/pmbus.h>
  13. #include <linux/slab.h>
  14. #include "pmbus.h"
  15. enum chips { pim4006, pim4328, pim4820 };
  16. struct pim4328_data {
  17. enum chips id;
  18. struct pmbus_driver_info info;
  19. };
  20. #define to_pim4328_data(x) container_of(x, struct pim4328_data, info)
  21. /* PIM4006 and PIM4328 */
  22. #define PIM4328_MFR_READ_VINA 0xd3
  23. #define PIM4328_MFR_READ_VINB 0xd4
  24. /* PIM4006 */
  25. #define PIM4328_MFR_READ_IINA 0xd6
  26. #define PIM4328_MFR_READ_IINB 0xd7
  27. #define PIM4328_MFR_FET_CHECKSTATUS 0xd9
  28. /* PIM4328 */
  29. #define PIM4328_MFR_STATUS_BITS 0xd5
  30. /* PIM4820 */
  31. #define PIM4328_MFR_READ_STATUS 0xd0
  32. static const struct i2c_device_id pim4328_id[] = {
  33. {"bmr455", pim4328},
  34. {"pim4006", pim4006},
  35. {"pim4106", pim4006},
  36. {"pim4206", pim4006},
  37. {"pim4306", pim4006},
  38. {"pim4328", pim4328},
  39. {"pim4406", pim4006},
  40. {"pim4820", pim4820},
  41. {}
  42. };
  43. MODULE_DEVICE_TABLE(i2c, pim4328_id);
  44. static int pim4328_read_word_data(struct i2c_client *client, int page,
  45. int phase, int reg)
  46. {
  47. int ret;
  48. if (page > 0)
  49. return -ENXIO;
  50. if (phase == 0xff)
  51. return -ENODATA;
  52. switch (reg) {
  53. case PMBUS_READ_VIN:
  54. ret = pmbus_read_word_data(client, page, phase,
  55. phase == 0 ? PIM4328_MFR_READ_VINA
  56. : PIM4328_MFR_READ_VINB);
  57. break;
  58. case PMBUS_READ_IIN:
  59. ret = pmbus_read_word_data(client, page, phase,
  60. phase == 0 ? PIM4328_MFR_READ_IINA
  61. : PIM4328_MFR_READ_IINB);
  62. break;
  63. default:
  64. ret = -ENODATA;
  65. }
  66. return ret;
  67. }
  68. static int pim4328_read_byte_data(struct i2c_client *client, int page, int reg)
  69. {
  70. const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
  71. struct pim4328_data *data = to_pim4328_data(info);
  72. int ret, status;
  73. if (page > 0)
  74. return -ENXIO;
  75. switch (reg) {
  76. case PMBUS_STATUS_BYTE:
  77. ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
  78. if (ret < 0)
  79. return ret;
  80. if (data->id == pim4006) {
  81. status = pmbus_read_word_data(client, page, 0xff,
  82. PIM4328_MFR_FET_CHECKSTATUS);
  83. if (status < 0)
  84. return status;
  85. if (status & 0x0630) /* Input UV */
  86. ret |= PB_STATUS_VIN_UV;
  87. } else if (data->id == pim4328) {
  88. status = pmbus_read_byte_data(client, page,
  89. PIM4328_MFR_STATUS_BITS);
  90. if (status < 0)
  91. return status;
  92. if (status & 0x04) /* Input UV */
  93. ret |= PB_STATUS_VIN_UV;
  94. if (status & 0x40) /* Output UV */
  95. ret |= PB_STATUS_NONE_ABOVE;
  96. } else if (data->id == pim4820) {
  97. status = pmbus_read_byte_data(client, page,
  98. PIM4328_MFR_READ_STATUS);
  99. if (status < 0)
  100. return status;
  101. if (status & 0x05) /* Input OV or OC */
  102. ret |= PB_STATUS_NONE_ABOVE;
  103. if (status & 0x1a) /* Input UV */
  104. ret |= PB_STATUS_VIN_UV;
  105. if (status & 0x40) /* OT */
  106. ret |= PB_STATUS_TEMPERATURE;
  107. }
  108. break;
  109. default:
  110. ret = -ENODATA;
  111. }
  112. return ret;
  113. }
  114. static int pim4328_probe(struct i2c_client *client)
  115. {
  116. int status;
  117. u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
  118. const struct i2c_device_id *mid;
  119. struct pim4328_data *data;
  120. struct pmbus_driver_info *info;
  121. struct pmbus_platform_data *pdata;
  122. struct device *dev = &client->dev;
  123. if (!i2c_check_functionality(client->adapter,
  124. I2C_FUNC_SMBUS_READ_BYTE_DATA
  125. | I2C_FUNC_SMBUS_BLOCK_DATA))
  126. return -ENODEV;
  127. data = devm_kzalloc(&client->dev, sizeof(struct pim4328_data),
  128. GFP_KERNEL);
  129. if (!data)
  130. return -ENOMEM;
  131. status = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, device_id);
  132. if (status < 0) {
  133. dev_err(&client->dev, "Failed to read Manufacturer Model\n");
  134. return status;
  135. }
  136. for (mid = pim4328_id; mid->name[0]; mid++) {
  137. if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
  138. break;
  139. }
  140. if (!mid->name[0]) {
  141. dev_err(&client->dev, "Unsupported device\n");
  142. return -ENODEV;
  143. }
  144. if (strcmp(client->name, mid->name))
  145. dev_notice(&client->dev,
  146. "Device mismatch: Configured %s, detected %s\n",
  147. client->name, mid->name);
  148. data->id = mid->driver_data;
  149. info = &data->info;
  150. info->pages = 1;
  151. info->read_byte_data = pim4328_read_byte_data;
  152. info->read_word_data = pim4328_read_word_data;
  153. pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data),
  154. GFP_KERNEL);
  155. if (!pdata)
  156. return -ENOMEM;
  157. dev->platform_data = pdata;
  158. pdata->flags = PMBUS_NO_CAPABILITY | PMBUS_NO_WRITE_PROTECT;
  159. switch (data->id) {
  160. case pim4006:
  161. info->phases[0] = 2;
  162. info->func[0] = PMBUS_PHASE_VIRTUAL | PMBUS_HAVE_VIN
  163. | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
  164. info->pfunc[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
  165. info->pfunc[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
  166. break;
  167. case pim4328:
  168. info->phases[0] = 2;
  169. info->func[0] = PMBUS_PHASE_VIRTUAL
  170. | PMBUS_HAVE_VCAP | PMBUS_HAVE_VIN
  171. | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
  172. info->pfunc[0] = PMBUS_HAVE_VIN;
  173. info->pfunc[1] = PMBUS_HAVE_VIN;
  174. info->format[PSC_VOLTAGE_IN] = direct;
  175. info->format[PSC_TEMPERATURE] = direct;
  176. info->format[PSC_CURRENT_OUT] = direct;
  177. pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
  178. break;
  179. case pim4820:
  180. info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_TEMP
  181. | PMBUS_HAVE_IIN;
  182. info->format[PSC_VOLTAGE_IN] = direct;
  183. info->format[PSC_TEMPERATURE] = direct;
  184. info->format[PSC_CURRENT_IN] = direct;
  185. pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
  186. break;
  187. default:
  188. return -ENODEV;
  189. }
  190. return pmbus_do_probe(client, info);
  191. }
  192. static struct i2c_driver pim4328_driver = {
  193. .driver = {
  194. .name = "pim4328",
  195. },
  196. .probe_new = pim4328_probe,
  197. .id_table = pim4328_id,
  198. };
  199. module_i2c_driver(pim4328_driver);
  200. MODULE_AUTHOR("Erik Rosen <[email protected]>");
  201. MODULE_DESCRIPTION("PMBus driver for PIM4006, PIM4328, PIM4820 power interface modules");
  202. MODULE_LICENSE("GPL");
  203. MODULE_IMPORT_NS(PMBUS);