X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=nct6775.c;h=49cbfad4b54c393b36153153e0ced4a4e0f43800;hb=e83646554bd680ea0655bcce1d17ec50fa87f4f0;hp=075bb3679ac54a8f7e70ba5ce569bc0e1d909a6b;hpb=5b5112711f86b7c24a8397e2787f22c532fa4509;p=groeck-nct6775 diff --git a/nct6775.c b/nct6775.c index 075bb36..49cbfad 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,7 @@ * 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 0xc911 0xc1 0x5ca3 * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -62,7 +63,7 @@ #define USE_ALTERNATE -enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 }; +enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792 }; /* used to set data->name = nct6775_device_names[data->sio_kind] */ static const char * const nct6775_device_names[] = { @@ -71,6 +72,7 @@ static const char * const nct6775_device_names[] = { "nct6776", "nct6779", "nct6791", + "nct6792", }; static unsigned short force_id; @@ -101,6 +103,7 @@ 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_ID_MASK 0xFFF0 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; @@ -275,6 +278,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)] = { @@ -455,6 +460,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)] = { @@ -508,6 +514,13 @@ static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] #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 +533,12 @@ static const s8 NCT6791_ALARM_BITS[] = { 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ 12, 9 }; /* intrusion0, intrusion1 */ +/* NCT6792 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 }; /* NCT6102D/NCT6106D specific data */ @@ -535,6 +554,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[] = { @@ -725,11 +745,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 @@ -814,8 +834,8 @@ 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; @@ -865,12 +885,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 { @@ -943,7 +963,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,7 +994,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) { @@ -1003,10 +1023,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 +1057,14 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) reg == 0x73 || reg == 0x75 || reg == 0x77; case nct6779: case nct6791: + case nct6792: 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 +1078,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); @@ -1298,6 +1316,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 +1334,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 */ @@ -1386,6 +1408,7 @@ static void nct6775_update_pwm_limits(struct device *dev) case nct6106: case nct6779: case nct6791: + case nct6792: reg = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i]); if (reg & data->CRITICAL_PWM_ENABLE_MASK) @@ -1458,7 +1481,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]); @@ -1467,6 +1491,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 +1501,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 +1524,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 +1536,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 +1558,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 +1576,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 +1594,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 +1620,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 +1655,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 +1669,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 +1679,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; @@ -1709,6 +1743,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 +1753,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 +1765,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 +1777,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) @@ -1926,6 +1963,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 +2040,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]); } @@ -2726,6 +2765,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 +2775,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 +2835,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6106: case nct6779: case nct6791: + case nct6792: nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); reg = nct6775_read_value(data, @@ -2869,6 +2911,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 */ @@ -2962,11 +3007,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 */ @@ -2998,6 +3043,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 +3108,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 +3130,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 +3147,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; @@ -3171,6 +3197,10 @@ 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); @@ -3189,20 +3219,17 @@ nct6775_check_fan_inputs(struct nct6775_data *data) } else if (data->kind == nct6776) { bool gpok = superio_inb(sioreg, 0x27) & 0x80; - superio_select(sioreg, NCT6775_LD_HWM); - regval = superio_inb(sioreg, 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,7 +3252,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data) pwm4pin = false; pwm5pin = false; pwm6pin = false; - } else { /* NCT6779D or NCT6791D */ + } else { /* NCT6779D, NCT6791D, or NCT6792D */ regval = superio_inb(sioreg, 0x1c); fan3pin = !(regval & (1 << 5)); @@ -3238,7 +3265,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data) fan4min = fan4pin; - if (data->kind == nct6791) { + if (data->kind == nct6791 || data->kind == nct6792) { regval = superio_inb(sioreg, 0x2d); fan6pin = (regval & (1 << 1)); pwm6pin = (regval & (1 << 0)); @@ -3286,17 +3313,19 @@ 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; + int num_attr_groups = 0; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, @@ -3376,7 +3405,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; @@ -3448,7 +3479,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; @@ -3518,7 +3551,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; @@ -3592,7 +3627,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 +3638,7 @@ static int nct6775_probe(struct platform_device *pdev) break; case nct6791: + case nct6792: data->in_num = 15; data->pwm_num = 6; data->auto_pwm_num = 4; @@ -3641,8 +3679,8 @@ static int nct6775_probe(struct platform_device *pdev) 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 +3696,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; @@ -3767,6 +3815,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 @@ -3821,6 +3913,7 @@ static int nct6775_probe(struct platform_device *pdev) case nct6106: case nct6779: case nct6791: + case nct6792: break; } @@ -3852,6 +3945,7 @@ static int nct6775_probe(struct platform_device *pdev) tmp |= 0x3e; break; case nct6791: + case nct6792: tmp |= 0x7e; break; } @@ -3871,65 +3965,74 @@ 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); +#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) +static int __maybe_unused nct6775_suspend(struct device *dev) { struct nct6775_data *data = nct6775_update_device(dev); @@ -3944,14 +4047,30 @@ 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) + nct6791_enable_io_mapping(sioreg); + + superio_exit(sioreg); + /* Restore limits */ for (i = 0; i < data->in_num; i++) { if (!(data->have_in & (1 << i))) @@ -3988,31 +4107,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, +#endif }; static const char * const nct6775_sio_names[] __initconst = { @@ -4021,6 +4135,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6776D/F", "NCT6779D", "NCT6791D", + "NCT6792D", }; /* nct6775_find() looks for a '627 in the Super-I/O config space */ @@ -4055,6 +4170,9 @@ 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; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); @@ -4079,15 +4197,9 @@ 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) + nct6791_enable_io_mapping(sioaddr); superio_exit(sioaddr); pr_info("Found %s or compatible chip at %#x:%#x\n", @@ -4100,7 +4212,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 +4247,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 +4285,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 +4308,7 @@ static void __exit sensors_nct6775_exit(void) } MODULE_AUTHOR("Guenter Roeck "); -MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver"); +MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver"); MODULE_LICENSE("GPL"); module_init(sensors_nct6775_init);