|
@@ -6,6 +6,7 @@
|
|
|
Rudolf Marek <r.marek@assembler.cz>
|
|
|
David Hubbard <david.c.hubbard@gmail.com>
|
|
|
Daniel J Blueman <daniel.blueman@gmail.com>
|
|
|
+ Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
|
|
|
|
|
|
Shamelessly ripped from the w83627hf driver
|
|
|
Copyright (C) 2003 Mark Studebaker
|
|
@@ -40,6 +41,8 @@
|
|
|
w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
|
|
|
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
|
|
|
w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
|
|
|
+ nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3
|
|
|
+ nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3
|
|
|
*/
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
@@ -58,7 +61,8 @@
|
|
|
#include <linux/io.h>
|
|
|
#include "lm75.h"
|
|
|
|
|
|
-enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
|
|
|
+enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775,
|
|
|
+ nct6776 };
|
|
|
|
|
|
/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
|
|
|
static const char * const w83627ehf_device_names[] = {
|
|
@@ -67,6 +71,8 @@ static const char * const w83627ehf_device_names[] = {
|
|
|
"w83627dhg",
|
|
|
"w83667hg",
|
|
|
"w83667hg",
|
|
|
+ "nct6775",
|
|
|
+ "nct6776",
|
|
|
};
|
|
|
|
|
|
static unsigned short force_id;
|
|
@@ -96,6 +102,8 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
|
|
|
#define SIO_W83627DHG_P_ID 0xb070
|
|
|
#define SIO_W83667HG_ID 0xa510
|
|
|
#define SIO_W83667HG_B_ID 0xb350
|
|
|
+#define SIO_NCT6775_ID 0xb470
|
|
|
+#define SIO_NCT6776_ID 0xc330
|
|
|
#define SIO_ID_MASK 0xFFF0
|
|
|
|
|
|
static inline void
|
|
@@ -176,6 +184,10 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
|
|
|
#define W83627EHF_REG_DIODE 0x59
|
|
|
#define W83627EHF_REG_SMI_OVT 0x4C
|
|
|
|
|
|
+/* NCT6775F has its own fan divider registers */
|
|
|
+#define NCT6775_REG_FANDIV1 0x506
|
|
|
+#define NCT6775_REG_FANDIV2 0x507
|
|
|
+
|
|
|
#define W83627EHF_REG_ALARM1 0x459
|
|
|
#define W83627EHF_REG_ALARM2 0x45A
|
|
|
#define W83627EHF_REG_ALARM3 0x45B
|
|
@@ -214,6 +226,28 @@ static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
|
|
|
static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
|
|
|
= { 0x68, 0x6a, 0x6c };
|
|
|
|
|
|
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
|
|
|
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
|
|
|
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
|
|
|
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
|
|
|
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
|
|
|
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
|
|
|
+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 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
|
|
|
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
|
|
|
+
|
|
|
+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 char *const w83667hg_b_temp_label[] = {
|
|
|
"SYSTIN",
|
|
|
"CPUTIN",
|
|
@@ -225,15 +259,71 @@ static const char *const w83667hg_b_temp_label[] = {
|
|
|
"PECI Agent 4"
|
|
|
};
|
|
|
|
|
|
-#define NUM_REG_TEMP 4
|
|
|
+static const char *const nct6775_temp_label[] = {
|
|
|
+ "",
|
|
|
+ "SYSTIN",
|
|
|
+ "CPUTIN",
|
|
|
+ "AUXTIN",
|
|
|
+ "AMD SB-TSI",
|
|
|
+ "PECI Agent 0",
|
|
|
+ "PECI Agent 1",
|
|
|
+ "PECI Agent 2",
|
|
|
+ "PECI Agent 3",
|
|
|
+ "PECI Agent 4",
|
|
|
+ "PECI Agent 5",
|
|
|
+ "PECI Agent 6",
|
|
|
+ "PECI Agent 7",
|
|
|
+ "PCH_CHIP_CPU_MAX_TEMP",
|
|
|
+ "PCH_CHIP_TEMP",
|
|
|
+ "PCH_CPU_TEMP",
|
|
|
+ "PCH_MCH_TEMP",
|
|
|
+ "PCH_DIM0_TEMP",
|
|
|
+ "PCH_DIM1_TEMP",
|
|
|
+ "PCH_DIM2_TEMP",
|
|
|
+ "PCH_DIM3_TEMP"
|
|
|
+};
|
|
|
+
|
|
|
+static const char *const nct6776_temp_label[] = {
|
|
|
+ "",
|
|
|
+ "SYSTIN",
|
|
|
+ "CPUTIN",
|
|
|
+ "AUXTIN",
|
|
|
+ "SMBUSMASTER 0",
|
|
|
+ "SMBUSMASTER 1",
|
|
|
+ "SMBUSMASTER 2",
|
|
|
+ "SMBUSMASTER 3",
|
|
|
+ "SMBUSMASTER 4",
|
|
|
+ "SMBUSMASTER 5",
|
|
|
+ "SMBUSMASTER 6",
|
|
|
+ "SMBUSMASTER 7",
|
|
|
+ "PECI Agent 0",
|
|
|
+ "PECI Agent 1",
|
|
|
+ "PCH_CHIP_CPU_MAX_TEMP",
|
|
|
+ "PCH_CHIP_TEMP",
|
|
|
+ "PCH_CPU_TEMP",
|
|
|
+ "PCH_MCH_TEMP",
|
|
|
+ "PCH_DIM0_TEMP",
|
|
|
+ "PCH_DIM1_TEMP",
|
|
|
+ "PCH_DIM2_TEMP",
|
|
|
+ "PCH_DIM3_TEMP",
|
|
|
+ "BYTE_TEMP"
|
|
|
+};
|
|
|
+
|
|
|
+#define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP)
|
|
|
|
|
|
static inline int is_word_sized(u16 reg)
|
|
|
{
|
|
|
- return (((reg & 0xff00) == 0x100
|
|
|
+ return ((((reg & 0xff00) == 0x100
|
|
|
|| (reg & 0xff00) == 0x200)
|
|
|
&& ((reg & 0x00ff) == 0x50
|
|
|
|| (reg & 0x00ff) == 0x53
|
|
|
- || (reg & 0x00ff) == 0x55));
|
|
|
+ || (reg & 0x00ff) == 0x55))
|
|
|
+ || (reg & 0xfff0) == 0x630
|
|
|
+ || reg == 0x640 || reg == 0x642
|
|
|
+ || ((reg & 0xfff0) == 0x650
|
|
|
+ && (reg & 0x000f) >= 0x06)
|
|
|
+ || reg == 0x73 || reg == 0x75 || reg == 0x77
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -253,11 +343,20 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
|
|
|
}
|
|
|
|
|
|
static inline unsigned int
|
|
|
-fan_from_reg(u8 reg, unsigned int div)
|
|
|
+fan_from_reg(int reg, u16 val, unsigned int div)
|
|
|
{
|
|
|
- if (reg == 0 || reg == 255)
|
|
|
+ if (val == 0)
|
|
|
return 0;
|
|
|
- return 1350000U / (reg * div);
|
|
|
+ if (is_word_sized(reg)) {
|
|
|
+ if ((val & 0xff1f) == 0xff1f)
|
|
|
+ return 0;
|
|
|
+ val = (val & 0x1f) | ((val & 0xff00) >> 3);
|
|
|
+ } else {
|
|
|
+ if (val == 255 || div == 0)
|
|
|
+ return 0;
|
|
|
+ val *= div;
|
|
|
+ }
|
|
|
+ return 1350000U / val;
|
|
|
}
|
|
|
|
|
|
static inline unsigned int
|
|
@@ -274,7 +373,7 @@ temp_from_reg(u16 reg, s16 regval)
|
|
|
return regval * 1000;
|
|
|
}
|
|
|
|
|
|
-static inline s16
|
|
|
+static inline u16
|
|
|
temp_to_reg(u16 reg, long temp)
|
|
|
{
|
|
|
if (is_word_sized(reg))
|
|
@@ -308,6 +407,10 @@ struct w83627ehf_data {
|
|
|
struct device *hwmon_dev;
|
|
|
struct mutex lock;
|
|
|
|
|
|
+ u16 reg_temp[NUM_REG_TEMP];
|
|
|
+ u16 reg_temp_over[NUM_REG_TEMP];
|
|
|
+ u16 reg_temp_hyst[NUM_REG_TEMP];
|
|
|
+ u16 reg_temp_config[NUM_REG_TEMP];
|
|
|
u8 temp_src[NUM_REG_TEMP];
|
|
|
const char * const *temp_label;
|
|
|
|
|
@@ -331,14 +434,15 @@ struct w83627ehf_data {
|
|
|
u8 in[10]; /* Register value */
|
|
|
u8 in_max[10]; /* Register value */
|
|
|
u8 in_min[10]; /* Register value */
|
|
|
- u8 fan[5];
|
|
|
- u8 fan_min[5];
|
|
|
+ u16 fan[5];
|
|
|
+ u16 fan_min[5];
|
|
|
u8 fan_div[5];
|
|
|
u8 has_fan; /* some fan inputs can be disabled */
|
|
|
+ u8 has_fan_min; /* some fans don't have min register */
|
|
|
u8 temp_type[3];
|
|
|
- s16 temp[4];
|
|
|
- s16 temp_max[4];
|
|
|
- s16 temp_max_hyst[4];
|
|
|
+ s16 temp[9];
|
|
|
+ s16 temp_max[9];
|
|
|
+ s16 temp_max_hyst[9];
|
|
|
u32 alarms;
|
|
|
|
|
|
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
|
|
@@ -364,7 +468,7 @@ struct w83627ehf_data {
|
|
|
u8 vid;
|
|
|
u8 vrm;
|
|
|
|
|
|
- u8 have_temp;
|
|
|
+ u16 have_temp;
|
|
|
u8 in6_skip;
|
|
|
};
|
|
|
|
|
@@ -428,6 +532,34 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* This function assumes that the caller holds data->update_lock */
|
|
|
+static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
|
|
|
+{
|
|
|
+ u8 reg;
|
|
|
+
|
|
|
+ switch (nr) {
|
|
|
+ case 0:
|
|
|
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
|
|
|
+ | (data->fan_div[0] & 0x7);
|
|
|
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
|
|
|
+ | ((data->fan_div[1] << 4) & 0x70);
|
|
|
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
|
|
|
+ case 2:
|
|
|
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
|
|
|
+ | (data->fan_div[2] & 0x7);
|
|
|
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
|
|
|
+ | ((data->fan_div[3] << 4) & 0x70);
|
|
|
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* This function assumes that the caller holds data->update_lock */
|
|
|
static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
|
|
|
{
|
|
@@ -479,6 +611,32 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void w83627ehf_write_fan_div_common(struct device *dev,
|
|
|
+ struct w83627ehf_data *data, int nr)
|
|
|
+{
|
|
|
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
|
|
|
+
|
|
|
+ if (sio_data->kind == nct6776)
|
|
|
+ ; /* no dividers, do nothing */
|
|
|
+ else if (sio_data->kind == nct6775)
|
|
|
+ nct6775_write_fan_div(data, nr);
|
|
|
+ else
|
|
|
+ w83627ehf_write_fan_div(data, nr);
|
|
|
+}
|
|
|
+
|
|
|
+static void nct6775_update_fan_div(struct w83627ehf_data *data)
|
|
|
+{
|
|
|
+ u8 i;
|
|
|
+
|
|
|
+ i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
|
|
|
+ data->fan_div[0] = i & 0x7;
|
|
|
+ data->fan_div[1] = (i & 0x70) >> 4;
|
|
|
+ i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
|
|
|
+ data->fan_div[2] = i & 0x7;
|
|
|
+ if (data->has_fan & (1<<3))
|
|
|
+ data->fan_div[3] = (i & 0x70) >> 4;
|
|
|
+}
|
|
|
+
|
|
|
static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
|
|
|
{
|
|
|
int i;
|
|
@@ -504,10 +662,79 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void w83627ehf_update_fan_div_common(struct device *dev,
|
|
|
+ struct w83627ehf_data *data)
|
|
|
+{
|
|
|
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
|
|
|
+
|
|
|
+ if (sio_data->kind == nct6776)
|
|
|
+ ; /* no dividers, do nothing */
|
|
|
+ else if (sio_data->kind == nct6775)
|
|
|
+ nct6775_update_fan_div(data);
|
|
|
+ else
|
|
|
+ w83627ehf_update_fan_div(data);
|
|
|
+}
|
|
|
+
|
|
|
+static void nct6775_update_pwm(struct w83627ehf_data *data)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int pwmcfg, fanmodecfg;
|
|
|
+
|
|
|
+ for (i = 0; i < data->pwm_num; i++) {
|
|
|
+ pwmcfg = w83627ehf_read_value(data,
|
|
|
+ W83627EHF_REG_PWM_ENABLE[i]);
|
|
|
+ fanmodecfg = w83627ehf_read_value(data,
|
|
|
+ NCT6775_REG_FAN_MODE[i]);
|
|
|
+ data->pwm_mode[i] =
|
|
|
+ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
|
|
|
+ data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
|
|
|
+ data->tolerance[i] = fanmodecfg & 0x0f;
|
|
|
+ data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void w83627ehf_update_pwm(struct w83627ehf_data *data)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
|
|
|
+
|
|
|
+ for (i = 0; i < data->pwm_num; i++) {
|
|
|
+ if (!(data->has_fan & (1 << i)))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
|
|
|
+ if (i != 1) {
|
|
|
+ pwmcfg = w83627ehf_read_value(data,
|
|
|
+ W83627EHF_REG_PWM_ENABLE[i]);
|
|
|
+ tolerance = w83627ehf_read_value(data,
|
|
|
+ W83627EHF_REG_TOLERANCE[i]);
|
|
|
+ }
|
|
|
+ data->pwm_mode[i] =
|
|
|
+ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
|
|
|
+ data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
|
|
|
+ & 3) + 1;
|
|
|
+ data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
|
|
|
+
|
|
|
+ data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void w83627ehf_update_pwm_common(struct device *dev,
|
|
|
+ struct w83627ehf_data *data)
|
|
|
+{
|
|
|
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
|
|
|
+
|
|
|
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
|
|
|
+ nct6775_update_pwm(data);
|
|
|
+ else
|
|
|
+ w83627ehf_update_pwm(data);
|
|
|
+}
|
|
|
+
|
|
|
static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
|
|
{
|
|
|
struct w83627ehf_data *data = dev_get_drvdata(dev);
|
|
|
- int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
|
|
|
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
|
|
|
+
|
|
|
int i;
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
@@ -515,7 +742,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
|
|
if (time_after(jiffies, data->last_updated + HZ + HZ/2)
|
|
|
|| !data->valid) {
|
|
|
/* Fan clock dividers */
|
|
|
- w83627ehf_update_fan_div(data);
|
|
|
+ w83627ehf_update_fan_div_common(dev, data);
|
|
|
|
|
|
/* Measured voltages and limits */
|
|
|
for (i = 0; i < data->in_num; i++) {
|
|
@@ -533,23 +760,29 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
|
|
continue;
|
|
|
|
|
|
data->fan[i] = w83627ehf_read_value(data,
|
|
|
- data->REG_FAN[i]);
|
|
|
- data->fan_min[i] = w83627ehf_read_value(data,
|
|
|
+ data->REG_FAN[i]);
|
|
|
+
|
|
|
+ if (data->has_fan_min & (1 << i))
|
|
|
+ data->fan_min[i] = w83627ehf_read_value(data,
|
|
|
data->REG_FAN_MIN[i]);
|
|
|
|
|
|
/* If we failed to measure the fan speed and clock
|
|
|
divider can be increased, let's try that for next
|
|
|
time */
|
|
|
- if (data->fan[i] == 0xff
|
|
|
- && data->fan_div[i] < 0x07) {
|
|
|
+ if (!is_word_sized(data->REG_FAN[i])
|
|
|
+ && (data->fan[i] == 0xff
|
|
|
+ || (sio_data->kind == nct6775
|
|
|
+ && data->fan[i] == 0x00))
|
|
|
+ && data->fan_div[i] < 0x07) {
|
|
|
dev_dbg(dev, "Increasing fan%d "
|
|
|
"clock divider from %u to %u\n",
|
|
|
i + 1, div_from_reg(data->fan_div[i]),
|
|
|
div_from_reg(data->fan_div[i] + 1));
|
|
|
data->fan_div[i]++;
|
|
|
- w83627ehf_write_fan_div(data, i);
|
|
|
+ w83627ehf_write_fan_div_common(dev, data, i);
|
|
|
/* Preserve min limit if possible */
|
|
|
- if (data->fan_min[i] >= 2
|
|
|
+ if ((data->has_fan_min & (1 << i))
|
|
|
+ && data->fan_min[i] >= 2
|
|
|
&& data->fan_min[i] != 255)
|
|
|
w83627ehf_write_value(data,
|
|
|
data->REG_FAN_MIN[i],
|
|
@@ -557,64 +790,54 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ w83627ehf_update_pwm_common(dev, data);
|
|
|
+
|
|
|
for (i = 0; i < data->pwm_num; i++) {
|
|
|
if (!(data->has_fan & (1 << i)))
|
|
|
continue;
|
|
|
|
|
|
- /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
|
|
|
- if (i != 1) {
|
|
|
- pwmcfg = w83627ehf_read_value(data,
|
|
|
- W83627EHF_REG_PWM_ENABLE[i]);
|
|
|
- tolerance = w83627ehf_read_value(data,
|
|
|
- W83627EHF_REG_TOLERANCE[i]);
|
|
|
- }
|
|
|
- data->pwm_mode[i] =
|
|
|
- ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
|
|
|
- ? 0 : 1;
|
|
|
- data->pwm_enable[i] =
|
|
|
- ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
|
|
|
- & 3) + 1;
|
|
|
- data->pwm[i] = w83627ehf_read_value(data,
|
|
|
- data->REG_PWM[i]);
|
|
|
- data->fan_start_output[i] = w83627ehf_read_value(data,
|
|
|
- data->REG_FAN_START_OUTPUT[i]);
|
|
|
- data->fan_stop_output[i] = w83627ehf_read_value(data,
|
|
|
- data->REG_FAN_STOP_OUTPUT[i]);
|
|
|
- data->fan_stop_time[i] = w83627ehf_read_value(data,
|
|
|
- data->REG_FAN_STOP_TIME[i]);
|
|
|
-
|
|
|
- if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
|
|
|
+ data->fan_start_output[i] =
|
|
|
+ w83627ehf_read_value(data,
|
|
|
+ data->REG_FAN_START_OUTPUT[i]);
|
|
|
+ data->fan_stop_output[i] =
|
|
|
+ w83627ehf_read_value(data,
|
|
|
+ data->REG_FAN_STOP_OUTPUT[i]);
|
|
|
+ data->fan_stop_time[i] =
|
|
|
+ w83627ehf_read_value(data,
|
|
|
+ data->REG_FAN_STOP_TIME[i]);
|
|
|
+
|
|
|
+ if (data->REG_FAN_MAX_OUTPUT &&
|
|
|
+ data->REG_FAN_MAX_OUTPUT[i] != 0xff)
|
|
|
data->fan_max_output[i] =
|
|
|
w83627ehf_read_value(data,
|
|
|
- data->REG_FAN_MAX_OUTPUT[i]);
|
|
|
+ data->REG_FAN_MAX_OUTPUT[i]);
|
|
|
|
|
|
- if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
|
|
|
+ if (data->REG_FAN_STEP_OUTPUT &&
|
|
|
+ data->REG_FAN_STEP_OUTPUT[i] != 0xff)
|
|
|
data->fan_step_output[i] =
|
|
|
w83627ehf_read_value(data,
|
|
|
- data->REG_FAN_STEP_OUTPUT[i]);
|
|
|
+ data->REG_FAN_STEP_OUTPUT[i]);
|
|
|
|
|
|
data->target_temp[i] =
|
|
|
w83627ehf_read_value(data,
|
|
|
data->REG_TARGET[i]) &
|
|
|
(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
|
|
|
- data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
|
|
|
- & 0x0f;
|
|
|
}
|
|
|
|
|
|
/* Measured temperatures and limits */
|
|
|
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]);
|
|
|
+ data->temp[i] = w83627ehf_read_value(data,
|
|
|
+ data->reg_temp[i]);
|
|
|
+ if (data->reg_temp_over[i])
|
|
|
+ data->temp_max[i]
|
|
|
+ = w83627ehf_read_value(data,
|
|
|
+ data->reg_temp_over[i]);
|
|
|
+ if (data->reg_temp_hyst[i])
|
|
|
+ data->temp_max_hyst[i]
|
|
|
+ = w83627ehf_read_value(data,
|
|
|
+ data->reg_temp_hyst[i]);
|
|
|
}
|
|
|
|
|
|
data->alarms = w83627ehf_read_value(data,
|
|
@@ -736,21 +959,29 @@ static struct sensor_device_attribute sda_in_max[] = {
|
|
|
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
|
|
|
};
|
|
|
|
|
|
-#define show_fan_reg(reg) \
|
|
|
-static ssize_t \
|
|
|
-show_##reg(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, "%d\n", \
|
|
|
- fan_from_reg(data->reg[nr], \
|
|
|
- div_from_reg(data->fan_div[nr]))); \
|
|
|
+static ssize_t
|
|
|
+show_fan(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, "%d\n",
|
|
|
+ fan_from_reg(data->REG_FAN[nr],
|
|
|
+ data->fan[nr],
|
|
|
+ div_from_reg(data->fan_div[nr])));
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t
|
|
|
+show_fan_min(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, "%d\n",
|
|
|
+ fan_from_reg(data->REG_FAN_MIN[nr],
|
|
|
+ data->fan_min[nr],
|
|
|
+ div_from_reg(data->fan_div[nr])));
|
|
|
}
|
|
|
-show_fan_reg(fan);
|
|
|
-show_fan_reg(fan_min);
|
|
|
|
|
|
static ssize_t
|
|
|
show_fan_div(struct device *dev, struct device_attribute *attr,
|
|
@@ -779,6 +1010,18 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
|
|
|
return err;
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
|
+ if (is_word_sized(data->REG_FAN_MIN[nr])) {
|
|
|
+ if (!val) {
|
|
|
+ val = 0xff1f;
|
|
|
+ } else {
|
|
|
+ if (val > 1350000U)
|
|
|
+ val = 135000U;
|
|
|
+ val = 1350000U / val;
|
|
|
+ val = (val & 0x1f) | ((val << 3) & 0xff00);
|
|
|
+ }
|
|
|
+ data->fan_min[nr] = val;
|
|
|
+ goto done; /* Leave fan divider alone */
|
|
|
+ }
|
|
|
if (!val) {
|
|
|
/* No min limit, alarm disabled */
|
|
|
data->fan_min[nr] = 255;
|
|
@@ -790,14 +1033,16 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
|
|
|
data->fan_min[nr] = 254;
|
|
|
new_div = 7; /* 128 == (1 << 7) */
|
|
|
dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
|
|
|
- "minimum\n", nr + 1, val, fan_from_reg(254, 128));
|
|
|
+ "minimum\n", nr + 1, val,
|
|
|
+ fan_from_reg(data->REG_FAN_MIN[nr], 254, 128));
|
|
|
} else if (!reg) {
|
|
|
/* Speed above this value cannot possibly be represented,
|
|
|
even with the lowest divider (1) */
|
|
|
data->fan_min[nr] = 1;
|
|
|
new_div = 0; /* 1 == (1 << 0) */
|
|
|
dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
|
|
|
- "maximum\n", nr + 1, val, fan_from_reg(1, 1));
|
|
|
+ "maximum\n", nr + 1, val,
|
|
|
+ fan_from_reg(data->REG_FAN_MIN[nr], 1, 1));
|
|
|
} else {
|
|
|
/* Automatically pick the best divider, i.e. the one such
|
|
|
that the min limit will correspond to a register value
|
|
@@ -827,10 +1072,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
|
|
|
nr + 1, div_from_reg(data->fan_div[nr]),
|
|
|
div_from_reg(new_div));
|
|
|
data->fan_div[nr] = new_div;
|
|
|
- w83627ehf_write_fan_div(data, nr);
|
|
|
+ w83627ehf_write_fan_div_common(dev, data, nr);
|
|
|
/* Give the chip time to sample a new speed value */
|
|
|
data->last_updated = jiffies;
|
|
|
}
|
|
|
+done:
|
|
|
w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
|
|
|
data->fan_min[nr]);
|
|
|
mutex_unlock(&data->update_lock);
|
|
@@ -884,7 +1130,7 @@ show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
|
|
|
}
|
|
|
|
|
|
-#define show_temp_reg(REG, reg) \
|
|
|
+#define show_temp_reg(addr, reg) \
|
|
|
static ssize_t \
|
|
|
show_##reg(struct device *dev, struct device_attribute *attr, \
|
|
|
char *buf) \
|
|
@@ -894,13 +1140,13 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
|
|
|
to_sensor_dev_attr(attr); \
|
|
|
int nr = sensor_attr->index; \
|
|
|
return sprintf(buf, "%d\n", \
|
|
|
- temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
|
|
|
+ temp_from_reg(data->addr[nr], data->reg[nr])); \
|
|
|
}
|
|
|
-show_temp_reg(TEMP, temp);
|
|
|
-show_temp_reg(TEMP_OVER, temp_max);
|
|
|
-show_temp_reg(TEMP_HYST, temp_max_hyst);
|
|
|
+show_temp_reg(reg_temp, temp);
|
|
|
+show_temp_reg(reg_temp_over, temp_max);
|
|
|
+show_temp_reg(reg_temp_hyst, temp_max_hyst);
|
|
|
|
|
|
-#define store_temp_reg(REG, reg) \
|
|
|
+#define store_temp_reg(addr, reg) \
|
|
|
static ssize_t \
|
|
|
store_##reg(struct device *dev, struct device_attribute *attr, \
|
|
|
const char *buf, size_t count) \
|
|
@@ -915,14 +1161,14 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
|
|
|
if (err < 0) \
|
|
|
return err; \
|
|
|
mutex_lock(&data->update_lock); \
|
|
|
- data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
|
|
|
- w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
|
|
|
+ data->reg[nr] = temp_to_reg(data->addr[nr], val); \
|
|
|
+ w83627ehf_write_value(data, data->addr[nr], \
|
|
|
data->reg[nr]); \
|
|
|
mutex_unlock(&data->update_lock); \
|
|
|
return count; \
|
|
|
}
|
|
|
-store_temp_reg(OVER, temp_max);
|
|
|
-store_temp_reg(HYST, temp_max_hyst);
|
|
|
+store_temp_reg(reg_temp_over, temp_max);
|
|
|
+store_temp_reg(reg_temp_hyst, temp_max_hyst);
|
|
|
|
|
|
static ssize_t
|
|
|
show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
|
|
@@ -938,6 +1184,11 @@ static struct sensor_device_attribute sda_temp_input[] = {
|
|
|
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
|
|
|
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
|
|
|
SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
|
|
|
+ SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
|
|
|
+ SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
|
|
|
+ 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),
|
|
|
};
|
|
|
|
|
|
static struct sensor_device_attribute sda_temp_label[] = {
|
|
@@ -945,6 +1196,11 @@ static struct sensor_device_attribute sda_temp_label[] = {
|
|
|
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),
|
|
|
+ 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[] = {
|
|
@@ -954,6 +1210,18 @@ static struct sensor_device_attribute sda_temp_max[] = {
|
|
|
store_temp_max, 1),
|
|
|
SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
|
|
|
store_temp_max, 2),
|
|
|
+ SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
|
|
|
+ store_temp_max, 3),
|
|
|
+ SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_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[] = {
|
|
@@ -963,6 +1231,18 @@ static struct sensor_device_attribute sda_temp_max_hyst[] = {
|
|
|
store_temp_max_hyst, 1),
|
|
|
SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
|
|
store_temp_max_hyst, 2),
|
|
|
+ SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
|
|
+ store_temp_max_hyst, 3),
|
|
|
+ SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_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[] = {
|
|
@@ -1048,6 +1328,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
|
|
|
const char *buf, size_t count)
|
|
|
{
|
|
|
struct w83627ehf_data *data = dev_get_drvdata(dev);
|
|
|
+ struct w83627ehf_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;
|
|
@@ -1060,12 +1341,25 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
|
|
|
|
|
|
if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
|
|
|
return -EINVAL;
|
|
|
+ /* SmartFan III mode is not supported on NCT6776F */
|
|
|
+ if (sio_data->kind == nct6776 && val == 4)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
mutex_lock(&data->update_lock);
|
|
|
- reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
|
|
|
data->pwm_enable[nr] = val;
|
|
|
- reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
|
|
|
- reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
|
|
|
- w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
|
|
|
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
|
|
|
+ reg = w83627ehf_read_value(data,
|
|
|
+ NCT6775_REG_FAN_MODE[nr]);
|
|
|
+ reg &= 0x0f;
|
|
|
+ reg |= (val - 1) << 4;
|
|
|
+ w83627ehf_write_value(data,
|
|
|
+ NCT6775_REG_FAN_MODE[nr], reg);
|
|
|
+ } else {
|
|
|
+ reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
|
|
|
+ reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
|
|
|
+ reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
|
|
|
+ w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
|
|
|
+ }
|
|
|
mutex_unlock(&data->update_lock);
|
|
|
return count;
|
|
|
}
|
|
@@ -1113,6 +1407,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
|
|
|
const char *buf, size_t count)
|
|
|
{
|
|
|
struct w83627ehf_data *data = dev_get_drvdata(dev);
|
|
|
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
|
|
|
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
|
|
int nr = sensor_attr->index;
|
|
|
u16 reg;
|
|
@@ -1127,13 +1422,22 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
|
|
|
val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
|
- reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
|
|
|
- data->tolerance[nr] = val;
|
|
|
- if (nr == 1)
|
|
|
- reg = (reg & 0x0f) | (val << 4);
|
|
|
- else
|
|
|
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
|
|
|
+ /* Limit tolerance further for NCT6776F */
|
|
|
+ if (sio_data->kind == nct6776 && val > 7)
|
|
|
+ val = 7;
|
|
|
+ reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
|
|
|
reg = (reg & 0xf0) | val;
|
|
|
- w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
|
|
|
+ w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
|
|
|
+ } else {
|
|
|
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
|
|
|
+ if (nr == 1)
|
|
|
+ reg = (reg & 0x0f) | (val << 4);
|
|
|
+ else
|
|
|
+ reg = (reg & 0xf0) | val;
|
|
|
+ w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
|
|
|
+ }
|
|
|
+ data->tolerance[nr] = val;
|
|
|
mutex_unlock(&data->update_lock);
|
|
|
return count;
|
|
|
}
|
|
@@ -1350,7 +1654,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
|
|
|
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->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
|
|
|
+ if (data->REG_FAN_STEP_OUTPUT &&
|
|
|
+ data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
|
|
|
device_remove_file(dev, &attr->dev_attr);
|
|
|
}
|
|
|
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
|
|
@@ -1381,10 +1686,10 @@ static void w83627ehf_device_remove_files(struct device *dev)
|
|
|
continue;
|
|
|
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_hyst[i].dev_attr);
|
|
|
+ if (i > 2)
|
|
|
+ continue;
|
|
|
device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
|
|
|
device_remove_file(dev, &sda_temp_type[i].dev_attr);
|
|
|
}
|
|
@@ -1409,13 +1714,13 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
|
|
|
for (i = 0; i < NUM_REG_TEMP; i++) {
|
|
|
if (!(data->have_temp & (1 << i)))
|
|
|
continue;
|
|
|
- if (!W83627EHF_REG_TEMP_CONFIG[i])
|
|
|
+ if (!data->reg_temp_config[i])
|
|
|
continue;
|
|
|
tmp = w83627ehf_read_value(data,
|
|
|
- W83627EHF_REG_TEMP_CONFIG[i]);
|
|
|
+ data->reg_temp_config[i]);
|
|
|
if (tmp & 0x01)
|
|
|
w83627ehf_write_value(data,
|
|
|
- W83627EHF_REG_TEMP_CONFIG[i],
|
|
|
+ data->reg_temp_config[i],
|
|
|
tmp & 0xfe);
|
|
|
}
|
|
|
|
|
@@ -1434,13 +1739,39 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
|
|
|
+ int r1, int r2)
|
|
|
+{
|
|
|
+ u16 tmp;
|
|
|
+
|
|
|
+ tmp = data->temp_src[r1];
|
|
|
+ data->temp_src[r1] = data->temp_src[r2];
|
|
|
+ data->temp_src[r2] = tmp;
|
|
|
+
|
|
|
+ tmp = data->reg_temp[r1];
|
|
|
+ data->reg_temp[r1] = data->reg_temp[r2];
|
|
|
+ data->reg_temp[r2] = tmp;
|
|
|
+
|
|
|
+ tmp = data->reg_temp_over[r1];
|
|
|
+ data->reg_temp_over[r1] = data->reg_temp_over[r2];
|
|
|
+ data->reg_temp_over[r2] = tmp;
|
|
|
+
|
|
|
+ tmp = data->reg_temp_hyst[r1];
|
|
|
+ data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
|
|
|
+ data->reg_temp_hyst[r2] = tmp;
|
|
|
+
|
|
|
+ tmp = data->reg_temp_config[r1];
|
|
|
+ data->reg_temp_config[r1] = data->reg_temp_config[r2];
|
|
|
+ data->reg_temp_config[r2] = tmp;
|
|
|
+}
|
|
|
+
|
|
|
static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device *dev = &pdev->dev;
|
|
|
struct w83627ehf_sio_data *sio_data = dev->platform_data;
|
|
|
struct w83627ehf_data *data;
|
|
|
struct resource *res;
|
|
|
- u8 fan4pin, fan5pin, en_vrm10;
|
|
|
+ u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
|
|
|
int i, err = 0;
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
|
@@ -1466,9 +1797,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
|
|
|
/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
|
|
|
data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
|
|
|
- /* 667HG has 3 pwms */
|
|
|
+ /* 667HG, NCT6775F, and NCT6776F have 3 pwms */
|
|
|
data->pwm_num = (sio_data->kind == w83667hg
|
|
|
- || sio_data->kind == w83667hg_b) ? 3 : 4;
|
|
|
+ || sio_data->kind == w83667hg_b
|
|
|
+ || sio_data->kind == nct6775
|
|
|
+ || sio_data->kind == nct6776) ? 3 : 4;
|
|
|
|
|
|
data->have_temp = 0x07;
|
|
|
/* Check temp3 configuration bit for 667HG */
|
|
@@ -1479,15 +1812,98 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
if (reg & 0x01)
|
|
|
data->have_temp &= ~(1 << 2);
|
|
|
else
|
|
|
- data->in6_skip = 1; /* Either temp3 or in6 */
|
|
|
+ data->in6_skip = 1; /* either temp3 or in6 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Deal with temperature register setup first. */
|
|
|
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
|
|
|
+ int mask = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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];
|
|
|
+ data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
|
|
|
+
|
|
|
+ src = w83627ehf_read_value(data,
|
|
|
+ NCT6775_REG_TEMP_SOURCE[i]);
|
|
|
+ src &= 0x1f;
|
|
|
+ if (src && !(mask & (1 << src))) {
|
|
|
+ data->have_temp |= 1 << i;
|
|
|
+ mask |= 1 << src;
|
|
|
+ }
|
|
|
+
|
|
|
+ data->temp_src[i] = src;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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 (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 = w83627ehf_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->in6_skip = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ data->temp_label = nct6776_temp_label;
|
|
|
} else if (sio_data->kind == w83667hg_b) {
|
|
|
u8 reg;
|
|
|
|
|
|
+ /*
|
|
|
+ * Temperature sources are selected with bank 0, registers 0x49
|
|
|
+ * and 0x4a.
|
|
|
+ */
|
|
|
+ for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
|
|
|
+ data->reg_temp[i] = W83627EHF_REG_TEMP[i];
|
|
|
+ data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
|
|
|
+ data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
|
|
|
+ data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
|
|
|
+ }
|
|
|
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;
|
|
|
+ data->temp_src[2] = (reg >> 4) & 0x07;
|
|
|
|
|
|
/*
|
|
|
* W83667HG-B has another temperature register at 0x7e.
|
|
@@ -1516,22 +1932,54 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
data->in6_skip = 1;
|
|
|
|
|
|
data->temp_label = w83667hg_b_temp_label;
|
|
|
+ } else {
|
|
|
+ /* Temperature sources are fixed */
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
+ data->reg_temp[i] = W83627EHF_REG_TEMP[i];
|
|
|
+ data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
|
|
|
+ data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
|
|
|
+ data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- data->REG_PWM = W83627EHF_REG_PWM;
|
|
|
- data->REG_TARGET = W83627EHF_REG_TARGET;
|
|
|
- data->REG_FAN = W83627EHF_REG_FAN;
|
|
|
- data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
|
|
|
- data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
|
|
|
- data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
|
|
|
- data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
|
|
|
- data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
|
|
|
- if (sio_data->kind == w83667hg_b) {
|
|
|
+ if (sio_data->kind == nct6775) {
|
|
|
+ data->REG_PWM = NCT6775_REG_PWM;
|
|
|
+ data->REG_TARGET = NCT6775_REG_TARGET;
|
|
|
+ data->REG_FAN = W83627EHF_REG_FAN;
|
|
|
+ data->REG_FAN_MIN = W83627EHF_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_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
|
|
|
+ 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->REG_PWM = NCT6775_REG_PWM;
|
|
|
+ data->REG_TARGET = NCT6775_REG_TARGET;
|
|
|
+ data->REG_FAN = NCT6776_REG_FAN;
|
|
|
+ data->REG_FAN_MIN = NCT6776_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_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
|
|
|
+ } else if (sio_data->kind == w83667hg_b) {
|
|
|
+ data->REG_PWM = W83627EHF_REG_PWM;
|
|
|
+ data->REG_TARGET = W83627EHF_REG_TARGET;
|
|
|
+ data->REG_FAN = W83627EHF_REG_FAN;
|
|
|
+ data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
|
|
|
+ data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
|
|
|
+ data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
|
|
|
+ data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
|
|
|
data->REG_FAN_MAX_OUTPUT =
|
|
|
W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
|
|
|
data->REG_FAN_STEP_OUTPUT =
|
|
|
W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
|
|
|
} else {
|
|
|
+ data->REG_PWM = W83627EHF_REG_PWM;
|
|
|
+ data->REG_TARGET = W83627EHF_REG_TARGET;
|
|
|
+ data->REG_FAN = W83627EHF_REG_FAN;
|
|
|
+ data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
|
|
|
+ data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
|
|
|
+ data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
|
|
|
+ data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
|
|
|
data->REG_FAN_MAX_OUTPUT =
|
|
|
W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
|
|
|
data->REG_FAN_STEP_OUTPUT =
|
|
@@ -1544,7 +1992,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
data->vrm = vid_which_vrm();
|
|
|
superio_enter(sio_data->sioreg);
|
|
|
/* Read VID value */
|
|
|
- if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
|
|
|
+ if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
|
|
|
+ sio_data->kind == nct6775 || sio_data->kind == nct6776) {
|
|
|
/* W83667HG has different pins for VID input and output, so
|
|
|
we can get the VID input values directly at logical device D
|
|
|
0xe3. */
|
|
@@ -1595,12 +2044,27 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
|
|
|
/* fan4 and fan5 share some pins with the GPIO and serial flash */
|
|
|
- if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
|
|
|
- fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
|
|
|
+ if (sio_data->kind == nct6775) {
|
|
|
+ /* On NCT6775, fan4 shares pins with the fdc interface */
|
|
|
+ fan3pin = 1;
|
|
|
+ fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
|
|
|
+ fan4min = 0;
|
|
|
+ fan5pin = 0;
|
|
|
+ } else if (sio_data->kind == nct6776) {
|
|
|
+ fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
|
|
|
+ fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
|
|
|
+ fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
|
|
|
+ fan4min = fan4pin;
|
|
|
+ } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
|
|
|
+ fan3pin = 1;
|
|
|
fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
|
|
|
+ fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
|
|
|
+ fan4min = fan4pin;
|
|
|
} else {
|
|
|
- fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
|
|
|
+ fan3pin = 1;
|
|
|
fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
|
|
|
+ fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
|
|
|
+ fan4min = fan4pin;
|
|
|
}
|
|
|
superio_exit(sio_data->sioreg);
|
|
|
|
|
@@ -1610,15 +2074,36 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
connected fan5 as input unless they are emitting log 1, which
|
|
|
is not the default. */
|
|
|
|
|
|
- data->has_fan = 0x07; /* fan1, fan2 and fan3 */
|
|
|
- i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
|
|
|
- if ((i & (1 << 2)) && fan4pin)
|
|
|
- data->has_fan |= (1 << 3);
|
|
|
- if (!(i & (1 << 1)) && fan5pin)
|
|
|
- data->has_fan |= (1 << 4);
|
|
|
+ data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
|
|
|
+
|
|
|
+ data->has_fan |= (fan3pin << 2);
|
|
|
+ data->has_fan_min |= (fan3pin << 2);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
|
|
|
+ */
|
|
|
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
|
|
|
+ data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
|
|
|
+ data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
|
|
|
+ } else {
|
|
|
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
|
|
|
+ if ((i & (1 << 2)) && fan4pin) {
|
|
|
+ data->has_fan |= (1 << 3);
|
|
|
+ data->has_fan_min |= (1 << 3);
|
|
|
+ }
|
|
|
+ if (!(i & (1 << 1)) && fan5pin) {
|
|
|
+ data->has_fan |= (1 << 4);
|
|
|
+ data->has_fan_min |= (1 << 4);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/* Read fan clock dividers immediately */
|
|
|
- w83627ehf_update_fan_div(data);
|
|
|
+ w83627ehf_update_fan_div_common(dev, data);
|
|
|
+
|
|
|
+ /* Read pwm data to save original values */
|
|
|
+ w83627ehf_update_pwm_common(dev, data);
|
|
|
+ for (i = 0; i < data->pwm_num; i++)
|
|
|
+ data->pwm_enable_orig[i] = data->pwm_enable[i];
|
|
|
|
|
|
/* Read pwm data to save original values */
|
|
|
w83627ehf_update_pwm_common(dev, data);
|
|
@@ -1635,7 +2120,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
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->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
|
|
|
+ if (data->REG_FAN_STEP_OUTPUT &&
|
|
|
+ data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
|
|
|
err = device_create_file(dev, &attr->dev_attr);
|
|
|
if (err)
|
|
|
goto exit_remove;
|
|
@@ -1668,12 +2154,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
if ((err = device_create_file(dev,
|
|
|
&sda_fan_input[i].dev_attr))
|
|
|
|| (err = device_create_file(dev,
|
|
|
- &sda_fan_alarm[i].dev_attr))
|
|
|
- || (err = device_create_file(dev,
|
|
|
- &sda_fan_div[i].dev_attr))
|
|
|
- || (err = device_create_file(dev,
|
|
|
- &sda_fan_min[i].dev_attr)))
|
|
|
+ &sda_fan_alarm[i].dev_attr)))
|
|
|
goto exit_remove;
|
|
|
+ if (sio_data->kind != nct6776) {
|
|
|
+ err = device_create_file(dev,
|
|
|
+ &sda_fan_div[i].dev_attr);
|
|
|
+ if (err)
|
|
|
+ goto exit_remove;
|
|
|
+ }
|
|
|
+ if (data->has_fan_min & (1 << i)) {
|
|
|
+ err = device_create_file(dev,
|
|
|
+ &sda_fan_min[i].dev_attr);
|
|
|
+ if (err)
|
|
|
+ goto exit_remove;
|
|
|
+ }
|
|
|
if (i < data->pwm_num &&
|
|
|
((err = device_create_file(dev,
|
|
|
&sda_pwm[i].dev_attr))
|
|
@@ -1701,12 +2195,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|
|
if (err)
|
|
|
goto exit_remove;
|
|
|
}
|
|
|
+ if (data->reg_temp_over[i]) {
|
|
|
+ err = device_create_file(dev,
|
|
|
+ &sda_temp_max[i].dev_attr);
|
|
|
+ if (err)
|
|
|
+ goto exit_remove;
|
|
|
+ }
|
|
|
+ if (data->reg_temp_hyst[i]) {
|
|
|
+ err = device_create_file(dev,
|
|
|
+ &sda_temp_max_hyst[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,
|
|
|
- &sda_temp_max_hyst[i].dev_attr))
|
|
|
- || (err = device_create_file(dev,
|
|
|
+ continue;
|
|
|
+ if ((err = device_create_file(dev,
|
|
|
&sda_temp_alarm[i].dev_attr))
|
|
|
|| (err = device_create_file(dev,
|
|
|
&sda_temp_type[i].dev_attr)))
|
|
@@ -1767,6 +2270,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
|
|
|
static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
|
|
|
static const char __initdata sio_name_W83667HG[] = "W83667HG";
|
|
|
static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
|
|
|
+ static const char __initdata sio_name_NCT6775[] = "NCT6775F";
|
|
|
+ static const char __initdata sio_name_NCT6776[] = "NCT6776F";
|
|
|
|
|
|
u16 val;
|
|
|
const char *sio_name;
|
|
@@ -1803,6 +2308,14 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
|
|
|
sio_data->kind = w83667hg_b;
|
|
|
sio_name = sio_name_W83667HG_B;
|
|
|
break;
|
|
|
+ case SIO_NCT6775_ID:
|
|
|
+ sio_data->kind = nct6775;
|
|
|
+ sio_name = sio_name_NCT6775;
|
|
|
+ break;
|
|
|
+ case SIO_NCT6776_ID:
|
|
|
+ sio_data->kind = nct6776;
|
|
|
+ sio_name = sio_name_NCT6776;
|
|
|
+ break;
|
|
|
default:
|
|
|
if (val != 0xffff)
|
|
|
pr_debug("unsupported chip ID: 0x%04x\n", val);
|