[PATCH 4/4] hwmon: (w83791d) add support for thermal cruise mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jean,

> I think you have a bug in your code. I also have minor stylistic
> comments.

thanks for spotting this one. Somehow I missed it during testing. Hereby an 
updated patch, which also fixes the minor style issues. 

> > +/* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */
> > +#define TARGET_TEMP_FROM_REG(val)    ((val) * 1000)
>
> This is the same as TEMP_FROM_REG so you could just use that.

Removed those. I added them to get symmetry.

> > +#define TOL_TEMP_TO_REG(val)         ((val) < 0 ? 0 : \
> > +                                     (val) >= 15000 ? 15 : \
> > +                                     ((val) + 500) / 1000)
>
> Note: if you want to spend some more time on the w83791d driver, one
> thing that would be welcome is converting all these macros to inline
> functions.

I am already planning to write some cleanup-patches later on, will add this to 
the list. 

> I am not necessarily very happy with the file names you came up with.
> pwm[1-3]_target is a bit ambiguous. Is it a temperature target or a fan
> speed target? If you were to implement support for the Fan Speed Cruise
> mode, how would you name the file?
>
> I did implement something like the Fan Speed Cruise mode in the f71085f
> driver. I named the files fan[1-3]_target, to make it clear what the
> target was. This is even part of Documentation/hwmon/sysfs-interface by
> now, and a second driver is implementing it that way (max6650).
> Following the same logic, the Thermal Cruise mode files should be named
> temp[1-3]_target (and presumably temp[1-3]_tolerance for the tolerance).
>
> Unfortunately it seems that you got your file names from the w83627ehf
> driver, so we already have one driver doing things that way (in fact 2:
> the w83l786ng driver is doing the same.) To make things even worse, the
> w83792d and w83793 drivers have a 3rd set of file names
> (thermal_cruise[1-3] and tolerance[1-3]). It would be nice if we could
> settle for one naming, document that in file sysfs-interface, and use
> that for all devices which implement Thermal Cruise mode.

I indeed looked at the other drivers for those names, but I agree that the 
temp_* is better. In the updated patch all occurences have been renamed.

Thanks for the review,

Marc

--
Adds support to set target temperature and tolerance for thermal cruise mode.

Signed-off-by: Marc Hulsman <m.hulsman at tudelft.nl>
---
 Documentation/hwmon/w83791d |   19 ++++-
 drivers/hwmon/w83791d.c     |  148 
++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+), 5 deletions(-)

---
Index: linux-2.6.27-rc1/drivers/hwmon/w83791d.c
===================================================================
--- linux-2.6.27-rc1.orig/drivers/hwmon/w83791d.c
+++ linux-2.6.27-rc1/drivers/hwmon/w83791d.c
@@ -125,6 +125,17 @@ static const u8 W83791D_REG_PWM[NUMBER_O
 	0xA1,			/* PWM 5 duty cycle register in DataSheet */
 };
 
+static const u8 W83791D_REG_TEMP_TARGET[3] = {
+	0x85,			/* PWM 1 target temperature for temp 1 */
+	0x86,			/* PWM 2 target temperature for temp 2 */
+	0x96,			/* PWM 3 target temperature for temp 3 */
+};
+
+static const u8 W83791D_REG_TEMP_TOL[2] = {
+	0x87,			/* PWM 1/2 temperature tolerance */
+	0x97,			/* PWM 3 temperature tolerance */
+};
+
 static const u8 W83791D_REG_FAN_CFG[2] = {
 	0x84,			/* FAN 1/2 configuration */
 	0x95,			/* FAN 3 configuration */
@@ -234,6 +245,15 @@ static u8 fan_to_reg(long rpm, int div)
 				 (val) < 0 ? ((val) - 250) / 500 * 128 : \
 				 ((val) + 250) / 500 * 128)
 
