Browse Source

hwmon: (w83791d) add pwm_enable support

Add support for pwm_enable.

Signed-off-by: Marc Hulsman <m.hulsman@tudelft.nl>
Acked-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Marc Hulsman 17 years ago
parent
commit
b5938f8c4a
2 changed files with 91 additions and 1 deletions
  1. 12 1
      Documentation/hwmon/w83791d
  2. 79 0
      drivers/hwmon/w83791d.c

+ 12 - 1
Documentation/hwmon/w83791d

@@ -108,6 +108,17 @@ going forward.
 The driver reads the hardware chip values at most once every three seconds.
 The driver reads the hardware chip values at most once every three seconds.
 User mode code requesting values more often will receive cached values.
 User mode code requesting values more often will receive cached values.
 
 
+/sys files
+----------
+The sysfs-interface is documented in the 'sysfs-interface' file. Only
+chip-specific options are documented here.
+
+pwm[1-3]_enable -	this file controls mode of fan/temperature control for
+			fan 1-3. Fan/PWM 4-5 only support manual mode.
+		            * 1 Manual mode
+		            * 2 Thermal Cruise mode   (no further support)
+		            * 3 Fan Speed Cruise mode (no further support)
+
 Alarms bitmap vs. beep_mask bitmask
 Alarms bitmap vs. beep_mask bitmask
 ------------------------------------
 ------------------------------------
 For legacy code using the alarms and beep_mask files:
 For legacy code using the alarms and beep_mask files:
@@ -138,4 +149,4 @@ global_enable:  alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
 
 
 W83791D TODO:
 W83791D TODO:
 ---------------
 ---------------
-Provide a patch for smart-fan control (still need appropriate motherboard/fans)
+Provide a patch for Thermal Cruise registers.

+ 79 - 0
drivers/hwmon/w83791d.c

@@ -287,6 +287,8 @@ struct w83791d_data {
 
 
 	/* PWMs */
 	/* PWMs */
 	u8 pwm[5];		/* pwm duty cycle */
 	u8 pwm[5];		/* pwm duty cycle */
+	u8 pwm_enable[3];	/* pwm enable status for fan 1-3
+					(fan 4-5 only support manual mode) */
 
 
 	/* Misc */
 	/* Misc */
 	u32 alarms;		/* realtime status register encoding,combined */
 	u32 alarms;		/* realtime status register encoding,combined */
@@ -707,6 +709,71 @@ static struct sensor_device_attribute sda_pwm[] = {
 			show_pwm, store_pwm, 4),
 			show_pwm, store_pwm, 4),
 };
 };
 
 
+static ssize_t show_pwmenable(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	struct w83791d_data *data = w83791d_update_device(dev);
+	return sprintf(buf, "%u\n", data->pwm_enable[nr] + 1);
+}
+
+static ssize_t store_pwmenable(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83791d_data *data = i2c_get_clientdata(client);
+	int nr = sensor_attr->index;
+	unsigned long val;
+	u8 reg_cfg_tmp;
+	u8 reg_idx = 0;
+	u8 val_shift = 0;
+	u8 keep_mask = 0;
+
+	int ret = strict_strtoul(buf, 10, &val);
+
+	if (ret || val < 1 || val > 3)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->pwm_enable[nr] = val - 1;
+	switch (nr) {
+	case 0:
+		reg_idx = 0;
+		val_shift = 2;
+		keep_mask = 0xf3;
+		break;
+	case 1:
+		reg_idx = 0;
+		val_shift = 4;
+		keep_mask = 0xcf;
+		break;
+	case 2:
+		reg_idx = 1;
+		val_shift = 2;
+		keep_mask = 0xf3;
+		break;
+	}
+
+	reg_cfg_tmp = w83791d_read(client, W83791D_REG_FAN_CFG[reg_idx]);
+	reg_cfg_tmp = (reg_cfg_tmp & keep_mask) |
+					data->pwm_enable[nr] << val_shift;
+
+	w83791d_write(client, W83791D_REG_FAN_CFG[reg_idx], reg_cfg_tmp);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+static struct sensor_device_attribute sda_pwmenable[] = {
+	SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 0),
+	SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 1),
+	SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+			show_pwmenable, store_pwmenable, 2),
+};
+
 /* read/write the temperature1, includes measured value and limits */
 /* read/write the temperature1, includes measured value and limits */
 static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
 static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
 				char *buf)
 				char *buf)
@@ -974,6 +1041,9 @@ static struct attribute *w83791d_attributes[] = {
 	&sda_pwm[0].dev_attr.attr,
 	&sda_pwm[0].dev_attr.attr,
 	&sda_pwm[1].dev_attr.attr,
 	&sda_pwm[1].dev_attr.attr,
 	&sda_pwm[2].dev_attr.attr,
 	&sda_pwm[2].dev_attr.attr,
+	&sda_pwmenable[0].dev_attr.attr,
+	&sda_pwmenable[1].dev_attr.attr,
+	&sda_pwmenable[2].dev_attr.attr,
 	NULL
 	NULL
 };
 };
 
 
@@ -1325,6 +1395,15 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
 						W83791D_REG_PWM[i]);
 						W83791D_REG_PWM[i]);
 		}
 		}
 
 
+		/* Update PWM enable status */
+		for (i = 0; i < 2; i++) {
+			reg_array_tmp[i] = w83791d_read(client,
+						W83791D_REG_FAN_CFG[i]);
+		}
+		data->pwm_enable[0] = (reg_array_tmp[0] >> 2) & 0x03;
+		data->pwm_enable[1] = (reg_array_tmp[0] >> 4) & 0x03;
+		data->pwm_enable[2] = (reg_array_tmp[1] >> 2) & 0x03;
+
 		/* Update the first temperature sensor */
 		/* Update the first temperature sensor */
 		for (i = 0; i < 3; i++) {
 		for (i = 0; i < 3; i++) {
 			data->temp1[i] = w83791d_read(client,
 			data->temp1[i] = w83791d_read(client,