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