diff options
author | Nuno Sá <nuno.sa@analog.com> | 2021-08-11 13:48:53 +0200 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2021-08-17 23:54:26 +0200 |
commit | 2aee7e67bee7a5aa741bad6a0a472f108b29ad40 (patch) | |
tree | 88c17b00df1651cb0c8ec4d2c0f5d00af959bf14 /drivers | |
parent | hwmon: (axi-fan-control) Handle irqs in natural order (diff) | |
download | linux-2aee7e67bee7a5aa741bad6a0a472f108b29ad40.tar.xz linux-2aee7e67bee7a5aa741bad6a0a472f108b29ad40.zip |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/axi-fan-control.c | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c index c898ad121dc7..d2092c17d993 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -8,6 +8,7 @@ #include <linux/clk.h> #include <linux/fpga/adi-axi-common.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> @@ -23,6 +24,14 @@ #define ADI_REG_PWM_PERIOD 0x00c0 #define ADI_REG_TACH_MEASUR 0x00c4 #define ADI_REG_TEMPERATURE 0x00c8 +#define ADI_REG_TEMP_00_H 0x0100 +#define ADI_REG_TEMP_25_L 0x0104 +#define ADI_REG_TEMP_25_H 0x0108 +#define ADI_REG_TEMP_50_L 0x010c +#define ADI_REG_TEMP_50_H 0x0110 +#define ADI_REG_TEMP_75_L 0x0114 +#define ADI_REG_TEMP_75_H 0x0118 +#define ADI_REG_TEMP_100_L 0x011c #define ADI_REG_IRQ_MASK 0x0040 #define ADI_REG_IRQ_PENDING 0x0044 @@ -62,6 +71,39 @@ static inline u32 axi_ioread(const u32 reg, return ioread32(ctl->base + reg); } +/* + * The core calculates the temperature as: + * T = /raw * 509.3140064 / 65535) - 280.2308787 + */ +static ssize_t axi_fan_control_show(struct device *dev, struct device_attribute *da, char *buf) +{ + struct axi_fan_control_data *ctl = dev_get_drvdata(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u32 temp = axi_ioread(attr->index, ctl); + + temp = DIV_ROUND_CLOSEST_ULL(temp * 509314ULL, 65535) - 280230; + + return sprintf(buf, "%u\n", temp); +} + +static ssize_t axi_fan_control_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct axi_fan_control_data *ctl = dev_get_drvdata(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u32 temp; + int ret; + + ret = kstrtou32(buf, 10, &temp); + if (ret) + return ret; + + temp = DIV_ROUND_CLOSEST_ULL((temp + 280230) * 65535ULL, 509314); + axi_iowrite(temp, attr->index, ctl); + + return count; +} + static long axi_fan_control_get_pwm_duty(const struct axi_fan_control_data *ctl) { u32 pwm_width = axi_ioread(ADI_REG_PWM_WIDTH, ctl); @@ -375,6 +417,36 @@ static const struct hwmon_chip_info axi_chip_info = { .info = axi_fan_control_info, }; +/* temperature threshold below which PWM should be 0% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp_hyst, axi_fan_control, ADI_REG_TEMP_00_H); +/* temperature threshold above which PWM should be 25% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, axi_fan_control, ADI_REG_TEMP_25_L); +/* temperature threshold below which PWM should be 25% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp_hyst, axi_fan_control, ADI_REG_TEMP_25_H); +/* temperature threshold above which PWM should be 50% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp, axi_fan_control, ADI_REG_TEMP_50_L); +/* temperature threshold below which PWM should be 50% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp_hyst, axi_fan_control, ADI_REG_TEMP_50_H); +/* temperature threshold above which PWM should be 75% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, axi_fan_control, ADI_REG_TEMP_75_L); +/* temperature threshold below which PWM should be 75% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp_hyst, axi_fan_control, ADI_REG_TEMP_75_H); +/* temperature threshold above which PWM should be 100% */ +static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, axi_fan_control, ADI_REG_TEMP_100_L); + +static struct attribute *axi_fan_control_attrs[] = { + &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(axi_fan_control); + static const u32 version_1_0_0 = ADI_AXI_PCORE_VER(1, 0, 'a'); static const struct of_device_id axi_fan_control_of_match[] = { @@ -459,7 +531,7 @@ static int axi_fan_control_probe(struct platform_device *pdev) name, ctl, &axi_chip_info, - NULL); + axi_fan_control_groups); return PTR_ERR_OR_ZERO(ctl->hdev); } |