dasharo-acpi.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Dasharo ACPI Driver
  4. */
  5. #include <linux/acpi.h>
  6. #include <linux/array_size.h>
  7. #include <linux/hwmon.h>
  8. #include <linux/module.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/types.h>
  11. #include <linux/units.h>
  12. enum dasharo_feature {
  13. DASHARO_FEATURE_TEMPERATURE = 0,
  14. DASHARO_FEATURE_FAN_PWM,
  15. DASHARO_FEATURE_FAN_TACH,
  16. DASHARO_FEATURE_MAX
  17. };
  18. enum dasharo_temperature {
  19. DASHARO_TEMPERATURE_CPU_PACKAGE = 0,
  20. DASHARO_TEMPERATURE_CPU_CORE,
  21. DASHARO_TEMPERATURE_GPU,
  22. DASHARO_TEMPERATURE_BOARD,
  23. DASHARO_TEMPERATURE_CHASSIS,
  24. DASHARO_TEMPERATURE_MAX
  25. };
  26. enum dasharo_fan {
  27. DASHARO_FAN_CPU = 0,
  28. DASHARO_FAN_GPU,
  29. DASHARO_FAN_CHASSIS,
  30. DASHARO_FAN_MAX
  31. };
  32. #define MAX_GROUPS_PER_FEAT 8
  33. static const char * const dasharo_group_names[DASHARO_FEATURE_MAX][MAX_GROUPS_PER_FEAT] = {
  34. [DASHARO_FEATURE_TEMPERATURE] = {
  35. [DASHARO_TEMPERATURE_CPU_PACKAGE] = "CPU Package",
  36. [DASHARO_TEMPERATURE_CPU_CORE] = "CPU Core",
  37. [DASHARO_TEMPERATURE_GPU] = "GPU",
  38. [DASHARO_TEMPERATURE_BOARD] = "Board",
  39. [DASHARO_TEMPERATURE_CHASSIS] = "Chassis",
  40. },
  41. [DASHARO_FEATURE_FAN_PWM] = {
  42. [DASHARO_FAN_CPU] = "CPU",
  43. [DASHARO_FAN_GPU] = "GPU",
  44. [DASHARO_FAN_CHASSIS] = "Chassis",
  45. },
  46. [DASHARO_FEATURE_FAN_TACH] = {
  47. [DASHARO_FAN_CPU] = "CPU",
  48. [DASHARO_FAN_GPU] = "GPU",
  49. [DASHARO_FAN_CHASSIS] = "Chassis",
  50. },
  51. };
  52. struct dasharo_capability {
  53. unsigned int group;
  54. unsigned int index;
  55. char name[16];
  56. };
  57. #define MAX_CAPS_PER_FEAT 24
  58. struct dasharo_data {
  59. struct platform_device *pdev;
  60. int caps_found[DASHARO_FEATURE_MAX];
  61. struct dasharo_capability capabilities[DASHARO_FEATURE_MAX][MAX_CAPS_PER_FEAT];
  62. };
  63. static int dasharo_get_feature_cap_count(struct dasharo_data *data, enum dasharo_feature feat, int cap)
  64. {
  65. struct acpi_object_list obj_list;
  66. union acpi_object obj[2];
  67. acpi_handle handle;
  68. acpi_status status;
  69. u64 count;
  70. obj[0].type = ACPI_TYPE_INTEGER;
  71. obj[0].integer.value = feat;
  72. obj[1].type = ACPI_TYPE_INTEGER;
  73. obj[1].integer.value = cap;
  74. obj_list.count = 2;
  75. obj_list.pointer = &obj[0];
  76. handle = ACPI_HANDLE(&data->pdev->dev);
  77. status = acpi_evaluate_integer(handle, "GFCP", &obj_list, &count);
  78. if (ACPI_FAILURE(status))
  79. return -ENODEV;
  80. return count;
  81. }
  82. static int dasharo_read_channel(struct dasharo_data *data, char *method, enum dasharo_feature feat, int channel, long *value)
  83. {
  84. struct acpi_object_list obj_list;
  85. union acpi_object obj[2];
  86. acpi_handle handle;
  87. acpi_status status;
  88. u64 val;
  89. if (feat >= ARRAY_SIZE(data->capabilities))
  90. return -EINVAL;
  91. if (channel >= data->caps_found[feat])
  92. return -EINVAL;
  93. obj[0].type = ACPI_TYPE_INTEGER;
  94. obj[0].integer.value = data->capabilities[feat][channel].group;
  95. obj[1].type = ACPI_TYPE_INTEGER;
  96. obj[1].integer.value = data->capabilities[feat][channel].index;
  97. obj_list.count = 2;
  98. obj_list.pointer = &obj[0];
  99. handle = ACPI_HANDLE(&data->pdev->dev);
  100. status = acpi_evaluate_integer(handle, method, &obj_list, &val);
  101. if (ACPI_FAILURE(status))
  102. return -ENODEV;
  103. *value = val;
  104. return 0;
  105. }
  106. static int dasharo_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  107. u32 attr, int channel, long *val)
  108. {
  109. struct dasharo_data *data = dev_get_drvdata(dev);
  110. long value;
  111. int ret;
  112. switch (type) {
  113. case hwmon_temp:
  114. ret = dasharo_read_channel(data, "GTMP", DASHARO_FEATURE_TEMPERATURE, channel, &value);
  115. if (!ret)
  116. *val = value * MILLIDEGREE_PER_DEGREE;
  117. break;
  118. case hwmon_fan:
  119. ret = dasharo_read_channel(data, "GFTH", DASHARO_FEATURE_FAN_TACH, channel, &value);
  120. if (!ret)
  121. *val = value;
  122. break;
  123. case hwmon_pwm:
  124. ret = dasharo_read_channel(data, "GFDC", DASHARO_FEATURE_FAN_PWM, channel, &value);
  125. if (!ret)
  126. *val = value;
  127. break;
  128. default:
  129. return -ENODEV;
  130. break;
  131. }
  132. return ret;
  133. }
  134. static int dasharo_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
  135. u32 attr, int channel, const char **str)
  136. {
  137. struct dasharo_data *data = dev_get_drvdata(dev);
  138. switch (type) {
  139. case hwmon_temp:
  140. if (channel >= data->caps_found[DASHARO_FEATURE_TEMPERATURE])
  141. return -EINVAL;
  142. *str = data->capabilities[DASHARO_FEATURE_TEMPERATURE][channel].name;
  143. break;
  144. case hwmon_fan:
  145. if (channel >= data->caps_found[DASHARO_FEATURE_FAN_TACH])
  146. return -EINVAL;
  147. *str = data->capabilities[DASHARO_FEATURE_FAN_TACH][channel].name;
  148. break;
  149. default:
  150. return -EOPNOTSUPP;
  151. }
  152. return 0;
  153. }
  154. static umode_t dasharo_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
  155. u32 attr, int channel)
  156. {
  157. const struct dasharo_data *data = drvdata;
  158. switch (type) {
  159. case hwmon_temp:
  160. if (channel < data->caps_found[DASHARO_FEATURE_TEMPERATURE])
  161. return 0444;
  162. break;
  163. case hwmon_pwm:
  164. if (channel < data->caps_found[DASHARO_FEATURE_FAN_PWM])
  165. return 0444;
  166. break;
  167. case hwmon_fan:
  168. if (channel < data->caps_found[DASHARO_FEATURE_FAN_TACH])
  169. return 0444;
  170. break;
  171. default:
  172. break;
  173. }
  174. return 0;
  175. }
  176. static const struct hwmon_ops dasharo_hwmon_ops = {
  177. .is_visible = dasharo_hwmon_is_visible,
  178. .read_string = dasharo_hwmon_read_string,
  179. .read = dasharo_hwmon_read,
  180. };
  181. // Max 24 capabilities per feature
  182. static const struct hwmon_channel_info * const dasharo_hwmon_info[] = {
  183. HWMON_CHANNEL_INFO(fan,
  184. HWMON_F_INPUT | HWMON_F_LABEL,
  185. HWMON_F_INPUT | HWMON_F_LABEL,
  186. HWMON_F_INPUT | HWMON_F_LABEL,
  187. HWMON_F_INPUT | HWMON_F_LABEL,
  188. HWMON_F_INPUT | HWMON_F_LABEL,
  189. HWMON_F_INPUT | HWMON_F_LABEL,
  190. HWMON_F_INPUT | HWMON_F_LABEL,
  191. HWMON_F_INPUT | HWMON_F_LABEL,
  192. HWMON_F_INPUT | HWMON_F_LABEL,
  193. HWMON_F_INPUT | HWMON_F_LABEL,
  194. HWMON_F_INPUT | HWMON_F_LABEL,
  195. HWMON_F_INPUT | HWMON_F_LABEL,
  196. HWMON_F_INPUT | HWMON_F_LABEL,
  197. HWMON_F_INPUT | HWMON_F_LABEL,
  198. HWMON_F_INPUT | HWMON_F_LABEL,
  199. HWMON_F_INPUT | HWMON_F_LABEL,
  200. HWMON_F_INPUT | HWMON_F_LABEL,
  201. HWMON_F_INPUT | HWMON_F_LABEL,
  202. HWMON_F_INPUT | HWMON_F_LABEL,
  203. HWMON_F_INPUT | HWMON_F_LABEL,
  204. HWMON_F_INPUT | HWMON_F_LABEL,
  205. HWMON_F_INPUT | HWMON_F_LABEL,
  206. HWMON_F_INPUT | HWMON_F_LABEL,
  207. HWMON_F_INPUT | HWMON_F_LABEL),
  208. HWMON_CHANNEL_INFO(temp,
  209. HWMON_T_INPUT | HWMON_T_LABEL,
  210. HWMON_T_INPUT | HWMON_T_LABEL,
  211. HWMON_T_INPUT | HWMON_T_LABEL,
  212. HWMON_T_INPUT | HWMON_T_LABEL,
  213. HWMON_T_INPUT | HWMON_T_LABEL,
  214. HWMON_T_INPUT | HWMON_T_LABEL,
  215. HWMON_T_INPUT | HWMON_T_LABEL,
  216. HWMON_T_INPUT | HWMON_T_LABEL,
  217. HWMON_T_INPUT | HWMON_T_LABEL,
  218. HWMON_T_INPUT | HWMON_T_LABEL,
  219. HWMON_T_INPUT | HWMON_T_LABEL,
  220. HWMON_T_INPUT | HWMON_T_LABEL,
  221. HWMON_T_INPUT | HWMON_T_LABEL,
  222. HWMON_T_INPUT | HWMON_T_LABEL,
  223. HWMON_T_INPUT | HWMON_T_LABEL,
  224. HWMON_T_INPUT | HWMON_T_LABEL,
  225. HWMON_T_INPUT | HWMON_T_LABEL,
  226. HWMON_T_INPUT | HWMON_T_LABEL,
  227. HWMON_T_INPUT | HWMON_T_LABEL,
  228. HWMON_T_INPUT | HWMON_T_LABEL,
  229. HWMON_T_INPUT | HWMON_T_LABEL,
  230. HWMON_T_INPUT | HWMON_T_LABEL,
  231. HWMON_T_INPUT | HWMON_T_LABEL,
  232. HWMON_T_INPUT | HWMON_T_LABEL),
  233. HWMON_CHANNEL_INFO(pwm,
  234. HWMON_PWM_INPUT,
  235. HWMON_PWM_INPUT,
  236. HWMON_PWM_INPUT,
  237. HWMON_PWM_INPUT,
  238. HWMON_PWM_INPUT,
  239. HWMON_PWM_INPUT,
  240. HWMON_PWM_INPUT,
  241. HWMON_PWM_INPUT,
  242. HWMON_PWM_INPUT,
  243. HWMON_PWM_INPUT,
  244. HWMON_PWM_INPUT,
  245. HWMON_PWM_INPUT,
  246. HWMON_PWM_INPUT,
  247. HWMON_PWM_INPUT,
  248. HWMON_PWM_INPUT,
  249. HWMON_PWM_INPUT,
  250. HWMON_PWM_INPUT,
  251. HWMON_PWM_INPUT,
  252. HWMON_PWM_INPUT,
  253. HWMON_PWM_INPUT,
  254. HWMON_PWM_INPUT,
  255. HWMON_PWM_INPUT,
  256. HWMON_PWM_INPUT,
  257. HWMON_PWM_INPUT),
  258. NULL
  259. };
  260. static const struct hwmon_chip_info dasharo_hwmon_chip_info = {
  261. .ops = &dasharo_hwmon_ops,
  262. .info = dasharo_hwmon_info,
  263. };
  264. static void dasharo_fill_feature_caps(struct dasharo_data *data, enum dasharo_feature feat)
  265. {
  266. struct dasharo_capability *cap;
  267. int cap_count = 0;
  268. int count;
  269. for (int group = 0; group < MAX_GROUPS_PER_FEAT; ++group) {
  270. count = dasharo_get_feature_cap_count(data, feat, group);
  271. if (count <= 0)
  272. continue;
  273. for (unsigned int i = 0; i < count; ++i) {
  274. if (cap_count >= ARRAY_SIZE(data->capabilities[feat]))
  275. break;
  276. cap = &data->capabilities[feat][cap_count];
  277. cap->group = group;
  278. cap->index = i;
  279. scnprintf(cap->name, sizeof(cap->name), "%s %d",
  280. dasharo_group_names[feat][group], i);
  281. cap_count++;
  282. }
  283. }
  284. data->caps_found[feat] = cap_count;
  285. }
  286. static int dasharo_probe(struct platform_device *pdev)
  287. {
  288. struct dasharo_data *data;
  289. struct device *hwmon;
  290. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  291. if (!data)
  292. return -ENOMEM;
  293. data->pdev = pdev;
  294. for (unsigned int i = 0; i < DASHARO_FEATURE_MAX; ++i)
  295. dasharo_fill_feature_caps(data, i);
  296. hwmon = devm_hwmon_device_register_with_info(&pdev->dev, "dasharo_acpi", data,
  297. &dasharo_hwmon_chip_info, NULL);
  298. return PTR_ERR_OR_ZERO(hwmon);
  299. }
  300. static const struct acpi_device_id dasharo_device_ids[] = {
  301. {"DSHR0001", 0},
  302. {}
  303. };
  304. MODULE_DEVICE_TABLE(acpi, dasharo_device_ids);
  305. static struct platform_driver dasharo_driver = {
  306. .driver = {
  307. .name = "dasharo-acpi",
  308. .acpi_match_table = dasharo_device_ids,
  309. },
  310. .probe = dasharo_probe,
  311. };
  312. module_platform_driver(dasharo_driver);
  313. MODULE_DESCRIPTION("Dasharo ACPI Driver");
  314. MODULE_AUTHOR("Michał Kopeć <michal.kopec@3mdeb.com>");
  315. MODULE_LICENSE("GPL");