|
@@ -24,6 +24,7 @@
|
|
|
#include "radeon.h"
|
|
|
#include "avivod.h"
|
|
|
#include "atom.h"
|
|
|
+#include "r600_dpm.h"
|
|
|
#include <linux/power_supply.h>
|
|
|
#include <linux/hwmon.h>
|
|
|
#include <linux/hwmon-sysfs.h>
|
|
@@ -554,6 +555,96 @@ fail:
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
+static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct radeon_device *rdev = dev_get_drvdata(dev);
|
|
|
+ u32 pwm_mode = 0;
|
|
|
+
|
|
|
+ if (rdev->asic->dpm.fan_ctrl_get_mode)
|
|
|
+ pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev);
|
|
|
+
|
|
|
+ /* never 0 (full-speed), fuse or smc-controlled always */
|
|
|
+ return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf,
|
|
|
+ size_t count)
|
|
|
+{
|
|
|
+ struct radeon_device *rdev = dev_get_drvdata(dev);
|
|
|
+ int err;
|
|
|
+ int value;
|
|
|
+
|
|
|
+ if(!rdev->asic->dpm.fan_ctrl_set_mode)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ err = kstrtoint(buf, 10, &value);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ switch(value) {
|
|
|
+ case 1: /* manual, percent-based */
|
|
|
+ rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC);
|
|
|
+ break;
|
|
|
+ default: /* disable */
|
|
|
+ rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%i\n", 0);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%i\n", 100); /* pwm uses percent-based fan-control */
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t radeon_hwmon_set_pwm1(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ struct radeon_device *rdev = dev_get_drvdata(dev);
|
|
|
+ int err;
|
|
|
+ u32 value;
|
|
|
+
|
|
|
+ err = kstrtou32(buf, 10, &value);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ err = rdev->asic->dpm.set_fan_speed_percent(rdev, value);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t radeon_hwmon_get_pwm1(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct radeon_device *rdev = dev_get_drvdata(dev);
|
|
|
+ int err;
|
|
|
+ u32 speed;
|
|
|
+
|
|
|
+ err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ return sprintf(buf, "%i\n", speed);
|
|
|
+}
|
|
|
+
|
|
|
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
|
|
|
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
|
|
|
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
|
|
@@ -601,11 +692,20 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
|
|
|
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
|
|
|
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
|
|
|
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
|
|
|
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0);
|
|
|
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0);
|
|
|
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
|
|
|
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
|
|
|
+
|
|
|
|
|
|
static struct attribute *hwmon_attributes[] = {
|
|
|
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
|
|
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
|
|
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
|
|
+ &sensor_dev_attr_pwm1.dev_attr.attr,
|
|
|
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
|
|
+ &sensor_dev_attr_pwm1_min.dev_attr.attr,
|
|
|
+ &sensor_dev_attr_pwm1_max.dev_attr.attr,
|
|
|
NULL
|
|
|
};
|
|
|
|
|
@@ -614,6 +714,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
|
|
|
{
|
|
|
struct device *dev = container_of(kobj, struct device, kobj);
|
|
|
struct radeon_device *rdev = dev_get_drvdata(dev);
|
|
|
+ umode_t effective_mode = attr->mode;
|
|
|
|
|
|
/* Skip limit attributes if DPM is not enabled */
|
|
|
if (rdev->pm.pm_method != PM_METHOD_DPM &&
|
|
@@ -621,7 +722,35 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
|
|
|
attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
|
|
|
return 0;
|
|
|
|
|
|
- return attr->mode;
|
|
|
+ /* Skip fan attributes if fan is not present */
|
|
|
+ if (rdev->pm.no_fan &&
|
|
|
+ (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
|
|
|
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
|
|
|
+ attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
|
|
|
+ attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* mask fan attributes if we have no bindings for this asic to expose */
|
|
|
+ if ((!rdev->asic->dpm.get_fan_speed_percent &&
|
|
|
+ attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
|
|
|
+ (!rdev->asic->dpm.fan_ctrl_get_mode &&
|
|
|
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
|
|
|
+ effective_mode &= ~S_IRUGO;
|
|
|
+
|
|
|
+ if ((!rdev->asic->dpm.set_fan_speed_percent &&
|
|
|
+ attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
|
|
|
+ (!rdev->asic->dpm.fan_ctrl_set_mode &&
|
|
|
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
|
|
|
+ effective_mode &= ~S_IWUSR;
|
|
|
+
|
|
|
+ /* hide max/min values if we can't both query and manage the fan */
|
|
|
+ if ((!rdev->asic->dpm.set_fan_speed_percent &&
|
|
|
+ !rdev->asic->dpm.get_fan_speed_percent) &&
|
|
|
+ (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
|
|
|
+ attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return effective_mode;
|
|
|
}
|
|
|
|
|
|
static const struct attribute_group hwmon_attrgroup = {
|