]> git.sur5r.net Git - groeck-nct6775/blobdiff - nct6775.c
Add support for fixed temperature registers supported by NCT6779D
[groeck-nct6775] / nct6775.c
index 242bdfc6045ff199404c4f64c369d6209fe5f740..970e976416dd9933df0ed5676ddf7bf9b34f54e4 100644 (file)
--- a/nct6775.c
+++ b/nct6775.c
@@ -169,6 +169,7 @@ static const u16 NCT6779_REG_IN[] = {
 };
 
 #define NCT6775_REG_VBAT               0x5D
+#define NCT6775_REG_DIODE              0x5E
 
 #define NCT6775_REG_FANDIV1            0x506
 #define NCT6775_REG_FANDIV2            0x507
@@ -222,6 +223,9 @@ static const u16 NCT6779_REG_FAN[] = { 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8 };
 static const u16 NCT6775_REG_TEMP[]
        = { 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
 static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
+static const u16 NCT6779_REG_TEMP_FIXED[]
+       = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495};
+
 static const u16 NCT6775_REG_TEMP_CONFIG[]
        = { 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
 static const u16 NCT6775_REG_TEMP_HYST[]
@@ -232,25 +236,28 @@ static const u16 NCT6775_REG_TEMP_OVER[]
 static const u16 NCT6775_REG_TEMP_SOURCE[]
        = { 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
 
-static const u16 NCT6775_REG_TEMP_SEL[] 
+static const u16 NCT6775_REG_TEMP_SEL[]
        = { 0x100, 0x200, 0x300, 0x800, 0x900 };
 
-static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] 
+static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[]
        = { 0x139, 0x239, 0x339, 0x839, 0x939 };
-static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] 
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[]
        = { 0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
-static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] 
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[]
        = { 0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
-static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] 
+static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[]
        = { 0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
-static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] 
+static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[]
        = { 0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
 
-static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] 
+static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[]
        = { 0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
 
 static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
 
+static const u16 NCT6779_REG_TEMP_OFFSET[]
+       = { 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
+
 static const u16 NCT6776_REG_TEMP_CONFIG[11]
        = { 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
 
@@ -356,6 +363,9 @@ static const char *const nct6779_temp_label[] = {
        "BYTE_TEMP"
 };
 
+#define NUM_TEMP       10      /* Max number of temp attribute sets w/ limits*/
+#define NUM_TEMP_FIXED 6       /* Max number of fixed temp attribute sets */
+
 #define NUM_REG_TEMP   ARRAY_SIZE(NCT6775_REG_TEMP)
 
 static inline int reg_to_pwm_enable(int pwm, int mode)
@@ -464,12 +474,14 @@ struct nct6775_data {
        struct device *hwmon_dev;
        struct mutex lock;
 
-       u16 reg_temp[3][NUM_REG_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst */
-       u8 temp_src[NUM_REG_TEMP];
-       u16 reg_temp_config[NUM_REG_TEMP];
+       u16 reg_temp[3][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst */
+       u8 temp_src[NUM_TEMP];
+       u16 reg_temp_config[NUM_TEMP];
        const char * const *temp_label;
 
+       u16 REG_CONFIG;
        u16 REG_VBAT;
+       u16 REG_DIODE;
 
        const u16 *REG_VIN;
        const u16 *REG_IN_MINMAX[2];
@@ -486,6 +498,7 @@ struct nct6775_data {
        const u16 *REG_PWM[3];
        const u16 *REG_PWM_READ;
 
+       const u16 *REG_TEMP_FIXED;
        const u16 *REG_TEMP_MON;
        const u16 *REG_AUTO_TEMP;
        const u16 *REG_AUTO_PWM;
@@ -524,9 +537,11 @@ struct nct6775_data {
        u8 has_fan;             /* some fan inputs can be disabled */
        u8 has_fan_min;         /* some fans don't have min register */
        bool has_fan_div;
-       u8 temp_type[3];
-       s8 temp_offset[3];
-       s16 temp[3][NUM_REG_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst */
+
+       u8 temp_fixed_num;      /* 3 or 6 */
+       u8 temp_type[NUM_TEMP_FIXED];
+       s8 temp_offset[NUM_TEMP_FIXED];
+       s16 temp[3][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst */
        u64 alarms;
        u8 caseopen;
 
@@ -564,7 +579,7 @@ struct nct6775_data {
        u8 vrm;
 
        u16 have_temp;
-       u16 have_temp_offset;
+       u16 have_temp_fixed;
        u16 have_in;
 };
 
@@ -633,8 +648,7 @@ static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
        return res;
 }
 
-static int nct6775_write_value(struct nct6775_data *data, u16 reg,
-                                u16 value)
+static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
 {
        int word_sized = is_word_sized(data, reg);
 
@@ -665,8 +679,7 @@ static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
        return res;
 }
 
-static int nct6775_write_temp(struct nct6775_data *data, u16 reg,
-                                      u16 value)
+static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
 {
        if (!is_word_sized(data, reg))
                value >>= 8;
@@ -702,7 +715,7 @@ static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
 }
 
 static void nct6775_write_fan_div_common(struct device *dev,
-                                          struct nct6775_data *data, int nr)
+                                        struct nct6775_data *data, int nr)
 {
        if (data->kind == nct6775)
                nct6775_write_fan_div(data, nr);
@@ -722,7 +735,7 @@ static void nct6775_update_fan_div(struct nct6775_data *data)
 }
 
 static void nct6775_update_fan_div_common(struct device *dev,
-                                           struct nct6775_data *data)
+                                         struct nct6775_data *data)
 {
        if (data->kind == nct6775)
                nct6775_update_fan_div(data);
@@ -916,7 +929,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
                nct6775_update_pwm_limits(dev);
 
                /* Measured temperatures and limits */
-               for (i = 0; i < NUM_REG_TEMP; i++) {
+               for (i = 0; i < NUM_TEMP; i++) {
                        if (!(data->have_temp & (1 << i)))
                                continue;
                        for (j = 0; j < 3; j++) {
@@ -925,7 +938,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
                                          = nct6775_read_temp(data,
                                                data->reg_temp[j][i]);
                        }
-                       if (!(data->have_temp_offset & (1 << i)))
+                       if (!(data->have_temp_fixed & (1 << i)))
                                continue;
                        data->temp_offset[i]
                          = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
@@ -983,12 +996,12 @@ store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
        return count;
 }
 
-static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
-                         char *buf)
+static ssize_t
+show_alarm(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;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        return sprintf(buf, "%u\n",
                       (unsigned int)((data->alarms >> nr) & 0x01));
 }
@@ -1217,8 +1230,8 @@ static ssize_t
 show_fan(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;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        return sprintf(buf, "%d\n", data->rpm[nr]);
 }
 
@@ -1226,20 +1239,19 @@ static ssize_t
 show_fan_min(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;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        return sprintf(buf, "%d\n",
                       data->fan_from_reg_min(data->fan_min[nr],
                                              data->fan_div[nr]));
 }
 
 static ssize_t
-show_fan_div(struct device *dev, struct device_attribute *attr,
-            char *buf)
+show_fan_div(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;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
 }
 
@@ -1248,8 +1260,8 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
              const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        unsigned long val;
        int err;
        unsigned int reg;
@@ -1332,6 +1344,7 @@ write_div:
                /* Give the chip time to sample a new speed value */
                data->last_updated = jiffies;
        }
+
 write_min:
        nct6775_write_value(data, data->REG_FAN_MIN[nr],
                              data->fan_min[nr]);
@@ -1381,8 +1394,8 @@ static ssize_t
 show_temp_label(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;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
 }
 
@@ -1424,9 +1437,9 @@ static ssize_t
 show_temp_offset(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);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 
-       return sprintf(buf, "%d\n", data->temp_offset[sensor_attr->index] * 1000);
+       return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
 }
 
 static ssize_t
@@ -1434,8 +1447,8 @@ store_temp_offset(struct device *dev, struct device_attribute *attr,
                  const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        long val;
        int err;
 
@@ -1457,11 +1470,53 @@ static ssize_t
 show_temp_type(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;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
 }
 
+static ssize_t
+store_temp_type(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       u8 vbat, diode, bit;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val != 1 && val != 3 && val != 4)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       data->temp_type[nr] = val;
+       vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr);
+       diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr);
+       bit = 0x02 << nr;
+       switch(val) {
+       case 1: /* CPU diode (diode, current mode) */
+               vbat |= bit;
+               diode |= bit;
+               break;
+       case 3: /* diode, voltage mode */
+               vbat |= bit;
+               break;
+       case 4: /* thermistor */
+               break;
+       };
+       nct6775_write_value(data, data->REG_VBAT, vbat);
+       nct6775_write_value(data, data->REG_DIODE, diode);
+
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
 static struct sensor_device_attribute_2 sda_temp_input[] = {
        SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
        SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
@@ -1469,6 +1524,10 @@ static struct sensor_device_attribute_2 sda_temp_input[] = {
        SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
        SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
        SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
+       SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
+       SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
+       SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
+       SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
 };
 
 static struct sensor_device_attribute sda_temp_label[] = {
@@ -1478,6 +1537,10 @@ 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),
+       SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
 };
 
 static struct sensor_device_attribute_2 sda_temp_max[] = {
@@ -1493,6 +1556,14 @@ static struct sensor_device_attribute_2 sda_temp_max[] = {
                      4, 1),
        SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
                      5, 1),
+       SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     6, 1),
+       SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     7, 1),
+       SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     8, 1),
+       SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     9, 1),
 };
 
 static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
