diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-12-04 11:30:54 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2013-04-08 00:16:39 -0400 |
commit | 77eb5b3703d995e6c72ef4a1e5411821f81df7e4 (patch) | |
tree | f91488312051b427872d45c7b7b62b0bee7b2098 /drivers/hwmon | |
parent | 84d19d92f78e10f8bdc1b3e1b5ddcaf5895edaf7 (diff) |
hwmon: (nct6775) Add support for pwm, pwm_mode, and pwm_enable
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/nct6775.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 56d7652d303b..ad4ecc04e239 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c | |||
@@ -96,6 +96,8 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); | |||
96 | #define SIO_NCT6779_ID 0xc560 | 96 | #define SIO_NCT6779_ID 0xc560 |
97 | #define SIO_ID_MASK 0xFFF0 | 97 | #define SIO_ID_MASK 0xFFF0 |
98 | 98 | ||
99 | enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; | ||
100 | |||
99 | static inline void | 101 | static inline void |
100 | superio_outb(int ioreg, int reg, int val) | 102 | superio_outb(int ioreg, int reg, int val) |
101 | { | 103 | { |
@@ -209,6 +211,15 @@ static const s8 NCT6775_ALARM_BITS[] = { | |||
209 | static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee }; | 211 | static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee }; |
210 | static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 }; | 212 | static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 }; |
211 | 213 | ||
214 | /* DC or PWM output fan configuration */ | ||
215 | static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 }; | ||
216 | static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 }; | ||
217 | |||
218 | static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 }; | ||
219 | |||
220 | static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 }; | ||
221 | static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 }; | ||
222 | |||
212 | static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; | 223 | static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; |
213 | static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d }; | 224 | static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d }; |
214 | static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 }; | 225 | static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 }; |
@@ -270,6 +281,9 @@ static const s8 NCT6776_ALARM_BITS[] = { | |||
270 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | 281 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ |
271 | 12, 9 }; /* intrusion0, intrusion1 */ | 282 | 12, 9 }; /* intrusion0, intrusion1 */ |
272 | 283 | ||
284 | static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 }; | ||
285 | static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 }; | ||
286 | |||
273 | static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 }; | 287 | static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 }; |
274 | static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 }; | 288 | static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 }; |
275 | 289 | ||
@@ -380,6 +394,20 @@ static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1] | |||
380 | static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] | 394 | static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] |
381 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; | 395 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; |
382 | 396 | ||
397 | static enum pwm_enable reg_to_pwm_enable(int pwm, int mode) | ||
398 | { | ||
399 | if (mode == 0 && pwm == 255) | ||
400 | return off; | ||
401 | return mode + 1; | ||
402 | } | ||
403 | |||
404 | static int pwm_enable_to_reg(enum pwm_enable mode) | ||
405 | { | ||
406 | if (mode == off) | ||
407 | return 0; | ||
408 | return mode - 1; | ||
409 | } | ||
410 | |||
383 | /* | 411 | /* |
384 | * Conversions | 412 | * Conversions |
385 | */ | 413 | */ |
@@ -471,9 +499,16 @@ struct nct6775_data { | |||
471 | const u16 *REG_IN_MINMAX[2]; | 499 | const u16 *REG_IN_MINMAX[2]; |
472 | 500 | ||
473 | const u16 *REG_FAN; | 501 | const u16 *REG_FAN; |
502 | const u16 *REG_FAN_MODE; | ||
474 | const u16 *REG_FAN_MIN; | 503 | const u16 *REG_FAN_MIN; |
475 | const u16 *REG_FAN_PULSES; | 504 | const u16 *REG_FAN_PULSES; |
476 | 505 | ||
506 | const u8 *REG_PWM_MODE; | ||
507 | const u8 *PWM_MODE_MASK; | ||
508 | |||
509 | const u16 *REG_PWM[1]; /* [0]=pwm */ | ||
510 | const u16 *REG_PWM_READ; | ||
511 | |||
477 | const u16 *REG_TEMP_SOURCE; /* temp register sources */ | 512 | const u16 *REG_TEMP_SOURCE; /* temp register sources */ |
478 | const u16 *REG_TEMP_OFFSET; | 513 | const u16 *REG_TEMP_OFFSET; |
479 | 514 | ||
@@ -494,6 +529,7 @@ struct nct6775_data { | |||
494 | u16 fan_min[5]; | 529 | u16 fan_min[5]; |
495 | u8 fan_pulses[5]; | 530 | u8 fan_pulses[5]; |
496 | u8 fan_div[5]; | 531 | u8 fan_div[5]; |
532 | u8 has_pwm; | ||
497 | u8 has_fan; /* some fan inputs can be disabled */ | 533 | u8 has_fan; /* some fan inputs can be disabled */ |
498 | u8 has_fan_min; /* some fans don't have min register */ | 534 | u8 has_fan_min; /* some fans don't have min register */ |
499 | bool has_fan_div; | 535 | bool has_fan_div; |
@@ -505,6 +541,18 @@ struct nct6775_data { | |||
505 | * 3=temp_crit */ | 541 | * 3=temp_crit */ |
506 | u64 alarms; | 542 | u64 alarms; |
507 | 543 | ||
544 | u8 pwm_num; /* number of pwm */ | ||
545 | u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */ | ||
546 | enum pwm_enable pwm_enable[5]; | ||
547 | /* 0->off | ||
548 | * 1->manual | ||
549 | * 2->thermal cruise mode (also called SmartFan I) | ||
550 | * 3->fan speed cruise mode | ||
551 | * 4->SmartFan III | ||
552 | * 5->enhanced variable thermal cruise (SmartFan IV) | ||
553 | */ | ||
554 | u8 pwm[1][5]; /* [0]=pwm */ | ||
555 | |||
508 | u8 vid; | 556 | u8 vid; |
509 | u8 vrm; | 557 | u8 vrm; |
510 | 558 | ||
@@ -781,6 +829,36 @@ static void nct6775_select_fan_div(struct device *dev, | |||
781 | } | 829 | } |
782 | } | 830 | } |
783 | 831 | ||
832 | static void nct6775_update_pwm(struct device *dev) | ||
833 | { | ||
834 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
835 | int i, j; | ||
836 | int fanmodecfg; | ||
837 | bool duty_is_dc; | ||
838 | |||
839 | for (i = 0; i < data->pwm_num; i++) { | ||
840 | if (!(data->has_pwm & (1 << i))) | ||
841 | continue; | ||
842 | |||
843 | duty_is_dc = data->REG_PWM_MODE[i] && | ||
844 | (nct6775_read_value(data, data->REG_PWM_MODE[i]) | ||
845 | & data->PWM_MODE_MASK[i]); | ||
846 | data->pwm_mode[i] = duty_is_dc; | ||
847 | |||
848 | fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]); | ||
849 | for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) { | ||
850 | if (data->REG_PWM[j] && data->REG_PWM[j][i]) { | ||
851 | data->pwm[j][i] | ||
852 | = nct6775_read_value(data, | ||
853 | data->REG_PWM[j][i]); | ||
854 | } | ||
855 | } | ||
856 | |||
857 | data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i], | ||
858 | (fanmodecfg >> 4) & 7); | ||
859 | } | ||
860 | } | ||
861 | |||
784 | static struct nct6775_data *nct6775_update_device(struct device *dev) | 862 | static struct nct6775_data *nct6775_update_device(struct device *dev) |
785 | { | 863 | { |
786 | struct nct6775_data *data = dev_get_drvdata(dev); | 864 | struct nct6775_data *data = dev_get_drvdata(dev); |
@@ -826,6 +904,8 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) | |||
826 | nct6775_select_fan_div(dev, data, i, reg); | 904 | nct6775_select_fan_div(dev, data, i, reg); |
827 | } | 905 | } |
828 | 906 | ||
907 | nct6775_update_pwm(dev); | ||
908 | |||
829 | /* Measured temperatures and limits */ | 909 | /* Measured temperatures and limits */ |
830 | for (i = 0; i < NUM_TEMP; i++) { | 910 | for (i = 0; i < NUM_TEMP; i++) { |
831 | if (!(data->have_temp & (1 << i))) | 911 | if (!(data->have_temp & (1 << i))) |
@@ -1600,6 +1680,170 @@ static struct sensor_device_attribute sda_temp_alarm[] = { | |||
1600 | #define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm) | 1680 | #define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm) |
1601 | 1681 | ||
1602 | static ssize_t | 1682 | static ssize_t |
1683 | show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) | ||
1684 | { | ||
1685 | struct nct6775_data *data = nct6775_update_device(dev); | ||
1686 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
1687 | |||
1688 | return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]); | ||
1689 | } | ||
1690 | |||
1691 | static ssize_t | ||
1692 | store_pwm_mode(struct device *dev, struct device_attribute *attr, | ||
1693 | const char *buf, size_t count) | ||
1694 | { | ||
1695 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
1696 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
1697 | int nr = sattr->index; | ||
1698 | unsigned long val; | ||
1699 | int err; | ||
1700 | u8 reg; | ||
1701 | |||
1702 | err = kstrtoul(buf, 10, &val); | ||
1703 | if (err < 0) | ||
1704 | return err; | ||
1705 | |||
1706 | if (val > 1) | ||
1707 | return -EINVAL; | ||
1708 | |||
1709 | /* Setting DC mode is not supported for all chips/channels */ | ||
1710 | if (data->REG_PWM_MODE[nr] == 0) { | ||
1711 | if (val) | ||
1712 | return -EINVAL; | ||
1713 | return count; | ||
1714 | } | ||
1715 | |||
1716 | mutex_lock(&data->update_lock); | ||
1717 | data->pwm_mode[nr] = val; | ||
1718 | reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]); | ||
1719 | reg &= ~data->PWM_MODE_MASK[nr]; | ||
1720 | if (val) | ||
1721 | reg |= data->PWM_MODE_MASK[nr]; | ||
1722 | nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); | ||
1723 | mutex_unlock(&data->update_lock); | ||
1724 | return count; | ||
1725 | } | ||
1726 | |||
1727 | static ssize_t | ||
1728 | show_pwm(struct device *dev, struct device_attribute *attr, char *buf) | ||
1729 | { | ||
1730 | struct nct6775_data *data = nct6775_update_device(dev); | ||
1731 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
1732 | int nr = sattr->nr; | ||
1733 | int index = sattr->index; | ||
1734 | int pwm; | ||
1735 | |||
1736 | /* | ||
1737 | * For automatic fan control modes, show current pwm readings. | ||
1738 | * Otherwise, show the configured value. | ||
1739 | */ | ||
1740 | if (index == 0 && data->pwm_enable[nr] > manual) | ||
1741 | pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]); | ||
1742 | else | ||
1743 | pwm = data->pwm[index][nr]; | ||
1744 | |||
1745 | return sprintf(buf, "%d\n", pwm); | ||
1746 | } | ||
1747 | |||
1748 | static ssize_t | ||
1749 | store_pwm(struct device *dev, struct device_attribute *attr, const char *buf, | ||
1750 | size_t count) | ||
1751 | { | ||
1752 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
1753 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
1754 | int nr = sattr->nr; | ||
1755 | int index = sattr->index; | ||
1756 | unsigned long val; | ||
1757 | int err; | ||
1758 | |||
1759 | err = kstrtoul(buf, 10, &val); | ||
1760 | if (err < 0) | ||
1761 | return err; | ||
1762 | val = clamp_val(val, 0, 255); | ||
1763 | |||
1764 | mutex_lock(&data->update_lock); | ||
1765 | data->pwm[index][nr] = val; | ||
1766 | nct6775_write_value(data, data->REG_PWM[index][nr], val); | ||
1767 | mutex_unlock(&data->update_lock); | ||
1768 | return count; | ||
1769 | } | ||
1770 | |||
1771 | static ssize_t | ||
1772 | show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) | ||
1773 | { | ||
1774 | struct nct6775_data *data = nct6775_update_device(dev); | ||
1775 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
1776 | |||
1777 | return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]); | ||
1778 | } | ||
1779 | |||
1780 | static ssize_t | ||
1781 | store_pwm_enable(struct device *dev, struct device_attribute *attr, | ||
1782 | const char *buf, size_t count) | ||
1783 | { | ||
1784 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
1785 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
1786 | int nr = sattr->index; | ||
1787 | unsigned long val; | ||
1788 | int err; | ||
1789 | u16 reg; | ||
1790 | |||
1791 | err = kstrtoul(buf, 10, &val); | ||
1792 | if (err < 0) | ||
1793 | return err; | ||
1794 | |||
1795 | if (val > sf4) | ||
1796 | return -EINVAL; | ||
1797 | |||
1798 | if (val == sf3 && data->kind != nct6775) | ||
1799 | return -EINVAL; | ||
1800 | |||
1801 | mutex_lock(&data->update_lock); | ||
1802 | data->pwm_enable[nr] = val; | ||
1803 | if (val == off) { | ||
1804 | /* | ||
1805 | * turn off pwm control: select manual mode, set pwm to maximum | ||
1806 | */ | ||
1807 | data->pwm[0][nr] = 255; | ||
1808 | nct6775_write_value(data, data->REG_PWM[0][nr], 255); | ||
1809 | } | ||
1810 | reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]); | ||
1811 | reg &= 0x0f; | ||
1812 | reg |= pwm_enable_to_reg(val) << 4; | ||
1813 | nct6775_write_value(data, data->REG_FAN_MODE[nr], reg); | ||
1814 | mutex_unlock(&data->update_lock); | ||
1815 | return count; | ||
1816 | } | ||
1817 | |||
1818 | static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0); | ||
1819 | static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0); | ||
1820 | static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0); | ||
1821 | static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0); | ||
1822 | static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0); | ||
1823 | |||
1824 | static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1825 | store_pwm_mode, 0); | ||
1826 | static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1827 | store_pwm_mode, 1); | ||
1828 | static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1829 | store_pwm_mode, 2); | ||
1830 | static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1831 | store_pwm_mode, 3); | ||
1832 | static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, show_pwm_mode, | ||
1833 | store_pwm_mode, 4); | ||
1834 | |||
1835 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1836 | store_pwm_enable, 0); | ||
1837 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1838 | store_pwm_enable, 1); | ||
1839 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1840 | store_pwm_enable, 2); | ||
1841 | static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1842 | store_pwm_enable, 3); | ||
1843 | static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable, | ||
1844 | store_pwm_enable, 4); | ||
1845 | |||
1846 | static ssize_t | ||
1603 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | 1847 | show_name(struct device *dev, struct device_attribute *attr, char *buf) |
1604 | { | 1848 | { |
1605 | struct nct6775_data *data = dev_get_drvdata(dev); | 1849 | struct nct6775_data *data = dev_get_drvdata(dev); |
@@ -1609,6 +1853,47 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf) | |||
1609 | 1853 | ||
1610 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 1854 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
1611 | 1855 | ||
1856 | static struct attribute *nct6775_attributes_pwm[5][4] = { | ||
1857 | { | ||
1858 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
1859 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | ||
1860 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
1861 | NULL | ||
1862 | }, | ||
1863 | { | ||
1864 | &sensor_dev_attr_pwm2.dev_attr.attr, | ||
1865 | &sensor_dev_attr_pwm2_mode.dev_attr.attr, | ||
1866 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | ||
1867 | NULL | ||
1868 | }, | ||
1869 | { | ||
1870 | &sensor_dev_attr_pwm3.dev_attr.attr, | ||
1871 | &sensor_dev_attr_pwm3_mode.dev_attr.attr, | ||
1872 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | ||
1873 | NULL | ||
1874 | }, | ||
1875 | { | ||
1876 | &sensor_dev_attr_pwm4.dev_attr.attr, | ||
1877 | &sensor_dev_attr_pwm4_mode.dev_attr.attr, | ||
1878 | &sensor_dev_attr_pwm4_enable.dev_attr.attr, | ||
1879 | NULL | ||
1880 | }, | ||
1881 | { | ||
1882 | &sensor_dev_attr_pwm5.dev_attr.attr, | ||
1883 | &sensor_dev_attr_pwm5_mode.dev_attr.attr, | ||
1884 | &sensor_dev_attr_pwm5_enable.dev_attr.attr, | ||
1885 | NULL | ||
1886 | }, | ||
1887 | }; | ||
1888 | |||
1889 | static const struct attribute_group nct6775_group_pwm[5] = { | ||
1890 | { .attrs = nct6775_attributes_pwm[0] }, | ||
1891 | { .attrs = nct6775_attributes_pwm[1] }, | ||
1892 | { .attrs = nct6775_attributes_pwm[2] }, | ||
1893 | { .attrs = nct6775_attributes_pwm[3] }, | ||
1894 | { .attrs = nct6775_attributes_pwm[4] }, | ||
1895 | }; | ||
1896 | |||
1612 | static ssize_t | 1897 | static ssize_t |
1613 | show_vid(struct device *dev, struct device_attribute *attr, char *buf) | 1898 | show_vid(struct device *dev, struct device_attribute *attr, char *buf) |
1614 | { | 1899 | { |
@@ -1681,6 +1966,9 @@ static void nct6775_device_remove_files(struct device *dev) | |||
1681 | int i; | 1966 | int i; |
1682 | struct nct6775_data *data = dev_get_drvdata(dev); | 1967 | struct nct6775_data *data = dev_get_drvdata(dev); |
1683 | 1968 | ||
1969 | for (i = 0; i < data->pwm_num; i++) | ||
1970 | sysfs_remove_group(&dev->kobj, &nct6775_group_pwm[i]); | ||
1971 | |||
1684 | for (i = 0; i < data->in_num; i++) | 1972 | for (i = 0; i < data->in_num; i++) |
1685 | sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]); | 1973 | sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]); |
1686 | 1974 | ||
@@ -1763,6 +2051,7 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, | |||
1763 | { | 2051 | { |
1764 | int regval; | 2052 | int regval; |
1765 | bool fan3pin, fan3min, fan4pin, fan4min, fan5pin; | 2053 | bool fan3pin, fan3min, fan4pin, fan4min, fan5pin; |
2054 | bool pwm3pin, pwm4pin, pwm5pin; | ||
1766 | int ret; | 2055 | int ret; |
1767 | 2056 | ||
1768 | ret = superio_enter(sio_data->sioreg); | 2057 | ret = superio_enter(sio_data->sioreg); |
@@ -1775,11 +2064,14 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, | |||
1775 | 2064 | ||
1776 | fan3pin = regval & (1 << 6); | 2065 | fan3pin = regval & (1 << 6); |
1777 | fan3min = fan3pin; | 2066 | fan3min = fan3pin; |
2067 | pwm3pin = regval & (1 << 7); | ||
1778 | 2068 | ||
1779 | /* On NCT6775, fan4 shares pins with the fdc interface */ | 2069 | /* On NCT6775, fan4 shares pins with the fdc interface */ |
1780 | fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); | 2070 | fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); |
1781 | fan4min = 0; | 2071 | fan4min = 0; |
1782 | fan5pin = 0; | 2072 | fan5pin = 0; |
2073 | pwm4pin = 0; | ||
2074 | pwm5pin = 0; | ||
1783 | } else if (data->kind == nct6776) { | 2075 | } else if (data->kind == nct6776) { |
1784 | bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80; | 2076 | bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80; |
1785 | 2077 | ||
@@ -1803,6 +2095,9 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, | |||
1803 | 2095 | ||
1804 | fan4min = fan4pin; | 2096 | fan4min = fan4pin; |
1805 | fan3min = fan3pin; | 2097 | fan3min = fan3pin; |
2098 | pwm3pin = fan3pin; | ||
2099 | pwm4pin = 0; | ||
2100 | pwm5pin = 0; | ||
1806 | } else { /* NCT6779D */ | 2101 | } else { /* NCT6779D */ |
1807 | regval = superio_inb(sio_data->sioreg, 0x1c); | 2102 | regval = superio_inb(sio_data->sioreg, 0x1c); |
1808 | 2103 | ||
@@ -1810,6 +2105,10 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, | |||
1810 | fan4pin = !(regval & (1 << 6)); | 2105 | fan4pin = !(regval & (1 << 6)); |
1811 | fan5pin = !(regval & (1 << 7)); | 2106 | fan5pin = !(regval & (1 << 7)); |
1812 | 2107 | ||
2108 | pwm3pin = !(regval & (1 << 0)); | ||
2109 | pwm4pin = !(regval & (1 << 1)); | ||
2110 | pwm5pin = !(regval & (1 << 2)); | ||
2111 | |||
1813 | fan3min = fan3pin; | 2112 | fan3min = fan3pin; |
1814 | fan4min = fan4pin; | 2113 | fan4min = fan4pin; |
1815 | } | 2114 | } |
@@ -1823,6 +2122,8 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, | |||
1823 | data->has_fan |= (fan4pin << 3) | (fan5pin << 4); | 2122 | data->has_fan |= (fan4pin << 3) | (fan5pin << 4); |
1824 | data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); | 2123 | data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); |
1825 | 2124 | ||
2125 | data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4); | ||
2126 | |||
1826 | return 0; | 2127 | return 0; |
1827 | } | 2128 | } |
1828 | 2129 | ||
@@ -1859,6 +2160,7 @@ static int nct6775_probe(struct platform_device *pdev) | |||
1859 | switch (data->kind) { | 2160 | switch (data->kind) { |
1860 | case nct6775: | 2161 | case nct6775: |
1861 | data->in_num = 9; | 2162 | data->in_num = 9; |
2163 | data->pwm_num = 3; | ||
1862 | data->has_fan_div = true; | 2164 | data->has_fan_div = true; |
1863 | data->temp_fixed_num = 3; | 2165 | data->temp_fixed_num = 3; |
1864 | 2166 | ||
@@ -1877,8 +2179,13 @@ static int nct6775_probe(struct platform_device *pdev) | |||
1877 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | 2179 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; |
1878 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | 2180 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; |
1879 | data->REG_FAN = NCT6775_REG_FAN; | 2181 | data->REG_FAN = NCT6775_REG_FAN; |
2182 | data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; | ||
1880 | data->REG_FAN_MIN = NCT6775_REG_FAN_MIN; | 2183 | data->REG_FAN_MIN = NCT6775_REG_FAN_MIN; |
1881 | data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES; | 2184 | data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES; |
2185 | data->REG_PWM[0] = NCT6775_REG_PWM; | ||
2186 | data->REG_PWM_READ = NCT6775_REG_PWM_READ; | ||
2187 | data->REG_PWM_MODE = NCT6775_REG_PWM_MODE; | ||
2188 | data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK; | ||
1882 | data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; | 2189 | data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; |
1883 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; | 2190 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; |
1884 | data->REG_ALARM = NCT6775_REG_ALARM; | 2191 | data->REG_ALARM = NCT6775_REG_ALARM; |
@@ -1894,6 +2201,7 @@ static int nct6775_probe(struct platform_device *pdev) | |||
1894 | break; | 2201 | break; |
1895 | case nct6776: | 2202 | case nct6776: |
1896 | data->in_num = 9; | 2203 | data->in_num = 9; |
2204 | data->pwm_num = 3; | ||
1897 | data->has_fan_div = false; | 2205 | data->has_fan_div = false; |
1898 | data->temp_fixed_num = 3; | 2206 | data->temp_fixed_num = 3; |
1899 | 2207 | ||
@@ -1912,8 +2220,13 @@ static int nct6775_probe(struct platform_device *pdev) | |||
1912 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | 2220 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; |
1913 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | 2221 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; |
1914 | data->REG_FAN = NCT6775_REG_FAN; | 2222 | data->REG_FAN = NCT6775_REG_FAN; |
2223 | data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; | ||
1915 | data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; | 2224 | data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; |
1916 | data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES; | 2225 | data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES; |
2226 | data->REG_PWM[0] = NCT6775_REG_PWM; | ||
2227 | data->REG_PWM_READ = NCT6775_REG_PWM_READ; | ||
2228 | data->REG_PWM_MODE = NCT6776_REG_PWM_MODE; | ||
2229 | data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK; | ||
1917 | data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; | 2230 | data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET; |
1918 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; | 2231 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; |
1919 | data->REG_ALARM = NCT6775_REG_ALARM; | 2232 | data->REG_ALARM = NCT6775_REG_ALARM; |
@@ -1929,6 +2242,7 @@ static int nct6775_probe(struct platform_device *pdev) | |||
1929 | break; | 2242 | break; |
1930 | case nct6779: | 2243 | case nct6779: |
1931 | data->in_num = 15; | 2244 | data->in_num = 15; |
2245 | data->pwm_num = 5; | ||
1932 | data->has_fan_div = false; | 2246 | data->has_fan_div = false; |
1933 | data->temp_fixed_num = 6; | 2247 | data->temp_fixed_num = 6; |
1934 | 2248 | ||
@@ -1947,8 +2261,13 @@ static int nct6775_probe(struct platform_device *pdev) | |||
1947 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | 2261 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; |
1948 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | 2262 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; |
1949 | data->REG_FAN = NCT6779_REG_FAN; | 2263 | data->REG_FAN = NCT6779_REG_FAN; |
2264 | data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; | ||
1950 | data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; | 2265 | data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; |
1951 | data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES; | 2266 | data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES; |
2267 | data->REG_PWM[0] = NCT6775_REG_PWM; | ||
2268 | data->REG_PWM_READ = NCT6775_REG_PWM_READ; | ||
2269 | data->REG_PWM_MODE = NCT6776_REG_PWM_MODE; | ||
2270 | data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK; | ||
1952 | data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; | 2271 | data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; |
1953 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; | 2272 | data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; |
1954 | data->REG_ALARM = NCT6779_REG_ALARM; | 2273 | data->REG_ALARM = NCT6779_REG_ALARM; |
@@ -2157,6 +2476,16 @@ static int nct6775_probe(struct platform_device *pdev) | |||
2157 | /* Read fan clock dividers immediately */ | 2476 | /* Read fan clock dividers immediately */ |
2158 | nct6775_init_fan_common(dev, data); | 2477 | nct6775_init_fan_common(dev, data); |
2159 | 2478 | ||
2479 | /* Register sysfs hooks */ | ||
2480 | for (i = 0; i < data->pwm_num; i++) { | ||
2481 | if (!(data->has_pwm & (1 << i))) | ||
2482 | continue; | ||
2483 | |||
2484 | err = sysfs_create_group(&dev->kobj, &nct6775_group_pwm[i]); | ||
2485 | if (err) | ||
2486 | goto exit_remove; | ||
2487 | } | ||
2488 | |||
2160 | for (i = 0; i < data->in_num; i++) { | 2489 | for (i = 0; i < data->in_num; i++) { |
2161 | if (!(data->have_in & (1 << i))) | 2490 | if (!(data->have_in & (1 << i))) |
2162 | continue; | 2491 | continue; |