X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=nct6775.c;h=f30c9b757c97ff3fe08ebd60ef92adca783262f0;hb=f361ce9049e115e479fd0fb79a76e1ace1365b2f;hp=6bc2f343d2a563edd029e2b2f5a84601aedf26ae;hpb=63ea34b6235a9480779b3c4de1197c8ff6c35e44;p=groeck-nct6775 diff --git a/nct6775.c b/nct6775.c index 6bc2f34..f30c9b7 100644 --- a/nct6775.c +++ b/nct6775.c @@ -37,6 +37,7 @@ * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3 + * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3 * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -61,7 +62,7 @@ #define USE_ALTERNATE -enum kinds { nct6106, nct6775, nct6776, nct6779 }; +enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 }; /* used to set data->name = nct6775_device_names[data->sio_kind] */ static const char * const nct6775_device_names[] = { @@ -69,6 +70,7 @@ static const char * const nct6775_device_names[] = { "nct6775", "nct6776", "nct6779", + "nct6791", }; static unsigned short force_id; @@ -98,6 +100,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6775_ID 0xb470 #define SIO_NCT6776_ID 0xc330 #define SIO_NCT6779_ID 0xc560 +#define SIO_NCT6791_ID 0xc800 #define SIO_ID_MASK 0xFFF0 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; @@ -174,6 +177,8 @@ superio_exit(int ioreg) #define NUM_REG_ALARM 7 /* Max number of alarm registers */ #define NUM_REG_BEEP 5 /* Max number of beep registers */ +#define NUM_FAN 6 + /* Common and NCT6775 specific data */ /* Voltage min/max registers for nr=7..14 are in bank 5 */ @@ -240,32 +245,38 @@ static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 }; /* Advanced Fan control, some values are common for all fans */ -static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 }; -static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 }; +static const u16 NCT6775_REG_TARGET[] = { + 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 }; +static const u16 NCT6775_REG_FAN_MODE[] = { + 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 }; static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = { - 0x103, 0x203, 0x303, 0x803, 0x903 }; + 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 }; static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = { - 0x104, 0x204, 0x304, 0x804, 0x904 }; + 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 }; static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { - 0x105, 0x205, 0x305, 0x805, 0x905 }; -static const u16 NCT6775_REG_FAN_START_OUTPUT[] - = { 0x106, 0x206, 0x306, 0x806, 0x906 }; + 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 }; +static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { + 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 }; static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a }; static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b }; static const u16 NCT6775_REG_FAN_STOP_TIME[] = { - 0x107, 0x207, 0x307, 0x807, 0x907 }; -static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 }; -static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 }; + 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 }; +static const u16 NCT6775_REG_PWM[] = { + 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 }; +static const u16 NCT6775_REG_PWM_READ[] = { + 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 }; static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d }; static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 }; -static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0 }; +static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 }; static const u16 NCT6775_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d }; +static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 }; + static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 0, 0x152, 0x252, 0x628, 0x629, 0x62A }; static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = { @@ -277,25 +288,25 @@ static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 }; static const u16 NCT6775_REG_TEMP_SEL[] = { - 0x100, 0x200, 0x300, 0x800, 0x900 }; + 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 }; static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = { - 0x139, 0x239, 0x339, 0x839, 0x939 }; + 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 }; static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = { - 0x13a, 0x23a, 0x33a, 0x83a, 0x93a }; + 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a }; static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = { - 0x13b, 0x23b, 0x33b, 0x83b, 0x93b }; + 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b }; static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = { - 0x13c, 0x23c, 0x33c, 0x83c, 0x93c }; + 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c }; static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = { - 0x13d, 0x23d, 0x33d, 0x83d, 0x93d }; + 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d }; static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 }; static const u16 NCT6775_REG_AUTO_TEMP[] = { - 0x121, 0x221, 0x321, 0x821, 0x921 }; + 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 }; static const u16 NCT6775_REG_AUTO_PWM[] = { - 0x127, 0x227, 0x327, 0x827, 0x927 }; + 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 }; #define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p)) #define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p)) @@ -303,9 +314,9 @@ static const u16 NCT6775_REG_AUTO_PWM[] = { static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 }; static const u16 NCT6775_REG_CRITICAL_TEMP[] = { - 0x135, 0x235, 0x335, 0x835, 0x935 }; + 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 }; static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = { - 0x138, 0x238, 0x338, 0x838, 0x938 }; + 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 }; static const char *const nct6775_temp_label[] = { "", @@ -361,16 +372,16 @@ static const s8 NCT6776_BEEP_BITS[] = { 30, 31 }; /* intrusion0, intrusion1 */ static const u16 NCT6776_REG_TOLERANCE_H[] = { - 0x10c, 0x20c, 0x30c, 0x80c, 0x90c }; + 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c }; -static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 }; -static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 }; +static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 }; +static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 }; static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 }; static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 }; static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = { - 0x13e, 0x23e, 0x33e, 0x83e, 0x93e }; + 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e }; static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A }; @@ -434,17 +445,19 @@ static const s8 NCT6779_BEEP_BITS[] = { 16, 17, -1, -1, -1, -1, /* temp1..temp6 */ 30, 31 }; /* intrusion0, intrusion1 */ -static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 }; +static const u16 NCT6779_REG_FAN[] = { + 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba }; static const u16 NCT6779_REG_FAN_PULSES[] = { - 0x644, 0x645, 0x646, 0x647, 0x648 }; + 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 }; static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = { - 0x136, 0x236, 0x336, 0x836, 0x936 }; + 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 }; #define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01 static const u16 NCT6779_REG_CRITICAL_PWM[] = { - 0x137, 0x237, 0x337, 0x837, 0x937 }; + 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 }; static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 }; +static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b }; static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 0x18, 0x152 }; static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = { @@ -494,6 +507,30 @@ static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1] static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; +/* NCT6791 specific data */ + +#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28 + +static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 }; +static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a }; +static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b }; +static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c }; +static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d }; +static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e }; + +static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = { + 0x459, 0x45A, 0x45B, 0x568, 0x45D }; + +static const s8 NCT6791_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, 33, /* fan1..fan6 */ + -1, -1, /* unused */ + 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ + 12, 9 }; /* intrusion0, intrusion1 */ + + /* NCT6102D/NCT6106D specific data */ #define NCT6106_REG_VBAT 0x318 @@ -508,6 +545,7 @@ static const u16 NCT6106_REG_IN[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 }; static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }; +static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a }; static const u16 NCT6106_REG_TEMP_HYST[] = { 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 }; static const u16 NCT6106_REG_TEMP_OVER[] = { @@ -694,14 +732,16 @@ static inline u8 in_to_reg(u32 val, u8 nr) struct nct6775_data { int addr; /* IO base of hw monitor block */ + int sioreg; /* SIO register address */ enum kinds kind; const char *name; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) struct device *hwmon_dev; - struct attribute_group *group_in; - struct attribute_group *group_fan; - struct attribute_group *group_temp; - struct attribute_group *group_pwm; +#endif + + int num_attr_groups; + const struct attribute_group *groups[6]; u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst, * 3=temp_crit, 4=temp_lcrit @@ -772,10 +812,10 @@ struct nct6775_data { u8 bank; /* current register bank */ u8 in_num; /* number of in inputs we have */ u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */ - unsigned int rpm[5]; - u16 fan_min[5]; - u8 fan_pulses[5]; - u8 fan_div[5]; + unsigned int rpm[NUM_FAN]; + u16 fan_min[NUM_FAN]; + u8 fan_pulses[NUM_FAN]; + u8 fan_div[NUM_FAN]; u8 has_pwm; u8 has_fan; /* some fan inputs can be disabled */ u8 has_fan_min; /* some fans don't have min register */ @@ -786,14 +826,16 @@ struct nct6775_data { u8 temp_fixed_num; /* 3 or 6 */ u8 temp_type[NUM_TEMP_FIXED]; s8 temp_offset[NUM_TEMP_FIXED]; - s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst, - * 3=temp_crit */ + s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst, + * 3=temp_crit, 4=temp_lcrit */ u64 alarms; u64 beeps; u8 pwm_num; /* number of pwm */ - u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */ - enum pwm_enable pwm_enable[5]; + u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage, + * 0->PWM variable duty cycle + */ + enum pwm_enable pwm_enable[NUM_FAN]; /* 0->off * 1->manual * 2->thermal cruise mode (also called SmartFan I) @@ -801,31 +843,31 @@ struct nct6775_data { * 4->SmartFan III * 5->enhanced variable thermal cruise (SmartFan IV) */ - u8 pwm[7][5]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor, - * [3]=pwm_max, [4]=pwm_step, - * [5]=weight_duty_step, [6]=weight_duty_base - */ + u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor, + * [3]=pwm_max, [4]=pwm_step, + * [5]=weight_duty_step, [6]=weight_duty_base + */ - u8 target_temp[5]; + u8 target_temp[NUM_FAN]; u8 target_temp_mask; - u32 target_speed[5]; - u32 target_speed_tolerance[5]; + u32 target_speed[NUM_FAN]; + u32 target_speed_tolerance[NUM_FAN]; u8 speed_tolerance_limit; - u8 temp_tolerance[2][5]; + u8 temp_tolerance[2][NUM_FAN]; u8 tolerance_mask; - u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */ + u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */ /* Automatic fan speed control registers */ int auto_pwm_num; - u8 auto_pwm[5][7]; - u8 auto_temp[5][7]; - u8 pwm_temp_sel[5]; - u8 pwm_weight_temp_sel[5]; - u8 weight_temp[3][5]; /* 0->temp_step, 1->temp_step_tol, - * 2->temp_base - */ + u8 auto_pwm[NUM_FAN][7]; + u8 auto_temp[NUM_FAN][7]; + u8 pwm_temp_sel[NUM_FAN]; + u8 pwm_weight_temp_sel[NUM_FAN]; + u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol, + * 2->temp_base + */ u8 vid; u8 vrm; @@ -913,7 +955,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, struct sensor_device_attribute_2 *a2; struct attribute **attrs; struct sensor_device_template **t; - int err, i, j, count; + int i, count; if (repeat <= 0) return ERR_PTR(-EINVAL); @@ -944,7 +986,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, for (i = 0; i < repeat; i++) { t = tg->templates; - for (j = 0; *t != NULL; j++) { + while (*t != NULL) { snprintf(su->name, sizeof(su->name), (*t)->dev_attr.attr.name, tg->base + i); if ((*t)->s2) { @@ -973,10 +1015,6 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, } } - err = sysfs_create_group(&dev->kobj, group); - if (err) - return ERR_PTR(-ENOMEM); - return group; } @@ -1010,8 +1048,9 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) || reg == 0x73 || reg == 0x75 || reg == 0x77; case nct6779: + case nct6791: return reg == 0x150 || reg == 0x153 || reg == 0x155 || - ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) || + ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) || reg == 0x402 || reg == 0x63a || reg == 0x63c || reg == 0x63e || reg == 0x640 || reg == 0x642 || @@ -1284,6 +1323,9 @@ static void nct6775_update_pwm(struct device *dev) if (reg & 0x80) data->pwm[2][i] = 0; + if (!data->REG_WEIGHT_TEMP_SEL[i]) + continue; + reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]); data->pwm_weight_temp_sel[i] = reg & 0x1f; /* If weight is disabled, report weight source as 0 */ @@ -1354,6 +1396,7 @@ static void nct6775_update_pwm_limits(struct device *dev) break; case nct6106: case nct6779: + case nct6791: reg = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i]); if (reg & data->CRITICAL_PWM_ENABLE_MASK) @@ -1426,7 +1469,8 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) = nct6775_read_temp(data, data->reg_temp[j][i]); } - if (!(data->have_temp_fixed & (1 << i))) + if (i >= NUM_TEMP_FIXED || + !(data->have_temp_fixed & (1 << i))) continue; data->temp_offset[i] = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]); @@ -1514,7 +1558,7 @@ static int find_temp_source(struct nct6775_data *data, int index, int count) if (src == source) return nr; } - return -1; + return -ENODEV; } static ssize_t @@ -1613,7 +1657,7 @@ store_temp_beep(struct device *dev, struct device_attribute *attr, nr = find_temp_source(data, sattr->index, data->num_temp_beeps); if (nr < 0) - return -ENODEV; + return nr; bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE]; regindex = bit >> 3; @@ -2694,6 +2738,7 @@ store_fan_time(struct device *dev, struct device_attribute *attr, return count; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2703,6 +2748,7 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +#endif static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf) @@ -2761,6 +2807,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, break; /* always enabled, nothing to do */ case nct6106: case nct6779: + case nct6791: nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); reg = nct6775_read_value(data, @@ -2836,6 +2883,9 @@ static umode_t nct6775_pwm_is_visible(struct kobject *kobj, if (!(data->has_pwm & (1 << pwm))) return 0; + if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */ + if (!data->REG_WEIGHT_TEMP_SEL[pwm]) + return 0; if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */ return 0; if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */ @@ -2929,11 +2979,11 @@ static struct sensor_device_template *nct6775_attributes_pwm_template[] = { &sensor_dev_template_pwm_step_down_time, &sensor_dev_template_pwm_start, &sensor_dev_template_pwm_floor, - &sensor_dev_template_pwm_weight_temp_sel, + &sensor_dev_template_pwm_weight_temp_sel, /* 14 */ &sensor_dev_template_pwm_weight_temp_step, &sensor_dev_template_pwm_weight_temp_step_tol, &sensor_dev_template_pwm_weight_temp_step_base, - &sensor_dev_template_pwm_weight_duty_step, + &sensor_dev_template_pwm_weight_duty_step, /* 18 */ &sensor_dev_template_pwm_max, /* 19 */ &sensor_dev_template_pwm_step, /* 20 */ &sensor_dev_template_pwm_weight_duty_base, /* 21 */ @@ -2951,7 +3001,6 @@ static struct sensor_device_template *nct6775_attributes_pwm_template[] = { &sensor_dev_template_pwm_auto_point6_temp, &sensor_dev_template_pwm_auto_point7_pwm, &sensor_dev_template_pwm_auto_point7_temp, /* 35 */ - NULL }; @@ -2977,7 +3026,6 @@ 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 - INTRUSION_ALARM_BASE; unsigned long val; u8 reg; @@ -2993,19 +3041,19 @@ clear_caseopen(struct device *dev, struct device_attribute *attr, * The CR registers are the same for all chips, and not all chips * support clearing the caseopen status through "regular" registers. */ - ret = superio_enter(sio_data->sioreg); + ret = superio_enter(data->sioreg); if (ret) { count = ret; goto error; } - superio_select(sio_data->sioreg, NCT6775_LD_ACPI); - reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]); + superio_select(data->sioreg, NCT6775_LD_ACPI); + reg = superio_inb(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); + superio_outb(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); + superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg); + superio_exit(data->sioreg); data->valid = false; /* Force cache refresh */ error: @@ -3030,16 +3078,16 @@ static umode_t nct6775_other_is_visible(struct kobject *kobj, struct device *dev = container_of(kobj, struct device, kobj); struct nct6775_data *data = dev_get_drvdata(dev); - if (index == 1 && !data->have_vid) + if (index == 0 && !data->have_vid) return 0; - if (index == 2 || index == 3) { - if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 2] < 0) + if (index == 1 || index == 2) { + if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0) return 0; } - if (index == 4 || index == 5) { - if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0) + if (index == 3 || index == 4) { + if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0) return 0; } @@ -3052,14 +3100,15 @@ static umode_t nct6775_other_is_visible(struct kobject *kobj, * Any change in order or content must be matched. */ static struct attribute *nct6775_attributes_other[] = { + &dev_attr_cpu0_vid.attr, /* 0 */ + &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */ + &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */ + &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */ + &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */ + &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) &dev_attr_name.attr, - &dev_attr_cpu0_vid.attr, /* 1 */ - &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 2 */ - &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 3 */ - &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 4 */ - &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 5 */ - &sensor_dev_attr_beep_enable.dev_attr.attr, /* 6 */ - +#endif NULL }; @@ -3068,27 +3117,6 @@ static const struct attribute_group nct6775_group_other = { .is_visible = nct6775_other_is_visible, }; -/* - * Driver and device management - */ - -static void nct6775_device_remove_files(struct device *dev) -{ - struct nct6775_data *data = dev_get_drvdata(dev); - - if (data->group_pwm) - sysfs_remove_group(&dev->kobj, data->group_pwm); - if (data->group_in) - sysfs_remove_group(&dev->kobj, data->group_in); - if (data->group_fan) - sysfs_remove_group(&dev->kobj, data->group_fan); - if (data->group_temp) - sysfs_remove_group(&dev->kobj, data->group_temp); - - sysfs_remove_group(&dev->kobj, &nct6775_group_other); -} - -/* Get the monitoring functions started */ static inline void nct6775_init_device(struct nct6775_data *data) { int i; @@ -3132,66 +3160,69 @@ static inline void nct6775_init_device(struct nct6775_data *data) } static void -nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, - struct nct6775_data *data) +nct6775_check_fan_inputs(struct nct6775_data *data) { + bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin; + bool pwm3pin, pwm4pin, pwm5pin, pwm6pin; + int sioreg = data->sioreg; int regval; - bool fan3pin, fan3min, fan4pin, fan4min, fan5pin; - bool pwm3pin, pwm4pin, pwm5pin; /* fan4 and fan5 share some pins with the GPIO and serial flash */ if (data->kind == nct6775) { - regval = superio_inb(sio_data->sioreg, 0x2c); + regval = superio_inb(sioreg, 0x2c); fan3pin = regval & (1 << 6); - fan3min = fan3pin; pwm3pin = regval & (1 << 7); /* On NCT6775, fan4 shares pins with the fdc interface */ - fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); - fan4min = 0; - fan5pin = 0; - pwm4pin = 0; - pwm5pin = 0; + fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); + fan4min = false; + fan5pin = false; + fan6pin = false; + pwm4pin = false; + pwm5pin = false; + pwm6pin = false; } else if (data->kind == nct6776) { - bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80; + bool gpok = superio_inb(sioreg, 0x27) & 0x80; - superio_select(sio_data->sioreg, NCT6775_LD_HWM); - regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE); + superio_select(sioreg, NCT6775_LD_HWM); + regval = superio_inb(sioreg, SIO_REG_ENABLE); if (regval & 0x80) fan3pin = gpok; else - fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); + fan3pin = !(superio_inb(sioreg, 0x24) & 0x40); if (regval & 0x40) fan4pin = gpok; else - fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01; + fan4pin = superio_inb(sioreg, 0x1C) & 0x01; if (regval & 0x20) fan5pin = gpok; else - fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02; + fan5pin = superio_inb(sioreg, 0x1C) & 0x02; fan4min = fan4pin; - fan3min = fan3pin; + fan6pin = false; pwm3pin = fan3pin; - pwm4pin = 0; - pwm5pin = 0; + pwm4pin = false; + pwm5pin = false; + pwm6pin = false; } else if (data->kind == nct6106) { - regval = superio_inb(sio_data->sioreg, 0x24); + regval = superio_inb(sioreg, 0x24); fan3pin = !(regval & 0x80); pwm3pin = regval & 0x08; - fan3min = fan3pin; fan4pin = false; fan4min = false; fan5pin = false; + fan6pin = false; pwm4pin = false; pwm5pin = false; - } else { /* NCT6779D */ - regval = superio_inb(sio_data->sioreg, 0x1c); + pwm6pin = false; + } else { /* NCT6779D or NCT6791D */ + regval = superio_inb(sioreg, 0x1c); fan3pin = !(regval & (1 << 5)); fan4pin = !(regval & (1 << 6)); @@ -3201,18 +3232,25 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data, pwm4pin = !(regval & (1 << 1)); pwm5pin = !(regval & (1 << 2)); - fan3min = fan3pin; fan4min = fan4pin; - } - data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */ - data->has_fan |= fan3pin << 2; - data->has_fan_min |= fan3min << 2; - - data->has_fan |= (fan4pin << 3) | (fan5pin << 4); - data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); + if (data->kind == nct6791) { + regval = superio_inb(sioreg, 0x2d); + fan6pin = (regval & (1 << 1)); + pwm6pin = (regval & (1 << 0)); + } else { /* NCT6779D */ + fan6pin = false; + pwm6pin = false; + } + } - data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4); + /* fan 1 and 2 (0x03) are always present */ + data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) | + (fan5pin << 4) | (fan6pin << 5); + data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) | + (fan5pin << 4); + data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | + (pwm5pin << 4) | (pwm6pin << 5); } static void add_temp_sensors(struct nct6775_data *data, const u16 *regp, @@ -3244,17 +3282,18 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp, static int nct6775_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct nct6775_sio_data *sio_data = dev->platform_data; + struct nct6775_sio_data *sio_data = dev_get_platdata(dev); struct nct6775_data *data; struct resource *res; int i, s, err = 0; int src, mask, available; const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config; - const u16 *reg_temp_alternate, *reg_temp_crit; + const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit; const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL; - int num_reg_temp; + int num_reg_temp, num_reg_temp_mon; u8 cr2a; struct attribute_group *group; + struct device *hwmon_dev; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, @@ -3267,6 +3306,7 @@ static int nct6775_probe(struct platform_device *pdev) return -ENOMEM; data->kind = sio_data->kind; + data->sioreg = sio_data->sioreg; data->addr = res->start; mutex_init(&data->update_lock); data->name = nct6775_device_names[data->kind]; @@ -3333,7 +3373,9 @@ static int nct6775_probe(struct platform_device *pdev) data->BEEP_BITS = NCT6106_BEEP_BITS; reg_temp = NCT6106_REG_TEMP; + reg_temp_mon = NCT6106_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON); reg_temp_over = NCT6106_REG_TEMP_OVER; reg_temp_hyst = NCT6106_REG_TEMP_HYST; reg_temp_config = NCT6106_REG_TEMP_CONFIG; @@ -3405,7 +3447,9 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_BEEP = NCT6775_REG_BEEP; reg_temp = NCT6775_REG_TEMP; + reg_temp_mon = NCT6775_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON); reg_temp_over = NCT6775_REG_TEMP_OVER; reg_temp_hyst = NCT6775_REG_TEMP_HYST; reg_temp_config = NCT6775_REG_TEMP_CONFIG; @@ -3475,7 +3519,9 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_BEEP = NCT6776_REG_BEEP; reg_temp = NCT6775_REG_TEMP; + reg_temp_mon = NCT6775_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON); reg_temp_over = NCT6775_REG_TEMP_OVER; reg_temp_hyst = NCT6775_REG_TEMP_HYST; reg_temp_config = NCT6776_REG_TEMP_CONFIG; @@ -3549,7 +3595,85 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_BEEP = NCT6776_REG_BEEP; reg_temp = NCT6779_REG_TEMP; + reg_temp_mon = NCT6779_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); + reg_temp_over = NCT6779_REG_TEMP_OVER; + reg_temp_hyst = NCT6779_REG_TEMP_HYST; + reg_temp_config = NCT6779_REG_TEMP_CONFIG; + reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE; + reg_temp_crit = NCT6779_REG_TEMP_CRIT; + + break; + case nct6791: + data->in_num = 15; + data->pwm_num = 6; + data->auto_pwm_num = 4; + data->has_fan_div = false; + data->temp_fixed_num = 6; + data->num_temp_alarms = 2; + data->num_temp_beeps = 2; + + data->ALARM_BITS = NCT6791_ALARM_BITS; + data->BEEP_BITS = NCT6779_BEEP_BITS; + + data->fan_from_reg = fan_from_reg13; + data->fan_from_reg_min = fan_from_reg13; + data->target_temp_mask = 0xff; + data->tolerance_mask = 0x07; + data->speed_tolerance_limit = 63; + + 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->DIODE_MASK = NCT6775_DIODE_MASK; + data->REG_VIN = NCT6779_REG_IN; + data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; + data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; + data->REG_TARGET = NCT6775_REG_TARGET; + data->REG_FAN = NCT6779_REG_FAN; + data->REG_FAN_MODE = NCT6775_REG_FAN_MODE; + data->REG_FAN_MIN = NCT6776_REG_FAN_MIN; + data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES; + data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT; + data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME; + data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME; + data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME; + data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H; + data->REG_PWM[0] = NCT6775_REG_PWM; + data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT; + data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT; + data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP; + data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE; + 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_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_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE; + data->CRITICAL_PWM_ENABLE_MASK + = NCT6779_CRITICAL_PWM_ENABLE_MASK; + data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM; + data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; + data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; + data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL; + data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL; + data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP; + data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL; + data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE; + data->REG_ALARM = NCT6791_REG_ALARM; + data->REG_BEEP = NCT6776_REG_BEEP; + + reg_temp = NCT6779_REG_TEMP; + reg_temp_mon = NCT6779_REG_TEMP_MON; + num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); reg_temp_over = NCT6779_REG_TEMP_OVER; reg_temp_hyst = NCT6779_REG_TEMP_HYST; reg_temp_config = NCT6779_REG_TEMP_CONFIG; @@ -3650,6 +3774,50 @@ static int nct6775_probe(struct platform_device *pdev) s++; } + /* + * Repeat with temperatures used for fan control. + * This set of registers does not support limits. + */ + for (i = 0; i < num_reg_temp_mon; i++) { + if (reg_temp_mon[i] == 0) + continue; + + src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f; + if (!src || (mask & (1 << src))) + continue; + + if (src >= data->temp_label_num || + !strlen(data->temp_label[src])) { + dev_info(dev, + "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", + src, i, data->REG_TEMP_SEL[i], + reg_temp_mon[i]); + continue; + } + + mask |= 1 << src; + + /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ + if (src <= data->temp_fixed_num) { + if (data->have_temp & (1 << (src - 1))) + continue; + data->have_temp |= 1 << (src - 1); + data->have_temp_fixed |= 1 << (src - 1); + data->reg_temp[0][src - 1] = reg_temp_mon[i]; + data->temp_src[src - 1] = src; + continue; + } + + if (s >= NUM_TEMP) + continue; + + /* Use dynamic index for other sources */ + data->have_temp |= 1 << s; + data->reg_temp[0][s] = reg_temp_mon[i]; + data->temp_src[s] = src; + s++; + } + #ifdef USE_ALTERNATE /* * Go through the list of alternate temp registers and enable @@ -3703,6 +3871,7 @@ static int nct6775_probe(struct platform_device *pdev) break; case nct6106: case nct6779: + case nct6791: break; } @@ -3733,6 +3902,9 @@ static int nct6775_probe(struct platform_device *pdev) case nct6779: tmp |= 0x3e; break; + case nct6791: + tmp |= 0x7e; + break; } superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE, tmp); @@ -3740,7 +3912,7 @@ static int nct6775_probe(struct platform_device *pdev) data->name); } - nct6775_check_fan_inputs(sio_data, data); + nct6775_check_fan_inputs(data); superio_exit(sio_data->sioreg); @@ -3750,72 +3922,81 @@ static int nct6775_probe(struct platform_device *pdev) /* Register sysfs hooks */ group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group, data->pwm_num); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_pwm = group; + if (IS_ERR(group)) + return PTR_ERR(group); + + data->groups[data->num_attr_groups++] = group; group = nct6775_create_attr_group(dev, &nct6775_in_template_group, fls(data->have_in)); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_in = group; + if (IS_ERR(group)) + return PTR_ERR(group); + + data->groups[data->num_attr_groups++] = group; group = nct6775_create_attr_group(dev, &nct6775_fan_template_group, fls(data->has_fan)); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_fan = group; + if (IS_ERR(group)) + return PTR_ERR(group); + + data->groups[data->num_attr_groups++] = group; group = nct6775_create_attr_group(dev, &nct6775_temp_template_group, fls(data->have_temp)); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_temp = group; + if (IS_ERR(group)) + return PTR_ERR(group); - err = sysfs_create_group(&dev->kobj, &nct6775_group_other); - if (err) - goto exit_remove; + data->groups[data->num_attr_groups++] = group; + data->groups[data->num_attr_groups++] = &nct6775_group_other; - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) + err = sysfs_create_groups(&dev->kobj, data->groups); + if (err < 0) + return err; + hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(hwmon_dev)) { + sysfs_remove_groups(&dev->kobj, data->groups); + return PTR_ERR(hwmon_dev); } - - return 0; - -exit_remove: - nct6775_device_remove_files(dev); - return err; + data->hwmon_dev = hwmon_dev; +#else + hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name, + data, data->groups); +#endif + return PTR_ERR_OR_ZERO(hwmon_dev); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) static int nct6775_remove(struct platform_device *pdev) { struct nct6775_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); - nct6775_device_remove_files(&pdev->dev); - + sysfs_remove_groups(&pdev->dev.kobj, data->groups); return 0; } +#endif + +static void nct6791_enable_io_mapping(int sioaddr) +{ + int val; + + val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE); + if (val & 0x10) { + pr_info("Enabling hardware monitor logical device mappings.\n"); + superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE, + val & ~0x10); + } +} #ifdef CONFIG_PM static int nct6775_suspend(struct device *dev) { struct nct6775_data *data = nct6775_update_device(dev); - struct nct6775_sio_data *sio_data = dev->platform_data; mutex_lock(&data->update_lock); data->vbat = nct6775_read_value(data, data->REG_VBAT); - if (sio_data->kind == nct6775) { + if (data->kind == nct6775) { data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1); data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2); } @@ -3827,12 +4008,20 @@ static int nct6775_suspend(struct device *dev) static int nct6775_resume(struct device *dev) { struct nct6775_data *data = dev_get_drvdata(dev); - struct nct6775_sio_data *sio_data = dev->platform_data; - int i, j; + int i, j, err = 0; mutex_lock(&data->update_lock); data->bank = 0xff; /* Force initial bank selection */ + if (data->kind == nct6791) { + err = superio_enter(data->sioreg); + if (err) + goto abort; + + nct6791_enable_io_mapping(data->sioreg); + superio_exit(data->sioreg); + } + /* Restore limits */ for (i = 0; i < data->in_num; i++) { if (!(data->have_in & (1 << i))) @@ -3864,21 +4053,24 @@ static int nct6775_resume(struct device *dev) /* Restore other settings */ nct6775_write_value(data, data->REG_VBAT, data->vbat); - if (sio_data->kind == nct6775) { + if (data->kind == nct6775) { nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1); nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2); } +abort: /* Force re-reading all values */ data->valid = false; mutex_unlock(&data->update_lock); - return 0; + return err; } static const struct dev_pm_ops nct6775_dev_pm_ops = { .suspend = nct6775_suspend, .resume = nct6775_resume, + .freeze = nct6775_suspend, + .restore = nct6775_resume, }; #define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops) @@ -3893,7 +4085,9 @@ static struct platform_driver nct6775_driver = { .pm = NCT6775_DEV_PM_OPS, }, .probe = nct6775_probe, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) .remove = nct6775_remove, +#endif }; static const char * const nct6775_sio_names[] __initconst = { @@ -3901,6 +4095,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6775F", "NCT6776D/F", "NCT6779D", + "NCT6791D", }; /* nct6775_find() looks for a '627 in the Super-I/O config space */ @@ -3932,6 +4127,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6779_ID: sio_data->kind = nct6779; break; + case SIO_NCT6791_ID: + sio_data->kind = nct6791; + break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); @@ -3957,6 +4155,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); } + if (sio_data->kind == nct6791) + nct6791_enable_io_mapping(sioaddr); + superio_exit(sioaddr); pr_info("Found %s or compatible chip at %#x:%#x\n", nct6775_sio_names[sio_data->kind], sioaddr, addr); @@ -3968,7 +4169,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) /* * when Super-I/O functions move to a separate file, the Super-I/O * bus will manage the lifetime of the device and this module will only keep - * track of the nct6775 driver. But since we platform_device_alloc(), we + * track of the nct6775 driver. But since we use platform_device_alloc(), we * must keep track of the device */ static struct platform_device *pdev[2];