diff options
author | Marc Hulsman <m.hulsman@tudelft.nl> | 2008-10-17 11:51:17 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-10-17 11:51:17 -0400 |
commit | 6495ce184033d5e70dfdf5bb8d149e9e02feaaa9 (patch) | |
tree | d1d0d2f2e52363f3c416413c5e554d4e42a61b16 /drivers/hwmon | |
parent | 6e1ecd9b8f1358ed4d099f0c54434240dc40debe (diff) |
hwmon: (w83791d) add manual PWM support
Add PWM manual control.
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>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/w83791d.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 6b1cec9950ff..a8ff4e126713 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c | |||
@@ -23,7 +23,7 @@ | |||
23 | Supports following chips: | 23 | Supports following chips: |
24 | 24 | ||
25 | Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA | 25 | Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA |
26 | w83791d 10 5 3 3 0x71 0x5ca3 yes no | 26 | w83791d 10 5 5 3 0x71 0x5ca3 yes no |
27 | 27 | ||
28 | The w83791d chip appears to be part way between the 83781d and the | 28 | The w83791d chip appears to be part way between the 83781d and the |
29 | 83792d. Thus, this file is derived from both the w83792d.c and | 29 | 83792d. Thus, this file is derived from both the w83792d.c and |
@@ -45,6 +45,7 @@ | |||
45 | #define NUMBER_OF_VIN 10 | 45 | #define NUMBER_OF_VIN 10 |
46 | #define NUMBER_OF_FANIN 5 | 46 | #define NUMBER_OF_FANIN 5 |
47 | #define NUMBER_OF_TEMPIN 3 | 47 | #define NUMBER_OF_TEMPIN 3 |
48 | #define NUMBER_OF_PWM 5 | ||
48 | 49 | ||
49 | /* Addresses to scan */ | 50 | /* Addresses to scan */ |
50 | static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, | 51 | static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, |
@@ -116,6 +117,14 @@ static const u8 W83791D_REG_FAN_MIN[NUMBER_OF_FANIN] = { | |||
116 | 0xBD, /* FAN 5 Count Low Limit in DataSheet */ | 117 | 0xBD, /* FAN 5 Count Low Limit in DataSheet */ |
117 | }; | 118 | }; |
118 | 119 | ||
120 | static const u8 W83791D_REG_PWM[NUMBER_OF_PWM] = { | ||
121 | 0x81, /* PWM 1 duty cycle register in DataSheet */ | ||
122 | 0x83, /* PWM 2 duty cycle register in DataSheet */ | ||
123 | 0x94, /* PWM 3 duty cycle register in DataSheet */ | ||
124 | 0xA0, /* PWM 4 duty cycle register in DataSheet */ | ||
125 | 0xA1, /* PWM 5 duty cycle register in DataSheet */ | ||
126 | }; | ||
127 | |||
119 | static const u8 W83791D_REG_FAN_CFG[2] = { | 128 | static const u8 W83791D_REG_FAN_CFG[2] = { |
120 | 0x84, /* FAN 1/2 configuration */ | 129 | 0x84, /* FAN 1/2 configuration */ |
121 | 0x95, /* FAN 3 configuration */ | 130 | 0x95, /* FAN 3 configuration */ |
@@ -276,6 +285,9 @@ struct w83791d_data { | |||
276 | two sensors with three values | 285 | two sensors with three values |
277 | (cur, over, hyst) */ | 286 | (cur, over, hyst) */ |
278 | 287 | ||
288 | /* PWMs */ | ||
289 | u8 pwm[5]; /* pwm duty cycle */ | ||
290 | |||
279 | /* Misc */ | 291 | /* Misc */ |
280 | u32 alarms; /* realtime status register encoding,combined */ | 292 | u32 alarms; /* realtime status register encoding,combined */ |
281 | u8 beep_enable; /* Global beep enable */ | 293 | u8 beep_enable; /* Global beep enable */ |
@@ -653,6 +665,48 @@ static struct sensor_device_attribute sda_fan_alarm[] = { | |||
653 | SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22), | 665 | SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22), |
654 | }; | 666 | }; |
655 | 667 | ||
668 | /* read/write PWMs */ | ||
669 | static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, | ||
670 | char *buf) | ||
671 | { | ||
672 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
673 | int nr = sensor_attr->index; | ||
674 | struct w83791d_data *data = w83791d_update_device(dev); | ||
675 | return sprintf(buf, "%u\n", data->pwm[nr]); | ||
676 | } | ||
677 | |||
678 | static ssize_t store_pwm(struct device *dev, struct device_attribute *attr, | ||
679 | const char *buf, size_t count) | ||
680 | { | ||
681 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
682 | struct i2c_client *client = to_i2c_client(dev); | ||
683 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
684 | int nr = sensor_attr->index; | ||
685 | unsigned long val; | ||
686 | |||
687 | if (strict_strtoul(buf, 10, &val)) | ||
688 | return -EINVAL; | ||
689 | |||
690 | mutex_lock(&data->update_lock); | ||
691 | data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); | ||
692 | w83791d_write(client, W83791D_REG_PWM[nr], data->pwm[nr]); | ||
693 | mutex_unlock(&data->update_lock); | ||
694 | return count; | ||
695 | } | ||
696 | |||
697 | static struct sensor_device_attribute sda_pwm[] = { | ||
698 | SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, | ||
699 | show_pwm, store_pwm, 0), | ||
700 | SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, | ||
701 | show_pwm, store_pwm, 1), | ||
702 | SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, | ||
703 | show_pwm, store_pwm, 2), | ||
704 | SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, | ||
705 | show_pwm, store_pwm, 3), | ||
706 | SENSOR_ATTR(pwm5, S_IWUSR | S_IRUGO, | ||
707 | show_pwm, store_pwm, 4), | ||
708 | }; | ||
709 | |||
656 | /* read/write the temperature1, includes measured value and limits */ | 710 | /* read/write the temperature1, includes measured value and limits */ |
657 | static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr, | 711 | static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr, |
658 | char *buf) | 712 | char *buf) |
@@ -917,6 +971,9 @@ static struct attribute *w83791d_attributes[] = { | |||
917 | &sda_beep_ctrl[1].dev_attr.attr, | 971 | &sda_beep_ctrl[1].dev_attr.attr, |
918 | &dev_attr_cpu0_vid.attr, | 972 | &dev_attr_cpu0_vid.attr, |
919 | &dev_attr_vrm.attr, | 973 | &dev_attr_vrm.attr, |
974 | &sda_pwm[0].dev_attr.attr, | ||
975 | &sda_pwm[1].dev_attr.attr, | ||
976 | &sda_pwm[2].dev_attr.attr, | ||
920 | NULL | 977 | NULL |
921 | }; | 978 | }; |
922 | 979 | ||
@@ -930,6 +987,8 @@ static const struct attribute_group w83791d_group = { | |||
930 | static struct attribute *w83791d_attributes_fanpwm45[] = { | 987 | static struct attribute *w83791d_attributes_fanpwm45[] = { |
931 | FAN_UNIT_ATTRS(3), | 988 | FAN_UNIT_ATTRS(3), |
932 | FAN_UNIT_ATTRS(4), | 989 | FAN_UNIT_ATTRS(4), |
990 | &sda_pwm[3].dev_attr.attr, | ||
991 | &sda_pwm[4].dev_attr.attr, | ||
933 | NULL | 992 | NULL |
934 | }; | 993 | }; |
935 | 994 | ||
@@ -1260,6 +1319,12 @@ static struct w83791d_data *w83791d_update_device(struct device *dev) | |||
1260 | for (i = 0; i < 3; i++) | 1319 | for (i = 0; i < 3; i++) |
1261 | data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04; | 1320 | data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04; |
1262 | 1321 | ||
1322 | /* Update PWM duty cycle */ | ||
1323 | for (i = 0; i < NUMBER_OF_PWM; i++) { | ||
1324 | data->pwm[i] = w83791d_read(client, | ||
1325 | W83791D_REG_PWM[i]); | ||
1326 | } | ||
1327 | |||
1263 | /* Update the first temperature sensor */ | 1328 | /* Update the first temperature sensor */ |
1264 | for (i = 0; i < 3; i++) { | 1329 | for (i = 0; i < 3; i++) { |
1265 | data->temp1[i] = w83791d_read(client, | 1330 | data->temp1[i] = w83791d_read(client, |