+/* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */
+#define TARGET_TEMP_TO_REG(val)		((val) < 0 ? 0 : \
+					(val) >= 127000 ? 127 : \
+					((val) + 500) / 1000)
+
+/* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
+#define TOL_TEMP_TO_REG(val)		((val) < 0 ? 0 : \
+					(val) >= 15000 ? 15 : \
+					((val) + 500) / 1000)
 
 #define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
 #define BEEP_MASK_FROM_REG(val)		((val) & 0xffffff)
@@ -290,6 +310,9 @@ struct w83791d_data {
 	u8 pwm_enable[3];	/* pwm enable status for fan 1-3
 					(fan 4-5 only support manual mode) */
 
+	u8 temp_target[3];	/* pwm 1-3 target temperature */
+	u8 temp_tolerance[3];	/* pwm 1-3 temperature tolerance */
+
 	/* Misc */
 	u32 alarms;		/* realtime status register encoding,combined */
 	u8 beep_enable;		/* Global beep enable */
@@ -774,6 +797,110 @@ static struct sensor_device_attribute sd
 			show_pwmenable, store_pwmenable, 2),
 };
 
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t show_temp_target(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n",TEMP1_FROM_REG(data->temp_target[nr]));
+}
+
+static ssize_t store_temp_target(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 target_mask;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->temp_target[nr] = TARGET_TEMP_TO_REG(val);
+	target_mask = w83791d_read(client,
+				W83791D_REG_TEMP_TARGET[nr]) & 0x80;
+	w83791d_write(client, W83791D_REG_TEMP_TARGET[nr],
+				data->temp_target[nr] | target_mask);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_temp_target[] = {
+	SENSOR_ATTR(temp1_target, S_IWUSR | S_IRUGO,
+			show_temp_target, store_temp_target, 0),
+	SENSOR_ATTR(temp2_target, S_IWUSR | S_IRUGO,
+			show_temp_target, store_temp_target, 1),
+	SENSOR_ATTR(temp3_target, S_IWUSR | S_IRUGO,
+			show_temp_target, store_temp_target, 2),
+};
+
+static ssize_t show_temp_tolerance(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	struct w83791d_data *data = w83791d_update_device(dev);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_tolerance[nr]));
+}
+
+static ssize_t store_temp_tolerance(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 target_mask;
+	u8 reg_idx = 0;
+	u8 val_shift = 0;
+	u8 keep_mask = 0;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+
+	switch (nr) {
+	case 0:
+		reg_idx = 0;
+		val_shift = 0;
+		keep_mask = 0xf0;
+		break;
+	case 1:
+		reg_idx = 0;
+		val_shift = 4;
+		keep_mask = 0x0f;
+		break;
+	case 2:
+		reg_idx = 1;
+		val_shift = 0;
+		keep_mask = 0xf0;
+		break;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->temp_tolerance[nr] = TOL_TEMP_TO_REG(val);
+	target_mask = w83791d_read(client,
+			W83791D_REG_TEMP_TOL[reg_idx]) & keep_mask;
+	w83791d_write(client, W83791D_REG_TEMP_TOL[reg_idx],
+			(data->temp_tolerance[nr] << val_shift) | target_mask);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static struct sensor_device_attribute sda_temp_tolerance[] = {
+	SENSOR_ATTR(temp1_tolerance, S_IWUSR | S_IRUGO,
+			show_temp_tolerance, store_temp_tolerance, 0),
+	SENSOR_ATTR(temp2_tolerance, S_IWUSR | S_IRUGO,
+			show_temp_tolerance, store_temp_tolerance, 1),
+	SENSOR_ATTR(temp3_tolerance, S_IWUSR | S_IRUGO,
+			show_temp_tolerance, store_temp_tolerance, 2),
+};
+
 /* read/write the temperature1, includes measured value and limits */
 static ssize_t show_temp1(struct device *dev, struct device_attribute 
*devattr,
 				char *buf)
@@ -1044,6 +1171,12 @@ static struct attribute *w83791d_attribu
 	&sda_pwmenable[0].dev_attr.attr,
 	&sda_pwmenable[1].dev_attr.attr,
 	&sda_pwmenable[2].dev_attr.attr,
+	&sda_temp_target[0].dev_attr.attr,
+	&sda_temp_target[1].dev_attr.attr,
+	&sda_temp_target[2].dev_attr.attr,
+	&sda_temp_tolerance[0].dev_attr.attr,
+	&sda_temp_tolerance[1].dev_attr.attr,
+	&sda_temp_tolerance[2].dev_attr.attr,
 	NULL
 };
 
@@ -1403,6 +1536,21 @@ static struct w83791d_data *w83791d_upda
 		data->pwm_enable[1] = ((reg_array_tmp[0] >> 4) & 0x03);
 		data->pwm_enable[2] = ((reg_array_tmp[1] >> 2) & 0x03);
 
+		/* Update PWM target temperature */
+		for (i = 0; i < 3; i++) {
+			data->temp_target[i] = w83791d_read(client,
+				W83791D_REG_TEMP_TARGET[i]) & 0x7f;
+		}
+
+		/* Update PWM temperature tolerance */
+		for (i = 0; i < 2; i++) {
+			reg_array_tmp[i] = w83791d_read(client,
+					W83791D_REG_TEMP_TOL[i]);
+		}
+		data->temp_tolerance[0] = reg_array_tmp[0] & 0x0f;
+		data->temp_tolerance[1] = (reg_array_tmp[0] >> 4) & 0x0f;
+		data->temp_tolerance[2] = reg_array_tmp[1] & 0x0f;
+
 		/* Update the first temperature sensor */
 		for (i = 0; i < 3; i++) {
 			data->temp1[i] = w83791d_read(client,
Index: linux-2.6.27-rc1/Documentation/hwmon/w83791d
===================================================================
--- linux-2.6.27-rc1.orig/Documentation/hwmon/w83791d
+++ linux-2.6.27-rc1/Documentation/hwmon/w83791d
@@ -77,6 +77,9 @@ readings can be divided by a programmabl
 
 Each fan controlled is controlled by PWM. The PWM duty cycle can be read and
 set for each fan separately. Valid values range from 0 (stop) to 255 (full).
+PWM 1-3 support Thermal Cruise mode, in which the PWMs are automatically
+regulated to keep respectively temp 1-3 at a certain target temperature.
+See below for the description of the sysfs-interface.
 
 The w83791d has a global bit used to enable beeping from the speaker when an
 alarm is triggered as well as a bitmask to enable or disable the beep for
@@ -116,9 +119,19 @@ chip-specific options are documented her
 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)
+		            * 2 Thermal Cruise mode
 		            * 3 Fan Speed Cruise mode (no further support)
 
+temp[1-3]_target - 	defines the target temperature for Thermal Cruise mode.
+			Unit: millidegree Celsius
+			RW
+
+temp[1-3]_tolerance - 	temperature tolerance for Thermal Cruise mode.
+			Specifies an interval around the target temperature
+			in which the fan speed is not changed.
+			Unit: millidegree Celsius
+			RW
+
 Alarms bitmap vs. beep_mask bitmask
 ------------------------------------
 For legacy code using the alarms and beep_mask files:
@@ -146,7 +159,3 @@ tart2        :  alarms: 0x020000 beep_ma
 tart3        :  alarms: 0x040000 beep_mask: 0x100000 <== mismatch
 case_open    :  alarms: 0x001000 beep_mask: 0x001000
 global_enable:  alarms: -------- beep_mask: 0x800000 (modified via 
beep_enable)
-
-W83791D TODO:
----------------
-Provide a patch for Thermal Cruise registers.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: w83791d_thermal_cruise.v2.patch
Type: text/x-diff
Size: 8895 bytes
Desc: not available
Url : http://lists.lm-sensors.org/pipermail/lm-sensors/attachments/20080930/c75c36db/attachment.bin 


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux