#include <linux/io.h>
#include "lm75.h"
+#define TESTING
+
enum kinds { nct6775, nct6776, nct6779 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */
static const u16 NCT6775_REG_ALARM[6] = { 0x459, 0x45A, 0x45B };
static const u16 NCT6779_REG_ALARM[6] = { 0x459, 0x45A, 0x45B, 0x568 };
-#define NCT6775_REG_CASEOPEN 0x42
-
-static const u8 NCT6775_CASEOPEN_MASK[] = { 0x10, 0x00 };
-static const u8 NCT6776_CASEOPEN_MASK[] = { 0x10, 0x40 };
+/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+
+static const s8 NCT6775_ALARM_BITS[]
+ = { 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, -1 }; /* intrusion0, intrusion1 */
+
+static const s8 NCT6776_ALARM_BITS[]
+ = { 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, 9 }; /* intrusion0, intrusion1 */
+
+static const s8 NCT6779_ALARM_BITS[]
+ = { 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, 9 }; /* intrusion0, intrusion1 */
+
+#define FAN_ALARM_BASE 16
+#define TEMP_ALARM_BASE 24
+#define INTRUSION_ALARM_BASE 30
static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
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 };
"BYTE_TEMP"
};
+static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label)]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
+
+static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label)]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
+
+static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label)]
+ = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x401, 0x402, 0x404 };
+
#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
u8 temp_src[NUM_TEMP];
u16 reg_temp_config[NUM_TEMP];
const char * const *temp_label;
+ int temp_label_num;
u16 REG_CONFIG;
u16 REG_VBAT;
u16 REG_DIODE;
+ const s8 *ALARM_BITS;
+
const u16 *REG_VIN;
const u16 *REG_IN_MINMAX[2];
*/
const u16 *REG_PWM_READ;
- const u16 *REG_TEMP_FIXED;
+ const u16 *REG_TEMP_ALTERNATE;
const u16 *REG_TEMP_MON;
const u16 *REG_AUTO_TEMP;
const u16 *REG_AUTO_PWM;
const u16 *REG_ALARM;
- u8 REG_CASEOPEN;
- const u8 *CASEOPEN_MASK;
-
unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
s8 temp_offset[NUM_TEMP_FIXED];
s16 temp[3][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst */
u64 alarms;
- u8 caseopen;
u8 pwm_num; /* number of pwm */
{
switch (data->kind) {
case nct6775:
+ return (((reg & 0xff00) == 0x100 ||
+ (reg & 0xff00) == 0x200) &&
+ ((reg & 0x00ff) == 0x50 ||
+ (reg & 0x00ff) == 0x53 ||
+ (reg & 0x00ff) == 0x55)) ||
+ (reg & 0xfff0) == 0x630 ||
+ reg == 0x640 || reg == 0x642 ||
+ reg == 0x662 ||
+ ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+ reg == 0x73 || reg == 0x75 || reg == 0x77;
case nct6776:
return (((reg & 0xff00) == 0x100 ||
(reg & 0xff00) == 0x200) &&
(reg & 0x00ff) == 0x53 ||
(reg & 0x00ff) == 0x55)) ||
(reg & 0xfff0) == 0x630 ||
+ reg == 0x402 ||
reg == 0x640 || reg == 0x642 ||
((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
reg == 0x73 || reg == 0x75 || reg == 0x77;
case nct6779:
return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
((reg & 0xfff0) == 0x4c0 && (reg & 0x000f) < 0x09) ||
+ reg == 0x402 ||
reg == 0x63a || reg == 0x63c || reg == 0x63e ||
reg == 0x640 || reg == 0x642 ||
reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
data->alarms |= ((u64)alarm) << (i << 3);
}
- data->caseopen = nct6775_read_value(data, data->REG_CASEOPEN);
-
data->last_updated = jiffies;
data->valid = 1;
}
{
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
- int nr = sattr->index;
+ int nr = data->ALARM_BITS[sattr->index];
return sprintf(buf, "%u\n",
(unsigned int)((data->alarms >> nr) & 0x01));
}
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
-static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
-static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21);
-static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20);
-static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
-static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
-static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 24);
-static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25);
-static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 26);
-static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 27);
-static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 28);
-static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 29);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
store_in_reg, 0, 1);
};
static struct sensor_device_attribute sda_fan_alarm[] = {
- SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
- SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
- SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
- SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
- SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
+ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 4),
};
static struct sensor_device_attribute sda_fan_min[] = {
};
static struct sensor_device_attribute sda_temp_alarm[] = {
- SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
- SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
- SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 1),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 2),
+ SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 3),
+ SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 4),
+ SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 5),
};
#define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm)
unsigned long val;
int err;
int reg;
- static const int max_src[] = {
- ARRAY_SIZE(nct6775_temp_label) - 1,
- ARRAY_SIZE(nct6776_temp_label) - 1,
- ARRAY_SIZE(nct6779_temp_label) - 1
- };
err = kstrtoul(buf, 10, &val);
if (err < 0)
if (val == 0 || val > 0x1f)
return -EINVAL;
- val = SENSORS_LIMIT(val, 1, max_src[data->kind]);
+ val = SENSORS_LIMIT(val, 1, data->temp_label_num - 1);
if (!strlen(data->temp_label[val]))
return -EINVAL;
/* Case open detection */
-static ssize_t
-show_caseopen(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct nct6775_data *data = nct6775_update_device(dev);
-
- return sprintf(buf, "%d\n",
- !!(data->caseopen & to_sensor_dev_attr_2(attr)->index));
-}
-
static ssize_t
clear_caseopen(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;
- int nr = to_sensor_dev_attr(attr)->index;
+ int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
unsigned long val;
u8 reg;
reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+ reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+ superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
superio_exit(sio_data->sioreg);
data->valid = 0; /* Force cache refresh */
}
static struct sensor_device_attribute sda_caseopen[] = {
- SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen,
- clear_caseopen, 0),
- SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_caseopen,
- clear_caseopen, 1),
+ SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+ clear_caseopen, INTRUSION_ALARM_BASE),
+ SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+ clear_caseopen, INTRUSION_ALARM_BASE + 1),
};
/*
data->has_fan_div = true;
data->temp_fixed_num = 3;
+ data->ALARM_BITS = NCT6775_ALARM_BITS;
+
data->fan_from_reg = fan_from_reg16;
data->fan_from_reg_min = fan_from_reg8;
+ data->temp_label = nct6775_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
+
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
data->REG_PWM_READ = NCT6775_REG_PWM_READ;
data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
+ data->REG_TEMP_ALTERNATE = NCT6775_REG_TEMP_ALTERNATE;
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_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6775_REG_ALARM;
- data->REG_CASEOPEN = NCT6775_REG_CASEOPEN;
- data->CASEOPEN_MASK = NCT6775_CASEOPEN_MASK;
reg_temp = NCT6775_REG_TEMP;
reg_temp_over = NCT6775_REG_TEMP_OVER;
data->has_fan_div = false;
data->temp_fixed_num = 3;
+ data->ALARM_BITS = NCT6776_ALARM_BITS;
+
data->fan_from_reg = fan_from_reg13;
data->fan_from_reg_min = fan_from_reg13;
+ data->temp_label = nct6776_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
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_ALTERNATE = NCT6776_REG_TEMP_ALTERNATE;
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_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6775_REG_ALARM;
- data->REG_CASEOPEN = NCT6775_REG_CASEOPEN;
- data->CASEOPEN_MASK = NCT6776_CASEOPEN_MASK;
reg_temp = NCT6775_REG_TEMP;
reg_temp_over = NCT6775_REG_TEMP_OVER;
data->has_fan_div = false;
data->temp_fixed_num = 6;
+ data->ALARM_BITS = NCT6779_ALARM_BITS;
+
data->fan_from_reg = fan_from_reg13;
data->fan_from_reg_min = fan_from_reg13;
+ data->temp_label = nct6779_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
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_ALTERNATE = NCT6779_REG_TEMP_ALTERNATE;
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_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6779_REG_ALARM;
- data->REG_CASEOPEN = NCT6775_REG_CASEOPEN;
- data->CASEOPEN_MASK = NCT6776_CASEOPEN_MASK;
reg_temp = NCT6779_REG_TEMP;
reg_temp_over = NCT6775_REG_TEMP_OVER;
if (!src || (mask & (1 << src)))
continue;
+ mask |= 1 << src;
+
/* 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];
/* 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];
s++;
}
- if (data->REG_TEMP_FIXED) {
- for (i = 0; i < NUM_TEMP_FIXED; i++) {
- if (data->have_temp & (1 << i))
+#ifdef TESTING
+ /*
+ * We may have alternate registers for some sensors.
+ * Go through the list and enable if possible.
+ * The temperature is already monitored if the respective bit in <mask>
+ * is set.
+ */
+ if (data->REG_TEMP_ALTERNATE) {
+ for (i = 0; i < data->temp_label_num; i++) {
+ if (!data->REG_TEMP_ALTERNATE[i])
+ continue;
+ if (mask & (1 << (i + 1)))
continue;
- if (!data->REG_TEMP_FIXED[i])
+ if (i < data->temp_fixed_num) {
+ if (data->have_temp & (1 << i))
+ continue;
+ data->have_temp |= 1 << i;
+ data->reg_temp[0][i] = data->REG_TEMP_ALTERNATE[i];
+ data->temp_src[i] = i + 1;
continue;
- data->have_temp |= 1 << i;
- data->reg_temp[0][i] = data->REG_TEMP_FIXED[i];
- data->temp_src[i] = i + 1;
+ }
+
+ if (s >= NUM_TEMP) /* Abort if no more space */
+ break;
+
+ data->have_temp |= 1 << s;
+ data->reg_temp[0][s] = data->REG_TEMP_ALTERNATE[i];
+ data->temp_src[s] = i + 1;
+ s++;
}
}
+#endif /* TESTING */
switch (data->kind) {
case nct6775:
- data->temp_label = nct6775_temp_label;
break;
case nct6776:
/*
else
data->have_in &= ~(1 << 6);
}
- data->temp_label = nct6776_temp_label;
break;
case nct6779:
/*
if (i == 5) /* AUXTIN3 */
data->have_in &= ~(1 << 14); /* no VIN7 */
}
- data->temp_label = nct6779_temp_label;
break;
}
&sda_temp_offset[i].dev_attr);
if (err)
goto exit_remove;
- if (i >= NUM_TEMP_ALARM)
+ if (i >= NUM_TEMP_ALARM ||
+ data->ALARM_BITS[TEMP_ALARM_BASE + i] < 0)
continue;
err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
if (err)
}
for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
- if (!data->CASEOPEN_MASK[i])
+ if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
continue;
err = device_create_file(dev, &sda_caseopen[i].dev_attr);
if (err)