diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index da9ec6983e13..c205d0e5ce5c 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 @@ -51,6 +53,8 @@ #include #include #include +#include +#include #include "lm75.h" #include "nct6775.h" @@ -73,6 +77,7 @@ static const char * const nct6775_device_names[] = { "nct6796", "nct6797", "nct6798", + "nct6799", }; /* Common and NCT6775 specific data */ @@ -1109,6 +1114,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 || @@ -1462,6 +1468,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 +1487,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 +1633,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 +1669,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 +1770,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 +1833,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 +1943,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 +2021,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 +2058,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 +2070,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 +2171,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 +2209,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 +2255,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 +2289,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 +2446,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 +2459,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 +2511,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 +2529,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 +2646,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 +2670,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 +2726,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 +2739,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 +2783,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 +2805,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 +2839,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 +2882,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 +2925,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 +3005,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 +3057,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 +3110,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 +3157,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 +3190,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 +3205,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 +3244,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 +3256,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 +3484,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 +3524,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,6 +3923,7 @@ 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 || @@ -3855,6 +3972,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK; break; case nct6798: + case nct6799: data->temp_label = nct6798_temp_label; data->temp_mask = NCT6798_TEMP_MASK; data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK; @@ -3918,6 +4036,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-platform.c b/drivers/hwmon/nct6775-platform.c index 41c97cfacfb8..f4333306ea00 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -18,10 +18,11 @@ #include #include #include +#include #include "nct6775.h" -enum sensor_access { access_direct, access_asuswmi }; +enum sensor_access { access_direct, access_asuswmi, access_asusacpi }; static const char * const nct6775_sio_names[] __initconst = { "NCT6106D", @@ -36,6 +37,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6796D", "NCT6797D", "NCT6798D", + "NCT6799D", }; static unsigned short force_id; @@ -86,6 +88,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 /* 0xd802 with revision */ #define SIO_ID_MASK 0xFFF8 /* @@ -98,6 +101,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); @@ -113,6 +117,16 @@ struct nct6775_sio_data { #define ASUSWMI_METHODID_RHWM 0x5248574D #define ASUSWMI_METHODID_WHWM 0x5748574D #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE +/* + * Newer boards have an ACPI method not exposed through any WMI GUID + * so we call it directly through acpi. + * Same METHODID values can be used as with WMI + */ +#define ASUSACPI_DEVICE_UID "AsusMbSwInterface" +#define ASUSACPI_DEVICE_HID "PNP0C14" +#define ASUSACPI_METHOD "WMBD" + +struct acpi_device *asus_acpi_dev; static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) { @@ -192,6 +206,85 @@ static void superio_wmi_exit(struct nct6775_sio_data *sio_data) { } + +static int nct6775_asusacpi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) +{ +#if IS_ENABLED(CONFIG_ACPI) + u32 args = bank | (reg << 8) | (val << 16); + acpi_status status; + unsigned long long result; + union acpi_object params[3]; + struct acpi_object_list input; + acpi_handle handle = acpi_device_handle(asus_acpi_dev); + + 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, ASUSACPI_METHOD, &input, &result); + if (ACPI_FAILURE(status)) + return -EIO; + + if (retval) + *retval = (u32)result & 0xFFFFFFFF; + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + +static inline int nct6775_asusacpi_write(u8 bank, u8 reg, u8 val) +{ + return nct6775_asusacpi_evaluate_method(ASUSWMI_METHODID_WHWM, bank, + reg, val, NULL); +} + +static inline int nct6775_asusacpi_read(u8 bank, u8 reg, u8 *val) +{ + u32 ret, tmp = 0; + + ret = nct6775_asusacpi_evaluate_method(ASUSWMI_METHODID_RHWM, bank, + reg, 0, &tmp); + *val = tmp; + return ret; +} + +static int superio_acpi_inb(struct nct6775_sio_data *sio_data, int reg) +{ + int tmp = 0; + + nct6775_asusacpi_evaluate_method(ASUSWMI_METHODID_RSIO, sio_data->ld, + reg, 0, &tmp); + return tmp; +} + +static void superio_acpi_outb(struct nct6775_sio_data *sio_data, int reg, int val) +{ + nct6775_asusacpi_evaluate_method(ASUSWMI_METHODID_WSIO, sio_data->ld, + reg, val, NULL); +} + +static void superio_acpi_select(struct nct6775_sio_data *sio_data, int ld) +{ + sio_data->ld = ld; +} + +static int superio_acpi_enter(struct nct6775_sio_data *sio_data) +{ + return 0; +} + +static void superio_acpi_exit(struct nct6775_sio_data *sio_data) +{ +} + static void superio_outb(struct nct6775_sio_data *sio_data, int reg, int val) { int ioreg = sio_data->sioreg; @@ -294,6 +387,58 @@ static int nct6775_wmi_reg_write(void *ctx, unsigned int reg, unsigned int value return res; } +static inline void nct6775_acpi_set_bank(struct nct6775_data *data, u16 reg) +{ + u8 bank = reg >> 8; + + data->bank = bank; +} + +static int nct6775_acpi_reg_read(void *ctx, unsigned int reg, unsigned int *val) +{ + struct nct6775_data *data = ctx; + int err, word_sized = nct6775_reg_is_word_sized(data, reg); + u8 tmp = 0; + u16 res; + + nct6775_acpi_set_bank(data, reg); + + err = nct6775_asusacpi_read(data->bank, reg & 0xff, &tmp); + if (err) + return err; + + res = tmp; + if (word_sized) { + err = nct6775_asusacpi_read(data->bank, (reg & 0xff) + 1, &tmp); + if (err) + return err; + + res = (res << 8) + tmp; + } + *val = res; + return 0; +} + +static int nct6775_acpi_reg_write(void *ctx, unsigned int reg, unsigned int value) +{ + struct nct6775_data *data = ctx; + int res, word_sized = nct6775_reg_is_word_sized(data, reg); + + nct6775_acpi_set_bank(data, reg); + + if (word_sized) { + res = nct6775_asusacpi_write(data->bank, reg & 0xff, value >> 8); + if (res) + return res; + + res = nct6775_asusacpi_write(data->bank, (reg & 0xff) + 1, value); + } else { + res = nct6775_asusacpi_write(data->bank, reg & 0xff, value); + } + + return res; +} + /* * On older chips, only registers 0x50-0x5f are banked. * On more recent chips, all registers are banked. @@ -364,7 +509,10 @@ static int __maybe_unused 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 +529,7 @@ static int __maybe_unused nct6775_suspend(struct device *dev) data->fandiv2 = tmp; } out: - mutex_unlock(&data->update_lock); + data->unlock(data, dev); return err; } @@ -393,7 +541,10 @@ static int __maybe_unused 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 +559,7 @@ static int __maybe_unused 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 +613,7 @@ static int __maybe_unused 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 +706,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); @@ -670,6 +821,23 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3)); pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + pwm7pin = !(cr1d & (BIT(2) | BIT(3))); + pwm7pin |= cr2d & BIT(7); + pwm7pin |= creb & BIT(2); + break; + case nct6799: + fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); + fan6pin |= cr2a & BIT(4); + fan6pin |= creb & BIT(5); + + fan7pin = cr1b & BIT(5); + fan7pin |= !(cr2b & BIT(2)); + fan7pin |= creb & BIT(3); + + pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); + pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3)); + pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + pwm7pin = !(cr1d & (BIT(2) | BIT(3))); pwm7pin |= cr2d & BIT(7); pwm7pin |= creb & BIT(2); @@ -719,7 +887,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 +912,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 +998,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data) case nct6796: case nct6797: case nct6798: + case nct6799: break; } @@ -866,6 +1037,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data) case nct6796: case nct6797: case nct6798: + case nct6799: tmp |= 0x7e; break; } @@ -895,6 +1067,263 @@ static const struct regmap_config nct6775_wmi_regmap_config = { .reg_write = nct6775_wmi_reg_write, }; +static const struct regmap_config nct6775_acpi_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .reg_read = nct6775_acpi_reg_read, + .reg_write = nct6775_acpi_reg_write, +}; + +/* Nuvoton SMBus address offsets */ +#define SMBHSTDAT 0 +#define SMBBLKSZ 1 +#define SMBHSTCMD 2 +//Index field is the Command field on other controllers +#define SMBHSTIDX 3 +#define SMBHSTCTL 4 +#define SMBHSTADD 5 +#define SMBHSTERR 9 +#define SMBHSTSTS 0xE + +/* Command register */ +#define NCT6793D_READ_BYTE 0 +#define NCT6793D_READ_WORD 1 +#define NCT6793D_WRITE_BYTE 8 +#define NCT6793D_WRITE_WORD 9 +#define NCT6793D_WRITE_BLOCK 10 + +/* Control register */ +#define NCT6793D_MANUAL_START 128 +#define NCT6793D_SOFT_RESET 64 + +/* Error register */ +#define NCT6793D_NO_ACK 32 + +/* Status register */ +#define NCT6793D_FIFO_EMPTY 1 +#define NCT6793D_MANUAL_ACTIVE 4 + +/* Other settings */ +#define MAX_RETRIES 400 + +/* Return negative errno on error. */ +static s32 nct6775_i2c_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + struct nct6775_data *adapdata = i2c_get_adapdata(adap); + union i2c_smbus_data tmp_data; + int timeout = 0, ret; + int i, len, cnt; + + tmp_data.word = 0; + cnt = 0; + len = 0; + + ret = adapdata->lock(adapdata); + if (ret) + return ret; + + outb_p(NCT6793D_SOFT_RESET, adapdata->addr + SMBHSTCTL); + + switch (size) { + case I2C_SMBUS_QUICK: + outb_p((addr << 1) | read_write, + adapdata->addr + SMBHSTADD); + break; + case I2C_SMBUS_BYTE_DATA: + tmp_data.byte = data->byte; + outb_p((addr << 1) | read_write, + adapdata->addr + SMBHSTADD); + outb_p(command, adapdata->addr + SMBHSTIDX); + if (read_write == I2C_SMBUS_WRITE) { + outb_p(tmp_data.byte, adapdata->addr + SMBHSTDAT); + outb_p(NCT6793D_WRITE_BYTE, adapdata->addr + SMBHSTCMD); + } else { + outb_p(NCT6793D_READ_BYTE, adapdata->addr + SMBHSTCMD); + } + break; + case I2C_SMBUS_BYTE: + outb_p((addr << 1) | read_write, + adapdata->addr + SMBHSTADD); + outb_p(command, adapdata->addr + SMBHSTIDX); + if (read_write == I2C_SMBUS_WRITE) { + outb_p(tmp_data.byte, adapdata->addr + SMBHSTDAT); + outb_p(NCT6793D_WRITE_BYTE, adapdata->addr + SMBHSTCMD); + } else { + outb_p(NCT6793D_READ_BYTE, adapdata->addr + SMBHSTCMD); + } + break; + case I2C_SMBUS_WORD_DATA: + outb_p((addr << 1) | read_write, + adapdata->addr + SMBHSTADD); + outb_p(command, adapdata->addr + SMBHSTIDX); + if (read_write == I2C_SMBUS_WRITE) { + outb_p(data->word & 0xff, adapdata->addr + SMBHSTDAT); + outb_p((data->word & 0xff00) >> 8, adapdata->addr + SMBHSTDAT); + outb_p(NCT6793D_WRITE_WORD, adapdata->addr + SMBHSTCMD); + } else { + outb_p(NCT6793D_READ_WORD, adapdata->addr + SMBHSTCMD); + } + break; + case I2C_SMBUS_BLOCK_DATA: + outb_p((addr << 1) | read_write, + adapdata->addr + SMBHSTADD); + outb_p(command, adapdata->addr + SMBHSTIDX); + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + + if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) { + ret = -EINVAL; + goto abort; + } + + outb_p(len, adapdata->addr + SMBBLKSZ); + + cnt = 1; + if (len >= 4) { + for (i = cnt; i <= 4; i++) + outb_p(data->block[i], adapdata->addr + SMBHSTDAT); + + len -= 4; + cnt += 4; + } else { + for (i = cnt; i <= len; i++) + outb_p(data->block[i], adapdata->addr + SMBHSTDAT); + + len = 0; + } + + outb_p(NCT6793D_WRITE_BLOCK, adapdata->addr + SMBHSTCMD); + } else { + ret = -EOPNOTSUPP; + goto abort; + } + break; + default: + dev_warn(&adap->dev, "Unsupported transaction %d\n", size); + ret = -EOPNOTSUPP; + goto abort; + } + + outb_p(NCT6793D_MANUAL_START, adapdata->addr + SMBHSTCTL); + + while ((size == I2C_SMBUS_BLOCK_DATA) && (len > 0)) { + if (read_write == I2C_SMBUS_WRITE) { + timeout = 0; + + while ((inb_p(adapdata->addr + SMBHSTSTS) & NCT6793D_FIFO_EMPTY) == 0) { + if (timeout > MAX_RETRIES) { + ret = -ETIMEDOUT; + goto abort; + } + + usleep_range(250, 500); + timeout++; + } + + // Load more bytes into FIFO + if (len >= 4) { + for (i = cnt; i <= (cnt + 4); i++) + outb_p(data->block[i], adapdata->addr + SMBHSTDAT); + + len -= 4; + cnt += 4; + } else { + for (i = cnt; i <= (cnt + len); i++) + outb_p(data->block[i], adapdata->addr + SMBHSTDAT); + + len = 0; + } + } else { + ret = -EOPNOTSUPP; + goto abort; + } + } + + //wait for manual mode to complete + timeout = 0; + while ((inb_p(adapdata->addr + SMBHSTSTS) & NCT6793D_MANUAL_ACTIVE) != 0) { + if (timeout > MAX_RETRIES) { + ret = -ETIMEDOUT; + goto abort; + } + + usleep_range(250, 500); + timeout++; + } + + if ((inb_p(adapdata->addr + SMBHSTERR) & NCT6793D_NO_ACK) != 0) { + ret = -ENXIO; + goto abort; + } + + if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK) + goto abort; + + switch (size) { + case I2C_SMBUS_QUICK: + case I2C_SMBUS_BYTE_DATA: + data->byte = inb_p(adapdata->addr + SMBHSTDAT); + break; + case I2C_SMBUS_WORD_DATA: + data->word = inb_p(adapdata->addr + SMBHSTDAT) + + (inb_p(adapdata->addr + SMBHSTDAT) << 8); + break; + } + +abort: + adapdata->unlock(adapdata, &adap->dev); + return ret; +} + +static u32 nct6775_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = nct6775_i2c_access, + .functionality = nct6775_i2c_func, +}; + +static int nct6775_i2c_add_adapter(acpi_handle acpi_wmi_mutex, struct nct6775_data *adapdata, + struct i2c_adapter **padap) +{ + struct i2c_adapter *adap; + int retval; + + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (!adap) + return -ENOMEM; + + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->algo = &smbus_algorithm; + + snprintf(adap->name, sizeof(adap->name), + "SMBus NCT67xx adapter at %04x", adapdata->addr); + + i2c_set_adapdata(adap, adapdata); + + retval = i2c_add_adapter(adap); + if (retval) { + kfree(adap); + return retval; + } + + *padap = adap; + return 0; +} + +static void nct6775_i2c_remove_adapter(struct i2c_adapter *adap) +{ + i2c_del_adapter(adap); + kfree(adap); +} + static int nct6775_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -902,6 +1331,7 @@ static int nct6775_platform_probe(struct platform_device *pdev) struct nct6775_data *data; struct resource *res; const struct regmap_config *regmapcfg; + int err; if (sio_data->access == access_direct) { res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -913,14 +1343,19 @@ 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; if (sio_data->access == access_direct) { data->addr = res->start; regmapcfg = &nct6775_regmap_config; - } else { + } else if (sio_data->access == access_asuswmi) { regmapcfg = &nct6775_wmi_regmap_config; + } else if (sio_data->access == access_asusacpi) { + regmapcfg = &nct6775_acpi_regmap_config; + } else { + return -ENODEV; } platform_set_drvdata(pdev, data); @@ -928,7 +1363,35 @@ static int nct6775_platform_probe(struct platform_device *pdev) data->driver_data = sio_data; data->driver_init = nct6775_platform_probe_init; - return nct6775_probe(&pdev->dev, data, regmapcfg); + err = nct6775_probe(&pdev->dev, data, regmapcfg); + + if (!err && sio_data->access == access_direct) { + switch (sio_data->kind) { + case nct6791: + case nct6792: + case nct6793: + case nct6795: + case nct6796: + case nct6798: + nct6775_i2c_add_adapter(data->acpi_wmi_mutex, data, + &data->i2c_adapter); + break; + default: + pr_err("i2c have not found"); + } + } + + return err; +} + +static int nct6775_remove(struct platform_device *pdev) +{ + struct nct6775_data *data = platform_get_drvdata(pdev); + + if (data->i2c_adapter) + nct6775_i2c_remove_adapter(data->i2c_adapter); + + return 0; } static struct platform_driver nct6775_driver = { @@ -937,6 +1400,7 @@ static struct platform_driver nct6775_driver = { .pm = &nct6775_dev_pm_ops, }, .probe = nct6775_platform_probe, + .remove = nct6775_remove, }; /* nct6775_find() looks for a '627 in the Super-I/O config space */ @@ -995,6 +1459,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 +1490,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); @@ -1092,6 +1559,124 @@ static const char * const asus_wmi_boards[] = { "TUF GAMING Z490-PLUS (WI-FI)", }; +static const char * const asus_acpi_boards[] = { + "ROG STRIX X670E-I GAMING WIFI", +}; +/* + * Callback for acpi_bus_for_each_dev() to find the + * right device by _UID and _HID and stop. + * return is an error to exit the loop + */ +static int nct6775_find_asus_acpi(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 (uid && !strcmp(uid, ASUSACPI_DEVICE_UID) && + hid && !strcmp(hid, ASUSACPI_DEVICE_HID)) { + asus_acpi_dev = adev; + return -EEXIST; + } + + return 0; +} + +static enum sensor_access nct6775_determine_access(const char *board_name) +{ + int ret; + u8 tmp; + enum sensor_access access = access_direct; + + ret = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards), + board_name); + if (ret >= 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); + return access_asuswmi; + } else { + pr_err("Can't read ChipID by Asus WMI.\n"); + } + } + + /* not WMI, try to find the ACPI device/method */ + ret = match_string(asus_acpi_boards, ARRAY_SIZE(asus_acpi_boards), + board_name); + if (ret >= 0) { + acpi_bus_for_each_dev(nct6775_find_asus_acpi, &asus_acpi_dev); + if (!asus_acpi_dev) + return access; + /* if reading chip id via ACPI succeeds, use ACPI */ + if (!nct6775_asusacpi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { + pr_info("Using Asus ACPI to access %#x chip.\n", tmp); + return access_asusacpi; + } else { + pr_err("Can't read ChipID by Asus ACPI.\n"); + } + } + + return access; +} + +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_LPCB_MUTEX, "\\_SB_.PCI0.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("MAXIMUS VII HERO", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("P8H67", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG MAXIMUS X HERO", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG MAXIMUS X HERO", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX Z370-H GAMING", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z170-DELUXE", &acpi_board_LPCB_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("Z170M-PLUS", &acpi_board_LPCB_MUTEX), + /* Possible i2c driver requirement */ + 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 X399-A", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME B450M-GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME Z270-A", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("PRIME Z370-A", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG CROSSHAIR VI Hero", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX X399-E GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX B350-F 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 Z270-E", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX Z370-E", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX Z490-F", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("ROG STRIX Z490-E GAMING", &acpi_board_SBRG_MUTEX), + DMI_MATCH_ASUS_WMI_BOARD("TUF B450 PLUS GAMING", &acpi_board_SBRG_MUTEX), + {} +}; +MODULE_DEVICE_TABLE(dmi, asus_wmi_info_table); + static int __init sensors_nct6775_platform_init(void) { int i, err; @@ -1102,7 +1687,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) @@ -1111,19 +1699,31 @@ static int __init sensors_nct6775_platform_init(void) board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); board_name = dmi_get_system_info(DMI_BOARD_NAME); + /* check if the board has WMI/ACPI access to the device */ if (board_name && board_vendor && - !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; + !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) + access = nct6775_determine_access(board_name); + + /* 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_err("Can't read ChipID by Asus WMI.\n"); + pr_info("No such ASUS mutex: %s\n", + board_info->acpi_mutex_path); } + } else { + pr_info("No mutex path\n"); } + } else { + pr_info("No dmi definition `%s`:`%s`\n", board_name, board_vendor); } /* @@ -1147,6 +1747,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; @@ -1154,6 +1755,12 @@ static int __init sensors_nct6775_platform_init(void) sio_data.sio_select = superio_wmi_select; sio_data.sio_enter = superio_wmi_enter; sio_data.sio_exit = superio_wmi_exit; + }else if (access == access_asusacpi) { + sio_data.sio_outb = superio_acpi_outb; + sio_data.sio_inb = superio_acpi_inb; + sio_data.sio_select = superio_acpi_select; + sio_data.sio_enter = superio_acpi_enter; + sio_data.sio_exit = superio_acpi_exit; } pdev[i] = platform_device_alloc(DRVNAME, address); @@ -1174,11 +1781,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..793f00d14716 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 */ @@ -176,6 +181,9 @@ struct nct6775_data { struct regmap *regmap; bool read_only; + /* ASUS boards specific i2c connected to nct6775 */ + struct i2c_adapter *i2c_adapter; + /* driver-specific (platform, i2c) initialization hook and data */ int (*driver_init)(struct nct6775_data *data); void *driver_data;