]> git.sur5r.net Git - groeck-nct6775/blobdiff - nct6775.c
Add attributes to set pwm temperature source
[groeck-nct6775] / nct6775.c
index 499706e1bd5c3f6805c58b949ef0becdcbbd91a1..7350e24f5052c07eb2810fa454cc3092686a77ab 100644 (file)
--- a/nct6775.c
+++ b/nct6775.c
@@ -202,51 +202,42 @@ static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
        0x104, 0x204, 0x304, 0x804, 0x904 };
 static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
        0x105, 0x205, 0x305, 0x805, 0x905 };
-static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
-       0x106, 0x206, 0x306, 0x806, 0x906 };
-static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
-       0x107, 0x207, 0x307, 0x807, 0x907 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[]
+       = { 0x106, 0x206, 0x306, 0x806, 0x906 };
+static const u16 NCT6775_REG_FAN_STOP_TIME[]
+       = { 0x107, 0x207, 0x307, 0x807, 0x907 };
 static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
 static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
 
-static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
-static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
 static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
 
 static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
 
-static const u16 NCT6779_REG_TOLERANCE_H[] = {
-       0x10c, 0x20c, 0x30c, 0x40c, 0x50c };
+static const u16 NCT6779_REG_TOLERANCE_H[]
+       = { 0x10c, 0x20c, 0x30c, 0x40c, 0x50c };
 
 static const u16 NCT6779_REG_FAN[] = { 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8 };
 