@@ -1508,6 +1579,14 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
                      4, 2),
        SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
                      5, 2),
+       SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     6, 2),
+       SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     7, 2),
+       SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     8, 2),
+       SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     9, 2),
 };
 
 static struct sensor_device_attribute sda_temp_offset[] = {
@@ -1517,6 +1596,27 @@ static struct sensor_device_attribute sda_temp_offset[] = {
                    store_temp_offset, 1),
        SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
                    store_temp_offset, 2),
+       SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 3),
+       SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 4),
+       SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 5),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
+       SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 0),
+       SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 1),
+       SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 2),
+       SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 3),
+       SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 4),
+       SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 5),
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -1525,19 +1625,15 @@ static struct sensor_device_attribute sda_temp_alarm[] = {
        SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
 };
 
-static struct sensor_device_attribute sda_temp_type[] = {
-       SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
-       SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
-       SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
-};
+#define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm)
 
 static ssize_t
 show_pwm_mode(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);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 
-       return sprintf(buf, "%d\n", !data->pwm_mode[sensor_attr->index]);
+       return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
 }
 
 static ssize_t
@@ -1545,8 +1641,8 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        unsigned long val;
        int err;
        u8 reg;
@@ -1580,9 +1676,9 @@ static ssize_t
 show_pwm_enable(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);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 
