1c3963bc0SZev Weiss // SPDX-License-Identifier: GPL-2.0-or-later 2c3963bc0SZev Weiss /* 3c3963bc0SZev Weiss * nct6775 - Platform driver for the hardware monitoring 4c3963bc0SZev Weiss * functionality of Nuvoton NCT677x Super-I/O chips 5c3963bc0SZev Weiss * 6c3963bc0SZev Weiss * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net> 7c3963bc0SZev Weiss */ 8c3963bc0SZev Weiss 9c3963bc0SZev Weiss #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10c3963bc0SZev Weiss 11c3963bc0SZev Weiss #include <linux/acpi.h> 12c3963bc0SZev Weiss #include <linux/dmi.h> 13c3963bc0SZev Weiss #include <linux/hwmon-sysfs.h> 14c3963bc0SZev Weiss #include <linux/hwmon-vid.h> 15c3963bc0SZev Weiss #include <linux/init.h> 16c3963bc0SZev Weiss #include <linux/io.h> 17c3963bc0SZev Weiss #include <linux/module.h> 18c3963bc0SZev Weiss #include <linux/platform_device.h> 19c3963bc0SZev Weiss #include <linux/regmap.h> 20c3963bc0SZev Weiss 21c3963bc0SZev Weiss #include "nct6775.h" 22c3963bc0SZev Weiss 23c3963bc0SZev Weiss enum sensor_access { access_direct, access_asuswmi }; 24c3963bc0SZev Weiss 25c3963bc0SZev Weiss static const char * const nct6775_sio_names[] __initconst = { 26*efe86092SKees Cook [nct6106] = "NCT6106D", 27*efe86092SKees Cook [nct6116] = "NCT6116D", 28*efe86092SKees Cook [nct6775] = "NCT6775F", 29*efe86092SKees Cook [nct6776] = "NCT6776D/F", 30*efe86092SKees Cook [nct6779] = "NCT6779D", 31*efe86092SKees Cook [nct6791] = "NCT6791D", 32*efe86092SKees Cook [nct6792] = "NCT6792D", 33*efe86092SKees Cook [nct6793] = "NCT6793D", 34*efe86092SKees Cook [nct6795] = "NCT6795D", 35*efe86092SKees Cook [nct6796] = "NCT6796D", 36*efe86092SKees Cook [nct6797] = "NCT6797D", 37*efe86092SKees Cook [nct6798] = "NCT6798D", 38*efe86092SKees Cook [nct6799] = "NCT6796D-S/NCT6799D-R", 39c3963bc0SZev Weiss }; 40c3963bc0SZev Weiss 41c3963bc0SZev Weiss static unsigned short force_id; 42c3963bc0SZev Weiss module_param(force_id, ushort, 0); 43c3963bc0SZev Weiss MODULE_PARM_DESC(force_id, "Override the detected device ID"); 44c3963bc0SZev Weiss 45c3963bc0SZev Weiss static unsigned short fan_debounce; 46c3963bc0SZev Weiss module_param(fan_debounce, ushort, 0); 47c3963bc0SZev Weiss MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); 48c3963bc0SZev Weiss 49c3963bc0SZev Weiss #define DRVNAME "nct6775" 50c3963bc0SZev Weiss 51c3963bc0SZev Weiss #define NCT6775_PORT_CHIPID 0x58 52c3963bc0SZev Weiss 53c3963bc0SZev Weiss /* 54c3963bc0SZev Weiss * ISA constants 55c3963bc0SZev Weiss */ 56c3963bc0SZev Weiss 57c3963bc0SZev Weiss #define IOREGION_ALIGNMENT (~7) 58c3963bc0SZev Weiss #define IOREGION_OFFSET 5 59c3963bc0SZev Weiss #define IOREGION_LENGTH 2 60c3963bc0SZev Weiss #define ADDR_REG_OFFSET 0 61c3963bc0SZev Weiss #define DATA_REG_OFFSET 1 62c3963bc0SZev Weiss 63c3963bc0SZev Weiss /* 64c3963bc0SZev Weiss * Super-I/O constants and functions 65c3963bc0SZev Weiss */ 66c3963bc0SZev Weiss 67c3963bc0SZev Weiss #define NCT6775_LD_ACPI 0x0a 68c3963bc0SZev Weiss #define NCT6775_LD_HWM 0x0b 69c3963bc0SZev Weiss #define NCT6775_LD_VID 0x0d 70c3963bc0SZev Weiss #define NCT6775_LD_12 0x12 71c3963bc0SZev Weiss 72c3963bc0SZev Weiss #define SIO_REG_LDSEL 0x07 /* Logical device select */ 73c3963bc0SZev Weiss #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ 74c3963bc0SZev Weiss #define SIO_REG_ENABLE 0x30 /* Logical device enable */ 75c3963bc0SZev Weiss #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ 76c3963bc0SZev Weiss 77c3963bc0SZev Weiss #define SIO_NCT6106_ID 0xc450 78c3963bc0SZev Weiss #define SIO_NCT6116_ID 0xd280 79c3963bc0SZev Weiss #define SIO_NCT6775_ID 0xb470 80c3963bc0SZev Weiss #define SIO_NCT6776_ID 0xc330 81c3963bc0SZev Weiss #define SIO_NCT6779_ID 0xc560 82c3963bc0SZev Weiss #define SIO_NCT6791_ID 0xc800 83c3963bc0SZev Weiss #define SIO_NCT6792_ID 0xc910 84c3963bc0SZev Weiss #define SIO_NCT6793_ID 0xd120 85c3963bc0SZev Weiss #define SIO_NCT6795_ID 0xd350 86c3963bc0SZev Weiss #define SIO_NCT6796_ID 0xd420 87c3963bc0SZev Weiss #define SIO_NCT6797_ID 0xd450 88c3963bc0SZev Weiss #define SIO_NCT6798_ID 0xd428 89aee395bbSGuenter Roeck #define SIO_NCT6799_ID 0xd800 90c3963bc0SZev Weiss #define SIO_ID_MASK 0xFFF8 91c3963bc0SZev Weiss 92c3963bc0SZev Weiss /* 93c3963bc0SZev Weiss * Control registers 94c3963bc0SZev Weiss */ 95c3963bc0SZev Weiss #define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0 96c3963bc0SZev Weiss 97c3963bc0SZev Weiss struct nct6775_sio_data { 98c3963bc0SZev Weiss int sioreg; 99c3963bc0SZev Weiss int ld; 100c3963bc0SZev Weiss enum kinds kind; 101c3963bc0SZev Weiss enum sensor_access access; 102c3963bc0SZev Weiss 103c3963bc0SZev Weiss /* superio_() callbacks */ 104c3963bc0SZev Weiss void (*sio_outb)(struct nct6775_sio_data *sio_data, int reg, int val); 105c3963bc0SZev Weiss int (*sio_inb)(struct nct6775_sio_data *sio_data, int reg); 106c3963bc0SZev Weiss void (*sio_select)(struct nct6775_sio_data *sio_data, int ld); 107c3963bc0SZev Weiss int (*sio_enter)(struct nct6775_sio_data *sio_data); 108c3963bc0SZev Weiss void (*sio_exit)(struct nct6775_sio_data *sio_data); 109c3963bc0SZev Weiss }; 110c3963bc0SZev Weiss 111c3b3747dSDenis Pauk #define ASUSWMI_METHOD "WMBD" 112c3963bc0SZev Weiss #define ASUSWMI_METHODID_RSIO 0x5253494F 113c3963bc0SZev Weiss #define ASUSWMI_METHODID_WSIO 0x5753494F 114c3963bc0SZev Weiss #define ASUSWMI_METHODID_RHWM 0x5248574D 115c3963bc0SZev Weiss #define ASUSWMI_METHODID_WHWM 0x5748574D 116c3963bc0SZev Weiss #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE 117c3b3747dSDenis Pauk #define ASUSWMI_DEVICE_HID "PNP0C14" 118c3b3747dSDenis Pauk #define ASUSWMI_DEVICE_UID "ASUSWMI" 119e2e09989SDenis Pauk #define ASUSMSI_DEVICE_UID "AsusMbSwInterface" 120c3b3747dSDenis Pauk 121c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 122c3b3747dSDenis Pauk /* 123c3b3747dSDenis Pauk * ASUS boards have only one device with WMI "WMBD" method and have provided 124c3b3747dSDenis Pauk * access to only one SuperIO chip at 0x0290. 125c3b3747dSDenis Pauk */ 126c3b3747dSDenis Pauk static struct acpi_device *asus_acpi_dev; 127c3b3747dSDenis Pauk #endif 128c3963bc0SZev Weiss 129c3963bc0SZev Weiss static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) 130c3963bc0SZev Weiss { 131c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 132c3b3747dSDenis Pauk acpi_handle handle = acpi_device_handle(asus_acpi_dev); 133c3963bc0SZev Weiss u32 args = bank | (reg << 8) | (val << 16); 134c3b3747dSDenis Pauk struct acpi_object_list input; 135c3b3747dSDenis Pauk union acpi_object params[3]; 136c3b3747dSDenis Pauk unsigned long long result; 137c3963bc0SZev Weiss acpi_status status; 138c3963bc0SZev Weiss 139c3b3747dSDenis Pauk params[0].type = ACPI_TYPE_INTEGER; 140c3b3747dSDenis Pauk params[0].integer.value = 0; 141c3b3747dSDenis Pauk params[1].type = ACPI_TYPE_INTEGER; 142c3b3747dSDenis Pauk params[1].integer.value = method_id; 143c3b3747dSDenis Pauk params[2].type = ACPI_TYPE_BUFFER; 144c3b3747dSDenis Pauk params[2].buffer.length = sizeof(args); 145c3b3747dSDenis Pauk params[2].buffer.pointer = (void *)&args; 146c3b3747dSDenis Pauk input.count = 3; 147c3b3747dSDenis Pauk input.pointer = params; 148c3963bc0SZev Weiss 149c3b3747dSDenis Pauk status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result); 150c3963bc0SZev Weiss if (ACPI_FAILURE(status)) 151c3963bc0SZev Weiss return -EIO; 152c3963bc0SZev Weiss 153c3963bc0SZev Weiss if (retval) 15408d40c1dSAndy Shevchenko *retval = result; 155c3963bc0SZev Weiss 156c3963bc0SZev Weiss return 0; 157c3963bc0SZev Weiss #else 158c3963bc0SZev Weiss return -EOPNOTSUPP; 159c3963bc0SZev Weiss #endif 160c3963bc0SZev Weiss } 161c3963bc0SZev Weiss 162c3963bc0SZev Weiss static inline int nct6775_asuswmi_write(u8 bank, u8 reg, u8 val) 163c3963bc0SZev Weiss { 164c3963bc0SZev Weiss return nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_WHWM, bank, 165c3963bc0SZev Weiss reg, val, NULL); 166c3963bc0SZev Weiss } 167c3963bc0SZev Weiss 168c3963bc0SZev Weiss static inline int nct6775_asuswmi_read(u8 bank, u8 reg, u8 *val) 169c3963bc0SZev Weiss { 170c3963bc0SZev Weiss u32 ret, tmp = 0; 171c3963bc0SZev Weiss 172c3963bc0SZev Weiss ret = nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RHWM, bank, 173c3963bc0SZev Weiss reg, 0, &tmp); 174c3963bc0SZev Weiss *val = tmp; 175c3963bc0SZev Weiss return ret; 176c3963bc0SZev Weiss } 177c3963bc0SZev Weiss 178c3963bc0SZev Weiss static int superio_wmi_inb(struct nct6775_sio_data *sio_data, int reg) 179c3963bc0SZev Weiss { 180c3963bc0SZev Weiss int tmp = 0; 181c3963bc0SZev Weiss 182c3963bc0SZev Weiss nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RSIO, sio_data->ld, 183c3963bc0SZev Weiss reg, 0, &tmp); 184c3963bc0SZev Weiss return tmp; 185c3963bc0SZev Weiss } 186c3963bc0SZev Weiss 187c3963bc0SZev Weiss static void superio_wmi_outb(struct nct6775_sio_data *sio_data, int reg, int val) 188c3963bc0SZev Weiss { 189c3963bc0SZev Weiss nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_WSIO, sio_data->ld, 190c3963bc0SZev Weiss reg, val, NULL); 191c3963bc0SZev Weiss } 192c3963bc0SZev Weiss 193c3963bc0SZev Weiss static void superio_wmi_select(struct nct6775_sio_data *sio_data, int ld) 194c3963bc0SZev Weiss { 195c3963bc0SZev Weiss sio_data->ld = ld; 196c3963bc0SZev Weiss } 197c3963bc0SZev Weiss 198c3963bc0SZev Weiss static int superio_wmi_enter(struct nct6775_sio_data *sio_data) 199c3963bc0SZev Weiss { 200c3963bc0SZev Weiss return 0; 201c3963bc0SZev Weiss } 202c3963bc0SZev Weiss 203c3963bc0SZev Weiss static void superio_wmi_exit(struct nct6775_sio_data *sio_data) 204c3963bc0SZev Weiss { 205c3963bc0SZev Weiss } 206c3963bc0SZev Weiss 207c3963bc0SZev Weiss static void superio_outb(struct nct6775_sio_data *sio_data, int reg, int val) 208c3963bc0SZev Weiss { 209c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 210c3963bc0SZev Weiss 211c3963bc0SZev Weiss outb(reg, ioreg); 212c3963bc0SZev Weiss outb(val, ioreg + 1); 213c3963bc0SZev Weiss } 214c3963bc0SZev Weiss 215c3963bc0SZev Weiss static int superio_inb(struct nct6775_sio_data *sio_data, int reg) 216c3963bc0SZev Weiss { 217c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 218c3963bc0SZev Weiss 219c3963bc0SZev Weiss outb(reg, ioreg); 220c3963bc0SZev Weiss return inb(ioreg + 1); 221c3963bc0SZev Weiss } 222c3963bc0SZev Weiss 223c3963bc0SZev Weiss static void superio_select(struct nct6775_sio_data *sio_data, int ld) 224c3963bc0SZev Weiss { 225c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 226c3963bc0SZev Weiss 227c3963bc0SZev Weiss outb(SIO_REG_LDSEL, ioreg); 228c3963bc0SZev Weiss outb(ld, ioreg + 1); 229c3963bc0SZev Weiss } 230c3963bc0SZev Weiss 231c3963bc0SZev Weiss static int superio_enter(struct nct6775_sio_data *sio_data) 232c3963bc0SZev Weiss { 233c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 234c3963bc0SZev Weiss 235c3963bc0SZev Weiss /* 236c3963bc0SZev Weiss * Try to reserve <ioreg> and <ioreg + 1> for exclusive access. 237c3963bc0SZev Weiss */ 238c3963bc0SZev Weiss if (!request_muxed_region(ioreg, 2, DRVNAME)) 239c3963bc0SZev Weiss return -EBUSY; 240c3963bc0SZev Weiss 241c3963bc0SZev Weiss outb(0x87, ioreg); 242c3963bc0SZev Weiss outb(0x87, ioreg); 243c3963bc0SZev Weiss 244c3963bc0SZev Weiss return 0; 245c3963bc0SZev Weiss } 246c3963bc0SZev Weiss 247c3963bc0SZev Weiss static void superio_exit(struct nct6775_sio_data *sio_data) 248c3963bc0SZev Weiss { 249c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 250c3963bc0SZev Weiss 251c3963bc0SZev Weiss outb(0xaa, ioreg); 252c3963bc0SZev Weiss outb(0x02, ioreg); 253c3963bc0SZev Weiss outb(0x02, ioreg + 1); 254c3963bc0SZev Weiss release_region(ioreg, 2); 255c3963bc0SZev Weiss } 256c3963bc0SZev Weiss 257c3963bc0SZev Weiss static inline void nct6775_wmi_set_bank(struct nct6775_data *data, u16 reg) 258c3963bc0SZev Weiss { 259c3963bc0SZev Weiss u8 bank = reg >> 8; 260c3963bc0SZev Weiss 261c3963bc0SZev Weiss data->bank = bank; 262c3963bc0SZev Weiss } 263c3963bc0SZev Weiss 264c3963bc0SZev Weiss static int nct6775_wmi_reg_read(void *ctx, unsigned int reg, unsigned int *val) 265c3963bc0SZev Weiss { 266c3963bc0SZev Weiss struct nct6775_data *data = ctx; 267c3963bc0SZev Weiss int err, word_sized = nct6775_reg_is_word_sized(data, reg); 268c3963bc0SZev Weiss u8 tmp = 0; 269c3963bc0SZev Weiss u16 res; 270c3963bc0SZev Weiss 271c3963bc0SZev Weiss nct6775_wmi_set_bank(data, reg); 272c3963bc0SZev Weiss 273c3963bc0SZev Weiss err = nct6775_asuswmi_read(data->bank, reg & 0xff, &tmp); 274c3963bc0SZev Weiss if (err) 275c3963bc0SZev Weiss return err; 276c3963bc0SZev Weiss 277c3963bc0SZev Weiss res = tmp; 278c3963bc0SZev Weiss if (word_sized) { 279c3963bc0SZev Weiss err = nct6775_asuswmi_read(data->bank, (reg & 0xff) + 1, &tmp); 280c3963bc0SZev Weiss if (err) 281c3963bc0SZev Weiss return err; 282c3963bc0SZev Weiss 283c3963bc0SZev Weiss res = (res << 8) + tmp; 284c3963bc0SZev Weiss } 285c3963bc0SZev Weiss *val = res; 286c3963bc0SZev Weiss return 0; 287c3963bc0SZev Weiss } 288c3963bc0SZev Weiss 289c3963bc0SZev Weiss static int nct6775_wmi_reg_write(void *ctx, unsigned int reg, unsigned int value) 290c3963bc0SZev Weiss { 291c3963bc0SZev Weiss struct nct6775_data *data = ctx; 292c3963bc0SZev Weiss int res, word_sized = nct6775_reg_is_word_sized(data, reg); 293c3963bc0SZev Weiss 294c3963bc0SZev Weiss nct6775_wmi_set_bank(data, reg); 295c3963bc0SZev Weiss 296c3963bc0SZev Weiss if (word_sized) { 297c3963bc0SZev Weiss res = nct6775_asuswmi_write(data->bank, reg & 0xff, value >> 8); 298c3963bc0SZev Weiss if (res) 299c3963bc0SZev Weiss return res; 300c3963bc0SZev Weiss 301c3963bc0SZev Weiss res = nct6775_asuswmi_write(data->bank, (reg & 0xff) + 1, value); 302c3963bc0SZev Weiss } else { 303c3963bc0SZev Weiss res = nct6775_asuswmi_write(data->bank, reg & 0xff, value); 304c3963bc0SZev Weiss } 305c3963bc0SZev Weiss 306c3963bc0SZev Weiss return res; 307c3963bc0SZev Weiss } 308c3963bc0SZev Weiss 309c3963bc0SZev Weiss /* 310c3963bc0SZev Weiss * On older chips, only registers 0x50-0x5f are banked. 311c3963bc0SZev Weiss * On more recent chips, all registers are banked. 312c3963bc0SZev Weiss * Assume that is the case and set the bank number for each access. 313c3963bc0SZev Weiss * Cache the bank number so it only needs to be set if it changes. 314c3963bc0SZev Weiss */ 315c3963bc0SZev Weiss static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg) 316c3963bc0SZev Weiss { 317c3963bc0SZev Weiss u8 bank = reg >> 8; 318c3963bc0SZev Weiss 319c3963bc0SZev Weiss if (data->bank != bank) { 320c3963bc0SZev Weiss outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET); 321c3963bc0SZev Weiss outb_p(bank, data->addr + DATA_REG_OFFSET); 322c3963bc0SZev Weiss data->bank = bank; 323c3963bc0SZev Weiss } 324c3963bc0SZev Weiss } 325c3963bc0SZev Weiss 326c3963bc0SZev Weiss static int nct6775_reg_read(void *ctx, unsigned int reg, unsigned int *val) 327c3963bc0SZev Weiss { 328c3963bc0SZev Weiss struct nct6775_data *data = ctx; 329c3963bc0SZev Weiss int word_sized = nct6775_reg_is_word_sized(data, reg); 330c3963bc0SZev Weiss 331c3963bc0SZev Weiss nct6775_set_bank(data, reg); 332c3963bc0SZev Weiss outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); 333c3963bc0SZev Weiss *val = inb_p(data->addr + DATA_REG_OFFSET); 334c3963bc0SZev Weiss if (word_sized) { 335c3963bc0SZev Weiss outb_p((reg & 0xff) + 1, 336c3963bc0SZev Weiss data->addr + ADDR_REG_OFFSET); 337c3963bc0SZev Weiss *val = (*val << 8) + inb_p(data->addr + DATA_REG_OFFSET); 338c3963bc0SZev Weiss } 339c3963bc0SZev Weiss return 0; 340c3963bc0SZev Weiss } 341c3963bc0SZev Weiss 342c3963bc0SZev Weiss static int nct6775_reg_write(void *ctx, unsigned int reg, unsigned int value) 343c3963bc0SZev Weiss { 344c3963bc0SZev Weiss struct nct6775_data *data = ctx; 345c3963bc0SZev Weiss int word_sized = nct6775_reg_is_word_sized(data, reg); 346c3963bc0SZev Weiss 347c3963bc0SZev Weiss nct6775_set_bank(data, reg); 348c3963bc0SZev Weiss outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); 349c3963bc0SZev Weiss if (word_sized) { 350c3963bc0SZev Weiss outb_p(value >> 8, data->addr + DATA_REG_OFFSET); 351c3963bc0SZev Weiss outb_p((reg & 0xff) + 1, 352c3963bc0SZev Weiss data->addr + ADDR_REG_OFFSET); 353c3963bc0SZev Weiss } 354c3963bc0SZev Weiss outb_p(value & 0xff, data->addr + DATA_REG_OFFSET); 355c3963bc0SZev Weiss return 0; 356c3963bc0SZev Weiss } 357c3963bc0SZev Weiss 358c3963bc0SZev Weiss static void nct6791_enable_io_mapping(struct nct6775_sio_data *sio_data) 359c3963bc0SZev Weiss { 360c3963bc0SZev Weiss int val; 361c3963bc0SZev Weiss 362c3963bc0SZev Weiss val = sio_data->sio_inb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE); 363c3963bc0SZev Weiss if (val & 0x10) { 364c3963bc0SZev Weiss pr_info("Enabling hardware monitor logical device mappings.\n"); 365c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE, 366c3963bc0SZev Weiss val & ~0x10); 367c3963bc0SZev Weiss } 368c3963bc0SZev Weiss } 369c3963bc0SZev Weiss 3708de7295cSJonathan Cameron static int nct6775_suspend(struct device *dev) 371c3963bc0SZev Weiss { 372c3963bc0SZev Weiss int err; 373c3963bc0SZev Weiss u16 tmp; 374f4e6960fSZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 375c3963bc0SZev Weiss 376c3963bc0SZev Weiss if (IS_ERR(data)) 377c3963bc0SZev Weiss return PTR_ERR(data); 378c3963bc0SZev Weiss 379c3963bc0SZev Weiss mutex_lock(&data->update_lock); 380c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_VBAT, &tmp); 381c3963bc0SZev Weiss if (err) 382c3963bc0SZev Weiss goto out; 383c3963bc0SZev Weiss data->vbat = tmp; 384c3963bc0SZev Weiss if (data->kind == nct6775) { 385c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_FANDIV1, &tmp); 386c3963bc0SZev Weiss if (err) 387c3963bc0SZev Weiss goto out; 388c3963bc0SZev Weiss data->fandiv1 = tmp; 389c3963bc0SZev Weiss 390c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_FANDIV2, &tmp); 391c3963bc0SZev Weiss if (err) 392c3963bc0SZev Weiss goto out; 393c3963bc0SZev Weiss data->fandiv2 = tmp; 394c3963bc0SZev Weiss } 395c3963bc0SZev Weiss out: 396c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 397c3963bc0SZev Weiss 398c3963bc0SZev Weiss return err; 399c3963bc0SZev Weiss } 400c3963bc0SZev Weiss 4018de7295cSJonathan Cameron static int nct6775_resume(struct device *dev) 402c3963bc0SZev Weiss { 403c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 404c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = dev_get_platdata(dev); 405c3963bc0SZev Weiss int i, j, err = 0; 406c3963bc0SZev Weiss u8 reg; 407c3963bc0SZev Weiss 408c3963bc0SZev Weiss mutex_lock(&data->update_lock); 409c3963bc0SZev Weiss data->bank = 0xff; /* Force initial bank selection */ 410c3963bc0SZev Weiss 411c3963bc0SZev Weiss err = sio_data->sio_enter(sio_data); 412c3963bc0SZev Weiss if (err) 413c3963bc0SZev Weiss goto abort; 414c3963bc0SZev Weiss 415c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 416c3963bc0SZev Weiss reg = sio_data->sio_inb(sio_data, SIO_REG_ENABLE); 417c3963bc0SZev Weiss if (reg != data->sio_reg_enable) 418c3963bc0SZev Weiss sio_data->sio_outb(sio_data, SIO_REG_ENABLE, data->sio_reg_enable); 419c3963bc0SZev Weiss 420c3963bc0SZev Weiss if (data->kind == nct6791 || data->kind == nct6792 || 421c3963bc0SZev Weiss data->kind == nct6793 || data->kind == nct6795 || 422c3963bc0SZev Weiss data->kind == nct6796 || data->kind == nct6797 || 423aee395bbSGuenter Roeck data->kind == nct6798 || data->kind == nct6799) 424c3963bc0SZev Weiss nct6791_enable_io_mapping(sio_data); 425c3963bc0SZev Weiss 426c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 427c3963bc0SZev Weiss 428c3963bc0SZev Weiss /* Restore limits */ 429c3963bc0SZev Weiss for (i = 0; i < data->in_num; i++) { 430c3963bc0SZev Weiss if (!(data->have_in & BIT(i))) 431c3963bc0SZev Weiss continue; 432c3963bc0SZev Weiss 433c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_IN_MINMAX[0][i], data->in[i][1]); 434c3963bc0SZev Weiss if (err) 435c3963bc0SZev Weiss goto abort; 436c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_IN_MINMAX[1][i], data->in[i][2]); 437c3963bc0SZev Weiss if (err) 438c3963bc0SZev Weiss goto abort; 439c3963bc0SZev Weiss } 440c3963bc0SZev Weiss 441c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { 442c3963bc0SZev Weiss if (!(data->has_fan_min & BIT(i))) 443c3963bc0SZev Weiss continue; 444c3963bc0SZev Weiss 445c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MIN[i], data->fan_min[i]); 446c3963bc0SZev Weiss if (err) 447c3963bc0SZev Weiss goto abort; 448c3963bc0SZev Weiss } 449c3963bc0SZev Weiss 450c3963bc0SZev Weiss for (i = 0; i < NUM_TEMP; i++) { 451c3963bc0SZev Weiss if (!(data->have_temp & BIT(i))) 452c3963bc0SZev Weiss continue; 453c3963bc0SZev Weiss 454c3963bc0SZev Weiss for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++) 455c3963bc0SZev Weiss if (data->reg_temp[j][i]) { 456c3963bc0SZev Weiss err = nct6775_write_temp(data, data->reg_temp[j][i], 457c3963bc0SZev Weiss data->temp[j][i]); 458c3963bc0SZev Weiss if (err) 459c3963bc0SZev Weiss goto abort; 460c3963bc0SZev Weiss } 461c3963bc0SZev Weiss } 462c3963bc0SZev Weiss 463c3963bc0SZev Weiss /* Restore other settings */ 464c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_VBAT, data->vbat); 465c3963bc0SZev Weiss if (err) 466c3963bc0SZev Weiss goto abort; 467c3963bc0SZev Weiss if (data->kind == nct6775) { 468c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1); 469c3963bc0SZev Weiss if (err) 470c3963bc0SZev Weiss goto abort; 471c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2); 472c3963bc0SZev Weiss } 473c3963bc0SZev Weiss 474c3963bc0SZev Weiss abort: 475c3963bc0SZev Weiss /* Force re-reading all values */ 476c3963bc0SZev Weiss data->valid = false; 477c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 478c3963bc0SZev Weiss 479c3963bc0SZev Weiss return err; 480c3963bc0SZev Weiss } 481c3963bc0SZev Weiss 4828de7295cSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume); 483c3963bc0SZev Weiss 484c3963bc0SZev Weiss static void 485c3963bc0SZev Weiss nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio_data) 486c3963bc0SZev Weiss { 487c3963bc0SZev Weiss bool fan3pin = false, fan4pin = false, fan4min = false; 488c3963bc0SZev Weiss bool fan5pin = false, fan6pin = false, fan7pin = false; 489c3963bc0SZev Weiss bool pwm3pin = false, pwm4pin = false, pwm5pin = false; 490c3963bc0SZev Weiss bool pwm6pin = false, pwm7pin = false; 491c3963bc0SZev Weiss 492c3963bc0SZev Weiss /* Store SIO_REG_ENABLE for use during resume */ 493c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 494c3963bc0SZev Weiss data->sio_reg_enable = sio_data->sio_inb(sio_data, SIO_REG_ENABLE); 495c3963bc0SZev Weiss 496c3963bc0SZev Weiss /* fan4 and fan5 share some pins with the GPIO and serial flash */ 497c3963bc0SZev Weiss if (data->kind == nct6775) { 498c3963bc0SZev Weiss int cr2c = sio_data->sio_inb(sio_data, 0x2c); 499c3963bc0SZev Weiss 500c3963bc0SZev Weiss fan3pin = cr2c & BIT(6); 501c3963bc0SZev Weiss pwm3pin = cr2c & BIT(7); 502c3963bc0SZev Weiss 503c3963bc0SZev Weiss /* On NCT6775, fan4 shares pins with the fdc interface */ 504c3963bc0SZev Weiss fan4pin = !(sio_data->sio_inb(sio_data, 0x2A) & 0x80); 505c3963bc0SZev Weiss } else if (data->kind == nct6776) { 506c3963bc0SZev Weiss bool gpok = sio_data->sio_inb(sio_data, 0x27) & 0x80; 507c3963bc0SZev Weiss const char *board_vendor, *board_name; 508c3963bc0SZev Weiss 509c3963bc0SZev Weiss board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 510c3963bc0SZev Weiss board_name = dmi_get_system_info(DMI_BOARD_NAME); 511c3963bc0SZev Weiss 512c3963bc0SZev Weiss if (board_name && board_vendor && 513c3963bc0SZev Weiss !strcmp(board_vendor, "ASRock")) { 514c3963bc0SZev Weiss /* 515c3963bc0SZev Weiss * Auxiliary fan monitoring is not enabled on ASRock 516c3963bc0SZev Weiss * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode. 517c3963bc0SZev Weiss * Observed with BIOS version 2.00. 518c3963bc0SZev Weiss */ 519c3963bc0SZev Weiss if (!strcmp(board_name, "Z77 Pro4-M")) { 520c3963bc0SZev Weiss if ((data->sio_reg_enable & 0xe0) != 0xe0) { 521c3963bc0SZev Weiss data->sio_reg_enable |= 0xe0; 522c3963bc0SZev Weiss sio_data->sio_outb(sio_data, SIO_REG_ENABLE, 523c3963bc0SZev Weiss data->sio_reg_enable); 524c3963bc0SZev Weiss } 525c3963bc0SZev Weiss } 526c3963bc0SZev Weiss } 527c3963bc0SZev Weiss 528c3963bc0SZev Weiss if (data->sio_reg_enable & 0x80) 529c3963bc0SZev Weiss fan3pin = gpok; 530c3963bc0SZev Weiss else 531c3963bc0SZev Weiss fan3pin = !(sio_data->sio_inb(sio_data, 0x24) & 0x40); 532c3963bc0SZev Weiss 533c3963bc0SZev Weiss if (data->sio_reg_enable & 0x40) 534c3963bc0SZev Weiss fan4pin = gpok; 535c3963bc0SZev Weiss else 536c3963bc0SZev Weiss fan4pin = sio_data->sio_inb(sio_data, 0x1C) & 0x01; 537c3963bc0SZev Weiss 538c3963bc0SZev Weiss if (data->sio_reg_enable & 0x20) 539c3963bc0SZev Weiss fan5pin = gpok; 540c3963bc0SZev Weiss else 541c3963bc0SZev Weiss fan5pin = sio_data->sio_inb(sio_data, 0x1C) & 0x02; 542c3963bc0SZev Weiss 543c3963bc0SZev Weiss fan4min = fan4pin; 544c3963bc0SZev Weiss pwm3pin = fan3pin; 545c3963bc0SZev Weiss } else if (data->kind == nct6106) { 546c3963bc0SZev Weiss int cr24 = sio_data->sio_inb(sio_data, 0x24); 547c3963bc0SZev Weiss 548c3963bc0SZev Weiss fan3pin = !(cr24 & 0x80); 549c3963bc0SZev Weiss pwm3pin = cr24 & 0x08; 550c3963bc0SZev Weiss } else if (data->kind == nct6116) { 551c3963bc0SZev Weiss int cr1a = sio_data->sio_inb(sio_data, 0x1a); 552c3963bc0SZev Weiss int cr1b = sio_data->sio_inb(sio_data, 0x1b); 553c3963bc0SZev Weiss int cr24 = sio_data->sio_inb(sio_data, 0x24); 554c3963bc0SZev Weiss int cr2a = sio_data->sio_inb(sio_data, 0x2a); 555c3963bc0SZev Weiss int cr2b = sio_data->sio_inb(sio_data, 0x2b); 556c3963bc0SZev Weiss int cr2f = sio_data->sio_inb(sio_data, 0x2f); 557c3963bc0SZev Weiss 558c3963bc0SZev Weiss fan3pin = !(cr2b & 0x10); 559c3963bc0SZev Weiss fan4pin = (cr2b & 0x80) || // pin 1(2) 560c3963bc0SZev Weiss (!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66) 561c3963bc0SZev Weiss fan5pin = (cr2b & 0x80) || // pin 126(127) 562c3963bc0SZev Weiss (!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96) 563c3963bc0SZev Weiss 564c3963bc0SZev Weiss pwm3pin = fan3pin && (cr24 & 0x08); 565c3963bc0SZev Weiss pwm4pin = fan4pin; 566c3963bc0SZev Weiss pwm5pin = fan5pin; 567c3963bc0SZev Weiss } else { 568c3963bc0SZev Weiss /* 569c3963bc0SZev Weiss * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, 570aee395bbSGuenter Roeck * NCT6797D, NCT6798D, NCT6799D 571c3963bc0SZev Weiss */ 572c3963bc0SZev Weiss int cr1a = sio_data->sio_inb(sio_data, 0x1a); 573c3963bc0SZev Weiss int cr1b = sio_data->sio_inb(sio_data, 0x1b); 574c3963bc0SZev Weiss int cr1c = sio_data->sio_inb(sio_data, 0x1c); 575c3963bc0SZev Weiss int cr1d = sio_data->sio_inb(sio_data, 0x1d); 576c3963bc0SZev Weiss int cr2a = sio_data->sio_inb(sio_data, 0x2a); 577c3963bc0SZev Weiss int cr2b = sio_data->sio_inb(sio_data, 0x2b); 578c3963bc0SZev Weiss int cr2d = sio_data->sio_inb(sio_data, 0x2d); 579c3963bc0SZev Weiss int cr2f = sio_data->sio_inb(sio_data, 0x2f); 580aee395bbSGuenter Roeck bool vsb_ctl_en = cr2f & BIT(0); 581c3963bc0SZev Weiss bool dsw_en = cr2f & BIT(3); 582c3963bc0SZev Weiss bool ddr4_en = cr2f & BIT(4); 583aee395bbSGuenter Roeck bool as_seq1_en = cr2f & BIT(7); 584c3963bc0SZev Weiss int cre0; 585aee395bbSGuenter Roeck int cre6; 586c3963bc0SZev Weiss int creb; 587c3963bc0SZev Weiss int cred; 588c3963bc0SZev Weiss 589368da76bSAhmad Khalifa cre6 = sio_data->sio_inb(sio_data, 0xe6); 590aee395bbSGuenter Roeck 591c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_12); 592c3963bc0SZev Weiss cre0 = sio_data->sio_inb(sio_data, 0xe0); 593c3963bc0SZev Weiss creb = sio_data->sio_inb(sio_data, 0xeb); 594c3963bc0SZev Weiss cred = sio_data->sio_inb(sio_data, 0xed); 595c3963bc0SZev Weiss 596c3963bc0SZev Weiss fan3pin = !(cr1c & BIT(5)); 597c3963bc0SZev Weiss fan4pin = !(cr1c & BIT(6)); 598c3963bc0SZev Weiss fan5pin = !(cr1c & BIT(7)); 599c3963bc0SZev Weiss 600c3963bc0SZev Weiss pwm3pin = !(cr1c & BIT(0)); 601c3963bc0SZev Weiss pwm4pin = !(cr1c & BIT(1)); 602c3963bc0SZev Weiss pwm5pin = !(cr1c & BIT(2)); 603c3963bc0SZev Weiss 604c3963bc0SZev Weiss switch (data->kind) { 605c3963bc0SZev Weiss case nct6791: 606c3963bc0SZev Weiss fan6pin = cr2d & BIT(1); 607c3963bc0SZev Weiss pwm6pin = cr2d & BIT(0); 608c3963bc0SZev Weiss break; 609c3963bc0SZev Weiss case nct6792: 610c3963bc0SZev Weiss fan6pin = !dsw_en && (cr2d & BIT(1)); 611c3963bc0SZev Weiss pwm6pin = !dsw_en && (cr2d & BIT(0)); 612c3963bc0SZev Weiss break; 613c3963bc0SZev Weiss case nct6793: 614c3963bc0SZev Weiss fan5pin |= cr1b & BIT(5); 615c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 616c3963bc0SZev Weiss 617c3963bc0SZev Weiss fan6pin = !dsw_en && (cr2d & BIT(1)); 618c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 619c3963bc0SZev Weiss 620c3963bc0SZev Weiss pwm5pin |= cr2d & BIT(7); 621c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 622c3963bc0SZev Weiss 623c3963bc0SZev Weiss pwm6pin = !dsw_en && (cr2d & BIT(0)); 624c3963bc0SZev Weiss pwm6pin |= creb & BIT(2); 625c3963bc0SZev Weiss break; 626c3963bc0SZev Weiss case nct6795: 627c3963bc0SZev Weiss fan5pin |= cr1b & BIT(5); 628c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 629c3963bc0SZev Weiss 630c3963bc0SZev Weiss fan6pin = (cr2a & BIT(4)) && 631c3963bc0SZev Weiss (!dsw_en || (cred & BIT(4))); 632c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 633c3963bc0SZev Weiss 634c3963bc0SZev Weiss pwm5pin |= cr2d & BIT(7); 635c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 636c3963bc0SZev Weiss 637c3963bc0SZev Weiss pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2)); 638c3963bc0SZev Weiss pwm6pin |= creb & BIT(2); 639c3963bc0SZev Weiss break; 640c3963bc0SZev Weiss case nct6796: 641c3963bc0SZev Weiss fan5pin |= cr1b & BIT(5); 642c3963bc0SZev Weiss fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0)); 643c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 644c3963bc0SZev Weiss 645c3963bc0SZev Weiss fan6pin = (cr2a & BIT(4)) && 646c3963bc0SZev Weiss (!dsw_en || (cred & BIT(4))); 647c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 648c3963bc0SZev Weiss 649c3963bc0SZev Weiss fan7pin = !(cr2b & BIT(2)); 650c3963bc0SZev Weiss 651c3963bc0SZev Weiss pwm5pin |= cr2d & BIT(7); 652c3963bc0SZev Weiss pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0)); 653c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 654c3963bc0SZev Weiss 655c3963bc0SZev Weiss pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2)); 656c3963bc0SZev Weiss pwm6pin |= creb & BIT(2); 657c3963bc0SZev Weiss 658c3963bc0SZev Weiss pwm7pin = !(cr1d & (BIT(2) | BIT(3))); 659c3963bc0SZev Weiss break; 660c3963bc0SZev Weiss case nct6797: 661c3963bc0SZev Weiss fan5pin |= !ddr4_en && (cr1b & BIT(5)); 662c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 663c3963bc0SZev Weiss 664c3963bc0SZev Weiss fan6pin = cr2a & BIT(4); 665c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 666c3963bc0SZev Weiss 667c3963bc0SZev Weiss fan7pin = cr1a & BIT(1); 668c3963bc0SZev Weiss 669c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 670c3963bc0SZev Weiss pwm5pin |= !ddr4_en && (cr2d & BIT(7)); 671c3963bc0SZev Weiss 672c3963bc0SZev Weiss pwm6pin = creb & BIT(2); 673c3963bc0SZev Weiss pwm6pin |= cred & BIT(2); 674c3963bc0SZev Weiss 675c3963bc0SZev Weiss pwm7pin = cr1d & BIT(4); 676c3963bc0SZev Weiss break; 677c3963bc0SZev Weiss case nct6798: 678c3963bc0SZev Weiss fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); 679c3963bc0SZev Weiss fan6pin |= cr2a & BIT(4); 680c3963bc0SZev Weiss fan6pin |= creb & BIT(5); 681c3963bc0SZev Weiss 682c3963bc0SZev Weiss fan7pin = cr1b & BIT(5); 683c3963bc0SZev Weiss fan7pin |= !(cr2b & BIT(2)); 684c3963bc0SZev Weiss fan7pin |= creb & BIT(3); 685c3963bc0SZev Weiss 686c3963bc0SZev Weiss pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); 687c3963bc0SZev Weiss pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3)); 688c3963bc0SZev Weiss pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 689c3963bc0SZev Weiss 690c3963bc0SZev Weiss pwm7pin = !(cr1d & (BIT(2) | BIT(3))); 691c3963bc0SZev Weiss pwm7pin |= cr2d & BIT(7); 692c3963bc0SZev Weiss pwm7pin |= creb & BIT(2); 693c3963bc0SZev Weiss break; 694aee395bbSGuenter Roeck case nct6799: 695aee395bbSGuenter Roeck fan4pin = cr1c & BIT(6); 696aee395bbSGuenter Roeck fan5pin = cr1c & BIT(7); 697aee395bbSGuenter Roeck 698aee395bbSGuenter Roeck fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); 699aee395bbSGuenter Roeck fan6pin |= cre6 & BIT(5); 700aee395bbSGuenter Roeck fan6pin |= creb & BIT(5); 701aee395bbSGuenter Roeck fan6pin |= !as_seq1_en && (cr2a & BIT(4)); 702aee395bbSGuenter Roeck 703aee395bbSGuenter Roeck fan7pin = cr1b & BIT(5); 704aee395bbSGuenter Roeck fan7pin |= !vsb_ctl_en && !(cr2b & BIT(2)); 705aee395bbSGuenter Roeck fan7pin |= creb & BIT(3); 706aee395bbSGuenter Roeck 707aee395bbSGuenter Roeck pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); 708aee395bbSGuenter Roeck pwm6pin |= !as_seq1_en && !(cred & BIT(2)) && (cr2a & BIT(3)); 709aee395bbSGuenter Roeck pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 710aee395bbSGuenter Roeck pwm6pin |= cre6 & BIT(3); 711aee395bbSGuenter Roeck 712aee395bbSGuenter Roeck pwm7pin = !vsb_ctl_en && !(cr1d & (BIT(2) | BIT(3))); 713aee395bbSGuenter Roeck pwm7pin |= creb & BIT(2); 714aee395bbSGuenter Roeck pwm7pin |= cr2d & BIT(7); 715aee395bbSGuenter Roeck 716aee395bbSGuenter Roeck break; 717c3963bc0SZev Weiss default: /* NCT6779D */ 718c3963bc0SZev Weiss break; 719c3963bc0SZev Weiss } 720c3963bc0SZev Weiss 721c3963bc0SZev Weiss fan4min = fan4pin; 722c3963bc0SZev Weiss } 723c3963bc0SZev Weiss 724c3963bc0SZev Weiss /* fan 1 and 2 (0x03) are always present */ 725c3963bc0SZev Weiss data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) | 726c3963bc0SZev Weiss (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6); 727c3963bc0SZev Weiss data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) | 728c3963bc0SZev Weiss (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6); 729c3963bc0SZev Weiss data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | 730c3963bc0SZev Weiss (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6); 731c3963bc0SZev Weiss } 732c3963bc0SZev Weiss 733c3963bc0SZev Weiss static ssize_t 734c3963bc0SZev Weiss cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) 735c3963bc0SZev Weiss { 736c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 737c3963bc0SZev Weiss 738c3963bc0SZev Weiss return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); 739c3963bc0SZev Weiss } 740c3963bc0SZev Weiss 741c3963bc0SZev Weiss static DEVICE_ATTR_RO(cpu0_vid); 742c3963bc0SZev Weiss 743c3963bc0SZev Weiss /* Case open detection */ 744c3963bc0SZev Weiss 745c3963bc0SZev Weiss static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee }; 746c3963bc0SZev Weiss static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 }; 747c3963bc0SZev Weiss 748c3963bc0SZev Weiss static ssize_t 749c3963bc0SZev Weiss clear_caseopen(struct device *dev, struct device_attribute *attr, 750c3963bc0SZev Weiss const char *buf, size_t count) 751c3963bc0SZev Weiss { 752c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 753c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = data->driver_data; 754c3963bc0SZev Weiss int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE; 755c3963bc0SZev Weiss unsigned long val; 756c3963bc0SZev Weiss u8 reg; 757c3963bc0SZev Weiss int ret; 758c3963bc0SZev Weiss 759c3963bc0SZev Weiss if (kstrtoul(buf, 10, &val) || val != 0) 760c3963bc0SZev Weiss return -EINVAL; 761c3963bc0SZev Weiss 762c3963bc0SZev Weiss mutex_lock(&data->update_lock); 763c3963bc0SZev Weiss 764c3963bc0SZev Weiss /* 765c3963bc0SZev Weiss * Use CR registers to clear caseopen status. 766c3963bc0SZev Weiss * The CR registers are the same for all chips, and not all chips 767c3963bc0SZev Weiss * support clearing the caseopen status through "regular" registers. 768c3963bc0SZev Weiss */ 769c3963bc0SZev Weiss ret = sio_data->sio_enter(sio_data); 770c3963bc0SZev Weiss if (ret) { 771c3963bc0SZev Weiss count = ret; 772c3963bc0SZev Weiss goto error; 773c3963bc0SZev Weiss } 774c3963bc0SZev Weiss 775c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_ACPI); 776c3963bc0SZev Weiss reg = sio_data->sio_inb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr]); 777c3963bc0SZev Weiss reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr]; 778c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg); 779c3963bc0SZev Weiss reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr]; 780c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg); 781c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 782c3963bc0SZev Weiss 783c3963bc0SZev Weiss data->valid = false; /* Force cache refresh */ 784c3963bc0SZev Weiss error: 785c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 786c3963bc0SZev Weiss return count; 787c3963bc0SZev Weiss } 788c3963bc0SZev Weiss 789c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion0_alarm, 0644, nct6775_show_alarm, 790c3963bc0SZev Weiss clear_caseopen, INTRUSION_ALARM_BASE); 791c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion1_alarm, 0644, nct6775_show_alarm, 792c3963bc0SZev Weiss clear_caseopen, INTRUSION_ALARM_BASE + 1); 793c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion0_beep, 0644, nct6775_show_beep, 794c3963bc0SZev Weiss nct6775_store_beep, INTRUSION_ALARM_BASE); 795c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion1_beep, 0644, nct6775_show_beep, 796c3963bc0SZev Weiss nct6775_store_beep, INTRUSION_ALARM_BASE + 1); 797c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(beep_enable, 0644, nct6775_show_beep, 798c3963bc0SZev Weiss nct6775_store_beep, BEEP_ENABLE_BASE); 799c3963bc0SZev Weiss 800c3963bc0SZev Weiss static umode_t nct6775_other_is_visible(struct kobject *kobj, 801c3963bc0SZev Weiss struct attribute *attr, int index) 802c3963bc0SZev Weiss { 803c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 804c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 805c3963bc0SZev Weiss 806c3963bc0SZev Weiss if (index == 0 && !data->have_vid) 807c3963bc0SZev Weiss return 0; 808c3963bc0SZev Weiss 809c3963bc0SZev Weiss if (index == 1 || index == 2) { 810c3963bc0SZev Weiss if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0) 811c3963bc0SZev Weiss return 0; 812c3963bc0SZev Weiss } 813c3963bc0SZev Weiss 814c3963bc0SZev Weiss if (index == 3 || index == 4) { 815c3963bc0SZev Weiss if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0) 816c3963bc0SZev Weiss return 0; 817c3963bc0SZev Weiss } 818c3963bc0SZev Weiss 819c3963bc0SZev Weiss return nct6775_attr_mode(data, attr); 820c3963bc0SZev Weiss } 821c3963bc0SZev Weiss 822c3963bc0SZev Weiss /* 823c3963bc0SZev Weiss * nct6775_other_is_visible uses the index into the following array 824c3963bc0SZev Weiss * to determine if attributes should be created or not. 825c3963bc0SZev Weiss * Any change in order or content must be matched. 826c3963bc0SZev Weiss */ 827c3963bc0SZev Weiss static struct attribute *nct6775_attributes_other[] = { 828c3963bc0SZev Weiss &dev_attr_cpu0_vid.attr, /* 0 */ 829c3963bc0SZev Weiss &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */ 830c3963bc0SZev Weiss &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */ 831c3963bc0SZev Weiss &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */ 832c3963bc0SZev Weiss &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */ 833c3963bc0SZev Weiss &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */ 834c3963bc0SZev Weiss 835c3963bc0SZev Weiss NULL 836c3963bc0SZev Weiss }; 837c3963bc0SZev Weiss 838c3963bc0SZev Weiss static const struct attribute_group nct6775_group_other = { 839c3963bc0SZev Weiss .attrs = nct6775_attributes_other, 840c3963bc0SZev Weiss .is_visible = nct6775_other_is_visible, 841c3963bc0SZev Weiss }; 842c3963bc0SZev Weiss 843c3963bc0SZev Weiss static int nct6775_platform_probe_init(struct nct6775_data *data) 844c3963bc0SZev Weiss { 845c3963bc0SZev Weiss int err; 846c3963bc0SZev Weiss u8 cr2a; 847c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = data->driver_data; 848c3963bc0SZev Weiss 849c3963bc0SZev Weiss err = sio_data->sio_enter(sio_data); 850c3963bc0SZev Weiss if (err) 851c3963bc0SZev Weiss return err; 852c3963bc0SZev Weiss 853c3963bc0SZev Weiss cr2a = sio_data->sio_inb(sio_data, 0x2a); 854c3963bc0SZev Weiss switch (data->kind) { 855c3963bc0SZev Weiss case nct6775: 856c3963bc0SZev Weiss data->have_vid = (cr2a & 0x40); 857c3963bc0SZev Weiss break; 858c3963bc0SZev Weiss case nct6776: 859c3963bc0SZev Weiss data->have_vid = (cr2a & 0x60) == 0x40; 860c3963bc0SZev Weiss break; 861c3963bc0SZev Weiss case nct6106: 862c3963bc0SZev Weiss case nct6116: 863c3963bc0SZev Weiss case nct6779: 864c3963bc0SZev Weiss case nct6791: 865c3963bc0SZev Weiss case nct6792: 866c3963bc0SZev Weiss case nct6793: 867c3963bc0SZev Weiss case nct6795: 868c3963bc0SZev Weiss case nct6796: 869c3963bc0SZev Weiss case nct6797: 870c3963bc0SZev Weiss case nct6798: 871aee395bbSGuenter Roeck case nct6799: 872c3963bc0SZev Weiss break; 873c3963bc0SZev Weiss } 874c3963bc0SZev Weiss 875c3963bc0SZev Weiss /* 876c3963bc0SZev Weiss * Read VID value 877c3963bc0SZev Weiss * We can get the VID input values directly at logical device D 0xe3. 878c3963bc0SZev Weiss */ 879c3963bc0SZev Weiss if (data->have_vid) { 880c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_VID); 881c3963bc0SZev Weiss data->vid = sio_data->sio_inb(sio_data, 0xe3); 882c3963bc0SZev Weiss data->vrm = vid_which_vrm(); 883c3963bc0SZev Weiss } 884c3963bc0SZev Weiss 885c3963bc0SZev Weiss if (fan_debounce) { 886c3963bc0SZev Weiss u8 tmp; 887c3963bc0SZev Weiss 888c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 889c3963bc0SZev Weiss tmp = sio_data->sio_inb(sio_data, 890c3963bc0SZev Weiss NCT6775_REG_CR_FAN_DEBOUNCE); 891c3963bc0SZev Weiss switch (data->kind) { 892c3963bc0SZev Weiss case nct6106: 893c3963bc0SZev Weiss case nct6116: 894c3963bc0SZev Weiss tmp |= 0xe0; 895c3963bc0SZev Weiss break; 896c3963bc0SZev Weiss case nct6775: 897c3963bc0SZev Weiss tmp |= 0x1e; 898c3963bc0SZev Weiss break; 899c3963bc0SZev Weiss case nct6776: 900c3963bc0SZev Weiss case nct6779: 901c3963bc0SZev Weiss tmp |= 0x3e; 902c3963bc0SZev Weiss break; 903c3963bc0SZev Weiss case nct6791: 904c3963bc0SZev Weiss case nct6792: 905c3963bc0SZev Weiss case nct6793: 906c3963bc0SZev Weiss case nct6795: 907c3963bc0SZev Weiss case nct6796: 908c3963bc0SZev Weiss case nct6797: 909c3963bc0SZev Weiss case nct6798: 910aee395bbSGuenter Roeck case nct6799: 911c3963bc0SZev Weiss tmp |= 0x7e; 912c3963bc0SZev Weiss break; 913c3963bc0SZev Weiss } 914c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6775_REG_CR_FAN_DEBOUNCE, 915c3963bc0SZev Weiss tmp); 916c3963bc0SZev Weiss pr_info("Enabled fan debounce for chip %s\n", data->name); 917c3963bc0SZev Weiss } 918c3963bc0SZev Weiss 919c3963bc0SZev Weiss nct6775_check_fan_inputs(data, sio_data); 920c3963bc0SZev Weiss 921c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 922c3963bc0SZev Weiss 923c3963bc0SZev Weiss return nct6775_add_attr_group(data, &nct6775_group_other); 924c3963bc0SZev Weiss } 925c3963bc0SZev Weiss 926c3963bc0SZev Weiss static const struct regmap_config nct6775_regmap_config = { 927c3963bc0SZev Weiss .reg_bits = 16, 928c3963bc0SZev Weiss .val_bits = 16, 929c3963bc0SZev Weiss .reg_read = nct6775_reg_read, 930c3963bc0SZev Weiss .reg_write = nct6775_reg_write, 931c3963bc0SZev Weiss }; 932c3963bc0SZev Weiss 933c3963bc0SZev Weiss static const struct regmap_config nct6775_wmi_regmap_config = { 934c3963bc0SZev Weiss .reg_bits = 16, 935c3963bc0SZev Weiss .val_bits = 16, 936c3963bc0SZev Weiss .reg_read = nct6775_wmi_reg_read, 937c3963bc0SZev Weiss .reg_write = nct6775_wmi_reg_write, 938c3963bc0SZev Weiss }; 939c3963bc0SZev Weiss 940c3963bc0SZev Weiss static int nct6775_platform_probe(struct platform_device *pdev) 941c3963bc0SZev Weiss { 942c3963bc0SZev Weiss struct device *dev = &pdev->dev; 943c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = dev_get_platdata(dev); 944c3963bc0SZev Weiss struct nct6775_data *data; 945c3963bc0SZev Weiss struct resource *res; 946c3963bc0SZev Weiss const struct regmap_config *regmapcfg; 947c3963bc0SZev Weiss 948c3963bc0SZev Weiss if (sio_data->access == access_direct) { 949c3963bc0SZev Weiss res = platform_get_resource(pdev, IORESOURCE_IO, 0); 950c3963bc0SZev Weiss if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, DRVNAME)) 951c3963bc0SZev Weiss return -EBUSY; 952c3963bc0SZev Weiss } 953c3963bc0SZev Weiss 954c3963bc0SZev Weiss data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 955c3963bc0SZev Weiss if (!data) 956c3963bc0SZev Weiss return -ENOMEM; 957c3963bc0SZev Weiss 958c3963bc0SZev Weiss data->kind = sio_data->kind; 959c3963bc0SZev Weiss data->sioreg = sio_data->sioreg; 960c3963bc0SZev Weiss 961c3963bc0SZev Weiss if (sio_data->access == access_direct) { 962c3963bc0SZev Weiss data->addr = res->start; 963c3963bc0SZev Weiss regmapcfg = &nct6775_regmap_config; 964c3963bc0SZev Weiss } else { 965c3963bc0SZev Weiss regmapcfg = &nct6775_wmi_regmap_config; 966c3963bc0SZev Weiss } 967c3963bc0SZev Weiss 968c3963bc0SZev Weiss platform_set_drvdata(pdev, data); 969c3963bc0SZev Weiss 970c3963bc0SZev Weiss data->driver_data = sio_data; 971c3963bc0SZev Weiss data->driver_init = nct6775_platform_probe_init; 972c3963bc0SZev Weiss 973c3963bc0SZev Weiss return nct6775_probe(&pdev->dev, data, regmapcfg); 974c3963bc0SZev Weiss } 975c3963bc0SZev Weiss 976c3963bc0SZev Weiss static struct platform_driver nct6775_driver = { 977c3963bc0SZev Weiss .driver = { 978c3963bc0SZev Weiss .name = DRVNAME, 9798de7295cSJonathan Cameron .pm = pm_sleep_ptr(&nct6775_dev_pm_ops), 980c3963bc0SZev Weiss }, 981c3963bc0SZev Weiss .probe = nct6775_platform_probe, 982c3963bc0SZev Weiss }; 983c3963bc0SZev Weiss 984c3963bc0SZev Weiss /* nct6775_find() looks for a '627 in the Super-I/O config space */ 985c3963bc0SZev Weiss static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) 986c3963bc0SZev Weiss { 987c3963bc0SZev Weiss u16 val; 988c3963bc0SZev Weiss int err; 989c3963bc0SZev Weiss int addr; 990c3963bc0SZev Weiss 991c3963bc0SZev Weiss sio_data->access = access_direct; 992c3963bc0SZev Weiss sio_data->sioreg = sioaddr; 993c3963bc0SZev Weiss 994c3963bc0SZev Weiss err = sio_data->sio_enter(sio_data); 995c3963bc0SZev Weiss if (err) 996c3963bc0SZev Weiss return err; 997c3963bc0SZev Weiss 998c3963bc0SZev Weiss val = (sio_data->sio_inb(sio_data, SIO_REG_DEVID) << 8) | 999c3963bc0SZev Weiss sio_data->sio_inb(sio_data, SIO_REG_DEVID + 1); 1000c3963bc0SZev Weiss if (force_id && val != 0xffff) 1001c3963bc0SZev Weiss val = force_id; 1002c3963bc0SZev Weiss 1003c3963bc0SZev Weiss switch (val & SIO_ID_MASK) { 1004c3963bc0SZev Weiss case SIO_NCT6106_ID: 1005c3963bc0SZev Weiss sio_data->kind = nct6106; 1006c3963bc0SZev Weiss break; 1007c3963bc0SZev Weiss case SIO_NCT6116_ID: 1008c3963bc0SZev Weiss sio_data->kind = nct6116; 1009c3963bc0SZev Weiss break; 1010c3963bc0SZev Weiss case SIO_NCT6775_ID: 1011c3963bc0SZev Weiss sio_data->kind = nct6775; 1012c3963bc0SZev Weiss break; 1013c3963bc0SZev Weiss case SIO_NCT6776_ID: 1014c3963bc0SZev Weiss sio_data->kind = nct6776; 1015c3963bc0SZev Weiss break; 1016c3963bc0SZev Weiss case SIO_NCT6779_ID: 1017c3963bc0SZev Weiss sio_data->kind = nct6779; 1018c3963bc0SZev Weiss break; 1019c3963bc0SZev Weiss case SIO_NCT6791_ID: 1020c3963bc0SZev Weiss sio_data->kind = nct6791; 1021c3963bc0SZev Weiss break; 1022c3963bc0SZev Weiss case SIO_NCT6792_ID: 1023c3963bc0SZev Weiss sio_data->kind = nct6792; 1024c3963bc0SZev Weiss break; 1025c3963bc0SZev Weiss case SIO_NCT6793_ID: 1026c3963bc0SZev Weiss sio_data->kind = nct6793; 1027c3963bc0SZev Weiss break; 1028c3963bc0SZev Weiss case SIO_NCT6795_ID: 1029c3963bc0SZev Weiss sio_data->kind = nct6795; 1030c3963bc0SZev Weiss break; 1031c3963bc0SZev Weiss case SIO_NCT6796_ID: 1032c3963bc0SZev Weiss sio_data->kind = nct6796; 1033c3963bc0SZev Weiss break; 1034c3963bc0SZev Weiss case SIO_NCT6797_ID: 1035c3963bc0SZev Weiss sio_data->kind = nct6797; 1036c3963bc0SZev Weiss break; 1037c3963bc0SZev Weiss case SIO_NCT6798_ID: 1038c3963bc0SZev Weiss sio_data->kind = nct6798; 1039c3963bc0SZev Weiss break; 1040aee395bbSGuenter Roeck case SIO_NCT6799_ID: 1041aee395bbSGuenter Roeck sio_data->kind = nct6799; 1042aee395bbSGuenter Roeck break; 1043c3963bc0SZev Weiss default: 1044c3963bc0SZev Weiss if (val != 0xffff) 1045c3963bc0SZev Weiss pr_debug("unsupported chip ID: 0x%04x\n", val); 1046c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 1047c3963bc0SZev Weiss return -ENODEV; 1048c3963bc0SZev Weiss } 1049c3963bc0SZev Weiss 1050c3963bc0SZev Weiss /* We have a known chip, find the HWM I/O address */ 1051c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 1052c3963bc0SZev Weiss val = (sio_data->sio_inb(sio_data, SIO_REG_ADDR) << 8) 1053c3963bc0SZev Weiss | sio_data->sio_inb(sio_data, SIO_REG_ADDR + 1); 1054c3963bc0SZev Weiss addr = val & IOREGION_ALIGNMENT; 1055c3963bc0SZev Weiss if (addr == 0) { 1056c3963bc0SZev Weiss pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n"); 1057c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 1058c3963bc0SZev Weiss return -ENODEV; 1059c3963bc0SZev Weiss } 1060c3963bc0SZev Weiss 1061c3963bc0SZev Weiss /* Activate logical device if needed */ 1062c3963bc0SZev Weiss val = sio_data->sio_inb(sio_data, SIO_REG_ENABLE); 1063c3963bc0SZev Weiss if (!(val & 0x01)) { 1064c3963bc0SZev Weiss pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n"); 1065c3963bc0SZev Weiss sio_data->sio_outb(sio_data, SIO_REG_ENABLE, val | 0x01); 1066c3963bc0SZev Weiss } 1067c3963bc0SZev Weiss 1068c3963bc0SZev Weiss if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || 1069c3963bc0SZev Weiss sio_data->kind == nct6793 || sio_data->kind == nct6795 || 1070c3963bc0SZev Weiss sio_data->kind == nct6796 || sio_data->kind == nct6797 || 1071aee395bbSGuenter Roeck sio_data->kind == nct6798 || sio_data->kind == nct6799) 1072c3963bc0SZev Weiss nct6791_enable_io_mapping(sio_data); 1073c3963bc0SZev Weiss 1074c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 1075c3963bc0SZev Weiss pr_info("Found %s or compatible chip at %#x:%#x\n", 1076c3963bc0SZev Weiss nct6775_sio_names[sio_data->kind], sioaddr, addr); 1077c3963bc0SZev Weiss 1078c3963bc0SZev Weiss return addr; 1079c3963bc0SZev Weiss } 1080c3963bc0SZev Weiss 1081c3963bc0SZev Weiss /* 1082c3963bc0SZev Weiss * when Super-I/O functions move to a separate file, the Super-I/O 1083c3963bc0SZev Weiss * bus will manage the lifetime of the device and this module will only keep 1084c3963bc0SZev Weiss * track of the nct6775 driver. But since we use platform_device_alloc(), we 1085c3963bc0SZev Weiss * must keep track of the device 1086c3963bc0SZev Weiss */ 1087c3963bc0SZev Weiss static struct platform_device *pdev[2]; 1088c3963bc0SZev Weiss 1089c3963bc0SZev Weiss static const char * const asus_wmi_boards[] = { 10905dcd53e3SDenis Pauk "B360M-BASALT", 10915dcd53e3SDenis Pauk "B360M-D3H", 10925dcd53e3SDenis Pauk "EX-B360M-V", 10935dcd53e3SDenis Pauk "EX-B360M-V3", 10945dcd53e3SDenis Pauk "EX-B360M-V5", 1095a4fffe48SDenis Pauk "EX-B460M-V5", 1096a4fffe48SDenis Pauk "EX-H410M-V3", 1097bcd2fbecSDenis Pauk "PRIME A520M-A", 1098bcd2fbecSDenis Pauk "PRIME A520M-A II", 1099bcd2fbecSDenis Pauk "PRIME A520M-E", 1100bcd2fbecSDenis Pauk "PRIME A520M-K", 1101c3963bc0SZev Weiss "PRIME B360-PLUS", 1102bcd2fbecSDenis Pauk "PRIME B360M-A", 1103bcd2fbecSDenis Pauk "PRIME B360M-C", 1104a4fffe48SDenis Pauk "PRIME B360M-D", 1105a4fffe48SDenis Pauk "PRIME B360M-K", 1106c3963bc0SZev Weiss "PRIME B460-PLUS", 11075dcd53e3SDenis Pauk "PRIME B460I-PLUS", 11085dcd53e3SDenis Pauk "PRIME B460M-A", 1109bcd2fbecSDenis Pauk "PRIME B460M-A R2.0", 11105dcd53e3SDenis Pauk "PRIME B460M-K", 1111c3963bc0SZev Weiss "PRIME B550-PLUS", 11125dcd53e3SDenis Pauk "PRIME B550-PLUS AC-HES", 1113c3963bc0SZev Weiss "PRIME B550M-A", 1114c3963bc0SZev Weiss "PRIME B550M-A (WI-FI)", 1115bcd2fbecSDenis Pauk "PRIME B550M-A AC", 1116bcd2fbecSDenis Pauk "PRIME B550M-A WIFI II", 1117bcd2fbecSDenis Pauk "PRIME B550M-K", 11185dcd53e3SDenis Pauk "PRIME H310-PLUS", 11195dcd53e3SDenis Pauk "PRIME H310I-PLUS", 11205dcd53e3SDenis Pauk "PRIME H310M-A", 11215dcd53e3SDenis Pauk "PRIME H310M-C", 11225dcd53e3SDenis Pauk "PRIME H310M-D", 11235dcd53e3SDenis Pauk "PRIME H310M-DASH", 11245dcd53e3SDenis Pauk "PRIME H310M-E", 11255dcd53e3SDenis Pauk "PRIME H310M-E/BR", 11265dcd53e3SDenis Pauk "PRIME H310M-F", 11275dcd53e3SDenis Pauk "PRIME H310M-K", 11285dcd53e3SDenis Pauk "PRIME H310T", 11295dcd53e3SDenis Pauk "PRIME H370-A", 11305dcd53e3SDenis Pauk "PRIME H370-PLUS", 11315dcd53e3SDenis Pauk "PRIME H370M-PLUS", 11325dcd53e3SDenis Pauk "PRIME H410I-PLUS", 1133a4fffe48SDenis Pauk "PRIME H410M-A", 1134a4fffe48SDenis Pauk "PRIME H410M-D", 1135a4fffe48SDenis Pauk "PRIME H410M-E", 1136a4fffe48SDenis Pauk "PRIME H410M-F", 1137a4fffe48SDenis Pauk "PRIME H410M-K", 1138a4fffe48SDenis Pauk "PRIME H410M-K R2.0", 113976412408SDenis Pauk "PRIME H410M-R", 11405dcd53e3SDenis Pauk "PRIME H470-PLUS", 11415dcd53e3SDenis Pauk "PRIME H470M-PLUS", 1142a4fffe48SDenis Pauk "PRIME H510M-K R2.0", 11435dcd53e3SDenis Pauk "PRIME Q370M-C", 1144c3963bc0SZev Weiss "PRIME X570-P", 1145c3963bc0SZev Weiss "PRIME X570-PRO", 1146a4fffe48SDenis Pauk "PRIME Z390-A", 1147a4fffe48SDenis Pauk "PRIME Z390-A/H10", 1148a4fffe48SDenis Pauk "PRIME Z390-P", 1149a4fffe48SDenis Pauk "PRIME Z390M-PLUS", 1150a4fffe48SDenis Pauk "PRIME Z490-A", 1151a4fffe48SDenis Pauk "PRIME Z490-P", 1152a4fffe48SDenis Pauk "PRIME Z490-V", 1153a4fffe48SDenis Pauk "PRIME Z490M-PLUS", 1154a4fffe48SDenis Pauk "PRO B460M-C", 1155a4fffe48SDenis Pauk "PRO H410M-C", 115602825926SDenis Pauk "PRO H410T", 11575dcd53e3SDenis Pauk "PRO Q470M-C", 115802825926SDenis Pauk "Pro A520M-C", 115902825926SDenis Pauk "Pro A520M-C II", 116002825926SDenis Pauk "Pro B550M-C", 116102825926SDenis Pauk "Pro WS X570-ACE", 116202825926SDenis Pauk "ProArt B550-CREATOR", 116302825926SDenis Pauk "ProArt X570-CREATOR WIFI", 116402825926SDenis Pauk "ProArt Z490-CREATOR 10G", 1165c3963bc0SZev Weiss "ROG CROSSHAIR VIII DARK HERO", 11661864069cSDenis Pauk "ROG CROSSHAIR VIII EXTREME", 1167c3963bc0SZev Weiss "ROG CROSSHAIR VIII FORMULA", 1168c3963bc0SZev Weiss "ROG CROSSHAIR VIII HERO", 11691864069cSDenis Pauk "ROG CROSSHAIR VIII HERO (WI-FI)", 1170c3963bc0SZev Weiss "ROG CROSSHAIR VIII IMPACT", 1171a4fffe48SDenis Pauk "ROG MAXIMUS XI APEX", 1172a4fffe48SDenis Pauk "ROG MAXIMUS XI CODE", 1173a4fffe48SDenis Pauk "ROG MAXIMUS XI EXTREME", 1174a4fffe48SDenis Pauk "ROG MAXIMUS XI FORMULA", 1175a4fffe48SDenis Pauk "ROG MAXIMUS XI GENE", 1176a4fffe48SDenis Pauk "ROG MAXIMUS XI HERO", 1177a4fffe48SDenis Pauk "ROG MAXIMUS XI HERO (WI-FI)", 1178a4fffe48SDenis Pauk "ROG MAXIMUS XII APEX", 1179a4fffe48SDenis Pauk "ROG MAXIMUS XII EXTREME", 1180a4fffe48SDenis Pauk "ROG MAXIMUS XII FORMULA", 1181a4fffe48SDenis Pauk "ROG MAXIMUS XII HERO (WI-FI)", 11825dcd53e3SDenis Pauk "ROG STRIX B360-F GAMING", 11835dcd53e3SDenis Pauk "ROG STRIX B360-G GAMING", 11845dcd53e3SDenis Pauk "ROG STRIX B360-H GAMING", 11855dcd53e3SDenis Pauk "ROG STRIX B360-H GAMING/OPTANE", 11865dcd53e3SDenis Pauk "ROG STRIX B360-I GAMING", 1187a4fffe48SDenis Pauk "ROG STRIX B460-F GAMING", 1188a4fffe48SDenis Pauk "ROG STRIX B460-G GAMING", 1189a4fffe48SDenis Pauk "ROG STRIX B460-H GAMING", 1190a4fffe48SDenis Pauk "ROG STRIX B460-I GAMING", 1191c3963bc0SZev Weiss "ROG STRIX B550-A GAMING", 1192c3963bc0SZev Weiss "ROG STRIX B550-E GAMING", 1193c3963bc0SZev Weiss "ROG STRIX B550-F GAMING", 1194c3963bc0SZev Weiss "ROG STRIX B550-F GAMING (WI-FI)", 1195c3963bc0SZev Weiss "ROG STRIX B550-F GAMING WIFI II", 1196c3963bc0SZev Weiss "ROG STRIX B550-I GAMING", 1197c05403e6SDenis Pauk "ROG STRIX B550-XE GAMING WIFI", 11985dcd53e3SDenis Pauk "ROG STRIX H370-F GAMING", 11995dcd53e3SDenis Pauk "ROG STRIX H370-I GAMING", 12005dcd53e3SDenis Pauk "ROG STRIX H470-I GAMING", 1201c3963bc0SZev Weiss "ROG STRIX X570-E GAMING", 120276412408SDenis Pauk "ROG STRIX X570-E GAMING WIFI II", 1203c3963bc0SZev Weiss "ROG STRIX X570-F GAMING", 1204c3963bc0SZev Weiss "ROG STRIX X570-I GAMING", 1205c3963bc0SZev Weiss "ROG STRIX Z390-E GAMING", 1206c3963bc0SZev Weiss "ROG STRIX Z390-F GAMING", 1207c3963bc0SZev Weiss "ROG STRIX Z390-H GAMING", 1208c3963bc0SZev Weiss "ROG STRIX Z390-I GAMING", 1209c3963bc0SZev Weiss "ROG STRIX Z490-A GAMING", 1210c3963bc0SZev Weiss "ROG STRIX Z490-E GAMING", 1211c3963bc0SZev Weiss "ROG STRIX Z490-F GAMING", 1212c3963bc0SZev Weiss "ROG STRIX Z490-G GAMING", 1213c3963bc0SZev Weiss "ROG STRIX Z490-G GAMING (WI-FI)", 1214c3963bc0SZev Weiss "ROG STRIX Z490-H GAMING", 1215c3963bc0SZev Weiss "ROG STRIX Z490-I GAMING", 12165dcd53e3SDenis Pauk "TUF B360-PLUS GAMING", 12175dcd53e3SDenis Pauk "TUF B360-PRO GAMING", 12185dcd53e3SDenis Pauk "TUF B360-PRO GAMING (WI-FI)", 12195dcd53e3SDenis Pauk "TUF B360M-E GAMING", 12205dcd53e3SDenis Pauk "TUF B360M-PLUS GAMING", 12215dcd53e3SDenis Pauk "TUF B360M-PLUS GAMING S", 12225dcd53e3SDenis Pauk "TUF B360M-PLUS GAMING/BR", 1223bcd2fbecSDenis Pauk "TUF GAMING A520M-PLUS", 1224bcd2fbecSDenis Pauk "TUF GAMING A520M-PLUS II", 1225bcd2fbecSDenis Pauk "TUF GAMING A520M-PLUS WIFI", 1226a4fffe48SDenis Pauk "TUF GAMING B460-PLUS", 1227a4fffe48SDenis Pauk "TUF GAMING B460-PRO (WI-FI)", 1228a4fffe48SDenis Pauk "TUF GAMING B460M-PLUS", 1229a4fffe48SDenis Pauk "TUF GAMING B460M-PLUS (WI-FI)", 1230a4fffe48SDenis Pauk "TUF GAMING B460M-PRO", 123102825926SDenis Pauk "TUF GAMING B550-PLUS", 1232a4fffe48SDenis Pauk "TUF GAMING B550-PLUS (WI-FI)", 123302825926SDenis Pauk "TUF GAMING B550-PLUS WIFI II", 123402825926SDenis Pauk "TUF GAMING B550-PRO", 1235a4fffe48SDenis Pauk "TUF GAMING B550M ZAKU (WI-FI)", 12361864069cSDenis Pauk "TUF GAMING B550M-E", 123723e8a379SDenis Pauk "TUF GAMING B550M-E WIFI", 1238c3963bc0SZev Weiss "TUF GAMING B550M-PLUS", 1239c3963bc0SZev Weiss "TUF GAMING B550M-PLUS (WI-FI)", 12401864069cSDenis Pauk "TUF GAMING B550M-PLUS WIFI II", 12415dcd53e3SDenis Pauk "TUF GAMING H470-PRO", 12425dcd53e3SDenis Pauk "TUF GAMING H470-PRO (WI-FI)", 1243c3963bc0SZev Weiss "TUF GAMING X570-PLUS", 1244c3963bc0SZev Weiss "TUF GAMING X570-PLUS (WI-FI)", 1245bcd2fbecSDenis Pauk "TUF GAMING X570-PLUS_BR", 1246c3963bc0SZev Weiss "TUF GAMING X570-PRO (WI-FI)", 12475dcd53e3SDenis Pauk "TUF GAMING X570-PRO WIFI II", 1248c3963bc0SZev Weiss "TUF GAMING Z490-PLUS", 1249c3963bc0SZev Weiss "TUF GAMING Z490-PLUS (WI-FI)", 12505dcd53e3SDenis Pauk "TUF H310-PLUS GAMING", 12515dcd53e3SDenis Pauk "TUF H310M-PLUS GAMING", 12525dcd53e3SDenis Pauk "TUF H310M-PLUS GAMING/BR", 12535dcd53e3SDenis Pauk "TUF H370-PRO GAMING", 12545dcd53e3SDenis Pauk "TUF H370-PRO GAMING (WI-FI)", 1255a4fffe48SDenis Pauk "TUF Z390-PLUS GAMING", 1256a4fffe48SDenis Pauk "TUF Z390-PLUS GAMING (WI-FI)", 1257a4fffe48SDenis Pauk "TUF Z390-PRO GAMING", 1258a4fffe48SDenis Pauk "TUF Z390M-PRO GAMING", 1259a4fffe48SDenis Pauk "TUF Z390M-PRO GAMING (WI-FI)", 1260a4fffe48SDenis Pauk "WS Z390 PRO", 1261bcd2fbecSDenis Pauk "Z490-GUNDAM (WI-FI)", 1262c3963bc0SZev Weiss }; 1263c3963bc0SZev Weiss 1264e2e09989SDenis Pauk static const char * const asus_msi_boards[] = { 1265a4fffe48SDenis Pauk "B560M-P", 1266a4fffe48SDenis Pauk "EX-B560M-V5", 1267bcd2fbecSDenis Pauk "EX-B660M-V5 D4", 1268e2e09989SDenis Pauk "EX-B660M-V5 PRO D4", 12695dcd53e3SDenis Pauk "EX-B760M-V5 D4", 1270a4fffe48SDenis Pauk "EX-H510M-V3", 1271a4fffe48SDenis Pauk "EX-H610M-V3 D4", 12725dcd53e3SDenis Pauk "PRIME A620M-A", 1273a4fffe48SDenis Pauk "PRIME B560-PLUS", 1274a4fffe48SDenis Pauk "PRIME B560-PLUS AC-HES", 1275a4fffe48SDenis Pauk "PRIME B560M-A", 1276a4fffe48SDenis Pauk "PRIME B560M-A AC", 1277a4fffe48SDenis Pauk "PRIME B560M-K", 1278e2e09989SDenis Pauk "PRIME B650-PLUS", 1279e2e09989SDenis Pauk "PRIME B650M-A", 1280e2e09989SDenis Pauk "PRIME B650M-A AX", 1281bcd2fbecSDenis Pauk "PRIME B650M-A AX II", 1282e2e09989SDenis Pauk "PRIME B650M-A II", 1283e2e09989SDenis Pauk "PRIME B650M-A WIFI", 1284e2e09989SDenis Pauk "PRIME B650M-A WIFI II", 1285a4fffe48SDenis Pauk "PRIME B660-PLUS D4", 12865dcd53e3SDenis Pauk "PRIME B660M-A AC D4", 1287e2e09989SDenis Pauk "PRIME B660M-A D4", 1288e2e09989SDenis Pauk "PRIME B660M-A WIFI D4", 12895dcd53e3SDenis Pauk "PRIME B760-PLUS", 12905dcd53e3SDenis Pauk "PRIME B760-PLUS D4", 12915dcd53e3SDenis Pauk "PRIME B760M-A", 12925dcd53e3SDenis Pauk "PRIME B760M-A AX D4", 12935dcd53e3SDenis Pauk "PRIME B760M-A D4", 12945dcd53e3SDenis Pauk "PRIME B760M-A WIFI", 12955dcd53e3SDenis Pauk "PRIME B760M-A WIFI D4", 12965dcd53e3SDenis Pauk "PRIME B760M-AJ D4", 12975dcd53e3SDenis Pauk "PRIME B760M-K D4", 1298a4fffe48SDenis Pauk "PRIME H510M-A", 1299a4fffe48SDenis Pauk "PRIME H510M-A WIFI", 1300a4fffe48SDenis Pauk "PRIME H510M-D", 1301a4fffe48SDenis Pauk "PRIME H510M-E", 1302a4fffe48SDenis Pauk "PRIME H510M-F", 1303a4fffe48SDenis Pauk "PRIME H510M-K", 13045dcd53e3SDenis Pauk "PRIME H510M-R", 13055dcd53e3SDenis Pauk "PRIME H510T2/CSM", 13065dcd53e3SDenis Pauk "PRIME H570-PLUS", 13075dcd53e3SDenis Pauk "PRIME H570M-PLUS", 1308a4fffe48SDenis Pauk "PRIME H610I-PLUS D4", 1309a4fffe48SDenis Pauk "PRIME H610M-A D4", 1310a4fffe48SDenis Pauk "PRIME H610M-A WIFI D4", 1311a4fffe48SDenis Pauk "PRIME H610M-D D4", 1312a4fffe48SDenis Pauk "PRIME H610M-E D4", 1313a4fffe48SDenis Pauk "PRIME H610M-F D4", 1314a4fffe48SDenis Pauk "PRIME H610M-K D4", 13155dcd53e3SDenis Pauk "PRIME H610M-R D4", 13165dcd53e3SDenis Pauk "PRIME H670-PLUS D4", 13175dcd53e3SDenis Pauk "PRIME H770-PLUS D4", 1318e2e09989SDenis Pauk "PRIME X670-P", 1319e2e09989SDenis Pauk "PRIME X670-P WIFI", 1320e2e09989SDenis Pauk "PRIME X670E-PRO WIFI", 132190b86248SErik Ekman "PRIME Z590-A", 132290b86248SErik Ekman "PRIME Z590-P", 1323bcd2fbecSDenis Pauk "PRIME Z590-P WIFI", 1324bcd2fbecSDenis Pauk "PRIME Z590-V", 132590b86248SErik Ekman "PRIME Z590M-PLUS", 1326a4fffe48SDenis Pauk "PRIME Z690-A", 1327a4fffe48SDenis Pauk "PRIME Z690-P", 1328a4fffe48SDenis Pauk "PRIME Z690-P D4", 1329a4fffe48SDenis Pauk "PRIME Z690-P WIFI", 1330a4fffe48SDenis Pauk "PRIME Z690-P WIFI D4", 1331a4fffe48SDenis Pauk "PRIME Z690M-PLUS D4", 1332a4fffe48SDenis Pauk "PRIME Z790-A WIFI", 1333a4fffe48SDenis Pauk "PRIME Z790-P", 1334a4fffe48SDenis Pauk "PRIME Z790-P D4", 1335a4fffe48SDenis Pauk "PRIME Z790-P WIFI", 1336a4fffe48SDenis Pauk "PRIME Z790-P WIFI D4", 1337a4fffe48SDenis Pauk "PRIME Z790M-PLUS", 1338a4fffe48SDenis Pauk "PRIME Z790M-PLUS D4", 1339a4fffe48SDenis Pauk "Pro B560M-C", 1340a4fffe48SDenis Pauk "Pro B560M-CT", 1341bcd2fbecSDenis Pauk "Pro B660M-C", 1342c05403e6SDenis Pauk "Pro B660M-C D4", 13435dcd53e3SDenis Pauk "Pro B760M-C", 13445dcd53e3SDenis Pauk "Pro B760M-CT", 1345a4fffe48SDenis Pauk "Pro H510M-C", 1346a4fffe48SDenis Pauk "Pro H510M-CT", 1347a4fffe48SDenis Pauk "Pro H610M-C", 1348a4fffe48SDenis Pauk "Pro H610M-C D4", 1349a4fffe48SDenis Pauk "Pro H610M-CT D4", 1350a4fffe48SDenis Pauk "Pro H610T D4", 13515dcd53e3SDenis Pauk "Pro Q670M-C", 1352bcd2fbecSDenis Pauk "Pro WS W680-ACE", 1353bcd2fbecSDenis Pauk "Pro WS W680-ACE IPMI", 13545dcd53e3SDenis Pauk "Pro WS W790-ACE", 13555dcd53e3SDenis Pauk "Pro WS W790E-SAGE SE", 1356bcd2fbecSDenis Pauk "ProArt B650-CREATOR", 1357e2e09989SDenis Pauk "ProArt B660-CREATOR D4", 13585dcd53e3SDenis Pauk "ProArt B760-CREATOR D4", 1359e2e09989SDenis Pauk "ProArt X670E-CREATOR WIFI", 1360a4fffe48SDenis Pauk "ProArt Z690-CREATOR WIFI", 1361bcd2fbecSDenis Pauk "ProArt Z790-CREATOR WIFI", 1362e2e09989SDenis Pauk "ROG CROSSHAIR X670E EXTREME", 1363e2e09989SDenis Pauk "ROG CROSSHAIR X670E GENE", 1364e2e09989SDenis Pauk "ROG CROSSHAIR X670E HERO", 1365bcd2fbecSDenis Pauk "ROG MAXIMUS XIII APEX", 1366bcd2fbecSDenis Pauk "ROG MAXIMUS XIII EXTREME", 1367e2e09989SDenis Pauk "ROG MAXIMUS XIII EXTREME GLACIAL", 1368bcd2fbecSDenis Pauk "ROG MAXIMUS XIII HERO", 1369bcd2fbecSDenis Pauk "ROG MAXIMUS Z690 APEX", 1370e2e09989SDenis Pauk "ROG MAXIMUS Z690 EXTREME", 1371e2e09989SDenis Pauk "ROG MAXIMUS Z690 EXTREME GLACIAL", 13725dcd53e3SDenis Pauk "ROG MAXIMUS Z690 FORMULA", 13735dcd53e3SDenis Pauk "ROG MAXIMUS Z690 HERO", 1374a4fffe48SDenis Pauk "ROG MAXIMUS Z690 HERO EVA", 1375a4fffe48SDenis Pauk "ROG MAXIMUS Z790 APEX", 1376bcd2fbecSDenis Pauk "ROG MAXIMUS Z790 EXTREME", 1377a4fffe48SDenis Pauk "ROG MAXIMUS Z790 HERO", 1378a4fffe48SDenis Pauk "ROG STRIX B560-A GAMING WIFI", 1379a4fffe48SDenis Pauk "ROG STRIX B560-E GAMING WIFI", 1380a4fffe48SDenis Pauk "ROG STRIX B560-F GAMING WIFI", 1381a4fffe48SDenis Pauk "ROG STRIX B560-G GAMING WIFI", 1382a4fffe48SDenis Pauk "ROG STRIX B560-I GAMING WIFI", 1383e2e09989SDenis Pauk "ROG STRIX B650-A GAMING WIFI", 1384e2e09989SDenis Pauk "ROG STRIX B650E-E GAMING WIFI", 1385e2e09989SDenis Pauk "ROG STRIX B650E-F GAMING WIFI", 1386e2e09989SDenis Pauk "ROG STRIX B650E-I GAMING WIFI", 1387bcd2fbecSDenis Pauk "ROG STRIX B660-A GAMING WIFI", 1388e2e09989SDenis Pauk "ROG STRIX B660-A GAMING WIFI D4", 1389e2e09989SDenis Pauk "ROG STRIX B660-F GAMING WIFI", 1390e2e09989SDenis Pauk "ROG STRIX B660-G GAMING WIFI", 1391e2e09989SDenis Pauk "ROG STRIX B660-I GAMING WIFI", 13925dcd53e3SDenis Pauk "ROG STRIX B760-A GAMING WIFI", 13935dcd53e3SDenis Pauk "ROG STRIX B760-A GAMING WIFI D4", 13945dcd53e3SDenis Pauk "ROG STRIX B760-F GAMING WIFI", 13955dcd53e3SDenis Pauk "ROG STRIX B760-G GAMING WIFI", 13965dcd53e3SDenis Pauk "ROG STRIX B760-G GAMING WIFI D4", 13975dcd53e3SDenis Pauk "ROG STRIX B760-I GAMING WIFI", 1398e2e09989SDenis Pauk "ROG STRIX X670E-A GAMING WIFI", 1399e2e09989SDenis Pauk "ROG STRIX X670E-E GAMING WIFI", 1400e2e09989SDenis Pauk "ROG STRIX X670E-F GAMING WIFI", 1401e2e09989SDenis Pauk "ROG STRIX X670E-I GAMING WIFI", 1402bcd2fbecSDenis Pauk "ROG STRIX Z590-A GAMING WIFI", 1403e2e09989SDenis Pauk "ROG STRIX Z590-A GAMING WIFI II", 1404bcd2fbecSDenis Pauk "ROG STRIX Z590-E GAMING WIFI", 1405bcd2fbecSDenis Pauk "ROG STRIX Z590-F GAMING WIFI", 1406bcd2fbecSDenis Pauk "ROG STRIX Z590-I GAMING WIFI", 1407a4fffe48SDenis Pauk "ROG STRIX Z690-A GAMING WIFI", 1408e2e09989SDenis Pauk "ROG STRIX Z690-A GAMING WIFI D4", 14095dcd53e3SDenis Pauk "ROG STRIX Z690-E GAMING WIFI", 14105dcd53e3SDenis Pauk "ROG STRIX Z690-F GAMING WIFI", 14115dcd53e3SDenis Pauk "ROG STRIX Z690-G GAMING WIFI", 1412a4fffe48SDenis Pauk "ROG STRIX Z690-I GAMING WIFI", 1413a4fffe48SDenis Pauk "ROG STRIX Z790-A GAMING WIFI", 1414a4fffe48SDenis Pauk "ROG STRIX Z790-A GAMING WIFI D4", 1415a4fffe48SDenis Pauk "ROG STRIX Z790-E GAMING WIFI", 1416a4fffe48SDenis Pauk "ROG STRIX Z790-F GAMING WIFI", 1417a4fffe48SDenis Pauk "ROG STRIX Z790-H GAMING WIFI", 1418a4fffe48SDenis Pauk "ROG STRIX Z790-I GAMING WIFI", 14195dcd53e3SDenis Pauk "TUF GAMING A620M-PLUS", 14205dcd53e3SDenis Pauk "TUF GAMING A620M-PLUS WIFI", 1421a4fffe48SDenis Pauk "TUF GAMING B560-PLUS WIFI", 1422a4fffe48SDenis Pauk "TUF GAMING B560M-E", 1423a4fffe48SDenis Pauk "TUF GAMING B560M-PLUS", 1424a4fffe48SDenis Pauk "TUF GAMING B560M-PLUS WIFI", 1425e2e09989SDenis Pauk "TUF GAMING B650-PLUS", 1426e2e09989SDenis Pauk "TUF GAMING B650-PLUS WIFI", 1427e2e09989SDenis Pauk "TUF GAMING B650M-PLUS", 1428e2e09989SDenis Pauk "TUF GAMING B650M-PLUS WIFI", 1429bcd2fbecSDenis Pauk "TUF GAMING B660-PLUS WIFI D4", 1430bcd2fbecSDenis Pauk "TUF GAMING B660M-E D4", 14315dcd53e3SDenis Pauk "TUF GAMING B660M-PLUS D4", 1432e2e09989SDenis Pauk "TUF GAMING B660M-PLUS WIFI", 14335dcd53e3SDenis Pauk "TUF GAMING B660M-PLUS WIFI D4", 14345dcd53e3SDenis Pauk "TUF GAMING B760-PLUS WIFI", 14355dcd53e3SDenis Pauk "TUF GAMING B760-PLUS WIFI D4", 14365dcd53e3SDenis Pauk "TUF GAMING B760M-BTF WIFI D4", 14375dcd53e3SDenis Pauk "TUF GAMING B760M-E D4", 14385dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS", 14395dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS D4", 14405dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS WIFI", 14415dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS WIFI D4", 14425dcd53e3SDenis Pauk "TUF GAMING H570-PRO", 14435dcd53e3SDenis Pauk "TUF GAMING H570-PRO WIFI", 14445dcd53e3SDenis Pauk "TUF GAMING H670-PRO WIFI D4", 14455dcd53e3SDenis Pauk "TUF GAMING H770-PRO WIFI", 1446e2e09989SDenis Pauk "TUF GAMING X670E-PLUS", 1447e2e09989SDenis Pauk "TUF GAMING X670E-PLUS WIFI", 1448bcd2fbecSDenis Pauk "TUF GAMING Z590-PLUS", 1449e2e09989SDenis Pauk "TUF GAMING Z590-PLUS WIFI", 1450a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS", 1451a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS D4", 1452a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS WIFI", 1453a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS WIFI D4", 1454a4fffe48SDenis Pauk "TUF GAMING Z790-PLUS D4", 1455a4fffe48SDenis Pauk "TUF GAMING Z790-PLUS WIFI", 1456a4fffe48SDenis Pauk "TUF GAMING Z790-PLUS WIFI D4", 1457bcd2fbecSDenis Pauk "Z590 WIFI GUNDAM EDITION", 1458e2e09989SDenis Pauk }; 1459e2e09989SDenis Pauk 1460c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 1461c3b3747dSDenis Pauk /* 1462c3b3747dSDenis Pauk * Callback for acpi_bus_for_each_dev() to find the right device 1463c3b3747dSDenis Pauk * by _UID and _HID and return 1 to stop iteration. 1464c3b3747dSDenis Pauk */ 1465c3b3747dSDenis Pauk static int nct6775_asuswmi_device_match(struct device *dev, void *data) 1466c3b3747dSDenis Pauk { 1467c3b3747dSDenis Pauk struct acpi_device *adev = to_acpi_device(dev); 1468c3b3747dSDenis Pauk 14691b515cfeSRaag Jadav if (acpi_dev_hid_uid_match(adev, ASUSWMI_DEVICE_HID, data)) { 1470c3b3747dSDenis Pauk asus_acpi_dev = adev; 1471c3b3747dSDenis Pauk return 1; 1472c3b3747dSDenis Pauk } 1473c3b3747dSDenis Pauk 1474c3b3747dSDenis Pauk return 0; 1475c3b3747dSDenis Pauk } 1476c3b3747dSDenis Pauk #endif 1477c3b3747dSDenis Pauk 1478c3b3747dSDenis Pauk static enum sensor_access nct6775_determine_access(const char *device_uid) 1479c3b3747dSDenis Pauk { 1480c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 1481c3b3747dSDenis Pauk u8 tmp; 1482c3b3747dSDenis Pauk 1483c3b3747dSDenis Pauk acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid); 1484c3b3747dSDenis Pauk if (!asus_acpi_dev) 1485c3b3747dSDenis Pauk return access_direct; 1486c3b3747dSDenis Pauk 1487c3b3747dSDenis Pauk /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */ 1488c3b3747dSDenis Pauk if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { 1489c3b3747dSDenis Pauk pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp); 1490c3b3747dSDenis Pauk return access_asuswmi; 1491c3b3747dSDenis Pauk } 1492c3b3747dSDenis Pauk #endif 1493c3b3747dSDenis Pauk 1494c3b3747dSDenis Pauk return access_direct; 1495c3b3747dSDenis Pauk } 1496c3b3747dSDenis Pauk 1497c3963bc0SZev Weiss static int __init sensors_nct6775_platform_init(void) 1498c3963bc0SZev Weiss { 1499c3963bc0SZev Weiss int i, err; 1500c3963bc0SZev Weiss bool found = false; 1501c3963bc0SZev Weiss int address; 1502c3963bc0SZev Weiss struct resource res; 1503c3963bc0SZev Weiss struct nct6775_sio_data sio_data; 1504c3963bc0SZev Weiss int sioaddr[2] = { 0x2e, 0x4e }; 1505c3963bc0SZev Weiss enum sensor_access access = access_direct; 1506c3963bc0SZev Weiss const char *board_vendor, *board_name; 1507c3963bc0SZev Weiss 1508c3963bc0SZev Weiss err = platform_driver_register(&nct6775_driver); 1509c3963bc0SZev Weiss if (err) 1510c3963bc0SZev Weiss return err; 1511c3963bc0SZev Weiss 1512c3963bc0SZev Weiss board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 1513c3963bc0SZev Weiss board_name = dmi_get_system_info(DMI_BOARD_NAME); 1514c3963bc0SZev Weiss 1515c3963bc0SZev Weiss if (board_name && board_vendor && 1516c3963bc0SZev Weiss !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) { 1517c3963bc0SZev Weiss err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards), 1518c3963bc0SZev Weiss board_name); 1519c3b3747dSDenis Pauk if (err >= 0) 1520c3b3747dSDenis Pauk access = nct6775_determine_access(ASUSWMI_DEVICE_UID); 1521e2e09989SDenis Pauk 1522e2e09989SDenis Pauk err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards), 1523e2e09989SDenis Pauk board_name); 1524e2e09989SDenis Pauk if (err >= 0) 1525e2e09989SDenis Pauk access = nct6775_determine_access(ASUSMSI_DEVICE_UID); 1526c3963bc0SZev Weiss } 1527c3963bc0SZev Weiss 1528c3963bc0SZev Weiss /* 1529c3963bc0SZev Weiss * initialize sio_data->kind and sio_data->sioreg. 1530c3963bc0SZev Weiss * 1531c3963bc0SZev Weiss * when Super-I/O functions move to a separate file, the Super-I/O 1532c3963bc0SZev Weiss * driver will probe 0x2e and 0x4e and auto-detect the presence of a 1533c3963bc0SZev Weiss * nct6775 hardware monitor, and call probe() 1534c3963bc0SZev Weiss */ 1535c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(pdev); i++) { 1536c3963bc0SZev Weiss sio_data.sio_outb = superio_outb; 1537c3963bc0SZev Weiss sio_data.sio_inb = superio_inb; 1538c3963bc0SZev Weiss sio_data.sio_select = superio_select; 1539c3963bc0SZev Weiss sio_data.sio_enter = superio_enter; 1540c3963bc0SZev Weiss sio_data.sio_exit = superio_exit; 1541c3963bc0SZev Weiss 1542c3963bc0SZev Weiss address = nct6775_find(sioaddr[i], &sio_data); 1543c3963bc0SZev Weiss if (address <= 0) 1544c3963bc0SZev Weiss continue; 1545c3963bc0SZev Weiss 1546c3963bc0SZev Weiss found = true; 1547c3963bc0SZev Weiss 1548c3963bc0SZev Weiss sio_data.access = access; 1549c3963bc0SZev Weiss 1550c3963bc0SZev Weiss if (access == access_asuswmi) { 1551c3963bc0SZev Weiss sio_data.sio_outb = superio_wmi_outb; 1552c3963bc0SZev Weiss sio_data.sio_inb = superio_wmi_inb; 1553c3963bc0SZev Weiss sio_data.sio_select = superio_wmi_select; 1554c3963bc0SZev Weiss sio_data.sio_enter = superio_wmi_enter; 1555c3963bc0SZev Weiss sio_data.sio_exit = superio_wmi_exit; 1556c3963bc0SZev Weiss } 1557c3963bc0SZev Weiss 1558c3963bc0SZev Weiss pdev[i] = platform_device_alloc(DRVNAME, address); 1559c3963bc0SZev Weiss if (!pdev[i]) { 1560c3963bc0SZev Weiss err = -ENOMEM; 1561c3963bc0SZev Weiss goto exit_device_unregister; 1562c3963bc0SZev Weiss } 1563c3963bc0SZev Weiss 1564c3963bc0SZev Weiss err = platform_device_add_data(pdev[i], &sio_data, 1565c3963bc0SZev Weiss sizeof(struct nct6775_sio_data)); 1566c3963bc0SZev Weiss if (err) 1567c3963bc0SZev Weiss goto exit_device_put; 1568c3963bc0SZev Weiss 1569c3963bc0SZev Weiss if (sio_data.access == access_direct) { 1570c3963bc0SZev Weiss memset(&res, 0, sizeof(res)); 1571c3963bc0SZev Weiss res.name = DRVNAME; 1572c3963bc0SZev Weiss res.start = address + IOREGION_OFFSET; 1573c3963bc0SZev Weiss res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; 1574c3963bc0SZev Weiss res.flags = IORESOURCE_IO; 1575c3963bc0SZev Weiss 1576c3963bc0SZev Weiss err = acpi_check_resource_conflict(&res); 1577c3963bc0SZev Weiss if (err) { 1578c3963bc0SZev Weiss platform_device_put(pdev[i]); 1579c3963bc0SZev Weiss pdev[i] = NULL; 1580c3963bc0SZev Weiss continue; 1581c3963bc0SZev Weiss } 1582c3963bc0SZev Weiss 1583c3963bc0SZev Weiss err = platform_device_add_resources(pdev[i], &res, 1); 1584c3963bc0SZev Weiss if (err) 1585c3963bc0SZev Weiss goto exit_device_put; 1586c3963bc0SZev Weiss } 1587c3963bc0SZev Weiss 1588c3963bc0SZev Weiss /* platform_device_add calls probe() */ 1589c3963bc0SZev Weiss err = platform_device_add(pdev[i]); 1590c3963bc0SZev Weiss if (err) 1591c3963bc0SZev Weiss goto exit_device_put; 1592c3963bc0SZev Weiss } 1593c3963bc0SZev Weiss if (!found) { 1594c3963bc0SZev Weiss err = -ENODEV; 1595c3963bc0SZev Weiss goto exit_unregister; 1596c3963bc0SZev Weiss } 1597c3963bc0SZev Weiss 1598c3963bc0SZev Weiss return 0; 1599c3963bc0SZev Weiss 1600c3963bc0SZev Weiss exit_device_put: 1601c3963bc0SZev Weiss platform_device_put(pdev[i]); 1602c3963bc0SZev Weiss exit_device_unregister: 1603452d5e29SAndy Shevchenko while (i--) 1604c3963bc0SZev Weiss platform_device_unregister(pdev[i]); 1605c3963bc0SZev Weiss exit_unregister: 1606c3963bc0SZev Weiss platform_driver_unregister(&nct6775_driver); 1607c3963bc0SZev Weiss return err; 1608c3963bc0SZev Weiss } 1609c3963bc0SZev Weiss 1610c3963bc0SZev Weiss static void __exit sensors_nct6775_platform_exit(void) 1611c3963bc0SZev Weiss { 1612c3963bc0SZev Weiss int i; 1613c3963bc0SZev Weiss 1614452d5e29SAndy Shevchenko for (i = 0; i < ARRAY_SIZE(pdev); i++) 1615c3963bc0SZev Weiss platform_device_unregister(pdev[i]); 1616c3963bc0SZev Weiss platform_driver_unregister(&nct6775_driver); 1617c3963bc0SZev Weiss } 1618c3963bc0SZev Weiss 1619c3963bc0SZev Weiss MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); 1620c3963bc0SZev Weiss MODULE_DESCRIPTION("Platform driver for NCT6775F and compatible chips"); 1621c3963bc0SZev Weiss MODULE_LICENSE("GPL"); 1622c3963bc0SZev Weiss MODULE_IMPORT_NS(HWMON_NCT6775); 1623c3963bc0SZev Weiss 1624c3963bc0SZev Weiss module_init(sensors_nct6775_platform_init); 1625c3963bc0SZev Weiss module_exit(sensors_nct6775_platform_exit); 1626