-static const u16 NCT6775_REG_TEMP[]
-       = { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
-static const u16 NCT6775_REG_TEMP_CONFIG[]
-       = { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
-static const u16 NCT6775_REG_TEMP_HYST[]
-       = { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
-static const u16 NCT6775_REG_TEMP_OVER[]
-       = { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
-static const u16 NCT6775_REG_TEMP_SOURCE[]
-       = { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
-
-static const u16 NCT6776_REG_TEMP_CONFIG[]
-       = { 0x18, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
-
-static const u16 NCT6779_REG_TEMP[]
-       = { 0x27, 0x150, 0x73, 0x75, 0x77, 0x79, 0x7b };
-static const u16 NCT6779_REG_TEMP_CONFIG[]
-       = { 0x18, 0x152, 0, 0, 0, 0, 0 };
-static const u16 NCT6779_REG_TEMP_SOURCE[]
-       = { 0x621, 0x622, 0x100, 0x200, 0x300, 0x800, 0x900 };
-static const u16 NCT6779_REG_TEMP_HYST[]
-       = { 0x3a, 0x153, 0, 0, 0, 0, 0, 0, 0 };
-static const u16 NCT6779_REG_TEMP_OVER[]
-       = { 0x39, 0x155, 0, 0, 0, 0, 0, 0, 0 };
-
-static const u16 NCT6775_REG_AUTO_BASE[] = {
-       0x100, 0x200, 0x300, 0x800, 0x900 };
+static const u16 NCT6775_REG_TEMP[11]
+       = { 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d, 0x73, 0x75, 0x77 };
+static const u16 NCT6775_REG_TEMP_CONFIG[11]
+       = { 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[11]
+       = { 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[11]
+       = { 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
+static const u16 NCT6775_REG_TEMP_SOURCE[11]
+       = { 0x621, 0x622, 0x623, 0x624, 0x625, 0x626, 0x100, 0x200, 0x300,
+           0x800, 0x900 };
+
+static const u16 NCT6776_REG_TEMP_CONFIG[11]
+       = { 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
+
+static const u16 NCT6779_REG_TEMP[11]
+       = { 0x27, 0x150, 0, 0, 0, 0, 0x73, 0x75, 0x77, 0x79, 0x7b };
+
+static const u16 NCT6775_REG_AUTO_BASE[]
+       = { 0x100, 0x200, 0x300, 0x800, 0x900 };
 
 #define NCT6775_REG_AUTO_TEMP(nr, p)   (NCT6775_REG_AUTO_BASE[nr] + 0x21 + (p))
 #define NCT6775_REG_AUTO_PWM(nr, p)    (NCT6775_REG_AUTO_BASE[nr] + 0x27 + (p))
@@ -344,6 +335,26 @@ static const char *const nct6779_temp_label[] = {
 
 #define NUM_REG_TEMP   ARRAY_SIZE(NCT6775_REG_TEMP)
 
+static inline int reg_to_pwm_enable(int pwm, int mode)
+{
+       if (mode == 0 && pwm == 255)
+               return 0;       /* off  */
+       if (mode == 3)          /* SmartFan III */
+               return 2;       /* convert to thermal cruise */
+       if (mode < 3)
+               return mode + 1;
+       return 4;               /* SmartFan IV */
+}
+
+static inline int pwm_enable_to_reg(int mode)
+{
+       if (mode == 0)
+               return 0;
+       if (mode < 4)
+               return mode - 1;
+       return 4;
+}
+
 static int is_word_sized(u16 reg)
 {
        return ((((reg & 0xff00) == 0x100
@@ -460,8 +471,6 @@ struct nct6775_data {
        const u16 *REG_FAN_MIN;
        const u16 *REG_FAN_START_OUTPUT;
        const u16 *REG_FAN_STOP_OUTPUT;
-       const u16 *REG_FAN_MAX_OUTPUT;
-       const u16 *REG_FAN_STEP_OUTPUT;
 
        unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
        unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
@@ -491,13 +500,12 @@ struct nct6775_data {
        u8 caseopen;
 
        u8 pwm_mode[5]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
-       u8 pwm_enable[5]; /* 1->manual
+       u8 pwm_enable[5]; /* 0->off
+                          * 1->manual
                           * 2->thermal cruise mode (also called SmartFan I)
                           * 3->fan speed cruise mode
-                          * 4->variable thermal cruise (also called
-                          * SmartFan III)
-                          * 5->enhanced variable thermal cruise (also called
-                          * SmartFan IV)
+                          * 4->enhanced variable thermal cruise (also called
+                          *    SmartFan IV)
                           */
        u8 pwm_num;             /* number of pwm */
        u8 pwm[5];
@@ -509,8 +517,6 @@ struct nct6775_data {
        u8 fan_stop_time[5]; /* time at minimum before disabling fan */
        u8 fan_step_up_time[5];
        u8 fan_step_down_time[5];
-       u8 fan_max_output[5]; /* maximum fan speed */
-       u8 fan_step_output[5]; /* rate of change output value */
 
        /* Automatic fan speed control registers */
        int auto_pwm_num;
@@ -668,7 +674,7 @@ static void nct6775_update_pwm(struct device *dev)
        struct nct6775_data *data = dev_get_drvdata(dev);
        struct nct6775_sio_data *sio_data = dev->platform_data;
        int i;
-       int pwmcfg, fanmodecfg, mode, tol;
+       int pwmcfg, fanmodecfg, tol;
 
        for (i = 0; i < data->pwm_num; i++) {
                if (!i) {
@@ -683,11 +689,9 @@ static void nct6775_update_pwm(struct device *dev)
                fanmodecfg = nct6775_read_value(data,
                                                  NCT6775_REG_FAN_MODE[i]);
                data->pwm[i] = nct6775_read_value(data, NCT6775_REG_PWM[i]);
-               mode = ((fanmodecfg >> 4) & 7);
-               if (data->pwm[i] == 255 && mode == 0)
-                       data->pwm_enable[i] = 0;
-               else
-                       data->pwm_enable[i] = mode + 1;
+               data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[i],
+                                                       (fanmodecfg >> 4) & 7);
+
                data->tolerance[i][0] = fanmodecfg & 0x0f;
                if (sio_data->kind == nct6779) {
                        tol = nct6775_read_value(data,
@@ -722,16 +726,6 @@ static void nct6775_update_pwm_limits(struct device *dev)
                data->fan_step_down_time[i] =
                  nct6775_read_value(data, NCT6775_REG_FAN_STEP_DOWN_TIME[i]);
 
-               if (data->REG_FAN_MAX_OUTPUT)
-                       data->fan_max_output[i] =
-                         nct6775_read_value(data,
-                                       data->REG_FAN_MAX_OUTPUT[i]);
-
-               if (data->REG_FAN_STEP_OUTPUT)
-                       data->fan_step_output[i] =
-                         nct6775_read_value(data,
-                                            data->REG_FAN_STEP_OUTPUT[i]);
-
                data->target_temp[i] =
                        nct6775_read_value(data,
                                           data->REG_TARGET[i]) &
@@ -1379,6 +1373,8 @@ static struct sensor_device_attribute sda_temp_input[] = {
        SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
        SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
        SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
+       SENSOR_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9),
+       SENSOR_ATTR(temp11_input, S_IRUGO, show_temp, NULL, 10),
 };
 
 static struct sensor_device_attribute sda_temp_label[] = {
@@ -1388,9 +1384,6 @@ static struct sensor_device_attribute sda_temp_label[] = {
        SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
        SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
        SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
-       SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
-       SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
-       SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
@@ -1406,12 +1399,6 @@ static struct sensor_device_attribute sda_temp_max[] = {
                    store_temp_max, 4),
        SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
                    store_temp_max, 5),
-       SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
-                   store_temp_max, 6),
-       SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
-                   store_temp_max, 7),
-       SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
-                   store_temp_max, 8),
 };
 
 static struct sensor_device_attribute sda_temp_max_hyst[] = {
@@ -1427,12 +1414,6 @@ static struct sensor_device_attribute sda_temp_max_hyst[] = {
                    store_temp_max_hyst, 4),
        SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
                    store_temp_max_hyst, 5),
-       SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
-                   store_temp_max_hyst, 6),
-       SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
-                   store_temp_max_hyst, 7),
-       SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
-                   store_temp_max_hyst, 8),
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -1568,7 +1549,6 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct nct6775_sio_data *sio_data = dev->platform_data;
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        unsigned long val;
@@ -1579,14 +1559,10 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
        if (err < 0)
                return err;
 
-       if (val > 5)
+       if (val > 4)
                return -EINVAL;
 
-       /* SmartFan III mode is only supported on NCT6775F */
-       if (sio_data->kind != nct6775 && val == 4)
-               return -EINVAL;
-
-       if (val == 5 && check_trip_points(data, nr)) {
+       if (val == 4 && check_trip_points(data, nr)) {
                dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
                dev_err(dev, "Adjust trip points and try again\n");
                return -EINVAL;
@@ -1598,21 +1574,65 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
                /*
                 * turn off pwm control: select manual mode, set pwm to maximum
                 */
-               val = 1;
                data->pwm[nr] = 255;
                nct6775_write_value(data, NCT6775_REG_PWM[nr], 255);
        }
        reg = nct6775_read_value(data, NCT6775_REG_FAN_MODE[nr]);
        reg &= 0x0f;
-       reg |= (val - 1) << 4;
+       reg |= (pwm_enable_to_reg(val) << 4);
        nct6775_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
+static ssize_t
+show_pwm_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       return sprintf(buf, "%d\n", data->temp_src[nr]);
+}
+
+static ssize_t
+store_pwm_temp_src(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct nct6775_sio_data *sio_data = dev->platform_data;
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       int nr = sensor_attr->index;
+       unsigned long val;
+       int err;
+       int reg;
+       static const int max_src[] = {
+           ARRAY_SIZE(nct6775_temp_label),
+           ARRAY_SIZE(nct6776_temp_label),
+           ARRAY_SIZE(nct6779_temp_label)
+       };
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       if (val == 0 || val >= max_src[sio_data->kind])
+               return -EINVAL;
 
-static ssize_t show_target_temp(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+       if (!strlen(data->temp_label[val]))
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       data->temp_src[nr] = val;
+       reg = nct6775_read_value(data, NCT6775_REG_TEMP_SOURCE[nr]);
+       reg &= 0xe0;
+       reg |= val;
+       nct6775_write_value(data, NCT6775_REG_TEMP_SOURCE[nr], reg);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t
+show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct nct6775_data *data = nct6775_update_device(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
@@ -1644,8 +1664,9 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static ssize_t show_auto_temp_hyst(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t
+show_auto_temp_hyst(struct device *dev, struct device_attribute *attr,
+                   char *buf)
 {
        struct nct6775_data *data = nct6775_update_device(dev);
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
@@ -1734,6 +1755,17 @@ static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
 static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
                          store_pwm_enable, 4);
 
+static SENSOR_DEVICE_ATTR(pwm1_temp_src, S_IWUSR | S_IRUGO, show_pwm_temp_src,
+                         store_pwm_temp_src, 6);
+static SENSOR_DEVICE_ATTR(pwm2_temp_src, S_IWUSR | S_IRUGO, show_pwm_temp_src,
+                         store_pwm_temp_src, 7);
+static SENSOR_DEVICE_ATTR(pwm3_temp_src, S_IWUSR | S_IRUGO, show_pwm_temp_src,
+                         store_pwm_temp_src, 8);
+static SENSOR_DEVICE_ATTR(pwm4_temp_src, S_IWUSR | S_IRUGO, show_pwm_temp_src,
+                         store_pwm_temp_src, 9);
+static SENSOR_DEVICE_ATTR(pwm5_temp_src, S_IWUSR | S_IRUGO, show_pwm_temp_src,
+                         store_pwm_temp_src, 10);
+
 static SENSOR_DEVICE_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
                          store_target_temp, 0);
 static SENSOR_DEVICE_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
@@ -1780,8 +1812,6 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 
 fan_functions(fan_start_output, FAN_START_OUTPUT)
 fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
-fan_functions(fan_max_output, FAN_MAX_OUTPUT)
-fan_functions(fan_step_output, FAN_STEP_OUTPUT)
 
 #define fan_step_functions(reg, REG) \
 static ssize_t show_##reg(struct device *dev, \
@@ -1884,11 +1914,12 @@ static SENSOR_DEVICE_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO,
 static SENSOR_DEVICE_ATTR(pwm5_stop_output, S_IWUSR | S_IRUGO,
                          show_fan_stop_output, store_fan_stop_output, 4);
 
-static struct attribute *nct6775_attributes_pwm[5][10] = {
+static struct attribute *nct6775_attributes_pwm[5][11] = {
        {
                &sensor_dev_attr_pwm1.dev_attr.attr,
                &sensor_dev_attr_pwm1_mode.dev_attr.attr,
                &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm1_temp_src.dev_attr.attr,
                &sensor_dev_attr_pwm1_target.dev_attr.attr,
                &sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
                &sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
@@ -1901,6 +1932,7 @@ static struct attribute *nct6775_attributes_pwm[5][10] = {
                &sensor_dev_attr_pwm2.dev_attr.attr,
                &sensor_dev_attr_pwm2_mode.dev_attr.attr,
                &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm2_temp_src.dev_attr.attr,
                &sensor_dev_attr_pwm2_target.dev_attr.attr,
                &sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
                &sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
@@ -1913,6 +1945,7 @@ static struct attribute *nct6775_attributes_pwm[5][10] = {
                &sensor_dev_attr_pwm3.dev_attr.attr,
                &sensor_dev_attr_pwm3_mode.dev_attr.attr,
                &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm3_temp_src.dev_attr.attr,
                &sensor_dev_attr_pwm3_target.dev_attr.attr,
                &sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
                &sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
@@ -1925,6 +1958,7 @@ static struct attribute *nct6775_attributes_pwm[5][10] = {
                &sensor_dev_attr_pwm4.dev_attr.attr,
                &sensor_dev_attr_pwm4_mode.dev_attr.attr,
                &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm4_temp_src.dev_attr.attr,
                &sensor_dev_attr_pwm4_target.dev_attr.attr,
                &sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
                &sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
@@ -1937,6 +1971,7 @@ static struct attribute *nct6775_attributes_pwm[5][10] = {
                &sensor_dev_attr_pwm5.dev_attr.attr,
                &sensor_dev_attr_pwm5_mode.dev_attr.attr,
                &sensor_dev_attr_pwm5_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm5_temp_src.dev_attr.attr,
                &sensor_dev_attr_pwm5_target.dev_attr.attr,
                &sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
                &sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
@@ -1955,33 +1990,6 @@ static const struct attribute_group nct6775_group_pwm[5] = {
        { .attrs = nct6775_attributes_pwm[4] },
 };
 
-/*
- * max and step settings are not supported on all chips.
- * Need to check support while generating/removing attribute files.
- */
-static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
-       SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
-                   store_fan_max_output, 0),
-       SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
-                   store_fan_step_output, 0),
-       SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
-                   store_fan_max_output, 1),
-       SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
-                   store_fan_step_output, 1),
-       SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
-                   store_fan_max_output, 2),
-       SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
-                   store_fan_step_output, 2),
-       SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
-                   store_fan_max_output, 3),
-       SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
-                   store_fan_step_output, 3),
-       SENSOR_ATTR(pwm5_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
-                   store_fan_max_output, 4),
-       SENSOR_ATTR(pwm5_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
-                   store_fan_step_output, 4),
-};
-
 static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -2391,9 +2399,6 @@ static void nct6775_device_remove_files(struct device *dev)
                                           &sda_auto_pwm_arrays[j].dev_attr);
        }
 
-       for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++)
-               device_remove_file(dev, &sda_sf3_max_step_arrays[i].dev_attr);
-
        for (i = 0; i < data->in_num; i++)
                sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);
 
@@ -2407,6 +2412,8 @@ static void nct6775_device_remove_files(struct device *dev)
                if (!(data->have_temp & (1 << i)))
                        continue;
                device_remove_file(dev, &sda_temp_input[i].dev_attr);
+               if (i > 5)
+                       continue;
                device_remove_file(dev, &sda_temp_label[i].dev_attr);
                device_remove_file(dev, &sda_temp_max[i].dev_attr);
                device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
@@ -2583,6 +2590,8 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
        struct nct6775_data *data;
        struct resource *res;
        int i, err = 0;
+       int mask = 0;
+       const u16 *reg_temp, *reg_temp_config;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
@@ -2636,43 +2645,52 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
        data->have_temp = 0;
 
        /* Deal with temperature register setup first. */
-       if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
-               int mask = 0;
+       switch(sio_data->kind == nct6775) {
+       case nct6775:
+               reg_temp = NCT6775_REG_TEMP;
+               reg_temp_config = NCT6775_REG_TEMP_CONFIG;
+       case nct6776:
+               reg_temp = NCT6775_REG_TEMP;
+               reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+               break;
+       case nct6779:
+               reg_temp = NCT6779_REG_TEMP;
+               reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+               break;
+       }
 
-               /*
-                * Display temperature sensor output only if it monitors
-                * a source other than one already reported. Always display
-                * first three temperature registers, though.
-                */
-               for (i = 0; i < NUM_REG_TEMP; i++) {
-                       u8 src;
-
-                       data->reg_temp[i] = NCT6775_REG_TEMP[i];
-                       data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
-                       data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
-                       if (sio_data->kind == nct6775)
-                               data->reg_temp_config[i]
-                                 = NCT6775_REG_TEMP_CONFIG[i];
-                       else
-                               data->reg_temp_config[i]
-                                 = NCT6776_REG_TEMP_CONFIG[i];
-
-                       src = nct6775_read_value(data,
-                                                NCT6775_REG_TEMP_SOURCE[i]);
-                       src &= 0x1f;
-                       if (src && !(mask & (1 << src))) {
-                               data->have_temp |= 1 << i;
-                               mask |= 1 << src;
-                       }
+       for (i = 0; i < NUM_REG_TEMP; i++) {
+               u8 src;
+
+               if (reg_temp[i] == 0)
+                       continue;
+
+               data->reg_temp[i] = reg_temp[i];
+               data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
+               data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
+               data->reg_temp_config[i] = reg_temp_config[i];
+
+               src = nct6775_read_value(data, NCT6775_REG_TEMP_SOURCE[i]);
+               src &= 0x1f;
+
+               /* Always display temp6..10 (fan control sources) if enabled */
+               if (src && (i > 5 || !(mask & (1 << src)))) {
+                       data->have_temp |= 1 << i;
+                       mask |= 1 << src;
+               }
 
-                       data->temp_src[i] = src;
+               data->temp_src[i] = src;
 
+               if (i < 6) {
                        /*
-                        * Now do some register swapping if index 0..2 don't
+                        * Do some register swapping if index 0..2 don't
                         * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
                         * Idea is to have the first three attributes
                         * report SYSTIN, CPUIN, and AUXIN if possible
                         * without overriding the basic system configuration.
+                        * Do this only for the first six temperature sources;
+                        * the remaining temperatures are fan control sources,
+                        * and we don't want to touch those.
                         */
                        if (i > 0 && data->temp_src[0] != 1
                            && data->temp_src[i] == 1)
@@ -2684,79 +2702,38 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                            && data->temp_src[i] == 3)
                                w82627ehf_swap_tempreg(data, 2, i);
                }
-               if (sio_data->kind == nct6776) {
-                       /*
-                        * On NCT6776, AUXTIN and VIN3 pins are shared.
-                        * Only way to detect it is to check if AUXTIN is used
-                        * as a temperature source, and if that source is
-                        * enabled.
-                        *
-                        * If that is the case, disable in6, which reports VIN3.
-                        * Otherwise disable temp3.
-                        */
-                       if (data->temp_src[2] == 3) {
-                               u8 reg;
-
-                               if (data->reg_temp_config[2])
-                                       reg = nct6775_read_value(data,
-                                               data->reg_temp_config[2]);
-                               else
-                                       reg = 0; /* Assume AUXTIN is used */
-
-                               if (reg & 0x01)
-                                       data->have_temp &= ~(1 << 2);
-                               else
-                                       data->have_in &= ~(1 << 6);
-                       }
-                       data->temp_label = nct6776_temp_label;
-               } else {
-                       data->temp_label = nct6775_temp_label;
-               }
-       } else if (sio_data->kind == nct6779) {
-               int mask = 0;
+       }
 
+       switch (sio_data->kind) {
+       case nct6775:
+               data->temp_label = nct6775_temp_label;
+               break;
+       case nct6776:
                /*
-                * Display temperature sensor output only if it monitors
-                * a source other than one already reported. Always display
-                * first three temperature registers, though.
+                * On NCT6776, AUXTIN and VIN3 pins are shared.
+                * Only way to detect it is to check if AUXTIN is used
+                * as a temperature source, and if that source is
+                * enabled.
+                *
+                * If that is the case, disable in6, which reports VIN3.
+                * Otherwise disable temp3.
                 */
-               for (i = 0; i < ARRAY_SIZE(NCT6779_REG_TEMP); i++) {
-                       u8 src;
-
-                       data->reg_temp[i] = NCT6779_REG_TEMP[i];
-                       data->reg_temp_over[i] = NCT6779_REG_TEMP_OVER[i];
-                       data->reg_temp_hyst[i] = NCT6779_REG_TEMP_HYST[i];
-                       data->reg_temp_config[i] = NCT6779_REG_TEMP_CONFIG[i];
-
-                       src = nct6775_read_value(data,
-                                                NCT6779_REG_TEMP_SOURCE[i]);
-                       src &= 0x1f;
-                       if (src && !(mask & (1 << src))) {
-                               data->have_temp |= 1 << i;
-                               mask |= 1 << src;
-                       }
+               if (data->temp_src[2] == 3) {
+                       u8 reg;
 
-                       data->temp_src[i] = src;
+                       if (data->reg_temp_config[2])
+                               reg = nct6775_read_value(data,
+                                       data->reg_temp_config[2]);
+                       else
+                               reg = 0; /* Assume AUXTIN is used */
 
-                       /*
-                        * Now do some register swapping if index 0..2 don't
-                        * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
-                        * Idea is to have the first three attributes
-                        * report SYSTIN, CPUIN, and AUXIN if possible
-                        * without overriding the basic system configuration.
-                        */
-                       if (i > 0 && data->temp_src[0] != 1
-                           && data->temp_src[i] == 1)
-                               w82627ehf_swap_tempreg(data, 0, i);
-                       if (i > 1 && data->temp_src[1] != 2
-                           && data->temp_src[i] == 2)
-                               w82627ehf_swap_tempreg(data, 1, i);
-                       if (i > 2 && data->temp_src[2] != 3
-                           && data->temp_src[i] == 3)
-                               w82627ehf_swap_tempreg(data, 2, i);
+                       if (reg & 0x01)
+                               data->have_temp &= ~(1 << 2);
+                       else
+                               data->have_in &= ~(1 << 6);
                }
-               data->temp_label = nct6779_temp_label;
-
+               data->temp_label = nct6776_temp_label;
+       case nct6779:
                /*
                 * Shared pins:
                 *      VIN4 / AUXTIN0
@@ -2778,6 +2755,8 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                        if (data->temp_src[i] == 6)             /* AUXTIN0 */
                                data->have_in &= ~(1 << 14);    /* no VIN7 */
                }
+               data->temp_label = nct6779_temp_label;
+               break;
        }
 
        if (sio_data->kind == nct6775) {
@@ -2790,8 +2769,6 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
                data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
                data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
-               data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
-               data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
        } else if (sio_data->kind == nct6776) {
                data->has_fan_div = false;
                data->fan_from_reg = fan_from_reg13;
@@ -2871,18 +2848,6 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                        goto exit_remove;
        }
 
-       if (data->REG_FAN_STEP_OUTPUT) {
-               for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
-                       struct sensor_device_attribute *attr =
-                               &sda_sf3_max_step_arrays[i];
-                       if (!(data->has_pwm & (1 << attr->index)))
-                               continue;
-                       err = device_create_file(dev, &attr->dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-       }
-
        for (i = 0; i < data->in_num; i++) {
                if (!(data->have_in & (1 << i)))
                        continue;
@@ -2923,6 +2888,8 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                err = device_create_file(dev, &sda_temp_input[i].dev_attr);
                if (err)
                        goto exit_remove;
+               if (i > 5)
+                       continue;
                if (data->temp_label) {
                        err = device_create_file(dev,
                                                 &sda_temp_label[i].dev_attr);