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 = { 26c3963bc0SZev Weiss "NCT6106D", 27c3963bc0SZev Weiss "NCT6116D", 28c3963bc0SZev Weiss "NCT6775F", 29c3963bc0SZev Weiss "NCT6776D/F", 30c3963bc0SZev Weiss "NCT6779D", 31c3963bc0SZev Weiss "NCT6791D", 32c3963bc0SZev Weiss "NCT6792D", 33c3963bc0SZev Weiss "NCT6793D", 34c3963bc0SZev Weiss "NCT6795D", 35c3963bc0SZev Weiss "NCT6796D", 36c3963bc0SZev Weiss "NCT6797D", 37c3963bc0SZev Weiss "NCT6798D", 38c3963bc0SZev Weiss }; 39c3963bc0SZev Weiss 40c3963bc0SZev Weiss static unsigned short force_id; 41c3963bc0SZev Weiss module_param(force_id, ushort, 0); 42c3963bc0SZev Weiss MODULE_PARM_DESC(force_id, "Override the detected device ID"); 43c3963bc0SZev Weiss 44c3963bc0SZev Weiss static unsigned short fan_debounce; 45c3963bc0SZev Weiss module_param(fan_debounce, ushort, 0); 46c3963bc0SZev Weiss MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); 47c3963bc0SZev Weiss 48c3963bc0SZev Weiss #define DRVNAME "nct6775" 49c3963bc0SZev Weiss 50c3963bc0SZev Weiss #define NCT6775_PORT_CHIPID 0x58 51c3963bc0SZev Weiss 52c3963bc0SZev Weiss /* 53c3963bc0SZev Weiss * ISA constants 54c3963bc0SZev Weiss */ 55c3963bc0SZev Weiss 56c3963bc0SZev Weiss #define IOREGION_ALIGNMENT (~7) 57c3963bc0SZev Weiss #define IOREGION_OFFSET 5 58c3963bc0SZev Weiss #define IOREGION_LENGTH 2 59c3963bc0SZev Weiss #define ADDR_REG_OFFSET 0 60c3963bc0SZev Weiss #define DATA_REG_OFFSET 1 61c3963bc0SZev Weiss 62c3963bc0SZev Weiss /* 63c3963bc0SZev Weiss * Super-I/O constants and functions 64c3963bc0SZev Weiss */ 65c3963bc0SZev Weiss 66c3963bc0SZev Weiss #define NCT6775_LD_ACPI 0x0a 67c3963bc0SZev Weiss #define NCT6775_LD_HWM 0x0b 68c3963bc0SZev Weiss #define NCT6775_LD_VID 0x0d 69c3963bc0SZev Weiss #define NCT6775_LD_12 0x12 70c3963bc0SZev Weiss 71c3963bc0SZev Weiss #define SIO_REG_LDSEL 0x07 /* Logical device select */ 72c3963bc0SZev Weiss #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ 73c3963bc0SZev Weiss #define SIO_REG_ENABLE 0x30 /* Logical device enable */ 74c3963bc0SZev Weiss #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ 75c3963bc0SZev Weiss 76c3963bc0SZev Weiss #define SIO_NCT6106_ID 0xc450 77c3963bc0SZev Weiss #define SIO_NCT6116_ID 0xd280 78c3963bc0SZev Weiss #define SIO_NCT6775_ID 0xb470 79c3963bc0SZev Weiss #define SIO_NCT6776_ID 0xc330 80c3963bc0SZev Weiss #define SIO_NCT6779_ID 0xc560 81c3963bc0SZev Weiss #define SIO_NCT6791_ID 0xc800 82c3963bc0SZev Weiss #define SIO_NCT6792_ID 0xc910 83c3963bc0SZev Weiss #define SIO_NCT6793_ID 0xd120 84c3963bc0SZev Weiss #define SIO_NCT6795_ID 0xd350 85c3963bc0SZev Weiss #define SIO_NCT6796_ID 0xd420 86c3963bc0SZev Weiss #define SIO_NCT6797_ID 0xd450 87c3963bc0SZev Weiss #define SIO_NCT6798_ID 0xd428 88c3963bc0SZev Weiss #define SIO_ID_MASK 0xFFF8 89c3963bc0SZev Weiss 90c3963bc0SZev Weiss /* 91c3963bc0SZev Weiss * Control registers 92c3963bc0SZev Weiss */ 93c3963bc0SZev Weiss #define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0 94c3963bc0SZev Weiss 95c3963bc0SZev Weiss struct nct6775_sio_data { 96c3963bc0SZev Weiss int sioreg; 97c3963bc0SZev Weiss int ld; 98c3963bc0SZev Weiss enum kinds kind; 99c3963bc0SZev Weiss enum sensor_access access; 100c3963bc0SZev Weiss 101c3963bc0SZev Weiss /* superio_() callbacks */ 102c3963bc0SZev Weiss void (*sio_outb)(struct nct6775_sio_data *sio_data, int reg, int val); 103c3963bc0SZev Weiss int (*sio_inb)(struct nct6775_sio_data *sio_data, int reg); 104c3963bc0SZev Weiss void (*sio_select)(struct nct6775_sio_data *sio_data, int ld); 105c3963bc0SZev Weiss int (*sio_enter)(struct nct6775_sio_data *sio_data); 106c3963bc0SZev Weiss void (*sio_exit)(struct nct6775_sio_data *sio_data); 107c3963bc0SZev Weiss }; 108c3963bc0SZev Weiss 109c3b3747dSDenis Pauk #define ASUSWMI_METHOD "WMBD" 110c3963bc0SZev Weiss #define ASUSWMI_METHODID_RSIO 0x5253494F 111c3963bc0SZev Weiss #define ASUSWMI_METHODID_WSIO 0x5753494F 112c3963bc0SZev Weiss #define ASUSWMI_METHODID_RHWM 0x5248574D 113c3963bc0SZev Weiss #define ASUSWMI_METHODID_WHWM 0x5748574D 114c3963bc0SZev Weiss #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE 115c3b3747dSDenis Pauk #define ASUSWMI_DEVICE_HID "PNP0C14" 116c3b3747dSDenis Pauk #define ASUSWMI_DEVICE_UID "ASUSWMI" 117e2e09989SDenis Pauk #define ASUSMSI_DEVICE_UID "AsusMbSwInterface" 118c3b3747dSDenis Pauk 119c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 120c3b3747dSDenis Pauk /* 121c3b3747dSDenis Pauk * ASUS boards have only one device with WMI "WMBD" method and have provided 122c3b3747dSDenis Pauk * access to only one SuperIO chip at 0x0290. 123c3b3747dSDenis Pauk */ 124c3b3747dSDenis Pauk static struct acpi_device *asus_acpi_dev; 125c3b3747dSDenis Pauk #endif 126c3963bc0SZev Weiss 127c3963bc0SZev Weiss static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) 128c3963bc0SZev Weiss { 129c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 130c3b3747dSDenis Pauk acpi_handle handle = acpi_device_handle(asus_acpi_dev); 131c3963bc0SZev Weiss u32 args = bank | (reg << 8) | (val << 16); 132c3b3747dSDenis Pauk struct acpi_object_list input; 133c3b3747dSDenis Pauk union acpi_object params[3]; 134c3b3747dSDenis Pauk unsigned long long result; 135c3963bc0SZev Weiss acpi_status status; 136c3963bc0SZev Weiss 137c3b3747dSDenis Pauk params[0].type = ACPI_TYPE_INTEGER; 138c3b3747dSDenis Pauk params[0].integer.value = 0; 139c3b3747dSDenis Pauk params[1].type = ACPI_TYPE_INTEGER; 140c3b3747dSDenis Pauk params[1].integer.value = method_id; 141c3b3747dSDenis Pauk params[2].type = ACPI_TYPE_BUFFER; 142c3b3747dSDenis Pauk params[2].buffer.length = sizeof(args); 143c3b3747dSDenis Pauk params[2].buffer.pointer = (void *)&args; 144c3b3747dSDenis Pauk input.count = 3; 145c3b3747dSDenis Pauk input.pointer = params; 146c3963bc0SZev Weiss 147c3b3747dSDenis Pauk status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result); 148c3963bc0SZev Weiss if (ACPI_FAILURE(status)) 149c3963bc0SZev Weiss return -EIO; 150c3963bc0SZev Weiss 151c3963bc0SZev Weiss if (retval) 15208d40c1dSAndy Shevchenko *retval = result; 153c3963bc0SZev Weiss 154c3963bc0SZev Weiss return 0; 155c3963bc0SZev Weiss #else 156c3963bc0SZev Weiss return -EOPNOTSUPP; 157c3963bc0SZev Weiss #endif 158c3963bc0SZev Weiss } 159c3963bc0SZev Weiss 160c3963bc0SZev Weiss static inline int nct6775_asuswmi_write(u8 bank, u8 reg, u8 val) 161c3963bc0SZev Weiss { 162c3963bc0SZev Weiss return nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_WHWM, bank, 163c3963bc0SZev Weiss reg, val, NULL); 164c3963bc0SZev Weiss } 165c3963bc0SZev Weiss 166c3963bc0SZev Weiss static inline int nct6775_asuswmi_read(u8 bank, u8 reg, u8 *val) 167c3963bc0SZev Weiss { 168c3963bc0SZev Weiss u32 ret, tmp = 0; 169c3963bc0SZev Weiss 170c3963bc0SZev Weiss ret = nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RHWM, bank, 171c3963bc0SZev Weiss reg, 0, &tmp); 172c3963bc0SZev Weiss *val = tmp; 173c3963bc0SZev Weiss return ret; 174c3963bc0SZev Weiss } 175c3963bc0SZev Weiss 176c3963bc0SZev Weiss static int superio_wmi_inb(struct nct6775_sio_data *sio_data, int reg) 177c3963bc0SZev Weiss { 178c3963bc0SZev Weiss int tmp = 0; 179c3963bc0SZev Weiss 180c3963bc0SZev Weiss nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RSIO, sio_data->ld, 181c3963bc0SZev Weiss reg, 0, &tmp); 182c3963bc0SZev Weiss return tmp; 183c3963bc0SZev Weiss } 184c3963bc0SZev Weiss 185c3963bc0SZev Weiss static void superio_wmi_outb(struct nct6775_sio_data *sio_data, int reg, int val) 186c3963bc0SZev Weiss { 187c3963bc0SZev Weiss nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_WSIO, sio_data->ld, 188c3963bc0SZev Weiss reg, val, NULL); 189c3963bc0SZev Weiss } 190c3963bc0SZev Weiss 191c3963bc0SZev Weiss static void superio_wmi_select(struct nct6775_sio_data *sio_data, int ld) 192c3963bc0SZev Weiss { 193c3963bc0SZev Weiss sio_data->ld = ld; 194c3963bc0SZev Weiss } 195c3963bc0SZev Weiss 196c3963bc0SZev Weiss static int superio_wmi_enter(struct nct6775_sio_data *sio_data) 197c3963bc0SZev Weiss { 198c3963bc0SZev Weiss return 0; 199c3963bc0SZev Weiss } 200c3963bc0SZev Weiss 201c3963bc0SZev Weiss static void superio_wmi_exit(struct nct6775_sio_data *sio_data) 202c3963bc0SZev Weiss { 203c3963bc0SZev Weiss } 204c3963bc0SZev Weiss 205c3963bc0SZev Weiss static void superio_outb(struct nct6775_sio_data *sio_data, int reg, int val) 206c3963bc0SZev Weiss { 207c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 208c3963bc0SZev Weiss 209c3963bc0SZev Weiss outb(reg, ioreg); 210c3963bc0SZev Weiss outb(val, ioreg + 1); 211c3963bc0SZev Weiss } 212c3963bc0SZev Weiss 213c3963bc0SZev Weiss static int superio_inb(struct nct6775_sio_data *sio_data, int reg) 214c3963bc0SZev Weiss { 215c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 216c3963bc0SZev Weiss 217c3963bc0SZev Weiss outb(reg, ioreg); 218c3963bc0SZev Weiss return inb(ioreg + 1); 219c3963bc0SZev Weiss } 220c3963bc0SZev Weiss 221c3963bc0SZev Weiss static void superio_select(struct nct6775_sio_data *sio_data, int ld) 222c3963bc0SZev Weiss { 223c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 224c3963bc0SZev Weiss 225c3963bc0SZev Weiss outb(SIO_REG_LDSEL, ioreg); 226c3963bc0SZev Weiss outb(ld, ioreg + 1); 227c3963bc0SZev Weiss } 228c3963bc0SZev Weiss 229c3963bc0SZev Weiss static int superio_enter(struct nct6775_sio_data *sio_data) 230c3963bc0SZev Weiss { 231c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 232c3963bc0SZev Weiss 233c3963bc0SZev Weiss /* 234c3963bc0SZev Weiss * Try to reserve <ioreg> and <ioreg + 1> for exclusive access. 235c3963bc0SZev Weiss */ 236c3963bc0SZev Weiss if (!request_muxed_region(ioreg, 2, DRVNAME)) 237c3963bc0SZev Weiss return -EBUSY; 238c3963bc0SZev Weiss 239c3963bc0SZev Weiss outb(0x87, ioreg); 240c3963bc0SZev Weiss outb(0x87, ioreg); 241c3963bc0SZev Weiss 242c3963bc0SZev Weiss return 0; 243c3963bc0SZev Weiss } 244c3963bc0SZev Weiss 245c3963bc0SZev Weiss static void superio_exit(struct nct6775_sio_data *sio_data) 246c3963bc0SZev Weiss { 247c3963bc0SZev Weiss int ioreg = sio_data->sioreg; 248c3963bc0SZev Weiss 249c3963bc0SZev Weiss outb(0xaa, ioreg); 250c3963bc0SZev Weiss outb(0x02, ioreg); 251c3963bc0SZev Weiss outb(0x02, ioreg + 1); 252c3963bc0SZev Weiss release_region(ioreg, 2); 253c3963bc0SZev Weiss } 254c3963bc0SZev Weiss 255c3963bc0SZev Weiss static inline void nct6775_wmi_set_bank(struct nct6775_data *data, u16 reg) 256c3963bc0SZev Weiss { 257c3963bc0SZev Weiss u8 bank = reg >> 8; 258c3963bc0SZev Weiss 259c3963bc0SZev Weiss data->bank = bank; 260c3963bc0SZev Weiss } 261c3963bc0SZev Weiss 262c3963bc0SZev Weiss static int nct6775_wmi_reg_read(void *ctx, unsigned int reg, unsigned int *val) 263c3963bc0SZev Weiss { 264c3963bc0SZev Weiss struct nct6775_data *data = ctx; 265c3963bc0SZev Weiss int err, word_sized = nct6775_reg_is_word_sized(data, reg); 266c3963bc0SZev Weiss u8 tmp = 0; 267c3963bc0SZev Weiss u16 res; 268c3963bc0SZev Weiss 269c3963bc0SZev Weiss nct6775_wmi_set_bank(data, reg); 270c3963bc0SZev Weiss 271c3963bc0SZev Weiss err = nct6775_asuswmi_read(data->bank, reg & 0xff, &tmp); 272c3963bc0SZev Weiss if (err) 273c3963bc0SZev Weiss return err; 274c3963bc0SZev Weiss 275c3963bc0SZev Weiss res = tmp; 276c3963bc0SZev Weiss if (word_sized) { 277c3963bc0SZev Weiss err = nct6775_asuswmi_read(data->bank, (reg & 0xff) + 1, &tmp); 278c3963bc0SZev Weiss if (err) 279c3963bc0SZev Weiss return err; 280c3963bc0SZev Weiss 281c3963bc0SZev Weiss res = (res << 8) + tmp; 282c3963bc0SZev Weiss } 283c3963bc0SZev Weiss *val = res; 284c3963bc0SZev Weiss return 0; 285c3963bc0SZev Weiss } 286c3963bc0SZev Weiss 287c3963bc0SZev Weiss static int nct6775_wmi_reg_write(void *ctx, unsigned int reg, unsigned int value) 288c3963bc0SZev Weiss { 289c3963bc0SZev Weiss struct nct6775_data *data = ctx; 290c3963bc0SZev Weiss int res, word_sized = nct6775_reg_is_word_sized(data, reg); 291c3963bc0SZev Weiss 292c3963bc0SZev Weiss nct6775_wmi_set_bank(data, reg); 293c3963bc0SZev Weiss 294c3963bc0SZev Weiss if (word_sized) { 295c3963bc0SZev Weiss res = nct6775_asuswmi_write(data->bank, reg & 0xff, value >> 8); 296c3963bc0SZev Weiss if (res) 297c3963bc0SZev Weiss return res; 298c3963bc0SZev Weiss 299c3963bc0SZev Weiss res = nct6775_asuswmi_write(data->bank, (reg & 0xff) + 1, value); 300c3963bc0SZev Weiss } else { 301c3963bc0SZev Weiss res = nct6775_asuswmi_write(data->bank, reg & 0xff, value); 302c3963bc0SZev Weiss } 303c3963bc0SZev Weiss 304c3963bc0SZev Weiss return res; 305c3963bc0SZev Weiss } 306c3963bc0SZev Weiss 307c3963bc0SZev Weiss /* 308c3963bc0SZev Weiss * On older chips, only registers 0x50-0x5f are banked. 309c3963bc0SZev Weiss * On more recent chips, all registers are banked. 310c3963bc0SZev Weiss * Assume that is the case and set the bank number for each access. 311c3963bc0SZev Weiss * Cache the bank number so it only needs to be set if it changes. 312c3963bc0SZev Weiss */ 313c3963bc0SZev Weiss static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg) 314c3963bc0SZev Weiss { 315c3963bc0SZev Weiss u8 bank = reg >> 8; 316c3963bc0SZev Weiss 317c3963bc0SZev Weiss if (data->bank != bank) { 318c3963bc0SZev Weiss outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET); 319c3963bc0SZev Weiss outb_p(bank, data->addr + DATA_REG_OFFSET); 320c3963bc0SZev Weiss data->bank = bank; 321c3963bc0SZev Weiss } 322c3963bc0SZev Weiss } 323c3963bc0SZev Weiss 324c3963bc0SZev Weiss static int nct6775_reg_read(void *ctx, unsigned int reg, unsigned int *val) 325c3963bc0SZev Weiss { 326c3963bc0SZev Weiss struct nct6775_data *data = ctx; 327c3963bc0SZev Weiss int word_sized = nct6775_reg_is_word_sized(data, reg); 328c3963bc0SZev Weiss 329c3963bc0SZev Weiss nct6775_set_bank(data, reg); 330c3963bc0SZev Weiss outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); 331c3963bc0SZev Weiss *val = inb_p(data->addr + DATA_REG_OFFSET); 332c3963bc0SZev Weiss if (word_sized) { 333c3963bc0SZev Weiss outb_p((reg & 0xff) + 1, 334c3963bc0SZev Weiss data->addr + ADDR_REG_OFFSET); 335c3963bc0SZev Weiss *val = (*val << 8) + inb_p(data->addr + DATA_REG_OFFSET); 336c3963bc0SZev Weiss } 337c3963bc0SZev Weiss return 0; 338c3963bc0SZev Weiss } 339c3963bc0SZev Weiss 340c3963bc0SZev Weiss static int nct6775_reg_write(void *ctx, unsigned int reg, unsigned int value) 341c3963bc0SZev Weiss { 342c3963bc0SZev Weiss struct nct6775_data *data = ctx; 343c3963bc0SZev Weiss int word_sized = nct6775_reg_is_word_sized(data, reg); 344c3963bc0SZev Weiss 345c3963bc0SZev Weiss nct6775_set_bank(data, reg); 346c3963bc0SZev Weiss outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); 347c3963bc0SZev Weiss if (word_sized) { 348c3963bc0SZev Weiss outb_p(value >> 8, data->addr + DATA_REG_OFFSET); 349c3963bc0SZev Weiss outb_p((reg & 0xff) + 1, 350c3963bc0SZev Weiss data->addr + ADDR_REG_OFFSET); 351c3963bc0SZev Weiss } 352c3963bc0SZev Weiss outb_p(value & 0xff, data->addr + DATA_REG_OFFSET); 353c3963bc0SZev Weiss return 0; 354c3963bc0SZev Weiss } 355c3963bc0SZev Weiss 356c3963bc0SZev Weiss static void nct6791_enable_io_mapping(struct nct6775_sio_data *sio_data) 357c3963bc0SZev Weiss { 358c3963bc0SZev Weiss int val; 359c3963bc0SZev Weiss 360c3963bc0SZev Weiss val = sio_data->sio_inb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE); 361c3963bc0SZev Weiss if (val & 0x10) { 362c3963bc0SZev Weiss pr_info("Enabling hardware monitor logical device mappings.\n"); 363c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE, 364c3963bc0SZev Weiss val & ~0x10); 365c3963bc0SZev Weiss } 366c3963bc0SZev Weiss } 367c3963bc0SZev Weiss 3688de7295cSJonathan Cameron static int nct6775_suspend(struct device *dev) 369c3963bc0SZev Weiss { 370c3963bc0SZev Weiss int err; 371c3963bc0SZev Weiss u16 tmp; 372f4e6960fSZev Weiss struct nct6775_data *data = nct6775_update_device(dev); 373c3963bc0SZev Weiss 374c3963bc0SZev Weiss if (IS_ERR(data)) 375c3963bc0SZev Weiss return PTR_ERR(data); 376c3963bc0SZev Weiss 377c3963bc0SZev Weiss mutex_lock(&data->update_lock); 378c3963bc0SZev Weiss err = nct6775_read_value(data, data->REG_VBAT, &tmp); 379c3963bc0SZev Weiss if (err) 380c3963bc0SZev Weiss goto out; 381c3963bc0SZev Weiss data->vbat = tmp; 382c3963bc0SZev Weiss if (data->kind == nct6775) { 383c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_FANDIV1, &tmp); 384c3963bc0SZev Weiss if (err) 385c3963bc0SZev Weiss goto out; 386c3963bc0SZev Weiss data->fandiv1 = tmp; 387c3963bc0SZev Weiss 388c3963bc0SZev Weiss err = nct6775_read_value(data, NCT6775_REG_FANDIV2, &tmp); 389c3963bc0SZev Weiss if (err) 390c3963bc0SZev Weiss goto out; 391c3963bc0SZev Weiss data->fandiv2 = tmp; 392c3963bc0SZev Weiss } 393c3963bc0SZev Weiss out: 394c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 395c3963bc0SZev Weiss 396c3963bc0SZev Weiss return err; 397c3963bc0SZev Weiss } 398c3963bc0SZev Weiss 3998de7295cSJonathan Cameron static int nct6775_resume(struct device *dev) 400c3963bc0SZev Weiss { 401c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 402c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = dev_get_platdata(dev); 403c3963bc0SZev Weiss int i, j, err = 0; 404c3963bc0SZev Weiss u8 reg; 405c3963bc0SZev Weiss 406c3963bc0SZev Weiss mutex_lock(&data->update_lock); 407c3963bc0SZev Weiss data->bank = 0xff; /* Force initial bank selection */ 408c3963bc0SZev Weiss 409c3963bc0SZev Weiss err = sio_data->sio_enter(sio_data); 410c3963bc0SZev Weiss if (err) 411c3963bc0SZev Weiss goto abort; 412c3963bc0SZev Weiss 413c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 414c3963bc0SZev Weiss reg = sio_data->sio_inb(sio_data, SIO_REG_ENABLE); 415c3963bc0SZev Weiss if (reg != data->sio_reg_enable) 416c3963bc0SZev Weiss sio_data->sio_outb(sio_data, SIO_REG_ENABLE, data->sio_reg_enable); 417c3963bc0SZev Weiss 418c3963bc0SZev Weiss if (data->kind == nct6791 || data->kind == nct6792 || 419c3963bc0SZev Weiss data->kind == nct6793 || data->kind == nct6795 || 420c3963bc0SZev Weiss data->kind == nct6796 || data->kind == nct6797 || 421c3963bc0SZev Weiss data->kind == nct6798) 422c3963bc0SZev Weiss nct6791_enable_io_mapping(sio_data); 423c3963bc0SZev Weiss 424c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 425c3963bc0SZev Weiss 426c3963bc0SZev Weiss /* Restore limits */ 427c3963bc0SZev Weiss for (i = 0; i < data->in_num; i++) { 428c3963bc0SZev Weiss if (!(data->have_in & BIT(i))) 429c3963bc0SZev Weiss continue; 430c3963bc0SZev Weiss 431c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_IN_MINMAX[0][i], data->in[i][1]); 432c3963bc0SZev Weiss if (err) 433c3963bc0SZev Weiss goto abort; 434c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_IN_MINMAX[1][i], data->in[i][2]); 435c3963bc0SZev Weiss if (err) 436c3963bc0SZev Weiss goto abort; 437c3963bc0SZev Weiss } 438c3963bc0SZev Weiss 439c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { 440c3963bc0SZev Weiss if (!(data->has_fan_min & BIT(i))) 441c3963bc0SZev Weiss continue; 442c3963bc0SZev Weiss 443c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_FAN_MIN[i], data->fan_min[i]); 444c3963bc0SZev Weiss if (err) 445c3963bc0SZev Weiss goto abort; 446c3963bc0SZev Weiss } 447c3963bc0SZev Weiss 448c3963bc0SZev Weiss for (i = 0; i < NUM_TEMP; i++) { 449c3963bc0SZev Weiss if (!(data->have_temp & BIT(i))) 450c3963bc0SZev Weiss continue; 451c3963bc0SZev Weiss 452c3963bc0SZev Weiss for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++) 453c3963bc0SZev Weiss if (data->reg_temp[j][i]) { 454c3963bc0SZev Weiss err = nct6775_write_temp(data, data->reg_temp[j][i], 455c3963bc0SZev Weiss data->temp[j][i]); 456c3963bc0SZev Weiss if (err) 457c3963bc0SZev Weiss goto abort; 458c3963bc0SZev Weiss } 459c3963bc0SZev Weiss } 460c3963bc0SZev Weiss 461c3963bc0SZev Weiss /* Restore other settings */ 462c3963bc0SZev Weiss err = nct6775_write_value(data, data->REG_VBAT, data->vbat); 463c3963bc0SZev Weiss if (err) 464c3963bc0SZev Weiss goto abort; 465c3963bc0SZev Weiss if (data->kind == nct6775) { 466c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1); 467c3963bc0SZev Weiss if (err) 468c3963bc0SZev Weiss goto abort; 469c3963bc0SZev Weiss err = nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2); 470c3963bc0SZev Weiss } 471c3963bc0SZev Weiss 472c3963bc0SZev Weiss abort: 473c3963bc0SZev Weiss /* Force re-reading all values */ 474c3963bc0SZev Weiss data->valid = false; 475c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 476c3963bc0SZev Weiss 477c3963bc0SZev Weiss return err; 478c3963bc0SZev Weiss } 479c3963bc0SZev Weiss 4808de7295cSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume); 481c3963bc0SZev Weiss 482c3963bc0SZev Weiss static void 483c3963bc0SZev Weiss nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio_data) 484c3963bc0SZev Weiss { 485c3963bc0SZev Weiss bool fan3pin = false, fan4pin = false, fan4min = false; 486c3963bc0SZev Weiss bool fan5pin = false, fan6pin = false, fan7pin = false; 487c3963bc0SZev Weiss bool pwm3pin = false, pwm4pin = false, pwm5pin = false; 488c3963bc0SZev Weiss bool pwm6pin = false, pwm7pin = false; 489c3963bc0SZev Weiss 490c3963bc0SZev Weiss /* Store SIO_REG_ENABLE for use during resume */ 491c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 492c3963bc0SZev Weiss data->sio_reg_enable = sio_data->sio_inb(sio_data, SIO_REG_ENABLE); 493c3963bc0SZev Weiss 494c3963bc0SZev Weiss /* fan4 and fan5 share some pins with the GPIO and serial flash */ 495c3963bc0SZev Weiss if (data->kind == nct6775) { 496c3963bc0SZev Weiss int cr2c = sio_data->sio_inb(sio_data, 0x2c); 497c3963bc0SZev Weiss 498c3963bc0SZev Weiss fan3pin = cr2c & BIT(6); 499c3963bc0SZev Weiss pwm3pin = cr2c & BIT(7); 500c3963bc0SZev Weiss 501c3963bc0SZev Weiss /* On NCT6775, fan4 shares pins with the fdc interface */ 502c3963bc0SZev Weiss fan4pin = !(sio_data->sio_inb(sio_data, 0x2A) & 0x80); 503c3963bc0SZev Weiss } else if (data->kind == nct6776) { 504c3963bc0SZev Weiss bool gpok = sio_data->sio_inb(sio_data, 0x27) & 0x80; 505c3963bc0SZev Weiss const char *board_vendor, *board_name; 506c3963bc0SZev Weiss 507c3963bc0SZev Weiss board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 508c3963bc0SZev Weiss board_name = dmi_get_system_info(DMI_BOARD_NAME); 509c3963bc0SZev Weiss 510c3963bc0SZev Weiss if (board_name && board_vendor && 511c3963bc0SZev Weiss !strcmp(board_vendor, "ASRock")) { 512c3963bc0SZev Weiss /* 513c3963bc0SZev Weiss * Auxiliary fan monitoring is not enabled on ASRock 514c3963bc0SZev Weiss * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode. 515c3963bc0SZev Weiss * Observed with BIOS version 2.00. 516c3963bc0SZev Weiss */ 517c3963bc0SZev Weiss if (!strcmp(board_name, "Z77 Pro4-M")) { 518c3963bc0SZev Weiss if ((data->sio_reg_enable & 0xe0) != 0xe0) { 519c3963bc0SZev Weiss data->sio_reg_enable |= 0xe0; 520c3963bc0SZev Weiss sio_data->sio_outb(sio_data, SIO_REG_ENABLE, 521c3963bc0SZev Weiss data->sio_reg_enable); 522c3963bc0SZev Weiss } 523c3963bc0SZev Weiss } 524c3963bc0SZev Weiss } 525c3963bc0SZev Weiss 526c3963bc0SZev Weiss if (data->sio_reg_enable & 0x80) 527c3963bc0SZev Weiss fan3pin = gpok; 528c3963bc0SZev Weiss else 529c3963bc0SZev Weiss fan3pin = !(sio_data->sio_inb(sio_data, 0x24) & 0x40); 530c3963bc0SZev Weiss 531c3963bc0SZev Weiss if (data->sio_reg_enable & 0x40) 532c3963bc0SZev Weiss fan4pin = gpok; 533c3963bc0SZev Weiss else 534c3963bc0SZev Weiss fan4pin = sio_data->sio_inb(sio_data, 0x1C) & 0x01; 535c3963bc0SZev Weiss 536c3963bc0SZev Weiss if (data->sio_reg_enable & 0x20) 537c3963bc0SZev Weiss fan5pin = gpok; 538c3963bc0SZev Weiss else 539c3963bc0SZev Weiss fan5pin = sio_data->sio_inb(sio_data, 0x1C) & 0x02; 540c3963bc0SZev Weiss 541c3963bc0SZev Weiss fan4min = fan4pin; 542c3963bc0SZev Weiss pwm3pin = fan3pin; 543c3963bc0SZev Weiss } else if (data->kind == nct6106) { 544c3963bc0SZev Weiss int cr24 = sio_data->sio_inb(sio_data, 0x24); 545c3963bc0SZev Weiss 546c3963bc0SZev Weiss fan3pin = !(cr24 & 0x80); 547c3963bc0SZev Weiss pwm3pin = cr24 & 0x08; 548c3963bc0SZev Weiss } else if (data->kind == nct6116) { 549c3963bc0SZev Weiss int cr1a = sio_data->sio_inb(sio_data, 0x1a); 550c3963bc0SZev Weiss int cr1b = sio_data->sio_inb(sio_data, 0x1b); 551c3963bc0SZev Weiss int cr24 = sio_data->sio_inb(sio_data, 0x24); 552c3963bc0SZev Weiss int cr2a = sio_data->sio_inb(sio_data, 0x2a); 553c3963bc0SZev Weiss int cr2b = sio_data->sio_inb(sio_data, 0x2b); 554c3963bc0SZev Weiss int cr2f = sio_data->sio_inb(sio_data, 0x2f); 555c3963bc0SZev Weiss 556c3963bc0SZev Weiss fan3pin = !(cr2b & 0x10); 557c3963bc0SZev Weiss fan4pin = (cr2b & 0x80) || // pin 1(2) 558c3963bc0SZev Weiss (!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66) 559c3963bc0SZev Weiss fan5pin = (cr2b & 0x80) || // pin 126(127) 560c3963bc0SZev Weiss (!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96) 561c3963bc0SZev Weiss 562c3963bc0SZev Weiss pwm3pin = fan3pin && (cr24 & 0x08); 563c3963bc0SZev Weiss pwm4pin = fan4pin; 564c3963bc0SZev Weiss pwm5pin = fan5pin; 565c3963bc0SZev Weiss } else { 566c3963bc0SZev Weiss /* 567c3963bc0SZev Weiss * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, 568c3963bc0SZev Weiss * NCT6797D, NCT6798D 569c3963bc0SZev Weiss */ 570c3963bc0SZev Weiss int cr1a = sio_data->sio_inb(sio_data, 0x1a); 571c3963bc0SZev Weiss int cr1b = sio_data->sio_inb(sio_data, 0x1b); 572c3963bc0SZev Weiss int cr1c = sio_data->sio_inb(sio_data, 0x1c); 573c3963bc0SZev Weiss int cr1d = sio_data->sio_inb(sio_data, 0x1d); 574c3963bc0SZev Weiss int cr2a = sio_data->sio_inb(sio_data, 0x2a); 575c3963bc0SZev Weiss int cr2b = sio_data->sio_inb(sio_data, 0x2b); 576c3963bc0SZev Weiss int cr2d = sio_data->sio_inb(sio_data, 0x2d); 577c3963bc0SZev Weiss int cr2f = sio_data->sio_inb(sio_data, 0x2f); 578c3963bc0SZev Weiss bool dsw_en = cr2f & BIT(3); 579c3963bc0SZev Weiss bool ddr4_en = cr2f & BIT(4); 580c3963bc0SZev Weiss int cre0; 581c3963bc0SZev Weiss int creb; 582c3963bc0SZev Weiss int cred; 583c3963bc0SZev Weiss 584c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_12); 585c3963bc0SZev Weiss cre0 = sio_data->sio_inb(sio_data, 0xe0); 586c3963bc0SZev Weiss creb = sio_data->sio_inb(sio_data, 0xeb); 587c3963bc0SZev Weiss cred = sio_data->sio_inb(sio_data, 0xed); 588c3963bc0SZev Weiss 589c3963bc0SZev Weiss fan3pin = !(cr1c & BIT(5)); 590c3963bc0SZev Weiss fan4pin = !(cr1c & BIT(6)); 591c3963bc0SZev Weiss fan5pin = !(cr1c & BIT(7)); 592c3963bc0SZev Weiss 593c3963bc0SZev Weiss pwm3pin = !(cr1c & BIT(0)); 594c3963bc0SZev Weiss pwm4pin = !(cr1c & BIT(1)); 595c3963bc0SZev Weiss pwm5pin = !(cr1c & BIT(2)); 596c3963bc0SZev Weiss 597c3963bc0SZev Weiss switch (data->kind) { 598c3963bc0SZev Weiss case nct6791: 599c3963bc0SZev Weiss fan6pin = cr2d & BIT(1); 600c3963bc0SZev Weiss pwm6pin = cr2d & BIT(0); 601c3963bc0SZev Weiss break; 602c3963bc0SZev Weiss case nct6792: 603c3963bc0SZev Weiss fan6pin = !dsw_en && (cr2d & BIT(1)); 604c3963bc0SZev Weiss pwm6pin = !dsw_en && (cr2d & BIT(0)); 605c3963bc0SZev Weiss break; 606c3963bc0SZev Weiss case nct6793: 607c3963bc0SZev Weiss fan5pin |= cr1b & BIT(5); 608c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 609c3963bc0SZev Weiss 610c3963bc0SZev Weiss fan6pin = !dsw_en && (cr2d & BIT(1)); 611c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 612c3963bc0SZev Weiss 613c3963bc0SZev Weiss pwm5pin |= cr2d & BIT(7); 614c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 615c3963bc0SZev Weiss 616c3963bc0SZev Weiss pwm6pin = !dsw_en && (cr2d & BIT(0)); 617c3963bc0SZev Weiss pwm6pin |= creb & BIT(2); 618c3963bc0SZev Weiss break; 619c3963bc0SZev Weiss case nct6795: 620c3963bc0SZev Weiss fan5pin |= cr1b & BIT(5); 621c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 622c3963bc0SZev Weiss 623c3963bc0SZev Weiss fan6pin = (cr2a & BIT(4)) && 624c3963bc0SZev Weiss (!dsw_en || (cred & BIT(4))); 625c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 626c3963bc0SZev Weiss 627c3963bc0SZev Weiss pwm5pin |= cr2d & BIT(7); 628c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 629c3963bc0SZev Weiss 630c3963bc0SZev Weiss pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2)); 631c3963bc0SZev Weiss pwm6pin |= creb & BIT(2); 632c3963bc0SZev Weiss break; 633c3963bc0SZev Weiss case nct6796: 634c3963bc0SZev Weiss fan5pin |= cr1b & BIT(5); 635c3963bc0SZev Weiss fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0)); 636c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 637c3963bc0SZev Weiss 638c3963bc0SZev Weiss fan6pin = (cr2a & BIT(4)) && 639c3963bc0SZev Weiss (!dsw_en || (cred & BIT(4))); 640c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 641c3963bc0SZev Weiss 642c3963bc0SZev Weiss fan7pin = !(cr2b & BIT(2)); 643c3963bc0SZev Weiss 644c3963bc0SZev Weiss pwm5pin |= cr2d & BIT(7); 645c3963bc0SZev Weiss pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0)); 646c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 647c3963bc0SZev Weiss 648c3963bc0SZev Weiss pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2)); 649c3963bc0SZev Weiss pwm6pin |= creb & BIT(2); 650c3963bc0SZev Weiss 651c3963bc0SZev Weiss pwm7pin = !(cr1d & (BIT(2) | BIT(3))); 652c3963bc0SZev Weiss break; 653c3963bc0SZev Weiss case nct6797: 654c3963bc0SZev Weiss fan5pin |= !ddr4_en && (cr1b & BIT(5)); 655c3963bc0SZev Weiss fan5pin |= creb & BIT(5); 656c3963bc0SZev Weiss 657c3963bc0SZev Weiss fan6pin = cr2a & BIT(4); 658c3963bc0SZev Weiss fan6pin |= creb & BIT(3); 659c3963bc0SZev Weiss 660c3963bc0SZev Weiss fan7pin = cr1a & BIT(1); 661c3963bc0SZev Weiss 662c3963bc0SZev Weiss pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 663c3963bc0SZev Weiss pwm5pin |= !ddr4_en && (cr2d & BIT(7)); 664c3963bc0SZev Weiss 665c3963bc0SZev Weiss pwm6pin = creb & BIT(2); 666c3963bc0SZev Weiss pwm6pin |= cred & BIT(2); 667c3963bc0SZev Weiss 668c3963bc0SZev Weiss pwm7pin = cr1d & BIT(4); 669c3963bc0SZev Weiss break; 670c3963bc0SZev Weiss case nct6798: 671c3963bc0SZev Weiss fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); 672c3963bc0SZev Weiss fan6pin |= cr2a & BIT(4); 673c3963bc0SZev Weiss fan6pin |= creb & BIT(5); 674c3963bc0SZev Weiss 675c3963bc0SZev Weiss fan7pin = cr1b & BIT(5); 676c3963bc0SZev Weiss fan7pin |= !(cr2b & BIT(2)); 677c3963bc0SZev Weiss fan7pin |= creb & BIT(3); 678c3963bc0SZev Weiss 679c3963bc0SZev Weiss pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); 680c3963bc0SZev Weiss pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3)); 681c3963bc0SZev Weiss pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); 682c3963bc0SZev Weiss 683c3963bc0SZev Weiss pwm7pin = !(cr1d & (BIT(2) | BIT(3))); 684c3963bc0SZev Weiss pwm7pin |= cr2d & BIT(7); 685c3963bc0SZev Weiss pwm7pin |= creb & BIT(2); 686c3963bc0SZev Weiss break; 687c3963bc0SZev Weiss default: /* NCT6779D */ 688c3963bc0SZev Weiss break; 689c3963bc0SZev Weiss } 690c3963bc0SZev Weiss 691c3963bc0SZev Weiss fan4min = fan4pin; 692c3963bc0SZev Weiss } 693c3963bc0SZev Weiss 694c3963bc0SZev Weiss /* fan 1 and 2 (0x03) are always present */ 695c3963bc0SZev Weiss data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) | 696c3963bc0SZev Weiss (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6); 697c3963bc0SZev Weiss data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) | 698c3963bc0SZev Weiss (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6); 699c3963bc0SZev Weiss data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | 700c3963bc0SZev Weiss (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6); 701c3963bc0SZev Weiss } 702c3963bc0SZev Weiss 703c3963bc0SZev Weiss static ssize_t 704c3963bc0SZev Weiss cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) 705c3963bc0SZev Weiss { 706c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 707c3963bc0SZev Weiss 708c3963bc0SZev Weiss return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); 709c3963bc0SZev Weiss } 710c3963bc0SZev Weiss 711c3963bc0SZev Weiss static DEVICE_ATTR_RO(cpu0_vid); 712c3963bc0SZev Weiss 713c3963bc0SZev Weiss /* Case open detection */ 714c3963bc0SZev Weiss 715c3963bc0SZev Weiss static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee }; 716c3963bc0SZev Weiss static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 }; 717c3963bc0SZev Weiss 718c3963bc0SZev Weiss static ssize_t 719c3963bc0SZev Weiss clear_caseopen(struct device *dev, struct device_attribute *attr, 720c3963bc0SZev Weiss const char *buf, size_t count) 721c3963bc0SZev Weiss { 722c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 723c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = data->driver_data; 724c3963bc0SZev Weiss int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE; 725c3963bc0SZev Weiss unsigned long val; 726c3963bc0SZev Weiss u8 reg; 727c3963bc0SZev Weiss int ret; 728c3963bc0SZev Weiss 729c3963bc0SZev Weiss if (kstrtoul(buf, 10, &val) || val != 0) 730c3963bc0SZev Weiss return -EINVAL; 731c3963bc0SZev Weiss 732c3963bc0SZev Weiss mutex_lock(&data->update_lock); 733c3963bc0SZev Weiss 734c3963bc0SZev Weiss /* 735c3963bc0SZev Weiss * Use CR registers to clear caseopen status. 736c3963bc0SZev Weiss * The CR registers are the same for all chips, and not all chips 737c3963bc0SZev Weiss * support clearing the caseopen status through "regular" registers. 738c3963bc0SZev Weiss */ 739c3963bc0SZev Weiss ret = sio_data->sio_enter(sio_data); 740c3963bc0SZev Weiss if (ret) { 741c3963bc0SZev Weiss count = ret; 742c3963bc0SZev Weiss goto error; 743c3963bc0SZev Weiss } 744c3963bc0SZev Weiss 745c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_ACPI); 746c3963bc0SZev Weiss reg = sio_data->sio_inb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr]); 747c3963bc0SZev Weiss reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr]; 748c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg); 749c3963bc0SZev Weiss reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr]; 750c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg); 751c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 752c3963bc0SZev Weiss 753c3963bc0SZev Weiss data->valid = false; /* Force cache refresh */ 754c3963bc0SZev Weiss error: 755c3963bc0SZev Weiss mutex_unlock(&data->update_lock); 756c3963bc0SZev Weiss return count; 757c3963bc0SZev Weiss } 758c3963bc0SZev Weiss 759c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion0_alarm, 0644, nct6775_show_alarm, 760c3963bc0SZev Weiss clear_caseopen, INTRUSION_ALARM_BASE); 761c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion1_alarm, 0644, nct6775_show_alarm, 762c3963bc0SZev Weiss clear_caseopen, INTRUSION_ALARM_BASE + 1); 763c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion0_beep, 0644, nct6775_show_beep, 764c3963bc0SZev Weiss nct6775_store_beep, INTRUSION_ALARM_BASE); 765c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(intrusion1_beep, 0644, nct6775_show_beep, 766c3963bc0SZev Weiss nct6775_store_beep, INTRUSION_ALARM_BASE + 1); 767c3963bc0SZev Weiss static SENSOR_DEVICE_ATTR(beep_enable, 0644, nct6775_show_beep, 768c3963bc0SZev Weiss nct6775_store_beep, BEEP_ENABLE_BASE); 769c3963bc0SZev Weiss 770c3963bc0SZev Weiss static umode_t nct6775_other_is_visible(struct kobject *kobj, 771c3963bc0SZev Weiss struct attribute *attr, int index) 772c3963bc0SZev Weiss { 773c3963bc0SZev Weiss struct device *dev = kobj_to_dev(kobj); 774c3963bc0SZev Weiss struct nct6775_data *data = dev_get_drvdata(dev); 775c3963bc0SZev Weiss 776c3963bc0SZev Weiss if (index == 0 && !data->have_vid) 777c3963bc0SZev Weiss return 0; 778c3963bc0SZev Weiss 779c3963bc0SZev Weiss if (index == 1 || index == 2) { 780c3963bc0SZev Weiss if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0) 781c3963bc0SZev Weiss return 0; 782c3963bc0SZev Weiss } 783c3963bc0SZev Weiss 784c3963bc0SZev Weiss if (index == 3 || index == 4) { 785c3963bc0SZev Weiss if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0) 786c3963bc0SZev Weiss return 0; 787c3963bc0SZev Weiss } 788c3963bc0SZev Weiss 789c3963bc0SZev Weiss return nct6775_attr_mode(data, attr); 790c3963bc0SZev Weiss } 791c3963bc0SZev Weiss 792c3963bc0SZev Weiss /* 793c3963bc0SZev Weiss * nct6775_other_is_visible uses the index into the following array 794c3963bc0SZev Weiss * to determine if attributes should be created or not. 795c3963bc0SZev Weiss * Any change in order or content must be matched. 796c3963bc0SZev Weiss */ 797c3963bc0SZev Weiss static struct attribute *nct6775_attributes_other[] = { 798c3963bc0SZev Weiss &dev_attr_cpu0_vid.attr, /* 0 */ 799c3963bc0SZev Weiss &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */ 800c3963bc0SZev Weiss &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */ 801c3963bc0SZev Weiss &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */ 802c3963bc0SZev Weiss &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */ 803c3963bc0SZev Weiss &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */ 804c3963bc0SZev Weiss 805c3963bc0SZev Weiss NULL 806c3963bc0SZev Weiss }; 807c3963bc0SZev Weiss 808c3963bc0SZev Weiss static const struct attribute_group nct6775_group_other = { 809c3963bc0SZev Weiss .attrs = nct6775_attributes_other, 810c3963bc0SZev Weiss .is_visible = nct6775_other_is_visible, 811c3963bc0SZev Weiss }; 812c3963bc0SZev Weiss 813c3963bc0SZev Weiss static int nct6775_platform_probe_init(struct nct6775_data *data) 814c3963bc0SZev Weiss { 815c3963bc0SZev Weiss int err; 816c3963bc0SZev Weiss u8 cr2a; 817c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = data->driver_data; 818c3963bc0SZev Weiss 819c3963bc0SZev Weiss err = sio_data->sio_enter(sio_data); 820c3963bc0SZev Weiss if (err) 821c3963bc0SZev Weiss return err; 822c3963bc0SZev Weiss 823c3963bc0SZev Weiss cr2a = sio_data->sio_inb(sio_data, 0x2a); 824c3963bc0SZev Weiss switch (data->kind) { 825c3963bc0SZev Weiss case nct6775: 826c3963bc0SZev Weiss data->have_vid = (cr2a & 0x40); 827c3963bc0SZev Weiss break; 828c3963bc0SZev Weiss case nct6776: 829c3963bc0SZev Weiss data->have_vid = (cr2a & 0x60) == 0x40; 830c3963bc0SZev Weiss break; 831c3963bc0SZev Weiss case nct6106: 832c3963bc0SZev Weiss case nct6116: 833c3963bc0SZev Weiss case nct6779: 834c3963bc0SZev Weiss case nct6791: 835c3963bc0SZev Weiss case nct6792: 836c3963bc0SZev Weiss case nct6793: 837c3963bc0SZev Weiss case nct6795: 838c3963bc0SZev Weiss case nct6796: 839c3963bc0SZev Weiss case nct6797: 840c3963bc0SZev Weiss case nct6798: 841c3963bc0SZev Weiss break; 842c3963bc0SZev Weiss } 843c3963bc0SZev Weiss 844c3963bc0SZev Weiss /* 845c3963bc0SZev Weiss * Read VID value 846c3963bc0SZev Weiss * We can get the VID input values directly at logical device D 0xe3. 847c3963bc0SZev Weiss */ 848c3963bc0SZev Weiss if (data->have_vid) { 849c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_VID); 850c3963bc0SZev Weiss data->vid = sio_data->sio_inb(sio_data, 0xe3); 851c3963bc0SZev Weiss data->vrm = vid_which_vrm(); 852c3963bc0SZev Weiss } 853c3963bc0SZev Weiss 854c3963bc0SZev Weiss if (fan_debounce) { 855c3963bc0SZev Weiss u8 tmp; 856c3963bc0SZev Weiss 857c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 858c3963bc0SZev Weiss tmp = sio_data->sio_inb(sio_data, 859c3963bc0SZev Weiss NCT6775_REG_CR_FAN_DEBOUNCE); 860c3963bc0SZev Weiss switch (data->kind) { 861c3963bc0SZev Weiss case nct6106: 862c3963bc0SZev Weiss case nct6116: 863c3963bc0SZev Weiss tmp |= 0xe0; 864c3963bc0SZev Weiss break; 865c3963bc0SZev Weiss case nct6775: 866c3963bc0SZev Weiss tmp |= 0x1e; 867c3963bc0SZev Weiss break; 868c3963bc0SZev Weiss case nct6776: 869c3963bc0SZev Weiss case nct6779: 870c3963bc0SZev Weiss tmp |= 0x3e; 871c3963bc0SZev Weiss break; 872c3963bc0SZev Weiss case nct6791: 873c3963bc0SZev Weiss case nct6792: 874c3963bc0SZev Weiss case nct6793: 875c3963bc0SZev Weiss case nct6795: 876c3963bc0SZev Weiss case nct6796: 877c3963bc0SZev Weiss case nct6797: 878c3963bc0SZev Weiss case nct6798: 879c3963bc0SZev Weiss tmp |= 0x7e; 880c3963bc0SZev Weiss break; 881c3963bc0SZev Weiss } 882c3963bc0SZev Weiss sio_data->sio_outb(sio_data, NCT6775_REG_CR_FAN_DEBOUNCE, 883c3963bc0SZev Weiss tmp); 884c3963bc0SZev Weiss pr_info("Enabled fan debounce for chip %s\n", data->name); 885c3963bc0SZev Weiss } 886c3963bc0SZev Weiss 887c3963bc0SZev Weiss nct6775_check_fan_inputs(data, sio_data); 888c3963bc0SZev Weiss 889c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 890c3963bc0SZev Weiss 891c3963bc0SZev Weiss return nct6775_add_attr_group(data, &nct6775_group_other); 892c3963bc0SZev Weiss } 893c3963bc0SZev Weiss 894c3963bc0SZev Weiss static const struct regmap_config nct6775_regmap_config = { 895c3963bc0SZev Weiss .reg_bits = 16, 896c3963bc0SZev Weiss .val_bits = 16, 897c3963bc0SZev Weiss .reg_read = nct6775_reg_read, 898c3963bc0SZev Weiss .reg_write = nct6775_reg_write, 899c3963bc0SZev Weiss }; 900c3963bc0SZev Weiss 901c3963bc0SZev Weiss static const struct regmap_config nct6775_wmi_regmap_config = { 902c3963bc0SZev Weiss .reg_bits = 16, 903c3963bc0SZev Weiss .val_bits = 16, 904c3963bc0SZev Weiss .reg_read = nct6775_wmi_reg_read, 905c3963bc0SZev Weiss .reg_write = nct6775_wmi_reg_write, 906c3963bc0SZev Weiss }; 907c3963bc0SZev Weiss 908c3963bc0SZev Weiss static int nct6775_platform_probe(struct platform_device *pdev) 909c3963bc0SZev Weiss { 910c3963bc0SZev Weiss struct device *dev = &pdev->dev; 911c3963bc0SZev Weiss struct nct6775_sio_data *sio_data = dev_get_platdata(dev); 912c3963bc0SZev Weiss struct nct6775_data *data; 913c3963bc0SZev Weiss struct resource *res; 914c3963bc0SZev Weiss const struct regmap_config *regmapcfg; 915c3963bc0SZev Weiss 916c3963bc0SZev Weiss if (sio_data->access == access_direct) { 917c3963bc0SZev Weiss res = platform_get_resource(pdev, IORESOURCE_IO, 0); 918c3963bc0SZev Weiss if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, DRVNAME)) 919c3963bc0SZev Weiss return -EBUSY; 920c3963bc0SZev Weiss } 921c3963bc0SZev Weiss 922c3963bc0SZev Weiss data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 923c3963bc0SZev Weiss if (!data) 924c3963bc0SZev Weiss return -ENOMEM; 925c3963bc0SZev Weiss 926c3963bc0SZev Weiss data->kind = sio_data->kind; 927c3963bc0SZev Weiss data->sioreg = sio_data->sioreg; 928c3963bc0SZev Weiss 929c3963bc0SZev Weiss if (sio_data->access == access_direct) { 930c3963bc0SZev Weiss data->addr = res->start; 931c3963bc0SZev Weiss regmapcfg = &nct6775_regmap_config; 932c3963bc0SZev Weiss } else { 933c3963bc0SZev Weiss regmapcfg = &nct6775_wmi_regmap_config; 934c3963bc0SZev Weiss } 935c3963bc0SZev Weiss 936c3963bc0SZev Weiss platform_set_drvdata(pdev, data); 937c3963bc0SZev Weiss 938c3963bc0SZev Weiss data->driver_data = sio_data; 939c3963bc0SZev Weiss data->driver_init = nct6775_platform_probe_init; 940c3963bc0SZev Weiss 941c3963bc0SZev Weiss return nct6775_probe(&pdev->dev, data, regmapcfg); 942c3963bc0SZev Weiss } 943c3963bc0SZev Weiss 944c3963bc0SZev Weiss static struct platform_driver nct6775_driver = { 945c3963bc0SZev Weiss .driver = { 946c3963bc0SZev Weiss .name = DRVNAME, 9478de7295cSJonathan Cameron .pm = pm_sleep_ptr(&nct6775_dev_pm_ops), 948c3963bc0SZev Weiss }, 949c3963bc0SZev Weiss .probe = nct6775_platform_probe, 950c3963bc0SZev Weiss }; 951c3963bc0SZev Weiss 952c3963bc0SZev Weiss /* nct6775_find() looks for a '627 in the Super-I/O config space */ 953c3963bc0SZev Weiss static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) 954c3963bc0SZev Weiss { 955c3963bc0SZev Weiss u16 val; 956c3963bc0SZev Weiss int err; 957c3963bc0SZev Weiss int addr; 958c3963bc0SZev Weiss 959c3963bc0SZev Weiss sio_data->access = access_direct; 960c3963bc0SZev Weiss sio_data->sioreg = sioaddr; 961c3963bc0SZev Weiss 962c3963bc0SZev Weiss err = sio_data->sio_enter(sio_data); 963c3963bc0SZev Weiss if (err) 964c3963bc0SZev Weiss return err; 965c3963bc0SZev Weiss 966c3963bc0SZev Weiss val = (sio_data->sio_inb(sio_data, SIO_REG_DEVID) << 8) | 967c3963bc0SZev Weiss sio_data->sio_inb(sio_data, SIO_REG_DEVID + 1); 968c3963bc0SZev Weiss if (force_id && val != 0xffff) 969c3963bc0SZev Weiss val = force_id; 970c3963bc0SZev Weiss 971c3963bc0SZev Weiss switch (val & SIO_ID_MASK) { 972c3963bc0SZev Weiss case SIO_NCT6106_ID: 973c3963bc0SZev Weiss sio_data->kind = nct6106; 974c3963bc0SZev Weiss break; 975c3963bc0SZev Weiss case SIO_NCT6116_ID: 976c3963bc0SZev Weiss sio_data->kind = nct6116; 977c3963bc0SZev Weiss break; 978c3963bc0SZev Weiss case SIO_NCT6775_ID: 979c3963bc0SZev Weiss sio_data->kind = nct6775; 980c3963bc0SZev Weiss break; 981c3963bc0SZev Weiss case SIO_NCT6776_ID: 982c3963bc0SZev Weiss sio_data->kind = nct6776; 983c3963bc0SZev Weiss break; 984c3963bc0SZev Weiss case SIO_NCT6779_ID: 985c3963bc0SZev Weiss sio_data->kind = nct6779; 986c3963bc0SZev Weiss break; 987c3963bc0SZev Weiss case SIO_NCT6791_ID: 988c3963bc0SZev Weiss sio_data->kind = nct6791; 989c3963bc0SZev Weiss break; 990c3963bc0SZev Weiss case SIO_NCT6792_ID: 991c3963bc0SZev Weiss sio_data->kind = nct6792; 992c3963bc0SZev Weiss break; 993c3963bc0SZev Weiss case SIO_NCT6793_ID: 994c3963bc0SZev Weiss sio_data->kind = nct6793; 995c3963bc0SZev Weiss break; 996c3963bc0SZev Weiss case SIO_NCT6795_ID: 997c3963bc0SZev Weiss sio_data->kind = nct6795; 998c3963bc0SZev Weiss break; 999c3963bc0SZev Weiss case SIO_NCT6796_ID: 1000c3963bc0SZev Weiss sio_data->kind = nct6796; 1001c3963bc0SZev Weiss break; 1002c3963bc0SZev Weiss case SIO_NCT6797_ID: 1003c3963bc0SZev Weiss sio_data->kind = nct6797; 1004c3963bc0SZev Weiss break; 1005c3963bc0SZev Weiss case SIO_NCT6798_ID: 1006c3963bc0SZev Weiss sio_data->kind = nct6798; 1007c3963bc0SZev Weiss break; 1008c3963bc0SZev Weiss default: 1009c3963bc0SZev Weiss if (val != 0xffff) 1010c3963bc0SZev Weiss pr_debug("unsupported chip ID: 0x%04x\n", val); 1011c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 1012c3963bc0SZev Weiss return -ENODEV; 1013c3963bc0SZev Weiss } 1014c3963bc0SZev Weiss 1015c3963bc0SZev Weiss /* We have a known chip, find the HWM I/O address */ 1016c3963bc0SZev Weiss sio_data->sio_select(sio_data, NCT6775_LD_HWM); 1017c3963bc0SZev Weiss val = (sio_data->sio_inb(sio_data, SIO_REG_ADDR) << 8) 1018c3963bc0SZev Weiss | sio_data->sio_inb(sio_data, SIO_REG_ADDR + 1); 1019c3963bc0SZev Weiss addr = val & IOREGION_ALIGNMENT; 1020c3963bc0SZev Weiss if (addr == 0) { 1021c3963bc0SZev Weiss pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n"); 1022c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 1023c3963bc0SZev Weiss return -ENODEV; 1024c3963bc0SZev Weiss } 1025c3963bc0SZev Weiss 1026c3963bc0SZev Weiss /* Activate logical device if needed */ 1027c3963bc0SZev Weiss val = sio_data->sio_inb(sio_data, SIO_REG_ENABLE); 1028c3963bc0SZev Weiss if (!(val & 0x01)) { 1029c3963bc0SZev Weiss pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n"); 1030c3963bc0SZev Weiss sio_data->sio_outb(sio_data, SIO_REG_ENABLE, val | 0x01); 1031c3963bc0SZev Weiss } 1032c3963bc0SZev Weiss 1033c3963bc0SZev Weiss if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || 1034c3963bc0SZev Weiss sio_data->kind == nct6793 || sio_data->kind == nct6795 || 1035c3963bc0SZev Weiss sio_data->kind == nct6796 || sio_data->kind == nct6797 || 1036c3963bc0SZev Weiss sio_data->kind == nct6798) 1037c3963bc0SZev Weiss nct6791_enable_io_mapping(sio_data); 1038c3963bc0SZev Weiss 1039c3963bc0SZev Weiss sio_data->sio_exit(sio_data); 1040c3963bc0SZev Weiss pr_info("Found %s or compatible chip at %#x:%#x\n", 1041c3963bc0SZev Weiss nct6775_sio_names[sio_data->kind], sioaddr, addr); 1042c3963bc0SZev Weiss 1043c3963bc0SZev Weiss return addr; 1044c3963bc0SZev Weiss } 1045c3963bc0SZev Weiss 1046c3963bc0SZev Weiss /* 1047c3963bc0SZev Weiss * when Super-I/O functions move to a separate file, the Super-I/O 1048c3963bc0SZev Weiss * bus will manage the lifetime of the device and this module will only keep 1049c3963bc0SZev Weiss * track of the nct6775 driver. But since we use platform_device_alloc(), we 1050c3963bc0SZev Weiss * must keep track of the device 1051c3963bc0SZev Weiss */ 1052c3963bc0SZev Weiss static struct platform_device *pdev[2]; 1053c3963bc0SZev Weiss 1054c3963bc0SZev Weiss static const char * const asus_wmi_boards[] = { 1055ea005526SHolger Kiehl "Pro A520M-C II", 105676412408SDenis Pauk "PRO H410T", 10571864069cSDenis Pauk "ProArt B550-CREATOR", 1058c3963bc0SZev Weiss "ProArt X570-CREATOR WIFI", 10591864069cSDenis Pauk "ProArt Z490-CREATOR 10G", 1060c3963bc0SZev Weiss "Pro B550M-C", 1061c3963bc0SZev Weiss "Pro WS X570-ACE", 1062c3963bc0SZev Weiss "PRIME B360-PLUS", 1063c3963bc0SZev Weiss "PRIME B460-PLUS", 1064c3963bc0SZev Weiss "PRIME B550-PLUS", 1065c3963bc0SZev Weiss "PRIME B550M-A", 1066c3963bc0SZev Weiss "PRIME B550M-A (WI-FI)", 106776412408SDenis Pauk "PRIME H410M-R", 1068c3963bc0SZev Weiss "PRIME X570-P", 1069c3963bc0SZev Weiss "PRIME X570-PRO", 1070c3963bc0SZev Weiss "ROG CROSSHAIR VIII DARK HERO", 10711864069cSDenis Pauk "ROG CROSSHAIR VIII EXTREME", 1072c3963bc0SZev Weiss "ROG CROSSHAIR VIII FORMULA", 1073c3963bc0SZev Weiss "ROG CROSSHAIR VIII HERO", 10741864069cSDenis Pauk "ROG CROSSHAIR VIII HERO (WI-FI)", 1075c3963bc0SZev Weiss "ROG CROSSHAIR VIII IMPACT", 1076c3963bc0SZev Weiss "ROG STRIX B550-A GAMING", 1077c3963bc0SZev Weiss "ROG STRIX B550-E GAMING", 1078c3963bc0SZev Weiss "ROG STRIX B550-F GAMING", 1079c3963bc0SZev Weiss "ROG STRIX B550-F GAMING (WI-FI)", 1080c3963bc0SZev Weiss "ROG STRIX B550-F GAMING WIFI II", 1081c3963bc0SZev Weiss "ROG STRIX B550-I GAMING", 1082c3963bc0SZev Weiss "ROG STRIX B550-XE GAMING (WI-FI)", 1083c3963bc0SZev Weiss "ROG STRIX X570-E GAMING", 108476412408SDenis Pauk "ROG STRIX X570-E GAMING WIFI II", 1085c3963bc0SZev Weiss "ROG STRIX X570-F GAMING", 1086c3963bc0SZev Weiss "ROG STRIX X570-I GAMING", 1087c3963bc0SZev Weiss "ROG STRIX Z390-E GAMING", 1088c3963bc0SZev Weiss "ROG STRIX Z390-F GAMING", 1089c3963bc0SZev Weiss "ROG STRIX Z390-H GAMING", 1090c3963bc0SZev Weiss "ROG STRIX Z390-I GAMING", 1091c3963bc0SZev Weiss "ROG STRIX Z490-A GAMING", 1092c3963bc0SZev Weiss "ROG STRIX Z490-E GAMING", 1093c3963bc0SZev Weiss "ROG STRIX Z490-F GAMING", 1094c3963bc0SZev Weiss "ROG STRIX Z490-G GAMING", 1095c3963bc0SZev Weiss "ROG STRIX Z490-G GAMING (WI-FI)", 1096c3963bc0SZev Weiss "ROG STRIX Z490-H GAMING", 1097c3963bc0SZev Weiss "ROG STRIX Z490-I GAMING", 10981864069cSDenis Pauk "TUF GAMING B550M-E", 1099*23e8a379SDenis Pauk "TUF GAMING B550M-E WIFI", 1100c3963bc0SZev Weiss "TUF GAMING B550M-PLUS", 1101c3963bc0SZev Weiss "TUF GAMING B550M-PLUS (WI-FI)", 11021864069cSDenis Pauk "TUF GAMING B550M-PLUS WIFI II", 1103c3963bc0SZev Weiss "TUF GAMING B550-PLUS", 110438ac173bSRobert Schmidt "TUF GAMING B550-PLUS WIFI II", 1105c3963bc0SZev Weiss "TUF GAMING B550-PRO", 1106c3963bc0SZev Weiss "TUF GAMING X570-PLUS", 1107c3963bc0SZev Weiss "TUF GAMING X570-PLUS (WI-FI)", 1108c3963bc0SZev Weiss "TUF GAMING X570-PRO (WI-FI)", 1109c3963bc0SZev Weiss "TUF GAMING Z490-PLUS", 1110c3963bc0SZev Weiss "TUF GAMING Z490-PLUS (WI-FI)", 1111c3963bc0SZev Weiss }; 1112c3963bc0SZev Weiss 1113e2e09989SDenis Pauk static const char * const asus_msi_boards[] = { 1114e2e09989SDenis Pauk "EX-B660M-V5 PRO D4", 1115e2e09989SDenis Pauk "PRIME B650-PLUS", 1116e2e09989SDenis Pauk "PRIME B650M-A", 1117e2e09989SDenis Pauk "PRIME B650M-A AX", 1118e2e09989SDenis Pauk "PRIME B650M-A II", 1119e2e09989SDenis Pauk "PRIME B650M-A WIFI", 1120e2e09989SDenis Pauk "PRIME B650M-A WIFI II", 1121e2e09989SDenis Pauk "PRIME B660M-A D4", 1122e2e09989SDenis Pauk "PRIME B660M-A WIFI D4", 1123e2e09989SDenis Pauk "PRIME X670-P", 1124e2e09989SDenis Pauk "PRIME X670-P WIFI", 1125e2e09989SDenis Pauk "PRIME X670E-PRO WIFI", 112690b86248SErik Ekman "PRIME Z590-A", 112790b86248SErik Ekman "PRIME Z590-P", 112890b86248SErik Ekman "PRIME Z590M-PLUS", 1129e2e09989SDenis Pauk "Pro B660M-C-D4", 1130e2e09989SDenis Pauk "ProArt B660-CREATOR D4", 1131e2e09989SDenis Pauk "ProArt X670E-CREATOR WIFI", 1132e2e09989SDenis Pauk "ROG CROSSHAIR X670E EXTREME", 1133e2e09989SDenis Pauk "ROG CROSSHAIR X670E GENE", 1134e2e09989SDenis Pauk "ROG CROSSHAIR X670E HERO", 1135e2e09989SDenis Pauk "ROG MAXIMUS XIII EXTREME GLACIAL", 1136e2e09989SDenis Pauk "ROG MAXIMUS Z690 EXTREME", 1137e2e09989SDenis Pauk "ROG MAXIMUS Z690 EXTREME GLACIAL", 1138e2e09989SDenis Pauk "ROG STRIX B650-A GAMING WIFI", 1139e2e09989SDenis Pauk "ROG STRIX B650E-E GAMING WIFI", 1140e2e09989SDenis Pauk "ROG STRIX B650E-F GAMING WIFI", 1141e2e09989SDenis Pauk "ROG STRIX B650E-I GAMING WIFI", 1142e2e09989SDenis Pauk "ROG STRIX B660-A GAMING WIFI D4", 1143e2e09989SDenis Pauk "ROG STRIX B660-F GAMING WIFI", 1144e2e09989SDenis Pauk "ROG STRIX B660-G GAMING WIFI", 1145e2e09989SDenis Pauk "ROG STRIX B660-I GAMING WIFI", 1146e2e09989SDenis Pauk "ROG STRIX X670E-A GAMING WIFI", 1147e2e09989SDenis Pauk "ROG STRIX X670E-E GAMING WIFI", 1148e2e09989SDenis Pauk "ROG STRIX X670E-F GAMING WIFI", 1149e2e09989SDenis Pauk "ROG STRIX X670E-I GAMING WIFI", 1150e2e09989SDenis Pauk "ROG STRIX Z590-A GAMING WIFI II", 1151e2e09989SDenis Pauk "ROG STRIX Z690-A GAMING WIFI D4", 1152e2e09989SDenis Pauk "TUF GAMING B650-PLUS", 1153e2e09989SDenis Pauk "TUF GAMING B650-PLUS WIFI", 1154e2e09989SDenis Pauk "TUF GAMING B650M-PLUS", 1155e2e09989SDenis Pauk "TUF GAMING B650M-PLUS WIFI", 1156e2e09989SDenis Pauk "TUF GAMING B660M-PLUS WIFI", 1157e2e09989SDenis Pauk "TUF GAMING X670E-PLUS", 1158e2e09989SDenis Pauk "TUF GAMING X670E-PLUS WIFI", 1159e2e09989SDenis Pauk "TUF GAMING Z590-PLUS WIFI", 1160e2e09989SDenis Pauk }; 1161e2e09989SDenis Pauk 1162c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 1163c3b3747dSDenis Pauk /* 1164c3b3747dSDenis Pauk * Callback for acpi_bus_for_each_dev() to find the right device 1165c3b3747dSDenis Pauk * by _UID and _HID and return 1 to stop iteration. 1166c3b3747dSDenis Pauk */ 1167c3b3747dSDenis Pauk static int nct6775_asuswmi_device_match(struct device *dev, void *data) 1168c3b3747dSDenis Pauk { 1169c3b3747dSDenis Pauk struct acpi_device *adev = to_acpi_device(dev); 1170c3b3747dSDenis Pauk const char *uid = acpi_device_uid(adev); 1171c3b3747dSDenis Pauk const char *hid = acpi_device_hid(adev); 1172c3b3747dSDenis Pauk 1173c3b3747dSDenis Pauk if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) { 1174c3b3747dSDenis Pauk asus_acpi_dev = adev; 1175c3b3747dSDenis Pauk return 1; 1176c3b3747dSDenis Pauk } 1177c3b3747dSDenis Pauk 1178c3b3747dSDenis Pauk return 0; 1179c3b3747dSDenis Pauk } 1180c3b3747dSDenis Pauk #endif 1181c3b3747dSDenis Pauk 1182c3b3747dSDenis Pauk static enum sensor_access nct6775_determine_access(const char *device_uid) 1183c3b3747dSDenis Pauk { 1184c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI) 1185c3b3747dSDenis Pauk u8 tmp; 1186c3b3747dSDenis Pauk 1187c3b3747dSDenis Pauk acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid); 1188c3b3747dSDenis Pauk if (!asus_acpi_dev) 1189c3b3747dSDenis Pauk return access_direct; 1190c3b3747dSDenis Pauk 1191c3b3747dSDenis Pauk /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */ 1192c3b3747dSDenis Pauk if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { 1193c3b3747dSDenis Pauk pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp); 1194c3b3747dSDenis Pauk return access_asuswmi; 1195c3b3747dSDenis Pauk } 1196c3b3747dSDenis Pauk #endif 1197c3b3747dSDenis Pauk 1198c3b3747dSDenis Pauk return access_direct; 1199c3b3747dSDenis Pauk } 1200c3b3747dSDenis Pauk 1201c3963bc0SZev Weiss static int __init sensors_nct6775_platform_init(void) 1202c3963bc0SZev Weiss { 1203c3963bc0SZev Weiss int i, err; 1204c3963bc0SZev Weiss bool found = false; 1205c3963bc0SZev Weiss int address; 1206c3963bc0SZev Weiss struct resource res; 1207c3963bc0SZev Weiss struct nct6775_sio_data sio_data; 1208c3963bc0SZev Weiss int sioaddr[2] = { 0x2e, 0x4e }; 1209c3963bc0SZev Weiss enum sensor_access access = access_direct; 1210c3963bc0SZev Weiss const char *board_vendor, *board_name; 1211c3963bc0SZev Weiss 1212c3963bc0SZev Weiss err = platform_driver_register(&nct6775_driver); 1213c3963bc0SZev Weiss if (err) 1214c3963bc0SZev Weiss return err; 1215c3963bc0SZev Weiss 1216c3963bc0SZev Weiss board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 1217c3963bc0SZev Weiss board_name = dmi_get_system_info(DMI_BOARD_NAME); 1218c3963bc0SZev Weiss 1219c3963bc0SZev Weiss if (board_name && board_vendor && 1220c3963bc0SZev Weiss !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) { 1221c3963bc0SZev Weiss err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards), 1222c3963bc0SZev Weiss board_name); 1223c3b3747dSDenis Pauk if (err >= 0) 1224c3b3747dSDenis Pauk access = nct6775_determine_access(ASUSWMI_DEVICE_UID); 1225e2e09989SDenis Pauk 1226e2e09989SDenis Pauk err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards), 1227e2e09989SDenis Pauk board_name); 1228e2e09989SDenis Pauk if (err >= 0) 1229e2e09989SDenis Pauk access = nct6775_determine_access(ASUSMSI_DEVICE_UID); 1230c3963bc0SZev Weiss } 1231c3963bc0SZev Weiss 1232c3963bc0SZev Weiss /* 1233c3963bc0SZev Weiss * initialize sio_data->kind and sio_data->sioreg. 1234c3963bc0SZev Weiss * 1235c3963bc0SZev Weiss * when Super-I/O functions move to a separate file, the Super-I/O 1236c3963bc0SZev Weiss * driver will probe 0x2e and 0x4e and auto-detect the presence of a 1237c3963bc0SZev Weiss * nct6775 hardware monitor, and call probe() 1238c3963bc0SZev Weiss */ 1239c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(pdev); i++) { 1240c3963bc0SZev Weiss sio_data.sio_outb = superio_outb; 1241c3963bc0SZev Weiss sio_data.sio_inb = superio_inb; 1242c3963bc0SZev Weiss sio_data.sio_select = superio_select; 1243c3963bc0SZev Weiss sio_data.sio_enter = superio_enter; 1244c3963bc0SZev Weiss sio_data.sio_exit = superio_exit; 1245c3963bc0SZev Weiss 1246c3963bc0SZev Weiss address = nct6775_find(sioaddr[i], &sio_data); 1247c3963bc0SZev Weiss if (address <= 0) 1248c3963bc0SZev Weiss continue; 1249c3963bc0SZev Weiss 1250c3963bc0SZev Weiss found = true; 1251c3963bc0SZev Weiss 1252c3963bc0SZev Weiss sio_data.access = access; 1253c3963bc0SZev Weiss 1254c3963bc0SZev Weiss if (access == access_asuswmi) { 1255c3963bc0SZev Weiss sio_data.sio_outb = superio_wmi_outb; 1256c3963bc0SZev Weiss sio_data.sio_inb = superio_wmi_inb; 1257c3963bc0SZev Weiss sio_data.sio_select = superio_wmi_select; 1258c3963bc0SZev Weiss sio_data.sio_enter = superio_wmi_enter; 1259c3963bc0SZev Weiss sio_data.sio_exit = superio_wmi_exit; 1260c3963bc0SZev Weiss } 1261c3963bc0SZev Weiss 1262c3963bc0SZev Weiss pdev[i] = platform_device_alloc(DRVNAME, address); 1263c3963bc0SZev Weiss if (!pdev[i]) { 1264c3963bc0SZev Weiss err = -ENOMEM; 1265c3963bc0SZev Weiss goto exit_device_unregister; 1266c3963bc0SZev Weiss } 1267c3963bc0SZev Weiss 1268c3963bc0SZev Weiss err = platform_device_add_data(pdev[i], &sio_data, 1269c3963bc0SZev Weiss sizeof(struct nct6775_sio_data)); 1270c3963bc0SZev Weiss if (err) 1271c3963bc0SZev Weiss goto exit_device_put; 1272c3963bc0SZev Weiss 1273c3963bc0SZev Weiss if (sio_data.access == access_direct) { 1274c3963bc0SZev Weiss memset(&res, 0, sizeof(res)); 1275c3963bc0SZev Weiss res.name = DRVNAME; 1276c3963bc0SZev Weiss res.start = address + IOREGION_OFFSET; 1277c3963bc0SZev Weiss res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; 1278c3963bc0SZev Weiss res.flags = IORESOURCE_IO; 1279c3963bc0SZev Weiss 1280c3963bc0SZev Weiss err = acpi_check_resource_conflict(&res); 1281c3963bc0SZev Weiss if (err) { 1282c3963bc0SZev Weiss platform_device_put(pdev[i]); 1283c3963bc0SZev Weiss pdev[i] = NULL; 1284c3963bc0SZev Weiss continue; 1285c3963bc0SZev Weiss } 1286c3963bc0SZev Weiss 1287c3963bc0SZev Weiss err = platform_device_add_resources(pdev[i], &res, 1); 1288c3963bc0SZev Weiss if (err) 1289c3963bc0SZev Weiss goto exit_device_put; 1290c3963bc0SZev Weiss } 1291c3963bc0SZev Weiss 1292c3963bc0SZev Weiss /* platform_device_add calls probe() */ 1293c3963bc0SZev Weiss err = platform_device_add(pdev[i]); 1294c3963bc0SZev Weiss if (err) 1295c3963bc0SZev Weiss goto exit_device_put; 1296c3963bc0SZev Weiss } 1297c3963bc0SZev Weiss if (!found) { 1298c3963bc0SZev Weiss err = -ENODEV; 1299c3963bc0SZev Weiss goto exit_unregister; 1300c3963bc0SZev Weiss } 1301c3963bc0SZev Weiss 1302c3963bc0SZev Weiss return 0; 1303c3963bc0SZev Weiss 1304c3963bc0SZev Weiss exit_device_put: 1305c3963bc0SZev Weiss platform_device_put(pdev[i]); 1306c3963bc0SZev Weiss exit_device_unregister: 1307452d5e29SAndy Shevchenko while (i--) 1308c3963bc0SZev Weiss platform_device_unregister(pdev[i]); 1309c3963bc0SZev Weiss exit_unregister: 1310c3963bc0SZev Weiss platform_driver_unregister(&nct6775_driver); 1311c3963bc0SZev Weiss return err; 1312c3963bc0SZev Weiss } 1313c3963bc0SZev Weiss 1314c3963bc0SZev Weiss static void __exit sensors_nct6775_platform_exit(void) 1315c3963bc0SZev Weiss { 1316c3963bc0SZev Weiss int i; 1317c3963bc0SZev Weiss 1318452d5e29SAndy Shevchenko for (i = 0; i < ARRAY_SIZE(pdev); i++) 1319c3963bc0SZev Weiss platform_device_unregister(pdev[i]); 1320c3963bc0SZev Weiss platform_driver_unregister(&nct6775_driver); 1321c3963bc0SZev Weiss } 1322c3963bc0SZev Weiss 1323c3963bc0SZev Weiss MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); 1324c3963bc0SZev Weiss MODULE_DESCRIPTION("Platform driver for NCT6775F and compatible chips"); 1325c3963bc0SZev Weiss MODULE_LICENSE("GPL"); 1326c3963bc0SZev Weiss MODULE_IMPORT_NS(HWMON_NCT6775); 1327c3963bc0SZev Weiss 1328c3963bc0SZev Weiss module_init(sensors_nct6775_platform_init); 1329c3963bc0SZev Weiss module_exit(sensors_nct6775_platform_exit); 1330