diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7ac3daaf59ce..f315bf5430af 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1507,7 +1507,7 @@ config SENSORS_NCT6775_CORE config SENSORS_NCT6775 tristate "Platform driver for Nuvoton NCT6775F and compatibles" depends on !PPC - depends on ACPI_WMI || ACPI_WMI=n + depends on ACPI || ACPI=n select HWMON_VID select SENSORS_NCT6775_CORE help diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index da9ec6983e13..cefb954efcc4 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -33,6 +33,7 @@ * (0xd451) * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3 * (0xd429) + * nct6799d 14 7 7 2+6 0xd802 0xc1 0x5ca3 * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -40,6 +41,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -73,6 +75,7 @@ static const char * const nct6775_device_names[] = { "nct6796", "nct6797", "nct6798", + "nct6799", }; /* Common and NCT6775 specific data */ @@ -381,7 +384,7 @@ static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 0x39, 0x155 }; static const u16 NCT6779_REG_TEMP_OFFSET[] = { - 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c }; + 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c, 0x44d, 0x449 }; static const char *const nct6779_temp_label[] = { "", @@ -654,6 +657,44 @@ static const char *const nct6798_temp_label[] = { #define NCT6798_TEMP_MASK 0xbfff0ffe #define NCT6798_VIRT_TEMP_MASK 0x80000c00 +static const char *const nct6799_temp_label[] = { + "", + "SYSTIN", + "CPUTIN", + "AUXTIN0", + "AUXTIN1", + "AUXTIN2", + "AUXTIN3", + "AUXTIN4", + "SMBUSMASTER 0", + "SMBUSMASTER 1", + "Virtual_TEMP", + "Virtual_TEMP", + "", + "AUXTIN5", + "", + "", + "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", /* undocumented */ + "PECI Agent 1 Calibration", /* undocumented */ + "", + "Virtual_TEMP" +}; + +#define NCT6799_TEMP_MASK 0xbfff2ffe +#define NCT6799_VIRT_TEMP_MASK 0x80000c00 + /* NCT6102D/NCT6106D specific data */ #define NCT6106_REG_VBAT 0x318 @@ -1109,6 +1150,7 @@ bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg) case nct6796: case nct6797: case nct6798: + case nct6799: return reg == 0x150 || reg == 0x153 || reg == 0x155 || (reg & 0xfff0) == 0x4c0 || reg == 0x402 || @@ -1150,7 +1192,7 @@ static int nct6775_write_fan_div(struct nct6775_data *data, int nr) if (err) return err; reg &= 0x70 >> oddshift; - reg |= data->fan_div[nr] & (0x7 << oddshift); + reg |= (data->fan_div[nr] & 0x7) << oddshift; return nct6775_write_value(data, fandiv_reg, reg); } @@ -1462,6 +1504,7 @@ static int nct6775_update_pwm_limits(struct device *dev) case nct6796: case nct6797: case nct6798: + case nct6799: err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i], ®); if (err) return err; @@ -1480,13 +1523,27 @@ static int nct6775_update_pwm_limits(struct device *dev) return 0; } +static int nct6775_lock(struct nct6775_data *data) +{ + mutex_lock(&data->update_lock); + + return 0; +} + +static void nct6775_unlock(struct nct6775_data *data, struct device *dev) +{ + mutex_unlock(&data->update_lock); +} + struct nct6775_data *nct6775_update_device(struct device *dev) { struct nct6775_data *data = dev_get_drvdata(dev); - int i, j, err = 0; + int i, j, err; u16 reg; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return data; if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { @@ -1612,7 +1669,7 @@ struct nct6775_data *nct6775_update_device(struct device *dev) data->valid = true; } out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? ERR_PTR(err) : data; } EXPORT_SYMBOL_GPL(nct6775_update_device); @@ -1648,10 +1705,14 @@ store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf, err = kstrtoul(buf, 10, &val); if (err < 0) return err; - mutex_lock(&data->update_lock); + + err = data->lock(data); + if (err) + return err; + data->in[nr][index] = in_to_reg(val, nr); err = nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr], data->in[nr][index]); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -1745,14 +1806,17 @@ nct6775_store_beep(struct device *dev, struct device_attribute *attr, const char if (val > 1) return -EINVAL; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + if (val) data->beeps |= (1ULL << nr); else data->beeps &= ~(1ULL << nr); err = nct6775_write_value(data, data->REG_BEEP[regindex], (data->beeps >> (regindex << 3)) & 0xff); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } EXPORT_SYMBOL_GPL(nct6775_store_beep); @@ -1805,14 +1869,17 @@ store_temp_beep(struct device *dev, struct device_attribute *attr, bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE]; regindex = bit >> 3; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + if (val) data->beeps |= (1ULL << bit); else data->beeps &= ~(1ULL << bit); err = nct6775_write_value(data, data->REG_BEEP[regindex], (data->beeps >> (regindex << 3)) & 0xff); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -1912,7 +1979,10 @@ store_fan_min(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + if (!data->has_fan_div) { /* NCT6776F or NCT6779D; we know this is a 13 bit register */ if (!val) { @@ -1987,7 +2057,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, write_min: err = nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2024,7 +2094,10 @@ store_fan_pulses(struct device *dev, struct device_attribute *attr, if (val > 4) return -EINVAL; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->fan_pulses[nr] = val & 3; err = nct6775_read_value(data, data->REG_FAN_PULSES[nr], ®); if (err) @@ -2033,7 +2106,7 @@ store_fan_pulses(struct device *dev, struct device_attribute *attr, reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr]; err = nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg); out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2134,10 +2207,13 @@ store_temp(struct device *dev, struct device_attribute *attr, const char *buf, if (err < 0) return err; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->temp[index][nr] = LM75_TEMP_TO_REG(val); err = nct6775_write_temp(data, data->reg_temp[index][nr], data->temp[index][nr]); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2169,10 +2245,13 @@ store_temp_offset(struct device *dev, struct device_attribute *attr, val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->temp_offset[nr] = val; err = nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2212,7 +2291,9 @@ store_temp_type(struct device *dev, struct device_attribute *attr, if (val != 1 && val != 3 && val != 4) return -EINVAL; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; data->temp_type[nr] = val; vbit = 0x02 << nr; @@ -2244,7 +2325,7 @@ store_temp_type(struct device *dev, struct device_attribute *attr, goto out; err = nct6775_write_value(data, data->REG_DIODE, diode); out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2401,7 +2482,10 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, return count; } - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->pwm_mode[nr] = val; err = nct6775_read_value(data, data->REG_PWM_MODE[nr], ®); if (err) @@ -2411,7 +2495,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, reg |= data->PWM_MODE_MASK[nr]; err = nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2463,7 +2547,10 @@ store_pwm(struct device *dev, struct device_attribute *attr, const char *buf, return err; val = clamp_val(val, minval[index], maxval[index]); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->pwm[index][nr] = val; err = nct6775_write_value(data, data->REG_PWM[index][nr], val); if (err) @@ -2478,7 +2565,7 @@ store_pwm(struct device *dev, struct device_attribute *attr, const char *buf, err = nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg); } out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2595,7 +2682,10 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, return -EINVAL; } - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->pwm_enable[nr] = val; if (val == off) { /* @@ -2616,7 +2706,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, reg |= pwm_enable_to_reg(val) << 4; err = nct6775_write_value(data, data->REG_FAN_MODE[nr], reg); out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2672,7 +2762,10 @@ store_pwm_temp_sel(struct device *dev, struct device_attribute *attr, if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1]) return -EINVAL; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + src = data->temp_src[val - 1]; data->pwm_temp_sel[nr] = src; err = nct6775_read_value(data, data->REG_TEMP_SEL[nr], ®); @@ -2682,7 +2775,7 @@ store_pwm_temp_sel(struct device *dev, struct device_attribute *attr, reg |= src; err = nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg); out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2726,7 +2819,10 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, !data->temp_src[val - 1])) return -EINVAL; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + if (val) { src = data->temp_src[val - 1]; data->pwm_weight_temp_sel[nr] = src; @@ -2745,7 +2841,7 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, err = nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg); } out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2779,10 +2875,13 @@ store_target_temp(struct device *dev, struct device_attribute *attr, val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->target_temp_mask); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->target_temp[nr] = val; err = pwm_update_registers(data, nr); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2819,10 +2918,13 @@ store_target_speed(struct device *dev, struct device_attribute *attr, val = clamp_val(val, 0, 1350000U); speed = fan_to_reg(val, data->fan_div[nr]); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->target_speed[nr] = speed; err = pwm_update_registers(data, nr); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2859,13 +2961,16 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr, /* Limit tolerance as needed */ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->temp_tolerance[index][nr] = val; if (index) err = pwm_update_registers(data, nr); else err = nct6775_write_value(data, data->REG_CRITICAL_TEMP_TOLERANCE[nr], val); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2936,10 +3041,13 @@ store_speed_tolerance(struct device *dev, struct device_attribute *attr, /* Limit tolerance as needed */ val = clamp_val(val, 0, data->speed_tolerance_limit); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->target_speed_tolerance[nr] = val; err = pwm_update_registers(data, nr); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -2985,10 +3093,13 @@ store_weight_temp(struct device *dev, struct device_attribute *attr, val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->weight_temp[index][nr] = val; err = nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -3035,10 +3146,13 @@ store_fan_time(struct device *dev, struct device_attribute *attr, return err; val = step_time_to_reg(val, data->pwm_mode[nr]); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->fan_time[index][nr] = val; err = nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val); - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -3079,7 +3193,10 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, val = 0xff; } - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->auto_pwm[nr][point] = val; if (point < data->auto_pwm_num) { err = nct6775_write_value(data, NCT6775_AUTO_PWM(data, nr, point), @@ -3109,6 +3226,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6796: case nct6797: case nct6798: + case nct6799: err = nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); if (err) break; @@ -3123,7 +3241,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, break; } } - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -3162,7 +3280,10 @@ store_auto_temp(struct device *dev, struct device_attribute *attr, if (val > 255000) return -EINVAL; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000); if (point < data->auto_pwm_num) { err = nct6775_write_value(data, NCT6775_AUTO_TEMP(data, nr, point), @@ -3171,7 +3292,7 @@ store_auto_temp(struct device *dev, struct device_attribute *attr, err = nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr], data->auto_temp[nr][point]); } - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err ? : count; } @@ -3399,6 +3520,29 @@ static int add_temp_sensors(struct nct6775_data *data, const u16 *regp, return 0; } +/* Wait for up to 0.5 s to acquire the lock */ +#define ASUSWMI_LOCK_TIMEOUT_MS 500 + +static int nct6775_wmi_lock(struct nct6775_data *data) +{ + acpi_status status; + + status = acpi_acquire_mutex(data->acpi_wmi_mutex, NULL, ASUSWMI_LOCK_TIMEOUT_MS); + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; +} + +static void nct6775_wmi_unlock(struct nct6775_data *data, struct device *dev) +{ + acpi_status status; + + status = acpi_release_mutex(data->acpi_wmi_mutex, NULL); + if (ACPI_FAILURE(status)) + dev_err(dev, "Failed to release mutex."); +} + int nct6775_probe(struct device *dev, struct nct6775_data *data, const struct regmap_config *regmapcfg) { @@ -3416,7 +3560,15 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); - mutex_init(&data->update_lock); + if (data->acpi_wmi_mutex) { + data->lock = nct6775_wmi_lock; + data->unlock = nct6775_wmi_unlock; + } else { + mutex_init(&data->update_lock); + data->lock = nct6775_lock; + data->unlock = nct6775_unlock; + } + data->name = nct6775_device_names[data->kind]; data->bank = 0xff; /* Force initial bank selection */ @@ -3807,10 +3959,12 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, case nct6796: case nct6797: case nct6798: + case nct6799: data->in_num = 15; data->pwm_num = (data->kind == nct6796 || data->kind == nct6797 || - data->kind == nct6798) ? 7 : 6; + data->kind == nct6798 || + data->kind == nct6799) ? 7 : 6; data->auto_pwm_num = 4; data->has_fan_div = false; data->temp_fixed_num = 6; @@ -3859,6 +4013,11 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, data->temp_mask = NCT6798_TEMP_MASK; data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK; break; + case nct6799: + data->temp_label = nct6799_temp_label; + data->temp_mask = NCT6799_TEMP_MASK; + data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK; + break; } data->REG_CONFIG = NCT6775_REG_CONFIG; @@ -3918,6 +4077,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, case nct6796: case nct6797: case nct6798: + case nct6799: data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP; num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP); break; diff --git a/drivers/hwmon/nct6775-i2c.c b/drivers/hwmon/nct6775-i2c.c index e1bcd1146191..779ce65db1a1 100644 --- a/drivers/hwmon/nct6775-i2c.c +++ b/drivers/hwmon/nct6775-i2c.c @@ -87,6 +87,7 @@ static const struct of_device_id __maybe_unused nct6775_i2c_of_match[] = { { .compatible = "nuvoton,nct6796", .data = (void *)nct6796, }, { .compatible = "nuvoton,nct6797", .data = (void *)nct6797, }, { .compatible = "nuvoton,nct6798", .data = (void *)nct6798, }, + { .compatible = "nuvoton,nct6799", .data = (void *)nct6799, }, { }, }; MODULE_DEVICE_TABLE(of, nct6775_i2c_of_match); @@ -104,6 +105,7 @@ static const struct i2c_device_id nct6775_i2c_id[] = { { "nct6796", nct6796 }, { "nct6797", nct6797 }, { "nct6798", nct6798 }, + { "nct6799", nct6799 }, { } }; MODULE_DEVICE_TABLE(i2c, nct6775_i2c_id); diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index b34783784213..256f5c668e7f 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "nct6775.h" @@ -36,6 +35,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6796D", "NCT6797D", "NCT6798D", + "NCT6799D", }; static unsigned short force_id; @@ -86,6 +86,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6796_ID 0xd420 #define SIO_NCT6797_ID 0xd450 #define SIO_NCT6798_ID 0xd428 +#define SIO_NCT6799_ID 0xd800 #define SIO_ID_MASK 0xFFF8 /* @@ -98,6 +99,7 @@ struct nct6775_sio_data { int ld; enum kinds kind; enum sensor_access access; + acpi_handle acpi_wmi_mutex; /* superio_() callbacks */ void (*sio_outb)(struct nct6775_sio_data *sio_data, int reg, int val); @@ -107,40 +109,51 @@ struct nct6775_sio_data { void (*sio_exit)(struct nct6775_sio_data *sio_data); }; -#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66" +#define ASUSWMI_METHOD "WMBD" #define ASUSWMI_METHODID_RSIO 0x5253494F #define ASUSWMI_METHODID_WSIO 0x5753494F #define ASUSWMI_METHODID_RHWM 0x5248574D #define ASUSWMI_METHODID_WHWM 0x5748574D #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE +#define ASUSWMI_DEVICE_HID "PNP0C14" +#define ASUSWMI_DEVICE_UID "ASUSWMI" +#define ASUSMSI_DEVICE_UID "AsusMbSwInterface" + +#if IS_ENABLED(CONFIG_ACPI) +/* + * ASUS boards have only one device with WMI "WMBD" method and have provided + * access to only one SuperIO chip at 0x0290. + */ +static struct acpi_device *asus_acpi_dev; +#endif static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) { -#if IS_ENABLED(CONFIG_ACPI_WMI) +#if IS_ENABLED(CONFIG_ACPI) + acpi_handle handle = acpi_device_handle(asus_acpi_dev); u32 args = bank | (reg << 8) | (val << 16); - struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; + union acpi_object params[3]; + unsigned long long result; acpi_status status; - union acpi_object *obj; - u32 tmp = ASUSWMI_UNSUPPORTED_METHOD; - - status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0, - method_id, &input, &output); + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = 0; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = method_id; + params[2].type = ACPI_TYPE_BUFFER; + params[2].buffer.length = sizeof(args); + params[2].buffer.pointer = (void *)&args; + input.count = 3; + input.pointer = params; + + status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result); if (ACPI_FAILURE(status)) return -EIO; - obj = output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = obj->integer.value; - if (retval) - *retval = tmp; + *retval = (u32)result & 0xFFFFFFFF; - kfree(obj); - - if (tmp == ASUSWMI_UNSUPPORTED_METHOD) - return -ENODEV; return 0; #else return -EOPNOTSUPP; @@ -364,7 +377,10 @@ static int nct6775_suspend(struct device *dev) if (IS_ERR(data)) return PTR_ERR(data); - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + err = nct6775_read_value(data, data->REG_VBAT, &tmp); if (err) goto out; @@ -381,7 +397,7 @@ static int nct6775_suspend(struct device *dev) data->fandiv2 = tmp; } out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err; } @@ -393,7 +409,10 @@ static int nct6775_resume(struct device *dev) int i, j, err = 0; u8 reg; - mutex_lock(&data->update_lock); + err = data->lock(data); + if (err) + return err; + data->bank = 0xff; /* Force initial bank selection */ err = sio_data->sio_enter(sio_data); @@ -408,7 +427,7 @@ static int nct6775_resume(struct device *dev) if (data->kind == nct6791 || data->kind == nct6792 || data->kind == nct6793 || data->kind == nct6795 || data->kind == nct6796 || data->kind == nct6797 || - data->kind == nct6798) + data->kind == nct6798 || data->kind == nct6799) nct6791_enable_io_mapping(sio_data); sio_data->sio_exit(sio_data); @@ -462,7 +481,7 @@ static int nct6775_resume(struct device *dev) abort: /* Force re-reading all values */ data->valid = false; - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err; } @@ -555,7 +574,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio } else { /* * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, - * NCT6797D, NCT6798D + * NCT6797D, NCT6798D, NCT6799D */ int cr1a = sio_data->sio_inb(sio_data, 0x1a); int cr1b = sio_data->sio_inb(sio_data, 0x1b); @@ -565,12 +584,17 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio int cr2b = sio_data->sio_inb(sio_data, 0x2b); int cr2d = sio_data->sio_inb(sio_data, 0x2d); int cr2f = sio_data->sio_inb(sio_data, 0x2f); + bool vsb_ctl_en = cr2f & BIT(0); bool dsw_en = cr2f & BIT(3); bool ddr4_en = cr2f & BIT(4); + bool as_seq1_en = cr2f & BIT(7); int cre0; + int cre6; int creb; int cred; + cre6 = sio_data->sio_inb(sio_data, 0xe0); + sio_data->sio_select(sio_data, NCT6775_LD_12); cre0 = sio_data->sio_inb(sio_data, 0xe0); creb = sio_data->sio_inb(sio_data, 0xeb); @@ -673,6 +697,29 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio pwm7pin = !(cr1d & (BIT(2) | BIT(3))); pwm7pin |= cr2d & BIT(7); pwm7pin |= creb & BIT(2); + break; + case nct6799: + fan4pin = cr1c & BIT(6); + fan5pin = cr1c & BIT(7); + + fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); + fan6pin |= cre6 & BIT(5); + fan6pin |= creb & BIT(5); + fan6pin |= !as_seq1_en && (cr2a & BIT(4)); + + fan7pin = cr1b & BIT(5); + fan7pin |= !vsb_ctl_en && !(cr2b & BIT(2)); + fan7pin |= creb & BIT(3); + + pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); + pwm6pin |= !as_seq1_en && !(cred & BIT(2)) && (cr2a & BIT(3)); + pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + pwm6pin |= cre6 & BIT(3); + + pwm7pin = !vsb_ctl_en && !(cr1d & (BIT(2) | BIT(3))); + pwm7pin |= creb & BIT(2); + pwm7pin |= cr2d & BIT(7); + break; default: /* NCT6779D */ break; @@ -719,7 +766,9 @@ clear_caseopen(struct device *dev, struct device_attribute *attr, if (kstrtoul(buf, 10, &val) || val != 0) return -EINVAL; - mutex_lock(&data->update_lock); + ret = data->lock(data); + if (ret) + return ret; /* * Use CR registers to clear caseopen status. @@ -742,7 +791,7 @@ clear_caseopen(struct device *dev, struct device_attribute *attr, data->valid = false; /* Force cache refresh */ error: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return count; } @@ -828,6 +877,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data) case nct6796: case nct6797: case nct6798: + case nct6799: break; } @@ -866,6 +916,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data) case nct6796: case nct6797: case nct6798: + case nct6799: tmp |= 0x7e; break; } @@ -913,6 +964,7 @@ static int nct6775_platform_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + data->acpi_wmi_mutex = sio_data->acpi_wmi_mutex; data->kind = sio_data->kind; data->sioreg = sio_data->sioreg; @@ -995,6 +1047,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6798_ID: sio_data->kind = nct6798; break; + case SIO_NCT6799_ID: + sio_data->kind = nct6799; + break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); @@ -1023,7 +1078,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || sio_data->kind == nct6793 || sio_data->kind == nct6795 || sio_data->kind == nct6796 || sio_data->kind == nct6797 || - sio_data->kind == nct6798) + sio_data->kind == nct6798 || sio_data->kind == nct6799) nct6791_enable_io_mapping(sio_data); sio_data->sio_exit(sio_data); @@ -1042,22 +1097,47 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) static struct platform_device *pdev[2]; static const char * const asus_wmi_boards[] = { - "PRO H410T", - "ProArt X570-CREATOR WIFI", - "Pro B550M-C", - "Pro WS X570-ACE", + "CROSSHAIR VI HERO", // use custom port definition "PRIME B360-PLUS", + "PRIME B450-PLUS", // use custom port definition + "PRIME B450M-GAMING II", // use custom port definition + "PRIME B450M-GAMING/BR", // use custom port definition "PRIME B460-PLUS", "PRIME B550-PLUS", "PRIME B550M-A", "PRIME B550M-A (WI-FI)", + "PRIME B550M-A AC", + "PRIME B550M-A WIFI II", + "PRIME B550M-K", "PRIME H410M-R", + "PRIME X370-PRO", // use custom port definition + "PRIME X470-PRO", // use custom port definition "PRIME X570-P", "PRIME X570-PRO", + "PRO H410T", + "Pro B550M-C", + "Pro WS X570-ACE", + "ProArt B550-CREATOR", + "ProArt X570-CREATOR WIFI", + "ProArt Z490-CREATOR 10G", + "ROG CROSSHAIR VI EXTREME", // use custom port definition + "ROG CROSSHAIR VI HERO (WI-FI AC)", // use custom port definition + "ROG CROSSHAIR VII HERO", // use custom port definition + "ROG CROSSHAIR VII HERO (WI-FI)", // use custom port definition "ROG CROSSHAIR VIII DARK HERO", + "ROG CROSSHAIR VIII EXTREME", "ROG CROSSHAIR VIII FORMULA", "ROG CROSSHAIR VIII HERO", + "ROG CROSSHAIR VIII HERO (WI-FI)", "ROG CROSSHAIR VIII IMPACT", + "ROG MAXIMUS XI HERO", + "ROG MAXIMUS XI HERO (WI-FI)", + "ROG STRIX B350-F GAMING", // use custom port definition + "ROG STRIX B350-I GAMING", // use custom port definition + "ROG STRIX B450-E GAMING", // use custom port definition + "ROG STRIX B450-F GAMING", // use custom port definition + "ROG STRIX B450-F GAMING II", // use custom port definition + "ROG STRIX B450-I GAMING", // use custom port definition "ROG STRIX B550-A GAMING", "ROG STRIX B550-E GAMING", "ROG STRIX B550-F GAMING", @@ -1065,6 +1145,10 @@ static const char * const asus_wmi_boards[] = { "ROG STRIX B550-F GAMING WIFI II", "ROG STRIX B550-I GAMING", "ROG STRIX B550-XE GAMING (WI-FI)", + "ROG STRIX X370-F GAMING", // use custom port definition + "ROG STRIX X370-I GAMING", // use custom port definition + "ROG STRIX X470-F GAMING", // use custom port definition + "ROG STRIX X470-I GAMING", // use custom port definition "ROG STRIX X570-E GAMING", "ROG STRIX X570-E GAMING WIFI II", "ROG STRIX X570-F GAMING", @@ -1080,17 +1164,197 @@ static const char * const asus_wmi_boards[] = { "ROG STRIX Z490-G GAMING (WI-FI)", "ROG STRIX Z490-H GAMING", "ROG STRIX Z490-I GAMING", - "TUF GAMING B550M-PLUS", - "TUF GAMING B550M-PLUS (WI-FI)", + "TUF B450 PLUS GAMING", // use custom port definition + "TUF GAMING B450-PLUS II", // use custom port definition "TUF GAMING B550-PLUS", "TUF GAMING B550-PLUS WIFI II", "TUF GAMING B550-PRO", + "TUF GAMING B550M-E", + "TUF GAMING B550M-E (WI-FI)", + "TUF GAMING B550M-PLUS", + "TUF GAMING B550M-PLUS (WI-FI)", + "TUF GAMING B550M-PLUS WIFI II", "TUF GAMING X570-PLUS", "TUF GAMING X570-PLUS (WI-FI)", "TUF GAMING X570-PRO (WI-FI)", "TUF GAMING Z490-PLUS", "TUF GAMING Z490-PLUS (WI-FI)", + "Z490-GUNDAM (WI-FI)", +}; + +static const char * const asus_msi_boards[] = { + "EX-B660M-V5 PRO D4", + "PRIME B650-PLUS", + "PRIME B650M-A", + "PRIME B650M-A AX", + "PRIME B650M-A II", + "PRIME B650M-A WIFI", + "PRIME B650M-A WIFI II", + "PRIME B660M-A D4", + "PRIME B660M-A WIFI D4", + "PRIME X670-P", + "PRIME X670-P WIFI", + "PRIME X670E-PRO WIFI", + "Pro B660M-C-D4", + "Pro WS W680-ACE", + "Pro WS W680-ACE IPMI", + "ProArt B660-CREATOR D4", + "ProArt X670E-CREATOR WIFI", + "ProArt Z790-CREATOR WIFI", // use custom port definition + "ROG CROSSHAIR X670E EXTREME", + "ROG CROSSHAIR X670E GENE", + "ROG CROSSHAIR X670E HERO", + "ROG MAXIMUS XIII EXTREME GLACIAL", + "ROG MAXIMUS Z690 EXTREME", + "ROG MAXIMUS Z690 EXTREME GLACIAL", + "ROG MAXIMUS Z790 EXTREME", // use custom port definition + "ROG STRIX B650-A GAMING WIFI", + "ROG STRIX B650E-E GAMING WIFI", + "ROG STRIX B650E-F GAMING WIFI", + "ROG STRIX B650E-I GAMING WIFI", + "ROG STRIX B660-A GAMING WIFI D4", + "ROG STRIX B660-F GAMING WIFI", + "ROG STRIX B660-G GAMING WIFI", + "ROG STRIX B660-I GAMING WIFI", + "ROG STRIX X670E-A GAMING WIFI", + "ROG STRIX X670E-E GAMING WIFI", + "ROG STRIX X670E-F GAMING WIFI", + "ROG STRIX X670E-I GAMING WIFI", + "ROG STRIX Z590-A GAMING WIFI II", + "ROG STRIX Z690-A GAMING WIFI D4", + "TUF GAMING B650-PLUS", + "TUF GAMING B650-PLUS WIFI", + "TUF GAMING B650M-PLUS", + "TUF GAMING B650M-PLUS WIFI", + "TUF GAMING B660M-PLUS WIFI", + "TUF GAMING X670E-PLUS", + "TUF GAMING X670E-PLUS WIFI", + "TUF GAMING Z590-PLUS WIFI", +}; + +#if IS_ENABLED(CONFIG_ACPI) +/* + * Callback for acpi_bus_for_each_dev() to find the right device + * by _UID and _HID and return 1 to stop iteration. + */ +static int nct6775_asuswmi_device_match(struct device *dev, void *data) +{ + struct acpi_device *adev = to_acpi_device(dev); + const char *uid = acpi_device_uid(adev); + const char *hid = acpi_device_hid(adev); + + if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && + uid && !strcmp(uid, data)) { + asus_acpi_dev = adev; + return 1; + } + + return 0; +} +#endif + +static enum sensor_access nct6775_determine_access(const char *device_uid) +{ +#if IS_ENABLED(CONFIG_ACPI) + u8 tmp; + + acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid); + if (!asus_acpi_dev) + return access_direct; + + /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */ + if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { + pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp); + return access_asuswmi; + } +#endif + + return access_direct; +} + +struct acpi_board_info { + char *acpi_mutex_path; +}; + +#define DMI_ASUS_BOARD_INFO(name, mutex_path) \ +static struct acpi_board_info name = { \ + .acpi_mutex_path = mutex_path, \ +} + +DMI_ASUS_BOARD_INFO(acpi_board_GPEM_MUTEX, "\\_GPE.MUT0"); +DMI_ASUS_BOARD_INFO(acpi_board_LPCB_MUTEX, "\\_SB_.PCI0.LPCB.SIO1.MUT0"); +DMI_ASUS_BOARD_INFO(acpi_board_0LPC_MUTEX, "\\_SB.PC00.LPCB.SIO1.MUT0"); +DMI_ASUS_BOARD_INFO(acpi_board_SBRG_MUTEX, "\\_SB.PCI0.SBRG.SIO1.MUT0"); + +#define DMI_MATCH_ASUS_WMI_BOARD(name, info) { \ + .matches = { \ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), \ + DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \ + }, \ + .driver_data = info, \ +} + +#define DMI_MATCH_ASUS_NONWMI_BOARD(name, info) { \ + .matches = { \ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), \ + DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \ + }, \ + .driver_data = info, \ +} + + +static const struct dmi_system_id asus_wmi_info_table[] = { + DMI_MATCH_ASUS_NONWMI_BOARD("P8Z68-V LX", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("B150 PRO GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("B150 PRO GAMING D3", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("B150M PRO GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("CROSSHAIR VI HERO", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("MAXIMUS IX APEX", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("MAXIMUS IX CODE", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("MAXIMUS IX EXTREME", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("MAXIMUS IX FORMULA", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("MAXIMUS IX HERO", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("MAXIMUS VII HERO", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("P8H67", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME B450M-GAMING/BR", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME B450M-GAMING II", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME B450-PLUS", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME X370-PRO", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME X470-PRO", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME Z270-A", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ProArt Z790-CREATOR WIFI", &acpi_board_0LPC_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG CROSSHAIR VI EXTREME", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG CROSSHAIR VI HERO (WI-FI AC)", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG CROSSHAIR VII HERO", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG CROSSHAIR VII HERO (WI-FI)", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG MAXIMUS X HERO", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG MAXIMUS Z790 EXTREME", &acpi_board_0LPC_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B350-F GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B350-I GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B450-E GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B450-F GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B450-F GAMING II", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B450-I GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX X370-F GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX X370-I GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX X470-F GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX X470-I GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX Z370-H GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("STRIX-Z270E-GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("STRIX-Z270F-GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("STRIX-Z270G-GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("STRIX-Z270H-GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("TUF B450 PLUS GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("TUF GAMING B450-PLUS II", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("TUF Z270 MARK 1", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z170 PRO GAMING", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z170 PRO GAMING/AURA", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z170-DELUXE", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z170M-PLUS", &acpi_board_GPEM_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z270-WS", &acpi_board_GPEM_MUTEX), + {} }; +MODULE_DEVICE_TABLE(dmi, asus_wmi_info_table); static int __init sensors_nct6775_platform_init(void) { @@ -1102,7 +1366,10 @@ static int __init sensors_nct6775_platform_init(void) int sioaddr[2] = { 0x2e, 0x4e }; enum sensor_access access = access_direct; const char *board_vendor, *board_name; - u8 tmp; + const struct dmi_system_id *dmi_id; + struct acpi_board_info *board_info; + acpi_handle acpi_wmi_mutex = NULL; + acpi_status status; err = platform_driver_register(&nct6775_driver); if (err) @@ -1115,14 +1382,36 @@ static int __init sensors_nct6775_platform_init(void) !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) { err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards), board_name); - if (err >= 0) { - /* if reading chip id via WMI succeeds, use WMI */ - if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { - pr_info("Using Asus WMI to access %#x chip.\n", tmp); - access = access_asuswmi; + if (err >= 0) + access = nct6775_determine_access(ASUSWMI_DEVICE_UID); + + err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards), + board_name); + if (err >= 0) + access = nct6775_determine_access(ASUSMSI_DEVICE_UID); + } + + if (access == access_direct) { + /* Mutext access check */ + dmi_id = dmi_first_match(asus_wmi_info_table); + if (dmi_id && dmi_id->driver_data) { + board_info = dmi_id->driver_data; + if (board_info->acpi_mutex_path) { + status = acpi_get_handle(NULL, board_info->acpi_mutex_path, + &acpi_wmi_mutex); + if (!ACPI_FAILURE(status)) { + pr_info("Using Asus WMI mutex: %s\n", + board_info->acpi_mutex_path); + access = access_direct; + } else { + pr_info("No such ASUS mutex: %s\n", + board_info->acpi_mutex_path); + } } else { - pr_err("Can't read ChipID by Asus WMI.\n"); + pr_info("No mutex path\n"); } + } else { + pr_info("No dmi definition `%s`:`%s`\n", board_name, board_vendor); } } @@ -1147,6 +1436,7 @@ static int __init sensors_nct6775_platform_init(void) found = true; sio_data.access = access; + sio_data.acpi_wmi_mutex = acpi_wmi_mutex; if (access == access_asuswmi) { sio_data.sio_outb = superio_wmi_outb; @@ -1174,11 +1464,13 @@ static int __init sensors_nct6775_platform_init(void) res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; res.flags = IORESOURCE_IO; - err = acpi_check_resource_conflict(&res); - if (err) { - platform_device_put(pdev[i]); - pdev[i] = NULL; - continue; + if (!acpi_wmi_mutex) { + err = acpi_check_resource_conflict(&res); + if (err) { + platform_device_put(pdev[i]); + pdev[i] = NULL; + continue; + } } err = platform_device_add_resources(pdev[i], &res, 1); diff --git a/drivers/hwmon/nct6775.h b/drivers/hwmon/nct6775.h index be41848c3cd2..c58ea93a5428 100644 --- a/drivers/hwmon/nct6775.h +++ b/drivers/hwmon/nct6775.h @@ -5,7 +5,7 @@ #include enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792, - nct6793, nct6795, nct6796, nct6797, nct6798 }; + nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 }; enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; #define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/ @@ -90,10 +90,15 @@ struct nct6775_data { unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg); unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg); - struct mutex update_lock; + struct mutex update_lock; /* non ACPI lock */ + acpi_handle acpi_wmi_mutex; /* ACPI lock */ + bool valid; /* true if following fields are valid */ unsigned long last_updated; /* In jiffies */ + int (*lock)(struct nct6775_data *data); + void (*unlock)(struct nct6775_data *data, struct device *dev); + /* Register values */ u8 bank; /* current register bank */ u8 in_num; /* number of in inputs we have */