cros_ec_hwmon.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * ChromeOS EC driver for hwmon
  4. *
  5. * Copyright (C) 2024 Thomas Weißschuh <linux@weissschuh.net>
  6. */
  7. #include <linux/device.h>
  8. #include <linux/hwmon.h>
  9. #include <linux/math.h>
  10. #include <linux/mod_devicetable.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/platform_data/cros_ec_commands.h>
  14. #include <linux/platform_data/cros_ec_proto.h>
  15. #include <linux/thermal.h>
  16. #include <linux/types.h>
  17. #include <linux/units.h>
  18. #define DRV_NAME "cros-ec-hwmon"
  19. #define CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION 0
  20. #define CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION 1
  21. #define CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION 2
  22. struct cros_ec_hwmon_priv {
  23. struct cros_ec_device *cros_ec;
  24. const char *temp_sensor_names[EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES];
  25. u8 usable_fans;
  26. bool fan_control_supported;
  27. bool temp_threshold_supported;
  28. u8 manual_fans; /* bits to indicate whether the fan is set to manual */
  29. u8 manual_fan_pwm[EC_FAN_SPEED_ENTRIES];
  30. };
  31. struct cros_ec_hwmon_cooling_priv {
  32. struct cros_ec_hwmon_priv *hwmon_priv;
  33. u8 index;
  34. };
  35. static int cros_ec_hwmon_read_fan_speed(struct cros_ec_device *cros_ec, u8 index, u16 *speed)
  36. {
  37. int ret;
  38. __le16 __speed;
  39. ret = cros_ec_cmd_readmem(cros_ec, EC_MEMMAP_FAN + index * 2, 2, &__speed);
  40. if (ret < 0)
  41. return ret;
  42. *speed = le16_to_cpu(__speed);
  43. return 0;
  44. }
  45. static int cros_ec_hwmon_read_pwm_value(struct cros_ec_device *cros_ec, u8 index, u8 *pwm_value)
  46. {
  47. struct ec_params_pwm_get_fan_duty req = {
  48. .fan_idx = index,
  49. };
  50. struct ec_response_pwm_get_fan_duty resp;
  51. int ret;
  52. ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION,
  53. EC_CMD_PWM_GET_FAN_DUTY, &req, sizeof(req), &resp, sizeof(resp));
  54. if (ret < 0)
  55. return ret;
  56. *pwm_value = (u8)DIV_ROUND_CLOSEST(le32_to_cpu(resp.percent) * 255, 100);
  57. return 0;
  58. }
  59. static int cros_ec_hwmon_read_pwm_enable(struct cros_ec_device *cros_ec, u8 index,
  60. u8 *control_method)
  61. {
  62. struct ec_params_auto_fan_ctrl_v2 req = {
  63. .cmd = EC_AUTO_FAN_CONTROL_CMD_GET,
  64. .fan_idx = index,
  65. };
  66. struct ec_response_auto_fan_control resp;
  67. int ret;
  68. ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION,
  69. EC_CMD_THERMAL_AUTO_FAN_CTRL, &req, sizeof(req), &resp, sizeof(resp));
  70. if (ret < 0)
  71. return ret;
  72. *control_method = resp.is_auto ? 2 : 1;
  73. return 0;
  74. }
  75. static int cros_ec_hwmon_read_fan_target(struct cros_ec_device *cros_ec, u16 *speed)
  76. {
  77. struct ec_response_pwm_get_fan_rpm resp;
  78. int ret;
  79. ret = cros_ec_cmd(cros_ec, 0, EC_CMD_PWM_GET_FAN_TARGET_RPM,
  80. NULL, 0, &resp, sizeof(resp));
  81. if (ret < 0)
  82. return ret;
  83. *speed = resp.rpm;
  84. return 0;
  85. }
  86. static int cros_ec_hwmon_read_temp(struct cros_ec_device *cros_ec, u8 index, u8 *temp)
  87. {
  88. unsigned int offset;
  89. int ret;
  90. if (index < EC_TEMP_SENSOR_ENTRIES)
  91. offset = EC_MEMMAP_TEMP_SENSOR + index;
  92. else
  93. offset = EC_MEMMAP_TEMP_SENSOR_B + index - EC_TEMP_SENSOR_ENTRIES;
  94. ret = cros_ec_cmd_readmem(cros_ec, offset, 1, temp);
  95. if (ret < 0)
  96. return ret;
  97. return 0;
  98. }
  99. static int cros_ec_hwmon_read_temp_threshold(struct cros_ec_device *cros_ec, u8 index,
  100. enum ec_temp_thresholds threshold, u32 *temp)
  101. {
  102. struct ec_params_thermal_get_threshold_v1 req = {};
  103. struct ec_thermal_config resp;
  104. int ret;
  105. req.sensor_num = index;
  106. ret = cros_ec_cmd(cros_ec, 1, EC_CMD_THERMAL_GET_THRESHOLD,
  107. &req, sizeof(req), &resp, sizeof(resp));
  108. if (ret < 0)
  109. return ret;
  110. *temp = resp.temp_host[threshold];
  111. return 0;
  112. }
  113. static bool cros_ec_hwmon_is_error_fan(u16 speed)
  114. {
  115. return speed == EC_FAN_SPEED_NOT_PRESENT || speed == EC_FAN_SPEED_STALLED;
  116. }
  117. static bool cros_ec_hwmon_is_error_temp(u8 temp)
  118. {
  119. return temp == EC_TEMP_SENSOR_NOT_PRESENT ||
  120. temp == EC_TEMP_SENSOR_ERROR ||
  121. temp == EC_TEMP_SENSOR_NOT_POWERED ||
  122. temp == EC_TEMP_SENSOR_NOT_CALIBRATED;
  123. }
  124. static long cros_ec_hwmon_temp_to_millicelsius(u8 temp)
  125. {
  126. return kelvin_to_millicelsius((((long)temp) + EC_TEMP_SENSOR_OFFSET));
  127. }
  128. static bool cros_ec_hwmon_attr_is_temp_threshold(u32 attr)
  129. {
  130. return attr == hwmon_temp_max ||
  131. attr == hwmon_temp_crit ||
  132. attr == hwmon_temp_emergency;
  133. }
  134. static enum ec_temp_thresholds cros_ec_hwmon_attr_to_thres(u32 attr)
  135. {
  136. if (attr == hwmon_temp_max)
  137. return EC_TEMP_THRESH_WARN;
  138. else if (attr == hwmon_temp_crit)
  139. return EC_TEMP_THRESH_HIGH;
  140. return EC_TEMP_THRESH_HALT; /* attr == hwmon_temp_emergency */
  141. }
  142. static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  143. u32 attr, int channel, long *val)
  144. {
  145. struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev);
  146. int ret = -EOPNOTSUPP;
  147. u8 control_method;
  148. u32 threshold;
  149. u8 pwm_value;
  150. u16 speed;
  151. u8 temp;
  152. if (type == hwmon_fan) {
  153. if (attr == hwmon_fan_input) {
  154. ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, channel, &speed);
  155. if (ret == 0) {
  156. if (cros_ec_hwmon_is_error_fan(speed))
  157. ret = -ENODATA;
  158. else
  159. *val = speed;
  160. }
  161. } else if (attr == hwmon_fan_fault) {
  162. ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, channel, &speed);
  163. if (ret == 0)
  164. *val = cros_ec_hwmon_is_error_fan(speed);
  165. } else if (attr == hwmon_fan_target) {
  166. ret = cros_ec_hwmon_read_fan_target(priv->cros_ec, &speed);
  167. if (ret == 0)
  168. *val = speed;
  169. }
  170. } else if (type == hwmon_pwm) {
  171. if (attr == hwmon_pwm_enable) {
  172. ret = cros_ec_hwmon_read_pwm_enable(priv->cros_ec, channel,
  173. &control_method);
  174. if (ret == 0)
  175. *val = control_method;
  176. } else if (attr == hwmon_pwm_input) {
  177. ret = cros_ec_hwmon_read_pwm_value(priv->cros_ec, channel, &pwm_value);
  178. if (ret == 0)
  179. *val = pwm_value;
  180. }
  181. } else if (type == hwmon_temp) {
  182. if (attr == hwmon_temp_input) {
  183. ret = cros_ec_hwmon_read_temp(priv->cros_ec, channel, &temp);
  184. if (ret == 0) {
  185. if (cros_ec_hwmon_is_error_temp(temp))
  186. ret = -ENODATA;
  187. else
  188. *val = cros_ec_hwmon_temp_to_millicelsius(temp);
  189. }
  190. } else if (attr == hwmon_temp_fault) {
  191. ret = cros_ec_hwmon_read_temp(priv->cros_ec, channel, &temp);
  192. if (ret == 0)
  193. *val = cros_ec_hwmon_is_error_temp(temp);
  194. } else if (cros_ec_hwmon_attr_is_temp_threshold(attr)) {
  195. ret = cros_ec_hwmon_read_temp_threshold(priv->cros_ec, channel,
  196. cros_ec_hwmon_attr_to_thres(attr),
  197. &threshold);
  198. if (ret == 0)
  199. *val = kelvin_to_millicelsius(threshold);
  200. }
  201. }
  202. return ret;
  203. }
  204. static int cros_ec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
  205. u32 attr, int channel, const char **str)
  206. {
  207. struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev);
  208. if (type == hwmon_temp && attr == hwmon_temp_label) {
  209. *str = priv->temp_sensor_names[channel];
  210. return 0;
  211. }
  212. return -EOPNOTSUPP;
  213. }
  214. static int cros_ec_hwmon_set_fan_pwm_val(struct cros_ec_device *cros_ec, u8 index, u8 val)
  215. {
  216. struct ec_params_pwm_set_fan_duty_v1 req = {
  217. .fan_idx = index,
  218. .percent = DIV_ROUND_CLOSEST((uint32_t)val * 100, 255),
  219. };
  220. int ret;
  221. ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION,
  222. EC_CMD_PWM_SET_FAN_DUTY, &req, sizeof(req), NULL, 0);
  223. if (ret < 0)
  224. return ret;
  225. return 0;
  226. }
  227. static int cros_ec_hwmon_write_pwm_input(struct cros_ec_device *cros_ec, u8 index, u8 val)
  228. {
  229. u8 control_method;
  230. int ret;
  231. ret = cros_ec_hwmon_read_pwm_enable(cros_ec, index, &control_method);
  232. if (ret)
  233. return ret;
  234. if (control_method != 1)
  235. return -EOPNOTSUPP;
  236. return cros_ec_hwmon_set_fan_pwm_val(cros_ec, index, val);
  237. }
  238. static int cros_ec_hwmon_write_pwm_enable(struct cros_ec_device *cros_ec, u8 index, u8 val)
  239. {
  240. struct ec_params_auto_fan_ctrl_v2 req = {
  241. .fan_idx = index,
  242. .cmd = EC_AUTO_FAN_CONTROL_CMD_SET,
  243. };
  244. int ret;
  245. /* No CrOS EC supports no fan speed control */
  246. if (val == 0)
  247. return -EOPNOTSUPP;
  248. req.set_auto = (val != 1) ? true : false;
  249. ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION,
  250. EC_CMD_THERMAL_AUTO_FAN_CTRL, &req, sizeof(req), NULL, 0);
  251. if (ret < 0)
  252. return ret;
  253. return 0;
  254. }
  255. static int cros_ec_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
  256. int channel, long val)
  257. {
  258. struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev);
  259. if (type == hwmon_pwm) {
  260. switch (attr) {
  261. case hwmon_pwm_input:
  262. return cros_ec_hwmon_write_pwm_input(priv->cros_ec, channel, val);
  263. case hwmon_pwm_enable:
  264. return cros_ec_hwmon_write_pwm_enable(priv->cros_ec, channel, val);
  265. default:
  266. return -EOPNOTSUPP;
  267. }
  268. }
  269. return -EOPNOTSUPP;
  270. }
  271. static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
  272. u32 attr, int channel)
  273. {
  274. const struct cros_ec_hwmon_priv *priv = data;
  275. u16 speed;
  276. if (type == hwmon_fan) {
  277. if (attr == hwmon_fan_target &&
  278. cros_ec_hwmon_read_fan_target(priv->cros_ec, &speed) == -EOPNOTSUPP)
  279. return 0;
  280. if (priv->usable_fans & BIT(channel))
  281. return 0444;
  282. } else if (type == hwmon_pwm) {
  283. if (priv->fan_control_supported && priv->usable_fans & BIT(channel))
  284. return 0644;
  285. } else if (type == hwmon_temp) {
  286. if (priv->temp_sensor_names[channel]) {
  287. if (cros_ec_hwmon_attr_is_temp_threshold(attr)) {
  288. if (priv->temp_threshold_supported)
  289. return 0444;
  290. } else {
  291. return 0444;
  292. }
  293. }
  294. }
  295. return 0;
  296. }
  297. static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = {
  298. HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
  299. HWMON_CHANNEL_INFO(fan,
  300. HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_TARGET,
  301. HWMON_F_INPUT | HWMON_F_FAULT,
  302. HWMON_F_INPUT | HWMON_F_FAULT,
  303. HWMON_F_INPUT | HWMON_F_FAULT),
  304. HWMON_CHANNEL_INFO(pwm,
  305. HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
  306. HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
  307. HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
  308. HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
  309. #define CROS_EC_HWMON_TEMP_PARAMS (HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL | \
  310. HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_EMERGENCY)
  311. HWMON_CHANNEL_INFO(temp,
  312. CROS_EC_HWMON_TEMP_PARAMS,
  313. CROS_EC_HWMON_TEMP_PARAMS,
  314. CROS_EC_HWMON_TEMP_PARAMS,
  315. CROS_EC_HWMON_TEMP_PARAMS,
  316. CROS_EC_HWMON_TEMP_PARAMS,
  317. CROS_EC_HWMON_TEMP_PARAMS,
  318. CROS_EC_HWMON_TEMP_PARAMS,
  319. CROS_EC_HWMON_TEMP_PARAMS,
  320. CROS_EC_HWMON_TEMP_PARAMS,
  321. CROS_EC_HWMON_TEMP_PARAMS,
  322. CROS_EC_HWMON_TEMP_PARAMS,
  323. CROS_EC_HWMON_TEMP_PARAMS,
  324. CROS_EC_HWMON_TEMP_PARAMS,
  325. CROS_EC_HWMON_TEMP_PARAMS,
  326. CROS_EC_HWMON_TEMP_PARAMS,
  327. CROS_EC_HWMON_TEMP_PARAMS,
  328. CROS_EC_HWMON_TEMP_PARAMS,
  329. CROS_EC_HWMON_TEMP_PARAMS,
  330. CROS_EC_HWMON_TEMP_PARAMS,
  331. CROS_EC_HWMON_TEMP_PARAMS,
  332. CROS_EC_HWMON_TEMP_PARAMS,
  333. CROS_EC_HWMON_TEMP_PARAMS,
  334. CROS_EC_HWMON_TEMP_PARAMS,
  335. CROS_EC_HWMON_TEMP_PARAMS),
  336. NULL
  337. };
  338. static int cros_ec_hwmon_cooling_get_max_state(struct thermal_cooling_device *cdev,
  339. unsigned long *val)
  340. {
  341. *val = 255;
  342. return 0;
  343. }
  344. static int cros_ec_hwmon_cooling_get_cur_state(struct thermal_cooling_device *cdev,
  345. unsigned long *val)
  346. {
  347. const struct cros_ec_hwmon_cooling_priv *priv = cdev->devdata;
  348. u8 read_val;
  349. int ret;
  350. ret = cros_ec_hwmon_read_pwm_value(priv->hwmon_priv->cros_ec, priv->index, &read_val);
  351. if (ret)
  352. return ret;
  353. *val = read_val;
  354. return 0;
  355. }
  356. static int cros_ec_hwmon_cooling_set_cur_state(struct thermal_cooling_device *cdev,
  357. unsigned long val)
  358. {
  359. const struct cros_ec_hwmon_cooling_priv *priv = cdev->devdata;
  360. return cros_ec_hwmon_write_pwm_input(priv->hwmon_priv->cros_ec, priv->index, val);
  361. }
  362. static const struct thermal_cooling_device_ops cros_ec_thermal_cooling_ops = {
  363. .get_max_state = cros_ec_hwmon_cooling_get_max_state,
  364. .get_cur_state = cros_ec_hwmon_cooling_get_cur_state,
  365. .set_cur_state = cros_ec_hwmon_cooling_set_cur_state,
  366. };
  367. static const struct hwmon_ops cros_ec_hwmon_ops = {
  368. .read = cros_ec_hwmon_read,
  369. .read_string = cros_ec_hwmon_read_string,
  370. .write = cros_ec_hwmon_write,
  371. .is_visible = cros_ec_hwmon_is_visible,
  372. };
  373. static const struct hwmon_chip_info cros_ec_hwmon_chip_info = {
  374. .ops = &cros_ec_hwmon_ops,
  375. .info = cros_ec_hwmon_info,
  376. };
  377. static void cros_ec_hwmon_probe_temp_sensors(struct device *dev, struct cros_ec_hwmon_priv *priv,
  378. u8 thermal_version)
  379. {
  380. struct ec_params_temp_sensor_get_info req = {};
  381. struct ec_response_temp_sensor_get_info resp;
  382. size_t candidates, i, sensor_name_size;
  383. int ret;
  384. u8 temp;
  385. if (thermal_version < 2)
  386. candidates = EC_TEMP_SENSOR_ENTRIES;
  387. else
  388. candidates = ARRAY_SIZE(priv->temp_sensor_names);
  389. for (i = 0; i < candidates; i++) {
  390. if (cros_ec_hwmon_read_temp(priv->cros_ec, i, &temp) < 0)
  391. continue;
  392. if (temp == EC_TEMP_SENSOR_NOT_PRESENT)
  393. continue;
  394. req.id = i;
  395. ret = cros_ec_cmd(priv->cros_ec, 0, EC_CMD_TEMP_SENSOR_GET_INFO,
  396. &req, sizeof(req), &resp, sizeof(resp));
  397. if (ret < 0)
  398. continue;
  399. sensor_name_size = strnlen(resp.sensor_name, sizeof(resp.sensor_name));
  400. priv->temp_sensor_names[i] = devm_kasprintf(dev, GFP_KERNEL, "%.*s",
  401. (int)sensor_name_size,
  402. resp.sensor_name);
  403. }
  404. }
  405. static void cros_ec_hwmon_probe_fans(struct cros_ec_hwmon_priv *priv)
  406. {
  407. u16 speed;
  408. size_t i;
  409. int ret;
  410. for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
  411. ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, i, &speed);
  412. if (ret == 0 && speed != EC_FAN_SPEED_NOT_PRESENT)
  413. priv->usable_fans |= BIT(i);
  414. }
  415. }
  416. static inline bool is_cros_ec_cmd_available(struct cros_ec_device *cros_ec,
  417. u16 cmd, u8 version)
  418. {
  419. int ret;
  420. ret = cros_ec_get_cmd_versions(cros_ec, cmd);
  421. return ret >= 0 && (ret & EC_VER_MASK(version));
  422. }
  423. static bool cros_ec_hwmon_probe_fan_control_supported(struct cros_ec_device *cros_ec)
  424. {
  425. return is_cros_ec_cmd_available(cros_ec, EC_CMD_PWM_GET_FAN_DUTY,
  426. CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION) &&
  427. is_cros_ec_cmd_available(cros_ec, EC_CMD_PWM_SET_FAN_DUTY,
  428. CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION) &&
  429. is_cros_ec_cmd_available(cros_ec, EC_CMD_THERMAL_AUTO_FAN_CTRL,
  430. CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION);
  431. }
  432. static void cros_ec_hwmon_register_fan_cooling_devices(struct device *dev,
  433. struct cros_ec_hwmon_priv *priv)
  434. {
  435. struct cros_ec_hwmon_cooling_priv *cpriv;
  436. struct thermal_cooling_device *cdev;
  437. const char *type;
  438. size_t i;
  439. if (!IS_ENABLED(CONFIG_THERMAL))
  440. return;
  441. if (!priv->fan_control_supported)
  442. return;
  443. for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
  444. if (!(priv->usable_fans & BIT(i)))
  445. continue;
  446. cpriv = devm_kzalloc(dev, sizeof(*cpriv), GFP_KERNEL);
  447. if (!cpriv)
  448. continue;
  449. type = devm_kasprintf(dev, GFP_KERNEL, "%s-fan%zu", dev_name(dev), i);
  450. if (!type) {
  451. dev_warn(dev, "no memory to compose cooling device type for fan %zu\n", i);
  452. continue;
  453. }
  454. cpriv->hwmon_priv = priv;
  455. cpriv->index = i;
  456. cdev = devm_thermal_of_cooling_device_register(dev, NULL, type, cpriv,
  457. &cros_ec_thermal_cooling_ops);
  458. if (IS_ERR(cdev)) {
  459. dev_warn(dev, "failed to register fan %zu as a cooling device: %pe\n", i,
  460. cdev);
  461. continue;
  462. }
  463. }
  464. }
  465. static int cros_ec_hwmon_probe(struct platform_device *pdev)
  466. {
  467. struct device *dev = &pdev->dev;
  468. struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
  469. struct cros_ec_device *cros_ec = ec_dev->ec_dev;
  470. struct cros_ec_hwmon_priv *priv;
  471. struct device *hwmon_dev;
  472. u8 thermal_version;
  473. int ret;
  474. ret = cros_ec_cmd_readmem(cros_ec, EC_MEMMAP_THERMAL_VERSION, 1, &thermal_version);
  475. if (ret < 0)
  476. return ret;
  477. /* Covers both fan and temp sensors */
  478. if (thermal_version == 0)
  479. return -ENODEV;
  480. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  481. if (!priv)
  482. return -ENOMEM;
  483. priv->cros_ec = cros_ec;
  484. cros_ec_hwmon_probe_temp_sensors(dev, priv, thermal_version);
  485. cros_ec_hwmon_probe_fans(priv);
  486. priv->fan_control_supported = cros_ec_hwmon_probe_fan_control_supported(priv->cros_ec);
  487. priv->temp_threshold_supported = is_cros_ec_cmd_available(priv->cros_ec,
  488. EC_CMD_THERMAL_GET_THRESHOLD, 1);
  489. cros_ec_hwmon_register_fan_cooling_devices(dev, priv);
  490. hwmon_dev = devm_hwmon_device_register_with_info(dev, "cros_ec", priv,
  491. &cros_ec_hwmon_chip_info, NULL);
  492. platform_set_drvdata(pdev, priv);
  493. return PTR_ERR_OR_ZERO(hwmon_dev);
  494. }
  495. static int cros_ec_hwmon_suspend(struct platform_device *pdev, pm_message_t state)
  496. {
  497. struct cros_ec_hwmon_priv *priv = platform_get_drvdata(pdev);
  498. u8 control_method;
  499. size_t i;
  500. int ret;
  501. if (!priv->fan_control_supported)
  502. return 0;
  503. /* EC sets fan control to auto after suspended, store settings before suspending. */
  504. for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
  505. if (!(priv->usable_fans & BIT(i)))
  506. continue;
  507. ret = cros_ec_hwmon_read_pwm_enable(priv->cros_ec, i, &control_method);
  508. if (ret) {
  509. dev_warn(&pdev->dev, "failed to get mode setting for fan %zu: %d\n", i,
  510. ret);
  511. continue;
  512. }
  513. if (control_method != 1) {
  514. priv->manual_fans &= ~BIT(i);
  515. continue;
  516. } else {
  517. priv->manual_fans |= BIT(i);
  518. }
  519. ret = cros_ec_hwmon_read_pwm_value(priv->cros_ec, i, &priv->manual_fan_pwm[i]);
  520. /*
  521. * If storing the value failed, invalidate the stored mode value by setting it
  522. * to auto control. EC will automatically switch to auto mode for that fan after
  523. * suspended.
  524. */
  525. if (ret) {
  526. dev_warn(&pdev->dev, "failed to get PWM setting for fan %zu: %pe\n", i,
  527. ERR_PTR(ret));
  528. priv->manual_fans &= ~BIT(i);
  529. continue;
  530. }
  531. }
  532. return 0;
  533. }
  534. static int cros_ec_hwmon_resume(struct platform_device *pdev)
  535. {
  536. const struct cros_ec_hwmon_priv *priv = platform_get_drvdata(pdev);
  537. size_t i;
  538. int ret;
  539. if (!priv->fan_control_supported)
  540. return 0;
  541. /* EC sets fan control to auto after suspend, restore to settings before suspend. */
  542. for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
  543. if (!(priv->manual_fans & BIT(i)))
  544. continue;
  545. /*
  546. * Setting fan PWM value to EC will change the mode to manual for that fan in EC as
  547. * well, so we do not need to issue a separate fan mode to manual call.
  548. */
  549. ret = cros_ec_hwmon_set_fan_pwm_val(priv->cros_ec, i, priv->manual_fan_pwm[i]);
  550. if (ret)
  551. dev_warn(&pdev->dev, "failed to restore settings for fan %zu: %pe\n", i,
  552. ERR_PTR(ret));
  553. }
  554. return 0;
  555. }
  556. static const struct platform_device_id cros_ec_hwmon_id[] = {
  557. { DRV_NAME, 0 },
  558. {}
  559. };
  560. static struct platform_driver cros_ec_hwmon_driver = {
  561. .driver.name = DRV_NAME,
  562. .probe = cros_ec_hwmon_probe,
  563. .suspend = pm_ptr(cros_ec_hwmon_suspend),
  564. .resume = pm_ptr(cros_ec_hwmon_resume),
  565. .id_table = cros_ec_hwmon_id,
  566. };
  567. module_platform_driver(cros_ec_hwmon_driver);
  568. MODULE_DEVICE_TABLE(platform, cros_ec_hwmon_id);
  569. MODULE_DESCRIPTION("ChromeOS EC Hardware Monitoring Driver");
  570. MODULE_AUTHOR("Thomas Weißschuh <linux@weissschuh.net");
  571. MODULE_LICENSE("GPL");