Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: (tc654) Add thermal_cooling device support

Adds thermal_cooling device support to the tc654/tc655
driver. This make it possible to integrate it into a
device-tree supported thermal-zone node as a
cooling device.

I have been using this patch as part of the Netgear WNDR4700
Centria NAS Router support within OpenWrt since 2016.

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Link: https://lore.kernel.org/r/20220213004733.2421193-1-chunkeey@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Christian Lamparter and committed by
Guenter Roeck
99cb5e9f 5f86cce6

+89 -15
+89 -15
drivers/hwmon/tc654.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/mutex.h> 17 17 #include <linux/slab.h> 18 + #include <linux/thermal.h> 18 19 #include <linux/util_macros.h> 19 20 20 21 enum tc654_regs { ··· 380 379 return sprintf(buf, "%d\n", pwm); 381 380 } 382 381 383 - static ssize_t pwm_store(struct device *dev, struct device_attribute *da, 384 - const char *buf, size_t count) 382 + static int _set_pwm(struct tc654_data *data, unsigned long val) 385 383 { 386 - struct tc654_data *data = dev_get_drvdata(dev); 387 384 struct i2c_client *client = data->client; 388 - unsigned long val; 389 385 int ret; 390 - 391 - if (kstrtoul(buf, 10, &val)) 392 - return -EINVAL; 393 - if (val > 255) 394 - return -EINVAL; 395 386 396 387 mutex_lock(&data->update_lock); 397 388 398 - if (val == 0) 389 + if (val == 0) { 399 390 data->config |= TC654_REG_CONFIG_SDM; 400 - else 391 + data->duty_cycle = 0; 392 + } else { 401 393 data->config &= ~TC654_REG_CONFIG_SDM; 402 - 403 - data->duty_cycle = find_closest(val, tc654_pwm_map, 404 - ARRAY_SIZE(tc654_pwm_map)); 394 + data->duty_cycle = val - 1; 395 + } 405 396 406 397 ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); 407 398 if (ret < 0) ··· 404 411 405 412 out: 406 413 mutex_unlock(&data->update_lock); 414 + return ret; 415 + } 416 + 417 + static ssize_t pwm_store(struct device *dev, struct device_attribute *da, 418 + const char *buf, size_t count) 419 + { 420 + struct tc654_data *data = dev_get_drvdata(dev); 421 + unsigned long val; 422 + int ret; 423 + 424 + if (kstrtoul(buf, 10, &val)) 425 + return -EINVAL; 426 + if (val > 255) 427 + return -EINVAL; 428 + if (val > 0) 429 + val = find_closest(val, tc654_pwm_map, ARRAY_SIZE(tc654_pwm_map)) + 1; 430 + 431 + ret = _set_pwm(data, val); 407 432 return ret < 0 ? ret : count; 408 433 } 409 434 ··· 454 443 ATTRIBUTE_GROUPS(tc654); 455 444 456 445 /* 446 + * thermal cooling device functions 447 + * 448 + * Account for the "ShutDown Mode (SDM)" state by offsetting 449 + * the 16 PWM duty cycle states by 1. 450 + * 451 + * State 0 = 0% PWM | Shutdown - Fan(s) are off 452 + * State 1 = 30% PWM | duty_cycle = 0 453 + * State 2 = ~35% PWM | duty_cycle = 1 454 + * [...] 455 + * State 15 = ~95% PWM | duty_cycle = 14 456 + * State 16 = 100% PWM | duty_cycle = 15 457 + */ 458 + #define TC654_MAX_COOLING_STATE 16 459 + 460 + static int tc654_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) 461 + { 462 + *state = TC654_MAX_COOLING_STATE; 463 + return 0; 464 + } 465 + 466 + static int tc654_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) 467 + { 468 + struct tc654_data *data = tc654_update_client(cdev->devdata); 469 + 470 + if (IS_ERR(data)) 471 + return PTR_ERR(data); 472 + 473 + if (data->config & TC654_REG_CONFIG_SDM) 474 + *state = 0; /* FAN is off */ 475 + else 476 + *state = data->duty_cycle + 1; /* offset PWM States by 1 */ 477 + 478 + return 0; 479 + } 480 + 481 + static int tc654_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) 482 + { 483 + struct tc654_data *data = tc654_update_client(cdev->devdata); 484 + 485 + if (IS_ERR(data)) 486 + return PTR_ERR(data); 487 + 488 + return _set_pwm(data, clamp_val(state, 0, TC654_MAX_COOLING_STATE)); 489 + } 490 + 491 + static const struct thermal_cooling_device_ops tc654_fan_cool_ops = { 492 + .get_max_state = tc654_get_max_state, 493 + .get_cur_state = tc654_get_cur_state, 494 + .set_cur_state = tc654_set_cur_state, 495 + }; 496 + 497 + /* 457 498 * device probe and removal 458 499 */ 459 500 ··· 535 472 hwmon_dev = 536 473 devm_hwmon_device_register_with_groups(dev, client->name, data, 537 474 tc654_groups); 538 - return PTR_ERR_OR_ZERO(hwmon_dev); 475 + if (IS_ERR(hwmon_dev)) 476 + return PTR_ERR(hwmon_dev); 477 + 478 + if (IS_ENABLED(CONFIG_THERMAL)) { 479 + struct thermal_cooling_device *cdev; 480 + 481 + cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name, 482 + hwmon_dev, &tc654_fan_cool_ops); 483 + return PTR_ERR_OR_ZERO(cdev); 484 + } 485 + 486 + return 0; 539 487 } 540 488 541 489 static const struct i2c_device_id tc654_id[] = {