-       return sprintf(buf, "%d\n", data->pwm_enable[sensor_attr->index]);
+       return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
 }
 
 static ssize_t
@@ -1659,8 +1755,8 @@ 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 sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        unsigned long val;
        int err;
        u16 reg;
@@ -1758,19 +1854,19 @@ 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);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 
        return sprintf(buf, "%d\n",
-                      data->target_temp[sensor_attr->index] * 1000);
+                      data->target_temp[sattr->index] * 1000);
 }
 
 static ssize_t
 store_target_temp(struct device *dev, struct device_attribute *attr,
-                       const char *buf, size_t count)
+                 const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        long val;
        int err;
 
@@ -1899,12 +1995,12 @@ static SENSOR_DEVICE_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
 static SENSOR_DEVICE_ATTR(pwm5_target, S_IWUSR | S_IRUGO, show_target_temp,
                          store_target_temp, 4);
 
-/* Monitored pwm temperatures */ 
-static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_pwm_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_pwm_temp, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_pwm_temp, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_pwm_temp, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_pwm_temp, NULL, 4);
+/* Monitored pwm temperatures */
+static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_pwm_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, show_pwm_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, show_pwm_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, show_pwm_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, show_pwm_temp, NULL, 4);
 
 /* Smart Fan registers */
 
