X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=nct6775.c;h=64855db20b0adbe58ad48b22bd932e15ba4d3a87;hb=3100f3c29f864d98528404218c7ad68c46471f1b;hp=37db9499ce98a9c78b08099eace22f847fa20f64;hpb=aa86b36874b261cd5c664b55e6028d3c63376431;p=groeck-nct6775 diff --git a/nct6775.c b/nct6775.c index 37db949..64855db 100644 --- a/nct6775.c +++ b/nct6775.c @@ -5,7 +5,7 @@ * Copyright (C) 2012 Guenter Roeck * * Derived from w83627ehf driver - * Copyright (C) 2005-2012 Jean Delvare + * Copyright (C) 2005-2012 Jean Delvare * Copyright (C) 2006 Yuan Mu (Winbond), * Rudolf Marek * David Hubbard @@ -38,6 +38,9 @@ * 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 + * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3 + * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3 + * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3 * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -56,13 +59,17 @@ #include #include #include +#include +#include #include +#include #include "lm75.h" #include "compat.h" #define USE_ALTERNATE -enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 }; +enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, + nct6795 }; /* used to set data->name = nct6775_device_names[data->sio_kind] */ static const char * const nct6775_device_names[] = { @@ -71,6 +78,20 @@ static const char * const nct6775_device_names[] = { "nct6776", "nct6779", "nct6791", + "nct6792", + "nct6793", + "nct6795", +}; + +static const char * const nct6775_sio_names[] __initconst = { + "NCT6106D", + "NCT6775F", + "NCT6776D/F", + "NCT6779D", + "NCT6791D", + "NCT6792D", + "NCT6793D", + "NCT6795D", }; static unsigned short force_id; @@ -90,6 +111,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define NCT6775_LD_ACPI 0x0a #define NCT6775_LD_HWM 0x0b #define NCT6775_LD_VID 0x0d +#define NCT6775_LD_12 0x12 #define SIO_REG_LDSEL 0x07 /* Logical device select */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ @@ -101,6 +123,9 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6776_ID 0xc330 #define SIO_NCT6779_ID 0xc560 #define SIO_NCT6791_ID 0xc800 +#define SIO_NCT6792_ID 0xc910 +#define SIO_NCT6793_ID 0xd120 +#define SIO_NCT6795_ID 0xd350 #define SIO_ID_MASK 0xFFF0 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; @@ -179,6 +204,8 @@ superio_exit(int ioreg) #define NUM_FAN 6 +#define TEMP_SOURCE_VIRTUAL 0x1f + /* Common and NCT6775 specific data */ /* Voltage min/max registers for nr=7..14 are in bank 5 */ @@ -275,6 +302,8 @@ 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)] = { @@ -340,15 +369,31 @@ static const char *const nct6775_temp_label[] = { "PCH_DIM3_TEMP" }; -static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 }; +#define NCT6775_TEMP_MASK 0x001ffffe -static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1] - = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06, - 0xa07 }; +static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = { + [13] = 0x661, + [14] = 0x662, + [15] = 0x664, +}; + +static const u16 NCT6775_REG_TEMP_CRIT[32] = { + [4] = 0xa00, + [5] = 0xa01, + [6] = 0xa02, + [7] = 0xa03, + [8] = 0xa04, + [9] = 0xa05, + [10] = 0xa06, + [11] = 0xa07 +}; /* NCT6776 specific data */ +/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */ +#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME +#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME + static const s8 NCT6776_ALARM_BITS[] = { 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */ @@ -410,11 +455,18 @@ static const char *const nct6776_temp_label[] = { "BYTE_TEMP" }; -static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 }; +#define NCT6776_TEMP_MASK 0x007ffffe + +static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = { + [14] = 0x401, + [15] = 0x402, + [16] = 0x404, +}; -static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; +static const u16 NCT6776_REG_TEMP_CRIT[32] = { + [11] = 0x709, + [12] = 0x70a, +}; /* NCT6779 specific data */ @@ -455,6 +507,7 @@ static const u16 NCT6779_REG_CRITICAL_PWM[] = { 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)] = { @@ -492,22 +545,39 @@ static const char *const nct6779_temp_label[] = { "PCH_DIM1_TEMP", "PCH_DIM2_TEMP", "PCH_DIM3_TEMP", - "BYTE_TEMP" + "BYTE_TEMP", + "", + "", + "", + "", + "Virtual_TEMP" }; -static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1] +#define NCT6779_TEMP_MASK 0x07ffff7e +#define NCT6791_TEMP_MASK 0x87ffff7e + +static const u16 NCT6779_REG_TEMP_ALTERNATE[32] = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407, 0x408, 0 }; -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 }; +static const u16 NCT6779_REG_TEMP_CRIT[32] = { + [15] = 0x709, + [16] = 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 }; @@ -520,6 +590,123 @@ static const s8 NCT6791_ALARM_BITS[] = { 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 12, 9 }; /* intrusion0, intrusion1 */ +/* NCT6792/NCT6793 specific data */ + +static const u16 NCT6792_REG_TEMP_MON[] = { + 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d }; +static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = { + 0xb2, 0xb3, 0xb4, 0xb5, 0xbf }; + +static const char *const nct6792_temp_label[] = { + "", + "SYSTIN", + "CPUTIN", + "AUXTIN0", + "AUXTIN1", + "AUXTIN2", + "AUXTIN3", + "", + "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", + "PECI Agent 0 Calibration", + "PECI Agent 1 Calibration", + "", + "", + "Virtual_TEMP" +}; + +#define NCT6792_TEMP_MASK 0x9fffff7e + +static const char *const nct6793_temp_label[] = { + "", + "SYSTIN", + "CPUTIN", + "AUXTIN0", + "AUXTIN1", + "AUXTIN2", + "AUXTIN3", + "", + "SMBUSMASTER 0", + "SMBUSMASTER 1", + "", + "", + "", + "", + "", + "", + "PECI Agent 0", + "PECI Agent 1", + "PCH_CHIP_CPU_MAX_TEMP", + "PCH_CHIP_TEMP", + "PCH_CPU_TEMP", + "PCH_MCH_TEMP", + "Agent0 Dimm0 ", + "Agent0 Dimm1", + "Agent1 Dimm0", + "Agent1 Dimm1", + "BYTE_TEMP0", + "BYTE_TEMP1", + "PECI Agent 0 Calibration", + "PECI Agent 1 Calibration", + "", + "Virtual_TEMP" +}; + +#define NCT6793_TEMP_MASK 0xbfff037e + +static const char *const nct6795_temp_label[] = { + "", + "SYSTIN", + "CPUTIN", + "AUXTIN0", + "AUXTIN1", + "AUXTIN2", + "AUXTIN3", + "", + "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_TEMP0", + "BYTE_TEMP1", + "PECI Agent 0 Calibration", + "PECI Agent 1 Calibration", + "", + "Virtual_TEMP" +}; + +#define NCT6795_TEMP_MASK 0xbfffff7e /* NCT6102D/NCT6106D specific data */ @@ -535,6 +722,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[] = { @@ -614,11 +802,16 @@ static const s8 NCT6106_BEEP_BITS[] = { 34, -1 /* intrusion0, intrusion1 */ }; -static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 }; +static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = { + [14] = 0x51, + [15] = 0x52, + [16] = 0x54, +}; -static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 }; +static const u16 NCT6106_REG_TEMP_CRIT[32] = { + [11] = 0x204, + [12] = 0x205, +}; static enum pwm_enable reg_to_pwm_enable(int pwm, int mode) { @@ -693,7 +886,7 @@ static u16 fan_to_reg(u32 fan, unsigned int divreg) static inline unsigned int div_from_reg(u8 reg) { - return 1 << reg; + return BIT(reg); } /* @@ -725,11 +918,11 @@ struct nct6775_data { 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 + + 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 @@ -737,7 +930,7 @@ struct nct6775_data { u8 temp_src[NUM_TEMP]; u16 reg_temp_config[NUM_TEMP]; const char * const *temp_label; - int temp_label_num; + u32 temp_mask; u16 REG_CONFIG; u16 REG_VBAT; @@ -865,12 +1058,12 @@ struct nct6775_data { u16 have_temp; u16 have_temp_fixed; u16 have_in; -#ifdef CONFIG_PM + /* Remember extra register values over suspend/resume */ u8 vbat; u8 fandiv1; u8 fandiv2; -#endif + u8 sio_reg_enable; }; struct nct6775_sio_data { @@ -878,6 +1071,88 @@ struct nct6775_sio_data { enum kinds kind; }; +#ifdef CONFIG_DEBUG_FS + +static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg); +static u16 nct6775_read_value(struct nct6775_data *data, u16 reg); + +static const char *temp_attr_names[5] = { + "input", + "max", + "hyst", + "crit", + "lcrit", +}; + +static int nct6775_seq_show(struct seq_file *s, void *v) +{ + struct device *dev = (struct device *)s->private; + struct nct6775_data *data = dev_get_drvdata(dev); + int i, j; + + seq_printf(s, "Temperatures:\n"); + for (i = 0; i < NUM_TEMP; i++) { + if (!(data->have_temp & BIT(i))) + continue; + seq_printf(s, " temp%d [source %d, %s]:\n", i + 1, + data->temp_src[i], + data->temp_label[data->temp_src[i]]); + for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) { + if (data->reg_temp[j][i]) { + seq_printf(s, " %s: reg=0x%x val=0x%x cached 0x%x\n", + temp_attr_names[j], + data->reg_temp[j][i], + nct6775_read_temp(data, data->reg_temp[j][i]), + (u16)data->temp[j][i]); + } + } + } + seq_printf(s, "Temperature sources:\n"); + for (i = 0; i < data->num_temp_alarms; i++) { + seq_printf(s, " index %d register 0x%x: val=0x%x\n", + i, data->REG_TEMP_SOURCE[i], + nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f); + } + return 0; +} + +static int nct6775_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, nct6775_seq_show, inode->i_private); +} + +static const struct file_operations nct6775_debug_operations = { + .open = nct6775_debug_open, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, +}; + +static void nct6775_debugfs_exit(void *data) +{ + debugfs_remove_recursive(data); +} + +static int nct6775_debugfs_init(struct device *dev) +{ + struct dentry *rootdir; + + rootdir = debugfs_create_dir(dev_name(dev), NULL); + if (!rootdir) + return -ENOMEM; + + devm_add_action(dev, nct6775_debugfs_exit, rootdir); + + debugfs_create_file("registers", S_IFREG | 0444, rootdir, + dev, &nct6775_debug_operations); + + return 0; +} + +#else +static int nct6775_debugfs_init(struct device *dev) { return 0; } +#endif + struct sensor_device_template { struct device_attribute dev_attr; union { @@ -934,7 +1209,8 @@ struct sensor_template_group { }; static struct attribute_group * -nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, +nct6775_create_attr_group(struct device *dev, + const struct sensor_template_group *tg, int repeat) { struct attribute_group *group; @@ -943,7 +1219,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); @@ -974,11 +1250,12 @@ 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) { a2 = &su->u.a2; + sysfs_attr_init(&a2->dev_attr.attr); a2->dev_attr.attr.name = su->name; a2->nr = (*t)->u.s.nr + i; a2->index = (*t)->u.s.index; @@ -989,6 +1266,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, *attrs = &a2->dev_attr.attr; } else { a = &su->u.a1; + sysfs_attr_init(&a->dev_attr.attr); a->dev_attr.attr.name = su->name; a->index = (*t)->u.index + i; a->dev_attr.attr.mode = @@ -1003,10 +1281,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; } @@ -1041,13 +1315,16 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) reg == 0x73 || reg == 0x75 || reg == 0x77; case nct6779: case nct6791: + case nct6792: + case nct6793: + case nct6795: return reg == 0x150 || reg == 0x153 || reg == 0x155 || ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) || reg == 0x402 || reg == 0x63a || reg == 0x63c || reg == 0x63e || reg == 0x640 || reg == 0x642 || reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 || - reg == 0x7b; + reg == 0x7b || reg == 0x7d; } return false; } @@ -1061,6 +1338,7 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg) { u8 bank = reg >> 8; + if (data->bank != bank) { outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET); outb_p(bank, data->addr + DATA_REG_OFFSET); @@ -1161,7 +1439,7 @@ static void nct6775_update_fan_div(struct nct6775_data *data) data->fan_div[1] = (i & 0x70) >> 4; i = nct6775_read_value(data, NCT6775_REG_FANDIV2); data->fan_div[2] = i & 0x7; - if (data->has_fan & (1 << 3)) + if (data->has_fan & BIT(3)) data->fan_div[3] = (i & 0x70) >> 4; } @@ -1183,7 +1461,7 @@ static void nct6775_init_fan_div(struct nct6775_data *data) * We'll compute a better divider later on. */ for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) { - if (!(data->has_fan & (1 << i))) + if (!(data->has_fan & BIT(i))) continue; if (data->fan_div[i] == 0) { data->fan_div[i] = 7; @@ -1206,7 +1484,7 @@ static void nct6775_init_fan_common(struct device *dev, * prevents the unnecessary warning when fanX_min is reported as 0. */ for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { - if (data->has_fan_min & (1 << i)) { + if (data->has_fan_min & BIT(i)) { reg = nct6775_read_value(data, data->REG_FAN_MIN[i]); if (!reg) nct6775_write_value(data, data->REG_FAN_MIN[i], @@ -1241,7 +1519,7 @@ static void nct6775_select_fan_div(struct device *dev, div_from_reg(fan_div)); /* Preserve min limit if possible */ - if (data->has_fan_min & (1 << nr)) { + if (data->has_fan_min & BIT(nr)) { fan_min = data->fan_min[nr]; if (fan_div > data->fan_div[nr]) { if (fan_min != 255 && fan_min > 1) @@ -1272,7 +1550,7 @@ static void nct6775_update_pwm(struct device *dev) bool duty_is_dc; for (i = 0; i < data->pwm_num; i++) { - if (!(data->has_pwm & (1 << i))) + if (!(data->has_pwm & BIT(i))) continue; duty_is_dc = data->REG_PWM_MODE[i] && @@ -1298,6 +1576,7 @@ static void nct6775_update_pwm(struct device *dev) if (!data->target_speed_tolerance[i] || data->pwm_enable[i] == speed_cruise) { u8 t = fanmodecfg & 0x0f; + if (data->REG_TOLERANCE_H) { t |= (nct6775_read_value(data, data->REG_TOLERANCE_H[i]) & 0x70) >> 1; @@ -1315,6 +1594,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 */ @@ -1338,7 +1620,7 @@ static void nct6775_update_pwm_limits(struct device *dev) u16 reg_t; for (i = 0; i < data->pwm_num; i++) { - if (!(data->has_pwm & (1 << i))) + if (!(data->has_pwm & BIT(i))) continue; for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) { @@ -1386,6 +1668,9 @@ static void nct6775_update_pwm_limits(struct device *dev) case nct6106: case nct6779: case nct6791: + case nct6792: + case nct6793: + case nct6795: reg = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i]); if (reg & data->CRITICAL_PWM_ENABLE_MASK) @@ -1413,7 +1698,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) /* Measured voltages and limits */ for (i = 0; i < data->in_num; i++) { - if (!(data->have_in & (1 << i))) + if (!(data->have_in & BIT(i))) continue; data->in[i][0] = nct6775_read_value(data, @@ -1428,14 +1713,14 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) for (i = 0; i < ARRAY_SIZE(data->rpm); i++) { u16 reg; - if (!(data->has_fan & (1 << i))) + if (!(data->has_fan & BIT(i))) continue; reg = nct6775_read_value(data, data->REG_FAN[i]); data->rpm[i] = data->fan_from_reg(reg, data->fan_div[i]); - if (data->has_fan_min & (1 << i)) + if (data->has_fan_min & BIT(i)) data->fan_min[i] = nct6775_read_value(data, data->REG_FAN_MIN[i]); data->fan_pulses[i] = @@ -1450,7 +1735,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) /* Measured temperatures and limits */ for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) { if (data->reg_temp[j][i]) @@ -1458,7 +1743,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 & BIT(i))) continue; data->temp_offset[i] = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]); @@ -1467,6 +1753,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) data->alarms = 0; for (i = 0; i < NUM_REG_ALARM; i++) { u8 alarm; + if (!data->REG_ALARM[i]) continue; alarm = nct6775_read_value(data, data->REG_ALARM[i]); @@ -1476,6 +1763,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) data->beeps = 0; for (i = 0; i < NUM_REG_BEEP; i++) { u8 beep; + if (!data->REG_BEEP[i]) continue; beep = nct6775_read_value(data, data->REG_BEEP[i]); @@ -1498,8 +1786,9 @@ show_in_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - int nr = sattr->nr; int index = sattr->index; + int nr = sattr->nr; + return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr)); } @@ -1509,10 +1798,12 @@ store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf, { struct nct6775_data *data = dev_get_drvdata(dev); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); - int nr = sattr->nr; int index = sattr->index; + int nr = sattr->nr; unsigned long val; - int err = kstrtoul(buf, 10, &val); + int err; + + err = kstrtoul(buf, 10, &val); if (err < 0) return err; mutex_lock(&data->update_lock); @@ -1529,6 +1820,7 @@ show_alarm(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = data->ALARM_BITS[sattr->index]; + return sprintf(buf, "%u\n", (unsigned int)((data->alarms >> nr) & 0x01)); } @@ -1546,7 +1838,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 @@ -1564,6 +1856,7 @@ show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf) nr = find_temp_source(data, sattr->index, data->num_temp_alarms); if (nr >= 0) { int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE]; + alarm = (data->alarms >> bit) & 0x01; } return sprintf(buf, "%u\n", alarm); @@ -1589,8 +1882,9 @@ store_beep(struct device *dev, struct device_attribute *attr, const char *buf, int nr = data->BEEP_BITS[sattr->index]; int regindex = nr >> 3; unsigned long val; + int err; - int err = kstrtoul(buf, 10, &val); + err = kstrtoul(buf, 10, &val); if (err < 0) return err; if (val > 1) @@ -1623,6 +1917,7 @@ show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf) nr = find_temp_source(data, sattr->index, data->num_temp_beeps); if (nr >= 0) { int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE]; + beep = (data->beeps >> bit) & 0x01; } return sprintf(buf, "%u\n", beep); @@ -1636,8 +1931,9 @@ store_temp_beep(struct device *dev, struct device_attribute *attr, struct nct6775_data *data = dev_get_drvdata(dev); int nr, bit, regindex; unsigned long val; + int err; - int err = kstrtoul(buf, 10, &val); + err = kstrtoul(buf, 10, &val); if (err < 0) return err; if (val > 1) @@ -1645,7 +1941,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; @@ -1669,7 +1965,7 @@ static umode_t nct6775_in_is_visible(struct kobject *kobj, struct nct6775_data *data = dev_get_drvdata(dev); int in = index / 5; /* voltage index */ - if (!(data->have_in & (1 << in))) + if (!(data->have_in & BIT(in))) return 0; return attr->mode; @@ -1698,7 +1994,7 @@ static struct sensor_device_template *nct6775_attributes_in_template[] = { NULL }; -static struct sensor_template_group nct6775_in_template_group = { +static const struct sensor_template_group nct6775_in_template_group = { .templates = nct6775_attributes_in_template, .is_visible = nct6775_in_is_visible, }; @@ -1709,6 +2005,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; + return sprintf(buf, "%d\n", data->rpm[nr]); } @@ -1718,6 +2015,7 @@ show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; + return sprintf(buf, "%d\n", data->fan_from_reg_min(data->fan_min[nr], data->fan_div[nr])); @@ -1729,6 +2027,7 @@ show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; + return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr])); } @@ -1740,9 +2039,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; unsigned long val; - int err; unsigned int reg; u8 new_div; + int err; err = kstrtoul(buf, 10, &val); if (err < 0) @@ -1776,7 +2075,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, * even with the highest divider (128) */ data->fan_min[nr] = 254; - new_div = 7; /* 128 == (1 << 7) */ + new_div = 7; /* 128 == BIT(7) */ dev_warn(dev, "fan%u low limit %lu below minimum %u, set to minimum\n", nr + 1, val, data->fan_from_reg_min(254, 7)); @@ -1786,7 +2085,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, * even with the lowest divider (1) */ data->fan_min[nr] = 1; - new_div = 0; /* 1 == (1 << 0) */ + new_div = 0; /* 1 == BIT(0) */ dev_warn(dev, "fan%u low limit %lu above maximum %u, set to maximum\n", nr + 1, val, data->fan_from_reg_min(1, 0)); @@ -1873,14 +2172,14 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj, int fan = index / 6; /* fan index */ int nr = index % 6; /* attribute index */ - if (!(data->has_fan & (1 << fan))) + if (!(data->has_fan & BIT(fan))) return 0; if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1) return 0; if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1) return 0; - if (nr == 4 && !(data->has_fan_min & (1 << fan))) + if (nr == 4 && !(data->has_fan_min & BIT(fan))) return 0; if (nr == 5 && data->kind != nct6775) return 0; @@ -1914,7 +2213,7 @@ static struct sensor_device_template *nct6775_attributes_fan_template[] = { NULL }; -static struct sensor_template_group nct6775_fan_template_group = { +static const struct sensor_template_group nct6775_fan_template_group = { .templates = nct6775_attributes_fan_template, .is_visible = nct6775_fan_is_visible, .base = 1, @@ -1926,6 +2225,7 @@ show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; + return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); } @@ -2002,6 +2302,7 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; + return sprintf(buf, "%d\n", (int)data->temp_type[nr]); } @@ -2056,7 +2357,10 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj, int temp = index / 10; /* temp index */ int nr = index % 10; /* attribute index */ - if (!(data->have_temp & (1 << temp))) + if (!(data->have_temp & BIT(temp))) + return 0; + + if (nr == 1 && !data->temp_label) return 0; if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0) @@ -2078,7 +2382,7 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj, return 0; /* offset and type only apply to fixed sensors */ - if (nr > 7 && !(data->have_temp_fixed & (1 << temp))) + if (nr > 7 && !(data->have_temp_fixed & BIT(temp))) return 0; return attr->mode; @@ -2121,7 +2425,7 @@ static struct sensor_device_template *nct6775_attributes_temp_template[] = { NULL }; -static struct sensor_template_group nct6775_temp_template_group = { +static const struct sensor_template_group nct6775_temp_template_group = { .templates = nct6775_attributes_temp_template, .is_visible = nct6775_temp_is_visible, .base = 1, @@ -2347,7 +2651,7 @@ show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src) int i, sel = 0; for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; if (src == data->temp_src[i]) { sel = i + 1; @@ -2383,7 +2687,7 @@ store_pwm_temp_sel(struct device *dev, struct device_attribute *attr, return err; if (val == 0 || val > NUM_TEMP) return -EINVAL; - if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1]) + if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1]) return -EINVAL; mutex_lock(&data->update_lock); @@ -2425,7 +2729,7 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, return err; if (val > NUM_TEMP) return -EINVAL; - if (val && (!(data->have_temp & (1 << (val - 1))) || + if (val && (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])) return -EINVAL; @@ -2726,6 +3030,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) { @@ -2735,6 +3040,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) @@ -2794,6 +3100,9 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6106: case nct6779: case nct6791: + case nct6792: + case nct6793: + case nct6795: nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); reg = nct6775_read_value(data, @@ -2866,9 +3175,12 @@ static umode_t nct6775_pwm_is_visible(struct kobject *kobj, int pwm = index / 36; /* pwm index */ int nr = index % 36; /* attribute index */ - if (!(data->has_pwm & (1 << pwm))) + if (!(data->has_pwm & BIT(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 */ @@ -2962,11 +3274,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 */ @@ -2988,7 +3300,7 @@ static struct sensor_device_template *nct6775_attributes_pwm_template[] = { NULL }; -static struct sensor_template_group nct6775_pwm_template_group = { +static const struct sensor_template_group nct6775_pwm_template_group = { .templates = nct6775_attributes_pwm_template, .is_visible = nct6775_pwm_is_visible, .base = 1, @@ -2998,6 +3310,7 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct nct6775_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } @@ -3062,16 +3375,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; } @@ -3084,14 +3397,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 }; @@ -3100,27 +3414,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; @@ -3135,7 +3428,7 @@ static inline void nct6775_init_device(struct nct6775_data *data) /* Enable temperature sensors if needed */ for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; if (!data->reg_temp_config[i]) continue; @@ -3153,7 +3446,7 @@ static inline void nct6775_init_device(struct nct6775_data *data) diode = nct6775_read_value(data, data->REG_DIODE); for (i = 0; i < data->temp_fixed_num; i++) { - if (!(data->have_temp_fixed & (1 << i))) + if (!(data->have_temp_fixed & BIT(i))) continue; if ((tmp & (data->DIODE_MASK << i))) /* diode */ data->temp_type[i] @@ -3171,12 +3464,16 @@ nct6775_check_fan_inputs(struct nct6775_data *data) int sioreg = data->sioreg; int regval; + /* Store SIO_REG_ENABLE for use during resume */ + superio_select(sioreg, NCT6775_LD_HWM); + data->sio_reg_enable = superio_inb(sioreg, SIO_REG_ENABLE); + /* fan4 and fan5 share some pins with the GPIO and serial flash */ if (data->kind == nct6775) { regval = superio_inb(sioreg, 0x2c); - fan3pin = regval & (1 << 6); - pwm3pin = regval & (1 << 7); + fan3pin = regval & BIT(6); + pwm3pin = regval & BIT(7); /* On NCT6775, fan4 shares pins with the fdc interface */ fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); @@ -3188,21 +3485,38 @@ nct6775_check_fan_inputs(struct nct6775_data *data) pwm6pin = false; } else if (data->kind == nct6776) { bool gpok = superio_inb(sioreg, 0x27) & 0x80; + const char *board_vendor, *board_name; - superio_select(sioreg, NCT6775_LD_HWM); - regval = superio_inb(sioreg, SIO_REG_ENABLE); + board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + board_name = dmi_get_system_info(DMI_BOARD_NAME); + + if (board_name && board_vendor && + !strcmp(board_vendor, "ASRock")) { + /* + * Auxiliary fan monitoring is not enabled on ASRock + * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode. + * Observed with BIOS version 2.00. + */ + if (!strcmp(board_name, "Z77 Pro4-M")) { + if ((data->sio_reg_enable & 0xe0) != 0xe0) { + data->sio_reg_enable |= 0xe0; + superio_outb(sioreg, SIO_REG_ENABLE, + data->sio_reg_enable); + } + } + } - if (regval & 0x80) + if (data->sio_reg_enable & 0x80) fan3pin = gpok; else fan3pin = !(superio_inb(sioreg, 0x24) & 0x40); - if (regval & 0x40) + if (data->sio_reg_enable & 0x40) fan4pin = gpok; else fan4pin = superio_inb(sioreg, 0x1C) & 0x01; - if (regval & 0x20) + if (data->sio_reg_enable & 0x20) fan5pin = gpok; else fan5pin = superio_inb(sioreg, 0x1C) & 0x02; @@ -3225,27 +3539,57 @@ nct6775_check_fan_inputs(struct nct6775_data *data) pwm4pin = false; pwm5pin = false; pwm6pin = false; - } else { /* NCT6779D or NCT6791D */ - regval = superio_inb(sioreg, 0x1c); + } else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D */ + int regval_1b, regval_2a, regval_eb; - fan3pin = !(regval & (1 << 5)); - fan4pin = !(regval & (1 << 6)); - fan5pin = !(regval & (1 << 7)); + regval = superio_inb(sioreg, 0x1c); - pwm3pin = !(regval & (1 << 0)); - pwm4pin = !(regval & (1 << 1)); - pwm5pin = !(regval & (1 << 2)); + fan3pin = !(regval & BIT(5)); + fan4pin = !(regval & BIT(6)); + fan5pin = !(regval & BIT(7)); - fan4min = fan4pin; + pwm3pin = !(regval & BIT(0)); + pwm4pin = !(regval & BIT(1)); + pwm5pin = !(regval & BIT(2)); - if (data->kind == nct6791) { - regval = superio_inb(sioreg, 0x2d); - fan6pin = (regval & (1 << 1)); - pwm6pin = (regval & (1 << 0)); - } else { /* NCT6779D */ + regval = superio_inb(sioreg, 0x2d); + switch (data->kind) { + case nct6791: + case nct6792: + fan6pin = regval & BIT(1); + pwm6pin = regval & BIT(0); + break; + case nct6793: + case nct6795: + regval_1b = superio_inb(sioreg, 0x1b); + regval_2a = superio_inb(sioreg, 0x2a); + + if (!pwm5pin) + pwm5pin = regval & BIT(7); + fan6pin = regval & BIT(1); + pwm6pin = regval & BIT(0); + if (!fan5pin) + fan5pin = regval_1b & BIT(5); + + superio_select(sioreg, NCT6775_LD_12); + regval_eb = superio_inb(sioreg, 0xeb); + if (!fan5pin) + fan5pin = regval_eb & BIT(5); + if (!pwm5pin) + pwm5pin = (regval_eb & BIT(4)) && + !(regval_2a & BIT(0)); + if (!fan6pin) + fan6pin = regval_eb & BIT(3); + if (!pwm6pin) + pwm6pin = regval_eb & BIT(2); + break; + default: /* NCT6779D */ fan6pin = false; pwm6pin = false; + break; } + + fan4min = fan4pin; } /* fan 1 and 2 (0x03) are always present */ @@ -3270,33 +3614,34 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp, continue; src = nct6775_read_value(data, regp[i]); src &= 0x1f; - if (!src || (*mask & (1 << src))) + if (!src || (*mask & BIT(src))) continue; - if (src >= data->temp_label_num || - !strlen(data->temp_label[src])) + if (!(data->temp_mask & BIT(src))) continue; index = __ffs(*available); nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src); - *available &= ~(1 << index); - *mask |= 1 << src; + *available &= ~BIT(index); + *mask |= BIT(src); } } 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; + int num_attr_groups = 0; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, @@ -3329,7 +3674,7 @@ static int nct6775_probe(struct platform_device *pdev) data->fan_from_reg_min = fan_from_reg13; data->temp_label = nct6776_temp_label; - data->temp_label_num = ARRAY_SIZE(nct6776_temp_label); + data->temp_mask = NCT6776_TEMP_MASK; data->REG_VBAT = NCT6106_REG_VBAT; data->REG_DIODE = NCT6106_REG_DIODE; @@ -3376,7 +3721,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 +3752,7 @@ static int nct6775_probe(struct platform_device *pdev) data->speed_tolerance_limit = 15; data->temp_label = nct6775_temp_label; - data->temp_label_num = ARRAY_SIZE(nct6775_temp_label); + data->temp_mask = NCT6775_TEMP_MASK; data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_VBAT = NCT6775_REG_VBAT; @@ -3448,7 +3795,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 +3824,7 @@ static int nct6775_probe(struct platform_device *pdev) data->speed_tolerance_limit = 63; data->temp_label = nct6776_temp_label; - data->temp_label_num = ARRAY_SIZE(nct6776_temp_label); + data->temp_mask = NCT6776_TEMP_MASK; data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_VBAT = NCT6775_REG_VBAT; @@ -3491,8 +3840,8 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_FAN_PULSES = NCT6776_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_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME; + data->REG_FAN_TIME[2] = NCT6776_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; @@ -3518,7 +3867,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; @@ -3545,7 +3896,7 @@ static int nct6775_probe(struct platform_device *pdev) data->speed_tolerance_limit = 63; data->temp_label = nct6779_temp_label; - data->temp_label_num = ARRAY_SIZE(nct6779_temp_label); + data->temp_mask = NCT6779_TEMP_MASK; data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_VBAT = NCT6775_REG_VBAT; @@ -3561,8 +3912,8 @@ static int nct6775_probe(struct platform_device *pdev) 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_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME; + data->REG_FAN_TIME[2] = NCT6776_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; @@ -3592,7 +3943,9 @@ 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; @@ -3601,6 +3954,9 @@ static int nct6775_probe(struct platform_device *pdev) break; case nct6791: + case nct6792: + case nct6793: + case nct6795: data->in_num = 15; data->pwm_num = 6; data->auto_pwm_num = 4; @@ -3618,8 +3974,25 @@ static int nct6775_probe(struct platform_device *pdev) data->tolerance_mask = 0x07; data->speed_tolerance_limit = 63; - data->temp_label = nct6779_temp_label; - data->temp_label_num = ARRAY_SIZE(nct6779_temp_label); + switch (data->kind) { + default: + case nct6791: + data->temp_label = nct6779_temp_label; + data->temp_mask = NCT6791_TEMP_MASK; + break; + case nct6792: + data->temp_label = nct6792_temp_label; + data->temp_mask = NCT6792_TEMP_MASK; + break; + case nct6793: + data->temp_label = nct6793_temp_label; + data->temp_mask = NCT6793_TEMP_MASK; + break; + case nct6795: + data->temp_label = nct6795_temp_label; + data->temp_mask = NCT6795_TEMP_MASK; + break; + } data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_VBAT = NCT6775_REG_VBAT; @@ -3635,14 +4008,14 @@ static int nct6775_probe(struct platform_device *pdev) 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_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME; + data->REG_FAN_TIME[2] = NCT6776_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] = NCT6775_REG_WEIGHT_DUTY_STEP; - data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE; + 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; @@ -3658,15 +4031,25 @@ static int nct6775_probe(struct platform_device *pdev) 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 = NCT6775_REG_WEIGHT_TEMP_SEL; - data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP; - data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL; - data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE; + 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; + if (data->kind == nct6791) + data->REG_BEEP = NCT6776_REG_BEEP; + else + data->REG_BEEP = NCT6792_REG_BEEP; reg_temp = NCT6779_REG_TEMP; num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); + if (data->kind == nct6791) { + reg_temp_mon = NCT6779_REG_TEMP_MON; + num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); + } else { + reg_temp_mon = NCT6792_REG_TEMP_MON; + num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON); + } reg_temp_over = NCT6779_REG_TEMP_OVER; reg_temp_hyst = NCT6779_REG_TEMP_HYST; reg_temp_config = NCT6779_REG_TEMP_CONFIG; @@ -3677,7 +4060,7 @@ static int nct6775_probe(struct platform_device *pdev) default: return -ENODEV; } - data->have_in = (1 << data->in_num) - 1; + data->have_in = BIT(data->in_num) - 1; data->have_temp = 0; /* @@ -3695,10 +4078,10 @@ static int nct6775_probe(struct platform_device *pdev) continue; src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; - if (!src || (mask & (1 << src))) - available |= 1 << i; + if (!src || (mask & BIT(src))) + available |= BIT(i); - mask |= 1 << src; + mask |= BIT(src); } /* @@ -3715,23 +4098,22 @@ static int nct6775_probe(struct platform_device *pdev) continue; src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; - if (!src || (mask & (1 << src))) + if (!src || (mask & BIT(src))) continue; - if (src >= data->temp_label_num || - !strlen(data->temp_label[src])) { + if (!(data->temp_mask & BIT(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_SOURCE[i], reg_temp[i]); continue; } - mask |= 1 << src; + mask |= BIT(src); /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ if (src <= data->temp_fixed_num) { - data->have_temp |= 1 << (src - 1); - data->have_temp_fixed |= 1 << (src - 1); + data->have_temp |= BIT(src - 1); + data->have_temp_fixed |= BIT(src - 1); data->reg_temp[0][src - 1] = reg_temp[i]; data->reg_temp[1][src - 1] = reg_temp_over[i]; data->reg_temp[2][src - 1] = reg_temp_hyst[i]; @@ -3751,7 +4133,7 @@ static int nct6775_probe(struct platform_device *pdev) continue; /* Use dynamic index for other sources */ - data->have_temp |= 1 << s; + data->have_temp |= BIT(s); data->reg_temp[0][s] = reg_temp[i]; data->reg_temp[1][s] = reg_temp_over[i]; data->reg_temp[2][s] = reg_temp_hyst[i]; @@ -3767,6 +4149,58 @@ 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) + continue; + + if (!(data->temp_mask & BIT(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; + } + + /* + * For virtual temperature sources, the 'virtual' temperature + * for each fan reflects a different temperature, and there + * are no duplicates. + */ + if (src != TEMP_SOURCE_VIRTUAL) { + if (mask & BIT(src)) + continue; + mask |= BIT(src); + } + + /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ + if (src <= data->temp_fixed_num) { + if (data->have_temp & BIT(src - 1)) + continue; + data->have_temp |= BIT(src - 1); + data->have_temp_fixed |= BIT(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 |= BIT(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 @@ -3774,16 +4208,18 @@ static int nct6775_probe(struct platform_device *pdev) * The temperature is already monitored if the respective bit in * is set. */ - for (i = 0; i < data->temp_label_num - 1; i++) { + for (i = 0; i < 32; i++) { + if (!(data->temp_mask & BIT(i + 1))) + continue; if (!reg_temp_alternate[i]) continue; - if (mask & (1 << (i + 1))) + if (mask & BIT(i + 1)) continue; if (i < data->temp_fixed_num) { - if (data->have_temp & (1 << i)) + if (data->have_temp & BIT(i)) continue; - data->have_temp |= 1 << i; - data->have_temp_fixed |= 1 << i; + data->have_temp |= BIT(i); + data->have_temp_fixed |= BIT(i); data->reg_temp[0][i] = reg_temp_alternate[i]; if (i < num_reg_temp) { data->reg_temp[1][i] = reg_temp_over[i]; @@ -3796,7 +4232,7 @@ static int nct6775_probe(struct platform_device *pdev) if (s >= NUM_TEMP) /* Abort if no more space */ break; - data->have_temp |= 1 << s; + data->have_temp |= BIT(s); data->reg_temp[0][s] = reg_temp_alternate[i]; data->temp_src[s] = i + 1; s++; @@ -3821,6 +4257,9 @@ static int nct6775_probe(struct platform_device *pdev) case nct6106: case nct6779: case nct6791: + case nct6792: + case nct6793: + case nct6795: break; } @@ -3852,6 +4291,9 @@ static int nct6775_probe(struct platform_device *pdev) tmp |= 0x3e; break; case nct6791: + case nct6792: + case nct6793: + case nct6795: tmp |= 0x7e; break; } @@ -3871,65 +4313,76 @@ 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[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[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[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[num_attr_groups++] = group; + data->groups[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); + if (!IS_ERR(hwmon_dev)) + nct6775_debugfs_init(hwmon_dev); +#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 -#ifdef CONFIG_PM -static int nct6775_suspend(struct device *dev) +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); + } +} + +static int __maybe_unused nct6775_suspend(struct device *dev) { struct nct6775_data *data = nct6775_update_device(dev); @@ -3944,17 +4397,34 @@ static int nct6775_suspend(struct device *dev) return 0; } -static int nct6775_resume(struct device *dev) +static int __maybe_unused nct6775_resume(struct device *dev) { struct nct6775_data *data = dev_get_drvdata(dev); - int i, j; + int sioreg = data->sioreg; + int i, j, err = 0; + u8 reg; mutex_lock(&data->update_lock); data->bank = 0xff; /* Force initial bank selection */ + err = superio_enter(sioreg); + if (err) + goto abort; + + superio_select(sioreg, NCT6775_LD_HWM); + reg = superio_inb(sioreg, SIO_REG_ENABLE); + if (reg != data->sio_reg_enable) + superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable); + + if (data->kind == nct6791 || data->kind == nct6792 || + data->kind == nct6793 || data->kind == nct6795) + nct6791_enable_io_mapping(sioreg); + + superio_exit(sioreg); + /* Restore limits */ for (i = 0; i < data->in_num; i++) { - if (!(data->have_in & (1 << i))) + if (!(data->have_in & BIT(i))) continue; nct6775_write_value(data, data->REG_IN_MINMAX[0][i], @@ -3964,7 +4434,7 @@ static int nct6775_resume(struct device *dev) } for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { - if (!(data->has_fan_min & (1 << i))) + if (!(data->has_fan_min & BIT(i))) continue; nct6775_write_value(data, data->REG_FAN_MIN[i], @@ -3972,7 +4442,7 @@ static int nct6775_resume(struct device *dev) } for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++) @@ -3988,39 +4458,26 @@ static int nct6775_resume(struct device *dev) 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, -}; - -#define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops) -#else -#define NCT6775_DEV_PM_OPS NULL -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume); static struct platform_driver nct6775_driver = { .driver = { .owner = THIS_MODULE, .name = DRVNAME, - .pm = NCT6775_DEV_PM_OPS, + .pm = &nct6775_dev_pm_ops, }, .probe = nct6775_probe, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) .remove = nct6775_remove, -}; - -static const char * const nct6775_sio_names[] __initconst = { - "NCT6106D", - "NCT6775F", - "NCT6776D/F", - "NCT6779D", - "NCT6791D", +#endif }; /* nct6775_find() looks for a '627 in the Super-I/O config space */ @@ -4034,11 +4491,11 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) if (err) return err; - if (force_id) + val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | + superio_inb(sioaddr, SIO_REG_DEVID + 1); + if (force_id && val != 0xffff) val = force_id; - else - val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) - | superio_inb(sioaddr, SIO_REG_DEVID + 1); + switch (val & SIO_ID_MASK) { case SIO_NCT6106_ID: sio_data->kind = nct6106; @@ -4055,6 +4512,15 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6791_ID: sio_data->kind = nct6791; break; + case SIO_NCT6792_ID: + sio_data->kind = nct6792; + break; + case SIO_NCT6793_ID: + sio_data->kind = nct6793; + break; + case SIO_NCT6795_ID: + sio_data->kind = nct6795; + break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); @@ -4079,15 +4545,10 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n"); superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); } - if (sio_data->kind == nct6791) { - 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); - } - } + + if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || + sio_data->kind == nct6793 || sio_data->kind == nct6795) + nct6791_enable_io_mapping(sioaddr); superio_exit(sioaddr); pr_info("Found %s or compatible chip at %#x:%#x\n", @@ -4100,7 +4561,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]; @@ -4135,7 +4596,7 @@ static int __init sensors_nct6775_init(void) pdev[i] = platform_device_alloc(DRVNAME, address); if (!pdev[i]) { err = -ENOMEM; - goto exit_device_put; + goto exit_device_unregister; } err = platform_device_add_data(pdev[i], &sio_data, @@ -4173,9 +4634,11 @@ static int __init sensors_nct6775_init(void) return 0; exit_device_put: - for (i = 0; i < ARRAY_SIZE(pdev); i++) { + platform_device_put(pdev[i]); +exit_device_unregister: + while (--i >= 0) { if (pdev[i]) - platform_device_put(pdev[i]); + platform_device_unregister(pdev[i]); } exit_unregister: platform_driver_unregister(&nct6775_driver); @@ -4194,7 +4657,7 @@ static void __exit sensors_nct6775_exit(void) } MODULE_AUTHOR("Guenter Roeck "); -MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver"); +MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips"); MODULE_LICENSE("GPL"); module_init(sensors_nct6775_init);