|
@@ -39,7 +39,7 @@
|
|
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
|
|
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
|
|
w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
|
|
w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
|
|
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
|
|
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
|
|
- w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
|
|
|
|
|
|
+ w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
|
|
*/
|
|
*/
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
@@ -164,10 +164,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
|
|
#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
|
|
#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
|
|
(0x550 + (nr) - 7))
|
|
(0x550 + (nr) - 7))
|
|
|
|
|
|
-static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
|
|
|
|
-static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
|
|
|
|
-static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
|
|
|
|
-static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
|
|
|
|
|
|
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
|
|
|
|
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
|
|
|
|
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
|
|
|
|
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
|
|
|
|
|
|
/* Fan clock dividers are spread over the following five registers */
|
|
/* Fan clock dividers are spread over the following five registers */
|
|
#define W83627EHF_REG_FANDIV1 0x47
|
|
#define W83627EHF_REG_FANDIV1 0x47
|
|
@@ -213,6 +213,19 @@ static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
|
|
static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
|
|
static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
|
|
static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
|
|
static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
|
|
|
|
|
|
|
|
+static const char *const w83667hg_b_temp_label[] = {
|
|
|
|
+ "SYSTIN",
|
|
|
|
+ "CPUTIN",
|
|
|
|
+ "AUXTIN",
|
|
|
|
+ "AMDTSI",
|
|
|
|
+ "PECI Agent 1",
|
|
|
|
+ "PECI Agent 2",
|
|
|
|
+ "PECI Agent 3",
|
|
|
|
+ "PECI Agent 4"
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define NUM_REG_TEMP 4
|
|
|
|
+
|
|
static inline int is_word_sized(u16 reg)
|
|
static inline int is_word_sized(u16 reg)
|
|
{
|
|
{
|
|
return (((reg & 0xff00) == 0x100
|
|
return (((reg & 0xff00) == 0x100
|
|
@@ -294,6 +307,9 @@ struct w83627ehf_data {
|
|
struct device *hwmon_dev;
|
|
struct device *hwmon_dev;
|
|
struct mutex lock;
|
|
struct mutex lock;
|
|
|
|
|
|
|
|
+ u8 temp_src[NUM_REG_TEMP];
|
|
|
|
+ const char * const *temp_label;
|
|
|
|
+
|
|
const u8 *REG_FAN_START_OUTPUT;
|
|
const u8 *REG_FAN_START_OUTPUT;
|
|
const u8 *REG_FAN_STOP_OUTPUT;
|
|
const u8 *REG_FAN_STOP_OUTPUT;
|
|
const u8 *REG_FAN_MAX_OUTPUT;
|
|
const u8 *REG_FAN_MAX_OUTPUT;
|
|
@@ -314,9 +330,9 @@ struct w83627ehf_data {
|
|
u8 fan_div[5];
|
|
u8 fan_div[5];
|
|
u8 has_fan; /* some fan inputs can be disabled */
|
|
u8 has_fan; /* some fan inputs can be disabled */
|
|
u8 temp_type[3];
|
|
u8 temp_type[3];
|
|
- s16 temp[3];
|
|
|
|
- s16 temp_max[3];
|
|
|
|
- s16 temp_max_hyst[3];
|
|
|
|
|
|
+ s16 temp[4];
|
|
|
|
+ s16 temp_max[4];
|
|
|
|
+ s16 temp_max_hyst[4];
|
|
u32 alarms;
|
|
u32 alarms;
|
|
|
|
|
|
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
|
|
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
|
|
@@ -339,7 +355,7 @@ struct w83627ehf_data {
|
|
u8 vid;
|
|
u8 vid;
|
|
u8 vrm;
|
|
u8 vrm;
|
|
|
|
|
|
- u8 temp3_disable;
|
|
|
|
|
|
+ u8 have_temp;
|
|
u8 in6_skip;
|
|
u8 in6_skip;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -577,12 +593,18 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
|
}
|
|
}
|
|
|
|
|
|
/* Measured temperatures and limits */
|
|
/* Measured temperatures and limits */
|
|
- for (i = 0; i < 3; i++) {
|
|
|
|
- data->temp[i] = w83627ehf_read_value(data,
|
|
|
|
- W83627EHF_REG_TEMP[i]);
|
|
|
|
- data->temp_max[i] = w83627ehf_read_value(data,
|
|
|
|
- W83627EHF_REG_TEMP_OVER[i]);
|
|
|
|
- data->temp_max_hyst[i] = w83627ehf_read_value(data,
|
|
|
|
|
|
+ for (i = 0; i < NUM_REG_TEMP; i++) {
|
|
|
|
+ if (!(data->have_temp & (1 << i)))
|
|
|
|
+ continue;
|
|
|
|
+ data->temp[i]
|
|
|
|
+ = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]);
|
|
|
|
+ if (i > 2)
|
|
|
|
+ break;
|
|
|
|
+ data->temp_max[i]
|
|
|
|
+ = w83627ehf_read_value(data,
|
|
|
|
+ W83627EHF_REG_TEMP_OVER[i]);
|
|
|
|
+ data->temp_max_hyst[i]
|
|
|
|
+ = w83627ehf_read_value(data,
|
|
W83627EHF_REG_TEMP_HYST[i]);
|
|
W83627EHF_REG_TEMP_HYST[i]);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -844,6 +866,15 @@ static struct sensor_device_attribute sda_fan_div[] = {
|
|
SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
|
|
SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static ssize_t
|
|
|
|
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
+{
|
|
|
|
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
|
|
|
|
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
|
|
|
+ int nr = sensor_attr->index;
|
|
|
|
+ return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
|
|
|
|
+}
|
|
|
|
+
|
|
#define show_temp_reg(REG, reg) \
|
|
#define show_temp_reg(REG, reg) \
|
|
static ssize_t \
|
|
static ssize_t \
|
|
show_##reg(struct device *dev, struct device_attribute *attr, \
|
|
show_##reg(struct device *dev, struct device_attribute *attr, \
|
|
@@ -897,6 +928,14 @@ static struct sensor_device_attribute sda_temp_input[] = {
|
|
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
|
|
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
|
|
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
|
|
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
|
|
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
|
|
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
|
|
|
|
+ SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct sensor_device_attribute sda_temp_label[] = {
|
|
|
|
+ SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
|
|
|
|
+ SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
|
|
|
|
+ SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
|
|
|
|
+ SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
|
|
};
|
|
};
|
|
|
|
|
|
static struct sensor_device_attribute sda_temp_max[] = {
|
|
static struct sensor_device_attribute sda_temp_max[] = {
|
|
@@ -1328,10 +1367,13 @@ static void w83627ehf_device_remove_files(struct device *dev)
|
|
device_remove_file(dev, &sda_target_temp[i].dev_attr);
|
|
device_remove_file(dev, &sda_target_temp[i].dev_attr);
|
|
device_remove_file(dev, &sda_tolerance[i].dev_attr);
|
|
device_remove_file(dev, &sda_tolerance[i].dev_attr);
|
|
}
|
|
}
|
|
- for (i = 0; i < 3; i++) {
|
|
|
|
- if ((i == 2) && data->temp3_disable)
|
|
|
|
|
|
+ for (i = 0; i < NUM_REG_TEMP; i++) {
|
|
|
|
+ if (!(data->have_temp & (1 << i)))
|
|
continue;
|
|
continue;
|
|
device_remove_file(dev, &sda_temp_input[i].dev_attr);
|
|
device_remove_file(dev, &sda_temp_input[i].dev_attr);
|
|
|
|
+ device_remove_file(dev, &sda_temp_label[i].dev_attr);
|
|
|
|
+ if (i > 2)
|
|
|
|
+ break;
|
|
device_remove_file(dev, &sda_temp_max[i].dev_attr);
|
|
device_remove_file(dev, &sda_temp_max[i].dev_attr);
|
|
device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
|
|
device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
|
|
device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
|
|
device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
|
|
@@ -1354,12 +1396,14 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
|
|
w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
|
|
w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
|
|
tmp | 0x01);
|
|
tmp | 0x01);
|
|
|
|
|
|
- /* Enable temp2 and temp3 if needed */
|
|
|
|
- for (i = 1; i < 3; i++) {
|
|
|
|
|
|
+ /* Enable temperature sensors if needed */
|
|
|
|
+ for (i = 0; i < NUM_REG_TEMP; i++) {
|
|
|
|
+ if (!(data->have_temp & (1 << i)))
|
|
|
|
+ continue;
|
|
|
|
+ if (!W83627EHF_REG_TEMP_CONFIG[i])
|
|
|
|
+ continue;
|
|
tmp = w83627ehf_read_value(data,
|
|
tmp = w83627ehf_read_value(data,
|
|
W83627EHF_REG_TEMP_CONFIG[i]);
|
|
W83627EHF_REG_TEMP_CONFIG[i]);
|
|
- if ((i == 2) && data->temp3_disable)
|
|
|
|
- continue;
|
|
|
|
if (tmp & 0x01)
|
|
if (tmp & 0x01)
|
|
w83627ehf_write_value(data,
|
|
w83627ehf_write_value(data,
|
|
W83627EHF_REG_TEMP_CONFIG[i],
|
|
W83627EHF_REG_TEMP_CONFIG[i],
|
|
@@ -1417,11 +1461,52 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
data->pwm_num = (sio_data->kind == w83667hg
|
|
data->pwm_num = (sio_data->kind == w83667hg
|
|
|| sio_data->kind == w83667hg_b) ? 3 : 4;
|
|
|| sio_data->kind == w83667hg_b) ? 3 : 4;
|
|
|
|
|
|
|
|
+ data->have_temp = 0x07;
|
|
/* Check temp3 configuration bit for 667HG */
|
|
/* Check temp3 configuration bit for 667HG */
|
|
- if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
|
|
|
|
- data->temp3_disable = w83627ehf_read_value(data,
|
|
|
|
- W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
|
|
|
|
- data->in6_skip = !data->temp3_disable;
|
|
|
|
|
|
+ if (sio_data->kind == w83667hg) {
|
|
|
|
+ u8 reg;
|
|
|
|
+
|
|
|
|
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
|
|
|
|
+ if (reg & 0x01)
|
|
|
|
+ data->have_temp &= ~(1 << 2);
|
|
|
|
+ else
|
|
|
|
+ data->in6_skip = 1; /* Either temp3 or in6 */
|
|
|
|
+ } else if (sio_data->kind == w83667hg_b) {
|
|
|
|
+ u8 reg;
|
|
|
|
+
|
|
|
|
+ reg = w83627ehf_read_value(data, 0x4a);
|
|
|
|
+ data->temp_src[0] = reg >> 5;
|
|
|
|
+ reg = w83627ehf_read_value(data, 0x49);
|
|
|
|
+ data->temp_src[1] = reg & 0x07;
|
|
|
|
+ data->temp_src[2] = (reg >> 4) & 0x07;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * W83667HG-B has another temperature register at 0x7e.
|
|
|
|
+ * The temperature source is selected with register 0x7d.
|
|
|
|
+ * Support it if the source differs from already reported
|
|
|
|
+ * sources.
|
|
|
|
+ */
|
|
|
|
+ reg = w83627ehf_read_value(data, 0x7d);
|
|
|
|
+ reg &= 0x07;
|
|
|
|
+ if (reg != data->temp_src[0] && reg != data->temp_src[1]
|
|
|
|
+ && reg != data->temp_src[2]) {
|
|
|
|
+ data->temp_src[3] = reg;
|
|
|
|
+ data->have_temp |= 1 << 3;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Chip supports either AUXTIN or VIN3. Try to find out which
|
|
|
|
+ * one.
|
|
|
|
+ */
|
|
|
|
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
|
|
|
|
+ if (data->temp_src[2] == 2 && (reg & 0x01))
|
|
|
|
+ data->have_temp &= ~(1 << 2);
|
|
|
|
+
|
|
|
|
+ if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
|
|
|
|
+ || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
|
|
|
|
+ data->in6_skip = 1;
|
|
|
|
+
|
|
|
|
+ data->temp_label = w83667hg_b_temp_label;
|
|
}
|
|
}
|
|
|
|
|
|
data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
|
|
data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
|
|
@@ -1584,13 +1669,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- for (i = 0; i < 3; i++) {
|
|
|
|
- if ((i == 2) && data->temp3_disable)
|
|
|
|
|
|
+ for (i = 0; i < NUM_REG_TEMP; i++) {
|
|
|
|
+ if (!(data->have_temp & (1 << i)))
|
|
continue;
|
|
continue;
|
|
- if ((err = device_create_file(dev,
|
|
|
|
- &sda_temp_input[i].dev_attr))
|
|
|
|
- || (err = device_create_file(dev,
|
|
|
|
- &sda_temp_max[i].dev_attr))
|
|
|
|
|
|
+ err = device_create_file(dev, &sda_temp_input[i].dev_attr);
|
|
|
|
+ if (err)
|
|
|
|
+ goto exit_remove;
|
|
|
|
+ if (data->temp_label) {
|
|
|
|
+ err = device_create_file(dev,
|
|
|
|
+ &sda_temp_label[i].dev_attr);
|
|
|
|
+ if (err)
|
|
|
|
+ goto exit_remove;
|
|
|
|
+ }
|
|
|
|
+ if (i > 2)
|
|
|
|
+ break;
|
|
|
|
+ if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr))
|
|
|| (err = device_create_file(dev,
|
|
|| (err = device_create_file(dev,
|
|
&sda_temp_max_hyst[i].dev_attr))
|
|
&sda_temp_max_hyst[i].dev_attr))
|
|
|| (err = device_create_file(dev,
|
|
|| (err = device_create_file(dev,
|