]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
hwmon: (axi-fan-control) Support temperature vs pwm points
authorNuno Sá <nuno.sa@analog.com>
Wed, 11 Aug 2021 11:48:53 +0000 (13:48 +0200)
committerGuenter Roeck <linux@roeck-us.net>
Tue, 17 Aug 2021 21:54:26 +0000 (14:54 -0700)
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>
drivers/hwmon/axi-fan-control.c

index c898ad121dc7121c952e0bbec770eb8d04d8cb84..d2092c17d9935500ccfa190763c37de66d99b30f 100644 (file)
@@ -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>
 #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);
 }