diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-03-25 00:49:54 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2012-05-20 22:41:50 -0400 |
commit | 9172b5d124c2f54374d8cc5ed6098ecd8fb988cd (patch) | |
tree | d80082b7b3f22fde5ad01af253f45c5bd5435833 /drivers/hwmon/it87.c | |
parent | a7871def65887dd42b51b89c674a90c085e934c9 (diff) |
hwmon: (it87) Create voltage attributes only if voltage is enabled
On IT8782F and IT8783F, some voltage input pins may be disabled. Don't create
sysfs attribute files if that is the case.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/it87.c')
-rw-r--r-- | drivers/hwmon/it87.c | 162 |
1 files changed, 124 insertions, 38 deletions
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index aebac1334ff6..bef8732f08b1 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -234,6 +234,7 @@ struct it87_sio_data { | |||
234 | u8 beep_pin; | 234 | u8 beep_pin; |
235 | u8 internal; /* Internal sensors can be labeled */ | 235 | u8 internal; /* Internal sensors can be labeled */ |
236 | /* Features skipped based on config or DMI */ | 236 | /* Features skipped based on config or DMI */ |
237 | u16 skip_in; | ||
237 | u8 skip_vid; | 238 | u8 skip_vid; |
238 | u8 skip_fan; | 239 | u8 skip_fan; |
239 | u8 skip_pwm; | 240 | u8 skip_pwm; |
@@ -1371,41 +1372,73 @@ static ssize_t show_name(struct device *dev, struct device_attribute | |||
1371 | } | 1372 | } |
1372 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 1373 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
1373 | 1374 | ||
1374 | static struct attribute *it87_attributes[] = { | 1375 | static struct attribute *it87_attributes_in[9][5] = { |
1376 | { | ||
1375 | &sensor_dev_attr_in0_input.dev_attr.attr, | 1377 | &sensor_dev_attr_in0_input.dev_attr.attr, |
1376 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
1377 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
1378 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
1379 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
1380 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
1381 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
1382 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
1383 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
1384 | &sensor_dev_attr_in0_min.dev_attr.attr, | 1378 | &sensor_dev_attr_in0_min.dev_attr.attr, |
1385 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
1386 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
1387 | &sensor_dev_attr_in3_min.dev_attr.attr, | ||
1388 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
1389 | &sensor_dev_attr_in5_min.dev_attr.attr, | ||
1390 | &sensor_dev_attr_in6_min.dev_attr.attr, | ||
1391 | &sensor_dev_attr_in7_min.dev_attr.attr, | ||
1392 | &sensor_dev_attr_in0_max.dev_attr.attr, | 1379 | &sensor_dev_attr_in0_max.dev_attr.attr, |
1393 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
1394 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
1395 | &sensor_dev_attr_in3_max.dev_attr.attr, | ||
1396 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
1397 | &sensor_dev_attr_in5_max.dev_attr.attr, | ||
1398 | &sensor_dev_attr_in6_max.dev_attr.attr, | ||
1399 | &sensor_dev_attr_in7_max.dev_attr.attr, | ||
1400 | &sensor_dev_attr_in0_alarm.dev_attr.attr, | 1380 | &sensor_dev_attr_in0_alarm.dev_attr.attr, |
1381 | NULL | ||
1382 | }, { | ||
1383 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
1384 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
1385 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
1401 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | 1386 | &sensor_dev_attr_in1_alarm.dev_attr.attr, |
1387 | NULL | ||
1388 | }, { | ||
1389 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
1390 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
1391 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
1402 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | 1392 | &sensor_dev_attr_in2_alarm.dev_attr.attr, |
1393 | NULL | ||
1394 | }, { | ||
1395 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
1396 | &sensor_dev_attr_in3_min.dev_attr.attr, | ||
1397 | &sensor_dev_attr_in3_max.dev_attr.attr, | ||
1403 | &sensor_dev_attr_in3_alarm.dev_attr.attr, | 1398 | &sensor_dev_attr_in3_alarm.dev_attr.attr, |
1399 | NULL | ||
1400 | }, { | ||
1401 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
1402 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
1403 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
1404 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | 1404 | &sensor_dev_attr_in4_alarm.dev_attr.attr, |
1405 | NULL | ||
1406 | }, { | ||
1407 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
1408 | &sensor_dev_attr_in5_min.dev_attr.attr, | ||
1409 | &sensor_dev_attr_in5_max.dev_attr.attr, | ||
1405 | &sensor_dev_attr_in5_alarm.dev_attr.attr, | 1410 | &sensor_dev_attr_in5_alarm.dev_attr.attr, |
1411 | NULL | ||
1412 | }, { | ||
1413 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
1414 | &sensor_dev_attr_in6_min.dev_attr.attr, | ||
1415 | &sensor_dev_attr_in6_max.dev_attr.attr, | ||
1406 | &sensor_dev_attr_in6_alarm.dev_attr.attr, | 1416 | &sensor_dev_attr_in6_alarm.dev_attr.attr, |
1417 | NULL | ||
1418 | }, { | ||
1419 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
1420 | &sensor_dev_attr_in7_min.dev_attr.attr, | ||
1421 | &sensor_dev_attr_in7_max.dev_attr.attr, | ||
1407 | &sensor_dev_attr_in7_alarm.dev_attr.attr, | 1422 | &sensor_dev_attr_in7_alarm.dev_attr.attr, |
1423 | NULL | ||
1424 | }, { | ||
1425 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
1426 | NULL | ||
1427 | } }; | ||
1428 | |||
1429 | static const struct attribute_group it87_group_in[9] = { | ||
1430 | { .attrs = it87_attributes_in[0] }, | ||
1431 | { .attrs = it87_attributes_in[1] }, | ||
1432 | { .attrs = it87_attributes_in[2] }, | ||
1433 | { .attrs = it87_attributes_in[3] }, | ||
1434 | { .attrs = it87_attributes_in[4] }, | ||
1435 | { .attrs = it87_attributes_in[5] }, | ||
1436 | { .attrs = it87_attributes_in[6] }, | ||
1437 | { .attrs = it87_attributes_in[7] }, | ||
1438 | { .attrs = it87_attributes_in[8] }, | ||
1439 | }; | ||
1408 | 1440 | ||
1441 | static struct attribute *it87_attributes[] = { | ||
1409 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 1442 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
1410 | &sensor_dev_attr_temp2_input.dev_attr.attr, | 1443 | &sensor_dev_attr_temp2_input.dev_attr.attr, |
1411 | &sensor_dev_attr_temp3_input.dev_attr.attr, | 1444 | &sensor_dev_attr_temp3_input.dev_attr.attr, |
@@ -1432,7 +1465,7 @@ static const struct attribute_group it87_group = { | |||
1432 | .attrs = it87_attributes, | 1465 | .attrs = it87_attributes, |
1433 | }; | 1466 | }; |
1434 | 1467 | ||
1435 | static struct attribute *it87_attributes_beep[] = { | 1468 | static struct attribute *it87_attributes_in_beep[] = { |
1436 | &sensor_dev_attr_in0_beep.dev_attr.attr, | 1469 | &sensor_dev_attr_in0_beep.dev_attr.attr, |
1437 | &sensor_dev_attr_in1_beep.dev_attr.attr, | 1470 | &sensor_dev_attr_in1_beep.dev_attr.attr, |
1438 | &sensor_dev_attr_in2_beep.dev_attr.attr, | 1471 | &sensor_dev_attr_in2_beep.dev_attr.attr, |
@@ -1441,7 +1474,10 @@ static struct attribute *it87_attributes_beep[] = { | |||
1441 | &sensor_dev_attr_in5_beep.dev_attr.attr, | 1474 | &sensor_dev_attr_in5_beep.dev_attr.attr, |
1442 | &sensor_dev_attr_in6_beep.dev_attr.attr, | 1475 | &sensor_dev_attr_in6_beep.dev_attr.attr, |
1443 | &sensor_dev_attr_in7_beep.dev_attr.attr, | 1476 | &sensor_dev_attr_in7_beep.dev_attr.attr, |
1477 | NULL | ||
1478 | }; | ||
1444 | 1479 | ||
1480 | static struct attribute *it87_attributes_beep[] = { | ||
1445 | &sensor_dev_attr_temp1_beep.dev_attr.attr, | 1481 | &sensor_dev_attr_temp1_beep.dev_attr.attr, |
1446 | &sensor_dev_attr_temp2_beep.dev_attr.attr, | 1482 | &sensor_dev_attr_temp2_beep.dev_attr.attr, |
1447 | &sensor_dev_attr_temp3_beep.dev_attr.attr, | 1483 | &sensor_dev_attr_temp3_beep.dev_attr.attr, |
@@ -1696,7 +1732,6 @@ static int __init it87_find(unsigned short *address, | |||
1696 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | 1732 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
1697 | } else if (sio_data->type == it8783) { | 1733 | } else if (sio_data->type == it8783) { |
1698 | int reg25, reg27, reg2A, reg2C, regEF; | 1734 | int reg25, reg27, reg2A, reg2C, regEF; |
1699 | bool uart6; | ||
1700 | 1735 | ||
1701 | sio_data->skip_vid = 1; /* No VID */ | 1736 | sio_data->skip_vid = 1; /* No VID */ |
1702 | 1737 | ||
@@ -1708,10 +1743,8 @@ static int __init it87_find(unsigned short *address, | |||
1708 | reg2C = superio_inb(IT87_SIO_PINX2_REG); | 1743 | reg2C = superio_inb(IT87_SIO_PINX2_REG); |
1709 | regEF = superio_inb(IT87_SIO_SPI_REG); | 1744 | regEF = superio_inb(IT87_SIO_SPI_REG); |
1710 | 1745 | ||
1711 | uart6 = reg2C & (1 << 2); | ||
1712 | |||
1713 | /* Check if fan3 is there or not */ | 1746 | /* Check if fan3 is there or not */ |
1714 | if ((reg27 & (1 << 0)) || !uart6) | 1747 | if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2))) |
1715 | sio_data->skip_fan |= (1 << 2); | 1748 | sio_data->skip_fan |= (1 << 2); |
1716 | if ((reg25 & (1 << 4)) | 1749 | if ((reg25 & (1 << 4)) |
1717 | || (!(reg2A & (1 << 1)) && (regEF & (1 << 0)))) | 1750 | || (!(reg2A & (1 << 1)) && (regEF & (1 << 0)))) |
@@ -1724,19 +1757,39 @@ static int __init it87_find(unsigned short *address, | |||
1724 | sio_data->skip_pwm |= (1 << 1); | 1757 | sio_data->skip_pwm |= (1 << 1); |
1725 | 1758 | ||
1726 | /* VIN5 */ | 1759 | /* VIN5 */ |
1727 | if ((reg27 & (1 << 0)) || uart6) | 1760 | if ((reg27 & (1 << 0)) || (reg2C & (1 << 2))) |
1728 | ; /* No VIN5 */ | 1761 | sio_data->skip_in |= (1 << 5); /* No VIN5 */ |
1729 | 1762 | ||
1730 | /* VIN6 */ | 1763 | /* VIN6 */ |
1731 | if ((reg27 & (1 << 1)) || uart6) | 1764 | if (reg27 & (1 << 1)) |
1732 | ; /* No VIN6 */ | 1765 | sio_data->skip_in |= (1 << 6); /* No VIN6 */ |
1733 | 1766 | ||
1734 | /* | 1767 | /* |
1735 | * VIN7 | 1768 | * VIN7 |
1736 | * Does not depend on bit 2 of Reg2C, contrary to datasheet. | 1769 | * Does not depend on bit 2 of Reg2C, contrary to datasheet. |
1737 | */ | 1770 | */ |
1738 | if (reg27 & (1 << 2)) | 1771 | if (reg27 & (1 << 2)) { |
1739 | ; /* No VIN7 (unless internal) */ | 1772 | /* |
1773 | * The data sheet is a bit unclear regarding the | ||
1774 | * internal voltage divider for VCCH5V. It says | ||
1775 | * "This bit enables and switches VIN7 (pin 91) to the | ||
1776 | * internal voltage divider for VCCH5V". | ||
1777 | * This is different to other chips, where the internal | ||
1778 | * voltage divider would connect VIN7 to an internal | ||
1779 | * voltage source. Maybe that is the case here as well. | ||
1780 | * | ||
1781 | * Since we don't know for sure, re-route it if that is | ||
1782 | * not the case, and ask the user to report if the | ||
1783 | * resulting voltage is sane. | ||
1784 | */ | ||
1785 | if (!(reg2C & (1 << 1))) { | ||
1786 | reg2C |= (1 << 1); | ||
1787 | superio_outb(IT87_SIO_PINX2_REG, reg2C); | ||
1788 | pr_notice("Routing internal VCCH5V to in7.\n"); | ||
1789 | } | ||
1790 | pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n"); | ||
1791 | pr_notice("Please report if it displays a reasonable voltage.\n"); | ||
1792 | } | ||
1740 | 1793 | ||
1741 | if (reg2C & (1 << 0)) | 1794 | if (reg2C & (1 << 0)) |
1742 | sio_data->internal |= (1 << 0); | 1795 | sio_data->internal |= (1 << 0); |
@@ -1747,6 +1800,7 @@ static int __init it87_find(unsigned short *address, | |||
1747 | 1800 | ||
1748 | } else { | 1801 | } else { |
1749 | int reg; | 1802 | int reg; |
1803 | bool uart6; | ||
1750 | 1804 | ||
1751 | superio_select(GPIO); | 1805 | superio_select(GPIO); |
1752 | 1806 | ||
@@ -1784,6 +1838,9 @@ static int __init it87_find(unsigned short *address, | |||
1784 | sio_data->vid_value = superio_inb(IT87_SIO_VID_REG); | 1838 | sio_data->vid_value = superio_inb(IT87_SIO_VID_REG); |
1785 | 1839 | ||
1786 | reg = superio_inb(IT87_SIO_PINX2_REG); | 1840 | reg = superio_inb(IT87_SIO_PINX2_REG); |
1841 | |||
1842 | uart6 = sio_data->type == it8782 && (reg & (1 << 2)); | ||
1843 | |||
1787 | /* | 1844 | /* |
1788 | * The IT8720F has no VIN7 pin, so VCCH should always be | 1845 | * The IT8720F has no VIN7 pin, so VCCH should always be |
1789 | * routed internally to VIN7 with an internal divider. | 1846 | * routed internally to VIN7 with an internal divider. |
@@ -1795,11 +1852,10 @@ static int __init it87_find(unsigned short *address, | |||
1795 | * setting. So we force the internal routing in this case. | 1852 | * setting. So we force the internal routing in this case. |
1796 | * | 1853 | * |
1797 | * On IT8782F, VIN7 is multiplexed with one of the UART6 pins. | 1854 | * On IT8782F, VIN7 is multiplexed with one of the UART6 pins. |
1798 | * If UART6 is enabled, re-route VIN7 to the internal divider. | 1855 | * If UART6 is enabled, re-route VIN7 to the internal divider |
1856 | * if that is not already the case. | ||
1799 | */ | 1857 | */ |
1800 | if ((sio_data->type == it8720 || | 1858 | if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) { |
1801 | (sio_data->type == it8782 && (reg & (1 << 2)))) | ||
1802 | && !(reg & (1 << 1))) { | ||
1803 | reg |= (1 << 1); | 1859 | reg |= (1 << 1); |
1804 | superio_outb(IT87_SIO_PINX2_REG, reg); | 1860 | superio_outb(IT87_SIO_PINX2_REG, reg); |
1805 | pr_notice("Routing internal VCCH to in7\n"); | 1861 | pr_notice("Routing internal VCCH to in7\n"); |
@@ -1810,6 +1866,14 @@ static int __init it87_find(unsigned short *address, | |||
1810 | sio_data->type == it8728) | 1866 | sio_data->type == it8728) |
1811 | sio_data->internal |= (1 << 1); | 1867 | sio_data->internal |= (1 << 1); |
1812 | 1868 | ||
1869 | /* | ||
1870 | * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7. | ||
1871 | * While VIN7 can be routed to the internal voltage divider, | ||
1872 | * VIN5 and VIN6 are not available if UART6 is enabled. | ||
1873 | */ | ||
1874 | if (uart6) | ||
1875 | sio_data->skip_in |= (1 << 5) | (1 << 6); | ||
1876 | |||
1813 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | 1877 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
1814 | } | 1878 | } |
1815 | if (sio_data->beep_pin) | 1879 | if (sio_data->beep_pin) |
@@ -1847,6 +1911,14 @@ static void it87_remove_files(struct device *dev) | |||
1847 | int i; | 1911 | int i; |
1848 | 1912 | ||
1849 | sysfs_remove_group(&dev->kobj, &it87_group); | 1913 | sysfs_remove_group(&dev->kobj, &it87_group); |
1914 | for (i = 0; i < 9; i++) { | ||
1915 | if (sio_data->skip_in & (1 << i)) | ||
1916 | continue; | ||
1917 | sysfs_remove_group(&dev->kobj, &it87_group_in[i]); | ||
1918 | if (it87_attributes_in_beep[i]) | ||
1919 | sysfs_remove_file(&dev->kobj, | ||
1920 | it87_attributes_in_beep[i]); | ||
1921 | } | ||
1850 | if (sio_data->beep_pin) | 1922 | if (sio_data->beep_pin) |
1851 | sysfs_remove_group(&dev->kobj, &it87_group_beep); | 1923 | sysfs_remove_group(&dev->kobj, &it87_group_beep); |
1852 | for (i = 0; i < 5; i++) { | 1924 | for (i = 0; i < 5; i++) { |
@@ -1949,6 +2021,20 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1949 | if (err) | 2021 | if (err) |
1950 | goto ERROR2; | 2022 | goto ERROR2; |
1951 | 2023 | ||
2024 | for (i = 0; i < 9; i++) { | ||
2025 | if (sio_data->skip_in & (1 << i)) | ||
2026 | continue; | ||
2027 | err = sysfs_create_group(&dev->kobj, &it87_group_in[i]); | ||
2028 | if (err) | ||
2029 | goto ERROR4; | ||
2030 | if (sio_data->beep_pin && it87_attributes_in_beep[i]) { | ||
2031 | err = sysfs_create_file(&dev->kobj, | ||
2032 | it87_attributes_in_beep[i]); | ||
2033 | if (err) | ||
2034 | goto ERROR4; | ||
2035 | } | ||
2036 | } | ||
2037 | |||
1952 | if (sio_data->beep_pin) { | 2038 | if (sio_data->beep_pin) { |
1953 | err = sysfs_create_group(&dev->kobj, &it87_group_beep); | 2039 | err = sysfs_create_group(&dev->kobj, &it87_group_beep); |
1954 | if (err) | 2040 | if (err) |