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

hwmon: (axi-fan-control) Support temperature vs pwm points

The HW has some predefined points where it will associate a PWM value.
However some users might want to better set these points to their
usecases. This patch exposes these points as pwm auto_points:

* pwm1_auto_point1_temp_hyst: temperature threshold below which PWM should
be 0%;
* pwm1_auto_point1_temp: temperature threshold above which PWM should be
25%;
* pwm1_auto_point2_temp_hyst: temperature threshold below which PWM should
be 25%;
* pwm1_auto_point2_temp: temperature threshold above which PWM should be
50%;
* pwm1_auto_point3_temp_hyst: temperature threshold below which PWM should
be 50%;
* pwm1_auto_point3_temp: temperature threshold above which PWM should be
75%;
* pwm1_auto_point4_temp_hyst: temperature threshold below which PWM should
be 75%;
* pwm1_auto_point4_temp: temperature threshold above which PWM should be
100%;

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20210811114853.159298-4-nuno.sa@analog.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Nuno Sá and committed by
Guenter Roeck
2aee7e67 e66705de

+73 -1
+73 -1
drivers/hwmon/axi-fan-control.c
··· 8 8 #include <linux/clk.h> 9 9 #include <linux/fpga/adi-axi-common.h> 10 10 #include <linux/hwmon.h> 11 + #include <linux/hwmon-sysfs.h> 11 12 #include <linux/interrupt.h> 12 13 #include <linux/io.h> 13 14 #include <linux/kernel.h> ··· 24 23 #define ADI_REG_PWM_PERIOD 0x00c0 25 24 #define ADI_REG_TACH_MEASUR 0x00c4 26 25 #define ADI_REG_TEMPERATURE 0x00c8 26 + #define ADI_REG_TEMP_00_H 0x0100 27 + #define ADI_REG_TEMP_25_L 0x0104 28 + #define ADI_REG_TEMP_25_H 0x0108 29 + #define ADI_REG_TEMP_50_L 0x010c 30 + #define ADI_REG_TEMP_50_H 0x0110 31 + #define ADI_REG_TEMP_75_L 0x0114 32 + #define ADI_REG_TEMP_75_H 0x0118 33 + #define ADI_REG_TEMP_100_L 0x011c 27 34 28 35 #define ADI_REG_IRQ_MASK 0x0040 29 36 #define ADI_REG_IRQ_PENDING 0x0044 ··· 69 60 const struct axi_fan_control_data *ctl) 70 61 { 71 62 return ioread32(ctl->base + reg); 63 + } 64 + 65 + /* 66 + * The core calculates the temperature as: 67 + * T = /raw * 509.3140064 / 65535) - 280.2308787 68 + */ 69 + static ssize_t axi_fan_control_show(struct device *dev, struct device_attribute *da, char *buf) 70 + { 71 + struct axi_fan_control_data *ctl = dev_get_drvdata(dev); 72 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 73 + u32 temp = axi_ioread(attr->index, ctl); 74 + 75 + temp = DIV_ROUND_CLOSEST_ULL(temp * 509314ULL, 65535) - 280230; 76 + 77 + return sprintf(buf, "%u\n", temp); 78 + } 79 + 80 + static ssize_t axi_fan_control_store(struct device *dev, struct device_attribute *da, 81 + const char *buf, size_t count) 82 + { 83 + struct axi_fan_control_data *ctl = dev_get_drvdata(dev); 84 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 85 + u32 temp; 86 + int ret; 87 + 88 + ret = kstrtou32(buf, 10, &temp); 89 + if (ret) 90 + return ret; 91 + 92 + temp = DIV_ROUND_CLOSEST_ULL((temp + 280230) * 65535ULL, 509314); 93 + axi_iowrite(temp, attr->index, ctl); 94 + 95 + return count; 72 96 } 73 97 74 98 static long axi_fan_control_get_pwm_duty(const struct axi_fan_control_data *ctl) ··· 417 375 .info = axi_fan_control_info, 418 376 }; 419 377 378 + /* temperature threshold below which PWM should be 0% */ 379 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp_hyst, axi_fan_control, ADI_REG_TEMP_00_H); 380 + /* temperature threshold above which PWM should be 25% */ 381 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, axi_fan_control, ADI_REG_TEMP_25_L); 382 + /* temperature threshold below which PWM should be 25% */ 383 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp_hyst, axi_fan_control, ADI_REG_TEMP_25_H); 384 + /* temperature threshold above which PWM should be 50% */ 385 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp, axi_fan_control, ADI_REG_TEMP_50_L); 386 + /* temperature threshold below which PWM should be 50% */ 387 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp_hyst, axi_fan_control, ADI_REG_TEMP_50_H); 388 + /* temperature threshold above which PWM should be 75% */ 389 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, axi_fan_control, ADI_REG_TEMP_75_L); 390 + /* temperature threshold below which PWM should be 75% */ 391 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp_hyst, axi_fan_control, ADI_REG_TEMP_75_H); 392 + /* temperature threshold above which PWM should be 100% */ 393 + static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, axi_fan_control, ADI_REG_TEMP_100_L); 394 + 395 + static struct attribute *axi_fan_control_attrs[] = { 396 + &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr, 397 + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, 398 + &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr, 399 + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, 400 + &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr, 401 + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, 402 + &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr, 403 + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, 404 + NULL, 405 + }; 406 + ATTRIBUTE_GROUPS(axi_fan_control); 407 + 420 408 static const u32 version_1_0_0 = ADI_AXI_PCORE_VER(1, 0, 'a'); 421 409 422 410 static const struct of_device_id axi_fan_control_of_match[] = { ··· 531 459 name, 532 460 ctl, 533 461 &axi_chip_info, 534 - NULL); 462 + axi_fan_control_groups); 535 463 536 464 return PTR_ERR_OR_ZERO(ctl->hdev); 537 465 }