aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Hulsman <m.hulsman@tudelft.nl>2008-10-17 11:51:17 -0400
committerJean Delvare <khali@mahadeva.delvare>2008-10-17 11:51:17 -0400
commita5a4598cd2e7cae456a7f2a100bf0e5c3c7811c7 (patch)
treed2a5da96eae842f33bea66101a92abf88612aa9f
parentb5938f8c4a530b2fad18f2293ffaf79ac9f5a148 (diff)
hwmon: (w83791d) add support for thermal cruise mode
Add support to set target temperature and tolerance for thermal cruise mode. 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>
-rw-r--r--Documentation/hwmon/w83791d19
-rw-r--r--drivers/hwmon/w83791d.c148
2 files changed, 162 insertions, 5 deletions
diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d
index b1e4798764e8..5663e491655c 100644
--- a/Documentation/hwmon/w83791d
+++ b/Documentation/hwmon/w83791d
@@ -77,6 +77,9 @@ readings can be divided by a programmable divider (1, 2, 4, 8, 16,
77 77
78Each fan controlled is controlled by PWM. The PWM duty cycle can be read and 78Each fan controlled is controlled by PWM. The PWM duty cycle can be read and
79set for each fan separately. Valid values range from 0 (stop) to 255 (full). 79set for each fan separately. Valid values range from 0 (stop) to 255 (full).
80PWM 1-3 support Thermal Cruise mode, in which the PWMs are automatically
81regulated to keep respectively temp 1-3 at a certain target temperature.
82See below for the description of the sysfs-interface.
80 83
81The w83791d has a global bit used to enable beeping from the speaker when an 84The w83791d has a global bit used to enable beeping from the speaker when an
82alarm is triggered as well as a bitmask to enable or disable the beep for 85alarm is triggered as well as a bitmask to enable or disable the beep for
@@ -116,9 +119,19 @@ chip-specific options are documented here.
116pwm[1-3]_enable - this file controls mode of fan/temperature control for 119pwm[1-3]_enable - this file controls mode of fan/temperature control for
117 fan 1-3. Fan/PWM 4-5 only support manual mode. 120 fan 1-3. Fan/PWM 4-5 only support manual mode.
118 * 1 Manual mode 121 * 1 Manual mode
119 * 2 Thermal Cruise mode (no further support) 122 * 2 Thermal Cruise mode
120 * 3 Fan Speed Cruise mode (no further support) 123 * 3 Fan Speed Cruise mode (no further support)
121 124
125temp[1-3]_target - defines the target temperature for Thermal Cruise mode.
126 Unit: millidegree Celsius
127 RW
128
129temp[1-3]_tolerance - temperature tolerance for Thermal Cruise mode.
130 Specifies an interval around the target temperature
131 in which the fan speed is not changed.
132 Unit: millidegree Celsius
133 RW
134
122Alarms bitmap vs. beep_mask bitmask 135Alarms bitmap vs. beep_mask bitmask
123------------------------------------ 136------------------------------------
124For legacy code using the alarms and beep_mask files: 137For legacy code using the alarms and beep_mask files:
@@ -146,7 +159,3 @@ tart2 : alarms: 0x020000 beep_mask: 0x080000 <== mismatch
146tart3 : alarms: 0x040000 beep_mask: 0x100000 <== mismatch 159tart3 : alarms: 0x040000 beep_mask: 0x100000 <== mismatch
147case_open : alarms: 0x001000 beep_mask: 0x001000 160case_open : alarms: 0x001000 beep_mask: 0x001000
148global_enable: alarms: -------- beep_mask: 0x800000 (modified via beep_enable) 161global_enable: alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
149
150W83791D TODO:
151---------------
152Provide a patch for Thermal Cruise registers.
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index a4d2b02d9e04..5768def8a4f2 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -125,6 +125,17 @@ static const u8 W83791D_REG_PWM[NUMBER_OF_PWM] = {
125 0xA1, /* PWM 5 duty cycle register in DataSheet */ 125 0xA1, /* PWM 5 duty cycle register in DataSheet */
126}; 126};
127 127
128static const u8 W83791D_REG_TEMP_TARGET[3] = {
129 0x85, /* PWM 1 target temperature for temp 1 */
130 0x86, /* PWM 2 target temperature for temp 2 */
131 0x96, /* PWM 3 target temperature for temp 3 */
132};
133
134static const u8 W83791D_REG_TEMP_TOL[2] = {
135 0x87, /* PWM 1/2 temperature tolerance */
136 0x97, /* PWM 3 temperature tolerance */
137};
138
128static const u8 W83791D_REG_FAN_CFG[2] = { 139static const u8 W83791D_REG_FAN_CFG[2] = {
129 0x84, /* FAN 1/2 configuration */ 140 0x84, /* FAN 1/2 configuration */
130 0x95, /* FAN 3 configuration */ 141 0x95, /* FAN 3 configuration */
@@ -234,6 +245,15 @@ static u8 fan_to_reg(long rpm, int div)
234 (val) < 0 ? ((val) - 250) / 500 * 128 : \ 245 (val) < 0 ? ((val) - 250) / 500 * 128 : \
235 ((val) + 250) / 500 * 128) 246 ((val) + 250) / 500 * 128)
236 247
248/* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */
249#define TARGET_TEMP_TO_REG(val) ((val) < 0 ? 0 : \
250 (val) >= 127000 ? 127 : \
251 ((val) + 500) / 1000)
252
253/* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
254#define TOL_TEMP_TO_REG(val) ((val) < 0 ? 0 : \
255 (val) >= 15000 ? 15 : \
256 ((val) + 500) / 1000)
237 257
238#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) 258#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
239#define BEEP_MASK_FROM_REG(val) ((val) & 0xffffff) 259#define BEEP_MASK_FROM_REG(val) ((val) & 0xffffff)
@@ -290,6 +310,9 @@ struct w83791d_data {
290 u8 pwm_enable[3]; /* pwm enable status for fan 1-3 310 u8 pwm_enable[3]; /* pwm enable status for fan 1-3
291 (fan 4-5 only support manual mode) */ 311 (fan 4-5 only support manual mode) */
292 312
313 u8 temp_target[3]; /* pwm 1-3 target temperature */
314 u8 temp_tolerance[3]; /* pwm 1-3 temperature tolerance */
315
293 /* Misc */ 316 /* Misc */
294 u32 alarms; /* realtime status register encoding,combined */ 317 u32 alarms; /* realtime status register encoding,combined */
295 u8 beep_enable; /* Global beep enable */ 318 u8 beep_enable; /* Global beep enable */
@@ -774,6 +797,110 @@ static struct sensor_device_attribute sda_pwmenable[] = {
774 show_pwmenable, store_pwmenable, 2), 797 show_pwmenable, store_pwmenable, 2),
775}; 798};
776 799
800/* For Smart Fan I / Thermal Cruise */
801static ssize_t show_temp_target(struct device *dev,
802 struct device_attribute *attr, char *buf)
803{
804 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
805 struct w83791d_data *data = w83791d_update_device(dev);
806 int nr = sensor_attr->index;
807 return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_target[nr]));
808}
809
810static ssize_t store_temp_target(struct device *dev,
811 struct device_attribute *attr, const char *buf, size_t count)
812{
813 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
814 struct i2c_client *client = to_i2c_client(dev);
815 struct w83791d_data *data = i2c_get_clientdata(client);
816 int nr = sensor_attr->index;
817 unsigned long val;
818 u8 target_mask;
819
820 if (strict_strtoul(buf, 10, &val))
821 return -EINVAL;
822
823 mutex_lock(&data->update_lock);
824 data->temp_target[nr] = TARGET_TEMP_TO_REG(val);
825 target_mask = w83791d_read(client,
826 W83791D_REG_TEMP_TARGET[nr]) & 0x80;
827 w83791d_write(client, W83791D_REG_TEMP_TARGET[nr],
828 data->temp_target[nr] | target_mask);
829 mutex_unlock(&data->update_lock);
830 return count;
831}
832
833static struct sensor_device_attribute sda_temp_target[] = {
834 SENSOR_ATTR(temp1_target, S_IWUSR | S_IRUGO,
835 show_temp_target, store_temp_target, 0),
836 SENSOR_ATTR(temp2_target, S_IWUSR | S_IRUGO,
837 show_temp_target, store_temp_target, 1),
838 SENSOR_ATTR(temp3_target, S_IWUSR | S_IRUGO,
839 show_temp_target, store_temp_target, 2),
840};
841
842static ssize_t show_temp_tolerance(struct device *dev,
843 struct device_attribute *attr, char *buf)
844{
845 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
846 struct w83791d_data *data = w83791d_update_device(dev);
847 int nr = sensor_attr->index;
848 return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_tolerance[nr]));
849}
850
851static ssize_t store_temp_tolerance(struct device *dev,
852 struct device_attribute *attr, const char *buf, size_t count)
853{
854 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
855 struct i2c_client *client = to_i2c_client(dev);
856 struct w83791d_data *data = i2c_get_clientdata(client);
857 int nr = sensor_attr->index;
858 unsigned long val;
859 u8 target_mask;
860 u8 reg_idx = 0;
861 u8 val_shift = 0;
862 u8 keep_mask = 0;
863
864 if (strict_strtoul(buf, 10, &val))
865 return -EINVAL;
866
867 switch (nr) {
868 case 0:
869 reg_idx = 0;
870 val_shift = 0;
871 keep_mask = 0xf0;
872 break;
873 case 1:
874 reg_idx = 0;
875 val_shift = 4;
876 keep_mask = 0x0f;
877 break;
878 case 2:
879 reg_idx = 1;
880 val_shift = 0;
881 keep_mask = 0xf0;
882 break;
883 }
884
885 mutex_lock(&data->update_lock);
886 data->temp_tolerance[nr] = TOL_TEMP_TO_REG(val);
887 target_mask = w83791d_read(client,
888 W83791D_REG_TEMP_TOL[reg_idx]) & keep_mask;
889 w83791d_write(client, W83791D_REG_TEMP_TOL[reg_idx],
890 (data->temp_tolerance[nr] << val_shift) | target_mask);
891 mutex_unlock(&data->update_lock);
892 return count;
893}
894
895static struct sensor_device_attribute sda_temp_tolerance[] = {
896 SENSOR_ATTR(temp1_tolerance, S_IWUSR | S_IRUGO,
897 show_temp_tolerance, store_temp_tolerance, 0),
898 SENSOR_ATTR(temp2_tolerance, S_IWUSR | S_IRUGO,
899 show_temp_tolerance, store_temp_tolerance, 1),
900 SENSOR_ATTR(temp3_tolerance, S_IWUSR | S_IRUGO,
901 show_temp_tolerance, store_temp_tolerance, 2),
902};
903
777/* read/write the temperature1, includes measured value and limits */ 904/* read/write the temperature1, includes measured value and limits */
778static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr, 905static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
779 char *buf) 906 char *buf)
@@ -1044,6 +1171,12 @@ static struct attribute *w83791d_attributes[] = {
1044 &sda_pwmenable[0].dev_attr.attr, 1171 &sda_pwmenable[0].dev_attr.attr,
1045 &sda_pwmenable[1].dev_attr.attr, 1172 &sda_pwmenable[1].dev_attr.attr,
1046 &sda_pwmenable[2].dev_attr.attr, 1173 &sda_pwmenable[2].dev_attr.attr,
1174 &sda_temp_target[0].dev_attr.attr,
1175 &sda_temp_target[1].dev_attr.attr,
1176 &sda_temp_target[2].dev_attr.attr,
1177 &sda_temp_tolerance[0].dev_attr.attr,
1178 &sda_temp_tolerance[1].dev_attr.attr,
1179 &sda_temp_tolerance[2].dev_attr.attr,
1047 NULL 1180 NULL
1048}; 1181};
1049 1182
@@ -1404,6 +1537,21 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
1404 data->pwm_enable[1] = (reg_array_tmp[0] >> 4) & 0x03; 1537 data->pwm_enable[1] = (reg_array_tmp[0] >> 4) & 0x03;
1405 data->pwm_enable[2] = (reg_array_tmp[1] >> 2) & 0x03; 1538 data->pwm_enable[2] = (reg_array_tmp[1] >> 2) & 0x03;
1406 1539
1540 /* Update PWM target temperature */
1541 for (i = 0; i < 3; i++) {
1542 data->temp_target[i] = w83791d_read(client,
1543 W83791D_REG_TEMP_TARGET[i]) & 0x7f;
1544 }
1545
1546 /* Update PWM temperature tolerance */
1547 for (i = 0; i < 2; i++) {
1548 reg_array_tmp[i] = w83791d_read(client,
1549 W83791D_REG_TEMP_TOL[i]);
1550 }
1551 data->temp_tolerance[0] = reg_array_tmp[0] & 0x0f;
1552 data->temp_tolerance[1] = (reg_array_tmp[0] >> 4) & 0x0f;
1553 data->temp_tolerance[2] = reg_array_tmp[1] & 0x0f;
1554
1407 /* Update the first temperature sensor */ 1555 /* Update the first temperature sensor */
1408 for (i = 0; i < 3; i++) { 1556 for (i = 0; i < 3; i++) {
1409 data->temp1[i] = w83791d_read(client, 1557 data->temp1[i] = w83791d_read(client,