@@ -1923,8 +2019,8 @@ store_pwm_weight_enable(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
        unsigned long val;
        int err;
        u8 reg;
@@ -2133,13 +2229,14 @@ store_fan_time(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-                        char *buf)
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
 
        return sprintf(buf, "%s\n", data->name);
 }
+
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
@@ -2199,7 +2296,7 @@ static SENSOR_DEVICE_ATTR_2(pwm5_stop_output, S_IWUSR | S_IRUGO, show_pwm,
 
 static struct attribute *nct6775_attributes_pwm[5][19] = {
        {
-               &sensor_dev_attr_temp7_input.dev_attr.attr,
+               &sensor_dev_attr_temp11_input.dev_attr.attr,
                &sensor_dev_attr_pwm1.dev_attr.attr,
                &sensor_dev_attr_pwm1_mode.dev_attr.attr,
                &sensor_dev_attr_pwm1_enable.dev_attr.attr,
@@ -2219,7 +2316,7 @@ static struct attribute *nct6775_attributes_pwm[5][19] = {
                NULL
        },
        {
-               &sensor_dev_attr_temp8_input.dev_attr.attr,
+               &sensor_dev_attr_temp12_input.dev_attr.attr,
                &sensor_dev_attr_pwm2.dev_attr.attr,
                &sensor_dev_attr_pwm2_mode.dev_attr.attr,
                &sensor_dev_attr_pwm2_enable.dev_attr.attr,
@@ -2239,7 +2336,7 @@ static struct attribute *nct6775_attributes_pwm[5][19] = {
                NULL
        },
        {
-               &sensor_dev_attr_temp9_input.dev_attr.attr,
+               &sensor_dev_attr_temp13_input.dev_attr.attr,
                &sensor_dev_attr_pwm3.dev_attr.attr,
                &sensor_dev_attr_pwm3_mode.dev_attr.attr,
                &sensor_dev_attr_pwm3_enable.dev_attr.attr,
@@ -2259,7 +2356,7 @@ static struct attribute *nct6775_attributes_pwm[5][19] = {
                NULL
        },
        {
-               &sensor_dev_attr_temp10_input.dev_attr.attr,
+               &sensor_dev_attr_temp14_input.dev_attr.attr,
                &sensor_dev_attr_pwm4.dev_attr.attr,
                &sensor_dev_attr_pwm4_mode.dev_attr.attr,
                &sensor_dev_attr_pwm4_enable.dev_attr.attr,
@@ -2279,7 +2376,7 @@ static struct attribute *nct6775_attributes_pwm[5][19] = {
                NULL
        },
        {
-               &sensor_dev_attr_temp11_input.dev_attr.attr,
+               &sensor_dev_attr_temp15_input.dev_attr.attr,
                &sensor_dev_attr_pwm5.dev_attr.attr,
                &sensor_dev_attr_pwm5_mode.dev_attr.attr,
                &sensor_dev_attr_pwm5_enable.dev_attr.attr,
@@ -2308,8 +2405,8 @@ static const struct attribute_group nct6775_group_pwm[5] = {
        { .attrs = nct6775_attributes_pwm[4] },
 };
 
-static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
-                            char *buf)
+static ssize_t
+show_auto_pwm(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);
@@ -2317,8 +2414,9 @@ static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
 }
 
-static ssize_t store_auto_pwm(struct device *dev, struct device_attribute *attr,
-                             const char *buf, size_t count)
+static ssize_t
+store_auto_pwm(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
@@ -2381,8 +2479,8 @@ static ssize_t store_auto_pwm(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
-                             char *buf)
+static ssize_t
+show_auto_temp(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);
@@ -2396,9 +2494,9 @@ static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
 }
 
-static ssize_t store_auto_temp(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
+static ssize_t
+store_auto_temp(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
@@ -2654,8 +2752,8 @@ show_vid(struct device *dev, struct device_attribute *attr, char *buf)
        struct nct6775_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
 }
-static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
 /* Case open detection */
 
@@ -2670,7 +2768,7 @@ show_caseopen(struct device *dev, struct device_attribute *attr, char *buf)
 
 static ssize_t
 clear_caseopen(struct device *dev, struct device_attribute *attr,
-                       const char *buf, size_t count)
+              const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
        struct nct6775_sio_data *sio_data = dev->platform_data;
@@ -2740,18 +2838,20 @@ static void nct6775_device_remove_files(struct device *dev)
                device_remove_file(dev, &sda_fan_div[i].dev_attr);
                device_remove_file(dev, &sda_fan_min[i].dev_attr);
        }
-       for (i = 0; i < NUM_REG_TEMP; i++) {
+       for (i = 0; i < NUM_TEMP; i++) {
                if (!(data->have_temp & (1 << i)))
                        continue;
                device_remove_file(dev, &sda_temp_input[i].dev_attr);
                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);
-               if (i > 2)
+               if (!(data->have_temp_fixed & (1 << i)))
                        continue;
-               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
                device_remove_file(dev, &sda_temp_type[i].dev_attr);
                device_remove_file(dev, &sda_temp_offset[i].dev_attr);
+               if (i >= NUM_TEMP_ALARM)
+                       continue;
+               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
        }
 
        device_remove_file(dev, &sda_caseopen[0].dev_attr);
@@ -2765,16 +2865,17 @@ static void nct6775_device_remove_files(struct device *dev)
 static inline void __devinit nct6775_init_device(struct nct6775_data *data)
 {
        int i;
-       u8 tmp;
+       u8 tmp, diode;
 
        /* Start monitoring if needed */
-       tmp = nct6775_read_value(data, NCT6775_REG_CONFIG);
-       if (!(tmp & 0x01))
-               nct6775_write_value(data, NCT6775_REG_CONFIG,
-                                     tmp | 0x01);
+       if (data->REG_CONFIG) {
+               tmp = nct6775_read_value(data, data->REG_CONFIG);
+               if (!(tmp & 0x01))
+                       nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
+       }
 
        /* Enable temperature sensors if needed */
-       for (i = 0; i < NUM_REG_TEMP; i++) {
+       for (i = 0; i < NUM_TEMP; i++) {
                if (!(data->have_temp & (1 << i)))
                        continue;
                if (!data->reg_temp_config[i])
@@ -2790,42 +2891,16 @@ static inline void __devinit nct6775_init_device(struct nct6775_data *data)
        if (!(tmp & 0x01))
                nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
 
-       for (i = 0; i < 3; i++) {
-               const char *label = NULL;
-
-               if (data->temp_label)
-                       label = data->temp_label[data->temp_src[i]];
-
-               /* Digital source overrides analog type */
-               if (label && strncmp(label, "PECI", 4) == 0)
-                       data->temp_type[i] = 6;
-               else if (label && strncmp(label, "AMD", 3) == 0)
-                       data->temp_type[i] = 5;
-               else if ((tmp & (0x02 << i)))
-                       data->temp_type[i] = 1; /* diode */
-               else
-                       data->temp_type[i] = 4; /* thermistor */
-       }
-}
-
-static void w82627ehf_swap_tempreg(struct nct6775_data *data,
-                                  int r1, int r2)
-{
-       u16 tmp, i;
-
-       tmp = data->temp_src[r1];
-       data->temp_src[r1] = data->temp_src[r2];
-       data->temp_src[r2] = tmp;
+       diode = nct6775_read_value(data, data->REG_DIODE);
 
-       for (i = 0; i < 3; i++) {
-               tmp = data->reg_temp[i][r1];
-               data->reg_temp[i][r1] = data->reg_temp[i][r2];
-               data->reg_temp[i][r2] = tmp;
+       for (i = 0; i < data->temp_fixed_num; i++) {
+               if (!(data->have_temp_fixed & (1 << i)))
+                       continue;
+               if ((tmp & (0x02 << i)))        /* diode */
+                       data->temp_type[i] = 3 - ((diode >> i) & 0x02);
+               else                            /* thermistor */
+                       data->temp_type[i] = 4;
        }
-
-       tmp = data->reg_temp_config[r1];
-       data->reg_temp_config[r1] = data->reg_temp_config[r2];
-       data->reg_temp_config[r2] = tmp;
 }
 
 static void __devinit
@@ -2911,7 +2986,7 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
        struct nct6775_sio_data *sio_data = dev->platform_data;
        struct nct6775_data *data;
        struct resource *res;
-       int i, err = 0;
+       int i, s, err = 0;
        int src, mask = 0;
        const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
 
@@ -2945,11 +3020,14 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                data->pwm_num = 3;
                data->auto_pwm_num = 6;
                data->has_fan_div = true;
+               data->temp_fixed_num = 3;
 
                data->fan_from_reg = fan_from_reg16;
                data->fan_from_reg_min = fan_from_reg8;
 
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
                data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
                data->REG_VIN = NCT6775_REG_IN;
                data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
                data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -2996,10 +3074,14 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                data->pwm_num = 3;
                data->auto_pwm_num = 4;
                data->has_fan_div = false;
+               data->temp_fixed_num = 3;
+
                data->fan_from_reg = fan_from_reg13;
                data->fan_from_reg_min = fan_from_reg13;
 
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
                data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
                data->REG_VIN = NCT6775_REG_IN;
                data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
                data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3047,11 +3129,14 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                data->pwm_num = 5;
                data->auto_pwm_num = 4;
                data->has_fan_div = false;
+               data->temp_fixed_num = 6;
 
                data->fan_from_reg = fan_from_reg13;
                data->fan_from_reg_min = fan_from_reg13;
 
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
                data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
                data->REG_VIN = NCT6779_REG_IN;
                data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
                data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3068,13 +3153,14 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                data->REG_PWM_READ = NCT6775_REG_PWM_READ;
                data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
                data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+               data->REG_TEMP_FIXED = NCT6779_REG_TEMP_FIXED;
                data->REG_TEMP_MON = NCT6775_REG_TEMP_MON;
                data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
                data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
                data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
                data->REG_CRITICAL_TEMP_TOLERANCE
                  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
-               data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+               data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
                data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
                data->REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
                data->REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
@@ -3101,49 +3187,57 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
        /* Default to no temperature inputs, code below will adjust as needed */
        data->have_temp = 0;
 
+       s = NUM_TEMP_FIXED;     /* Index for first non-standard temperature */
        for (i = 0; i < NUM_REG_TEMP; i++) {
                if (reg_temp[i] == 0)
                        continue;
 
-               data->reg_temp[0][i] = reg_temp[i];
-               data->reg_temp[1][i] = reg_temp_over[i];
-               data->reg_temp[2][i] = reg_temp_hyst[i];
-               data->reg_temp_config[i] = reg_temp_config[i];
-
                src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]);
                src &= 0x1f;
 
-               if (src && !(mask & (1 << src))) {
-                       data->have_temp |= 1 << i;
+               if (!src || (mask & (1 << src)))
+                       continue;
+
+               /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
+               if (src <= data->temp_fixed_num) {
+                       data->have_temp |= (1 << (src - 1));
+                       data->have_temp_fixed |= (1 << (src - 1));
                        mask |= 1 << src;
+                       data->reg_temp[0][src - 1] = reg_temp[i];
+                       data->reg_temp[1][src - 1] = reg_temp_over[i];
+                       data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+                       data->reg_temp_config[src - 1] = reg_temp_config[i];
+                       data->temp_src[src - 1] = src;
+                       continue;
                }
 
-               data->temp_src[i] = src;
+               if (s >= NUM_TEMP)
+                       continue;
 
-               /*
-                * 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)
-                               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);
+               /* Use dynamic index for other sources */
+               data->have_temp |= 1 << s;
+               mask |= 1 << src;
+
+               data->reg_temp[0][s] = reg_temp[i];
+               data->reg_temp[1][s] = reg_temp_over[i];
+               data->reg_temp[2][s] = reg_temp_hyst[i];
+               data->reg_temp_config[s] = reg_temp_config[i];
+
+
+               data->temp_src[s] = src;
+               s++;
        }
-       data->have_temp_offset = data->have_temp & 0x07;
-       for (i = 0; i < 3; i++) {
-               if (data->temp_src[i] > 3)
-                       data->have_temp_offset &= ~(1 << i);
+
+       if (data->REG_TEMP_FIXED) {
+               for (i = 0; i < NUM_TEMP_FIXED; i++) {
+                       if (data->have_temp & (1 << i))
+                               continue;
+                       if (!data->REG_TEMP_FIXED[i])
+                               continue;
+                       data->have_temp |= (1 << i);
+                       data->reg_temp[0][i] = data->REG_TEMP_FIXED[i];
+                       data->temp_src[i] = i + 1;
+               }
        }
 
        switch (data->kind) {
@@ -3160,15 +3254,9 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                 * 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 (data->have_temp & (1 << 2)) {
+                       u8 reg = nct6775_read_value(data,
+                                                   data->reg_temp_config[2]);
                        if (reg & 0x01)
                                data->have_temp &= ~(1 << 2);
                        else
@@ -3189,13 +3277,13 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                for (i = 0; i < ARRAY_SIZE(NCT6779_REG_TEMP); i++) {
                        if (!(data->have_temp & (1 << i)))
                                continue;
-                       if (data->temp_src[i] == 3)             /* AUXTIN0 */
+                       if (i == 2)                             /* AUXTIN0 */
                                data->have_in &= ~(1 << 6);     /* no VIN4 */
-                       if (data->temp_src[i] == 4)             /* AUXTIN1 */
+                       if (i == 3)                             /* AUXTIN1 */
                                data->have_in &= ~(1 << 10);    /* no VIN5 */
-                       if (data->temp_src[i] == 5)             /* AUXTIN2 */
+                       if (i == 4)                             /* AUXTIN2 */
                                data->have_in &= ~(1 << 11);    /* no VIN6 */
-                       if (data->temp_src[i] == 6)             /* AUXTIN0 */
+                       if (i == 5)                             /* AUXTIN3 */
                                data->have_in &= ~(1 << 14);    /* no VIN7 */
                }
                data->temp_label = nct6779_temp_label;
@@ -3307,7 +3395,7 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                }
        }
 
-       for (i = 0; i < NUM_REG_TEMP; i++) {
+       for (i = 0; i < NUM_TEMP; i++) {
                if (!(data->have_temp & (1 << i)))
                        continue;
                err = device_create_file(dev, &sda_temp_input[i].dev_attr);
@@ -3331,20 +3419,20 @@ static int __devinit nct6775_probe(struct platform_device *pdev)
                        if (err)
                                goto exit_remove;
                }
-               if (i > 2)
+               if (!(data->have_temp_fixed & (1 << i)))
                        continue;
-               err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
+               err = device_create_file(dev, &sda_temp_type[i].dev_attr);
                if (err)
                        goto exit_remove;
-               err = device_create_file(dev, &sda_temp_type[i].dev_attr);
+               err = device_create_file(dev,
+                                        &sda_temp_offset[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+               if (i >= NUM_TEMP_ALARM)
+                       continue;
+               err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
                if (err)
                        goto exit_remove;
-               if (data->have_temp_offset & (1 << i)) {
-                       err = device_create_file(dev,
-                                                &sda_temp_offset[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
        }
 
        for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {