aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/it87.c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2010-03-05 16:17:21 -0500
committerJean Delvare <khali@linux-fr.org>2010-03-05 16:17:21 -0500
commit4f3f51bc21d434f8d91a79438a1957ec0baa9e30 (patch)
treeb61b17498c2b3a46377692526f56551681d1894d /drivers/hwmon/it87.c
parent404a552d8ae6847ae17f3c749bd5d312da08efe4 (diff)
hwmon: (it87) Add support for old automatic fan speed control
Add support for the automatic fan speed control interface as implemented by IT8705F chips up to revision F and IT8712F chips up to revision G. This implementation fits very well in our standard sysfs interface. I implemented the old and not the new interface because the only chip I have at hand is an old one, and the new interface is more difficult to map to the standard sysfs interface. Adding support later should be possible though, if someone with a supported chip is interested. Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/it87.c')
-rw-r--r--drivers/hwmon/it87.c182
1 files changed, 180 insertions, 2 deletions
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 8282282eb4ca..bbb0c7443b9b 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -192,6 +192,9 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
192 192
193#define IT87_REG_CHIPID 0x58 193#define IT87_REG_CHIPID 0x58
194 194
195#define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
196#define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i))
197
195#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) 198#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
196#define IN_FROM_REG(val) ((val) * 16) 199#define IN_FROM_REG(val) ((val) * 16)
197 200
@@ -293,6 +296,10 @@ struct it87_data {
293 u8 pwm_ctrl[3]; /* Register value */ 296 u8 pwm_ctrl[3]; /* Register value */
294 u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */ 297 u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */
295 u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */ 298 u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
299
300 /* Automatic fan speed control registers */
301 u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */
302 s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
296}; 303};
297 304
298static inline int has_16bit_fans(const struct it87_data *data) 305static inline int has_16bit_fans(const struct it87_data *data)
@@ -307,6 +314,15 @@ static inline int has_16bit_fans(const struct it87_data *data)
307 || data->type == it8720; 314 || data->type == it8720;
308} 315}
309 316
317static inline int has_old_autopwm(const struct it87_data *data)
318{
319 /* The old automatic fan speed control interface is implemented
320 by IT8705F chips up to revision F and IT8712F chips up to
321 revision G. */
322 return (data->type == it87 && data->revision < 0x03)
323 || (data->type == it8712 && data->revision < 0x08);
324}
325
310static int it87_probe(struct platform_device *pdev); 326static int it87_probe(struct platform_device *pdev);
311static int __devexit it87_remove(struct platform_device *pdev); 327static int __devexit it87_remove(struct platform_device *pdev);
312 328
@@ -813,6 +829,13 @@ static ssize_t set_pwm_temp_map(struct device *dev,
813 long val; 829 long val;
814 u8 reg; 830 u8 reg;
815 831
832 /* This check can go away if we ever support automatic fan speed
833 control on newer chips. */
834 if (!has_old_autopwm(data)) {
835 dev_notice(dev, "Mapping change disabled for safety reasons\n");
836 return -EINVAL;
837 }
838
816 if (strict_strtol(buf, 10, &val) < 0) 839 if (strict_strtol(buf, 10, &val) < 0)
817 return -EINVAL; 840 return -EINVAL;
818 841
@@ -842,6 +865,72 @@ static ssize_t set_pwm_temp_map(struct device *dev,
842 return count; 865 return count;
843} 866}
844 867
868static ssize_t show_auto_pwm(struct device *dev,
869 struct device_attribute *attr, char *buf)
870{
871 struct it87_data *data = it87_update_device(dev);
872 struct sensor_device_attribute_2 *sensor_attr =
873 to_sensor_dev_attr_2(attr);
874 int nr = sensor_attr->nr;
875 int point = sensor_attr->index;
876
877 return sprintf(buf, "%d\n", PWM_FROM_REG(data->auto_pwm[nr][point]));
878}
879
880static ssize_t set_auto_pwm(struct device *dev,
881 struct device_attribute *attr, const char *buf, size_t count)
882{
883 struct it87_data *data = dev_get_drvdata(dev);
884 struct sensor_device_attribute_2 *sensor_attr =
885 to_sensor_dev_attr_2(attr);
886 int nr = sensor_attr->nr;
887 int point = sensor_attr->index;
888 long val;
889
890 if (strict_strtol(buf, 10, &val) < 0 || val < 0 || val > 255)
891 return -EINVAL;
892
893 mutex_lock(&data->update_lock);
894 data->auto_pwm[nr][point] = PWM_TO_REG(val);
895 it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
896 data->auto_pwm[nr][point]);
897 mutex_unlock(&data->update_lock);
898 return count;
899}
900
901static ssize_t show_auto_temp(struct device *dev,
902 struct device_attribute *attr, char *buf)
903{
904 struct it87_data *data = it87_update_device(dev);
905 struct sensor_device_attribute_2 *sensor_attr =
906 to_sensor_dev_attr_2(attr);
907 int nr = sensor_attr->nr;
908 int point = sensor_attr->index;
909
910 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->auto_temp[nr][point]));
911}
912
913static ssize_t set_auto_temp(struct device *dev,
914 struct device_attribute *attr, const char *buf, size_t count)
915{
916 struct it87_data *data = dev_get_drvdata(dev);
917 struct sensor_device_attribute_2 *sensor_attr =
918 to_sensor_dev_attr_2(attr);
919 int nr = sensor_attr->nr;
920 int point = sensor_attr->index;
921 long val;
922
923 if (strict_strtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
924 return -EINVAL;
925
926 mutex_lock(&data->update_lock);
927 data->auto_temp[nr][point] = TEMP_TO_REG(val);
928 it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point),
929 data->auto_temp[nr][point]);
930 mutex_unlock(&data->update_lock);
931 return count;
932}
933
845#define show_fan_offset(offset) \ 934#define show_fan_offset(offset) \
846static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ 935static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
847 show_fan, NULL, offset - 1); \ 936 show_fan, NULL, offset - 1); \
@@ -863,8 +952,34 @@ static DEVICE_ATTR(pwm##offset##_freq, \
863 (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \ 952 (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \
864 show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); \ 953 show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); \
865static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp, \ 954static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp, \
866 S_IRUGO, show_pwm_temp_map, set_pwm_temp_map, \ 955 S_IRUGO | S_IWUSR, show_pwm_temp_map, set_pwm_temp_map, \
867 offset - 1); 956 offset - 1); \
957static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_pwm, \
958 S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \
959 offset - 1, 0); \
960static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_pwm, \
961 S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \
962 offset - 1, 1); \
963static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_pwm, \
964 S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \
965 offset - 1, 2); \
966static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_pwm, \
967 S_IRUGO, show_auto_pwm, NULL, offset - 1, 3); \
968static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp, \
969 S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
970 offset - 1, 1); \
971static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp_hyst, \
972 S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
973 offset - 1, 0); \
974static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_temp, \
975 S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
976 offset - 1, 2); \
977static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_temp, \
978 S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
979 offset - 1, 3); \
980static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_temp, \
981 S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
982 offset - 1, 4);
868 983
869show_pwm_offset(1); 984show_pwm_offset(1);
870show_pwm_offset(2); 985show_pwm_offset(2);
@@ -1219,6 +1334,47 @@ static const struct attribute_group it87_group_pwm[3] = {
1219 { .attrs = it87_attributes_pwm[2] }, 1334 { .attrs = it87_attributes_pwm[2] },
1220}; 1335};
1221 1336
1337static struct attribute *it87_attributes_autopwm[3][9+1] = { {
1338 &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
1339 &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
1340 &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
1341 &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
1342 &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
1343 &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
1344 &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
1345 &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
1346 &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
1347 NULL
1348}, {
1349 &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
1350 &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
1351 &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
1352 &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
1353 &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
1354 &sensor_dev_attr_pwm2_auto_point1_temp_hyst.dev_attr.attr,
1355 &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
1356 &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
1357 &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
1358 NULL
1359}, {
1360 &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
1361 &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
1362 &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
1363 &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
1364 &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
1365 &sensor_dev_attr_pwm3_auto_point1_temp_hyst.dev_attr.attr,
1366 &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
1367 &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
1368 &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
1369 NULL
1370} };
1371
1372static const struct attribute_group it87_group_autopwm[3] = {
1373 { .attrs = it87_attributes_autopwm[0] },
1374 { .attrs = it87_attributes_autopwm[1] },
1375 { .attrs = it87_attributes_autopwm[2] },
1376};
1377
1222static struct attribute *it87_attributes_fan_beep[] = { 1378static struct attribute *it87_attributes_fan_beep[] = {
1223 &sensor_dev_attr_fan1_beep.dev_attr.attr, 1379 &sensor_dev_attr_fan1_beep.dev_attr.attr,
1224 &sensor_dev_attr_fan2_beep.dev_attr.attr, 1380 &sensor_dev_attr_fan2_beep.dev_attr.attr,
@@ -1382,6 +1538,9 @@ static void it87_remove_files(struct device *dev)
1382 if (sio_data->skip_pwm & (1 << 0)) 1538 if (sio_data->skip_pwm & (1 << 0))
1383 continue; 1539 continue;
1384 sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]); 1540 sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
1541 if (has_old_autopwm(data))
1542 sysfs_remove_group(&dev->kobj,
1543 &it87_group_autopwm[i]);
1385 } 1544 }
1386 if (!sio_data->skip_vid) 1545 if (!sio_data->skip_vid)
1387 sysfs_remove_group(&dev->kobj, &it87_group_vid); 1546 sysfs_remove_group(&dev->kobj, &it87_group_vid);
@@ -1491,6 +1650,13 @@ static int __devinit it87_probe(struct platform_device *pdev)
1491 &it87_group_pwm[i]); 1650 &it87_group_pwm[i]);
1492 if (err) 1651 if (err)
1493 goto ERROR4; 1652 goto ERROR4;
1653
1654 if (!has_old_autopwm(data))
1655 continue;
1656 err = sysfs_create_group(&dev->kobj,
1657 &it87_group_autopwm[i]);
1658 if (err)
1659 goto ERROR4;
1494 } 1660 }
1495 } 1661 }
1496 1662
@@ -1624,6 +1790,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
1624 for (i = 0; i < 3; i++) { 1790 for (i = 0; i < 3; i++) {
1625 data->pwm_temp_map[i] = i; 1791 data->pwm_temp_map[i] = i;
1626 data->pwm_duty[i] = 0x7f; /* Full speed */ 1792 data->pwm_duty[i] = 0x7f; /* Full speed */
1793 data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
1627 } 1794 }
1628 1795
1629 /* Some chips seem to have default value 0xff for all limit 1796 /* Some chips seem to have default value 0xff for all limit
@@ -1703,6 +1870,17 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
1703 data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; 1870 data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
1704 else /* Manual mode */ 1871 else /* Manual mode */
1705 data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f; 1872 data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
1873
1874 if (has_old_autopwm(data)) {
1875 int i;
1876
1877 for (i = 0; i < 5 ; i++)
1878 data->auto_temp[nr][i] = it87_read_value(data,
1879 IT87_REG_AUTO_TEMP(nr, i));
1880 for (i = 0; i < 3 ; i++)
1881 data->auto_pwm[nr][i] = it87_read_value(data,
1882 IT87_REG_AUTO_PWM(nr, i));
1883 }
1706} 1884}
1707 1885
1708static struct it87_data *it87_update_device(struct device *dev) 1886static struct it87_data *it87_update_device(struct device *dev)