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 = {
26efe86092SKees Cook [nct6106] = "NCT6106D",
27efe86092SKees Cook [nct6116] = "NCT6116D",
28efe86092SKees Cook [nct6775] = "NCT6775F",
29efe86092SKees Cook [nct6776] = "NCT6776D/F",
30efe86092SKees Cook [nct6779] = "NCT6779D",
31efe86092SKees Cook [nct6791] = "NCT6791D",
32efe86092SKees Cook [nct6792] = "NCT6792D",
33efe86092SKees Cook [nct6793] = "NCT6793D",
34efe86092SKees Cook [nct6795] = "NCT6795D",
35efe86092SKees Cook [nct6796] = "NCT6796D",
36efe86092SKees Cook [nct6797] = "NCT6797D",
37efe86092SKees Cook [nct6798] = "NCT6798D",
38efe86092SKees 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
nct6775_asuswmi_evaluate_method(u32 method_id,u8 bank,u8 reg,u8 val,u32 * retval)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
nct6775_asuswmi_write(u8 bank,u8 reg,u8 val)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
nct6775_asuswmi_read(u8 bank,u8 reg,u8 * val)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
superio_wmi_inb(struct nct6775_sio_data * sio_data,int reg)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
superio_wmi_outb(struct nct6775_sio_data * sio_data,int reg,int val)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
superio_wmi_select(struct nct6775_sio_data * sio_data,int ld)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
superio_wmi_enter(struct nct6775_sio_data * sio_data)198c3963bc0SZev Weiss static int superio_wmi_enter(struct nct6775_sio_data *sio_data)
199c3963bc0SZev Weiss {
200c3963bc0SZev Weiss return 0;
201c3963bc0SZev Weiss }
202c3963bc0SZev Weiss
superio_wmi_exit(struct nct6775_sio_data * sio_data)203c3963bc0SZev Weiss static void superio_wmi_exit(struct nct6775_sio_data *sio_data)
204c3963bc0SZev Weiss {
205c3963bc0SZev Weiss }
206c3963bc0SZev Weiss
superio_outb(struct nct6775_sio_data * sio_data,int reg,int val)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
superio_inb(struct nct6775_sio_data * sio_data,int reg)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
superio_select(struct nct6775_sio_data * sio_data,int ld)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
superio_enter(struct nct6775_sio_data * sio_data)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
superio_exit(struct nct6775_sio_data * sio_data)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
nct6775_wmi_set_bank(struct nct6775_data * data,u16 reg)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
nct6775_wmi_reg_read(void * ctx,unsigned int reg,unsigned int * val)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
nct6775_wmi_reg_write(void * ctx,unsigned int reg,unsigned int value)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 */
nct6775_set_bank(struct nct6775_data * data,u16 reg)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
nct6775_reg_read(void * ctx,unsigned int reg,unsigned int * val)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
nct6775_reg_write(void * ctx,unsigned int reg,unsigned int value)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
nct6791_enable_io_mapping(struct nct6775_sio_data * sio_data)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
nct6775_suspend(struct device * dev)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
nct6775_resume(struct device * dev)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
nct6775_check_fan_inputs(struct nct6775_data * data,struct nct6775_sio_data * sio_data)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
cpu0_vid_show(struct device * dev,struct device_attribute * attr,char * buf)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
clear_caseopen(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
nct6775_other_is_visible(struct kobject * kobj,struct attribute * attr,int index)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
nct6775_platform_probe_init(struct nct6775_data * data)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
nct6775_platform_probe(struct platform_device * pdev)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 */
nct6775_find(int sioaddr,struct nct6775_sio_data * sio_data)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",
1272*1f432e4cSDenis Pauk "G15CF",
12735dcd53e3SDenis Pauk "PRIME A620M-A",
1274a4fffe48SDenis Pauk "PRIME B560-PLUS",
1275a4fffe48SDenis Pauk "PRIME B560-PLUS AC-HES",
1276a4fffe48SDenis Pauk "PRIME B560M-A",
1277a4fffe48SDenis Pauk "PRIME B560M-A AC",
1278a4fffe48SDenis Pauk "PRIME B560M-K",
1279e2e09989SDenis Pauk "PRIME B650-PLUS",
1280e2e09989SDenis Pauk "PRIME B650M-A",
1281e2e09989SDenis Pauk "PRIME B650M-A AX",
1282bcd2fbecSDenis Pauk "PRIME B650M-A AX II",
1283e2e09989SDenis Pauk "PRIME B650M-A II",
1284e2e09989SDenis Pauk "PRIME B650M-A WIFI",
1285e2e09989SDenis Pauk "PRIME B650M-A WIFI II",
1286a4fffe48SDenis Pauk "PRIME B660-PLUS D4",
12875dcd53e3SDenis Pauk "PRIME B660M-A AC D4",
1288e2e09989SDenis Pauk "PRIME B660M-A D4",
1289e2e09989SDenis Pauk "PRIME B660M-A WIFI D4",
12905dcd53e3SDenis Pauk "PRIME B760-PLUS",
12915dcd53e3SDenis Pauk "PRIME B760-PLUS D4",
12925dcd53e3SDenis Pauk "PRIME B760M-A",
12935dcd53e3SDenis Pauk "PRIME B760M-A AX D4",
12945dcd53e3SDenis Pauk "PRIME B760M-A D4",
12955dcd53e3SDenis Pauk "PRIME B760M-A WIFI",
12965dcd53e3SDenis Pauk "PRIME B760M-A WIFI D4",
12975dcd53e3SDenis Pauk "PRIME B760M-AJ D4",
12985dcd53e3SDenis Pauk "PRIME B760M-K D4",
1299a4fffe48SDenis Pauk "PRIME H510M-A",
1300a4fffe48SDenis Pauk "PRIME H510M-A WIFI",
1301a4fffe48SDenis Pauk "PRIME H510M-D",
1302a4fffe48SDenis Pauk "PRIME H510M-E",
1303a4fffe48SDenis Pauk "PRIME H510M-F",
1304a4fffe48SDenis Pauk "PRIME H510M-K",
13055dcd53e3SDenis Pauk "PRIME H510M-R",
13065dcd53e3SDenis Pauk "PRIME H510T2/CSM",
13075dcd53e3SDenis Pauk "PRIME H570-PLUS",
13085dcd53e3SDenis Pauk "PRIME H570M-PLUS",
1309a4fffe48SDenis Pauk "PRIME H610I-PLUS D4",
1310a4fffe48SDenis Pauk "PRIME H610M-A D4",
1311a4fffe48SDenis Pauk "PRIME H610M-A WIFI D4",
1312a4fffe48SDenis Pauk "PRIME H610M-D D4",
1313a4fffe48SDenis Pauk "PRIME H610M-E D4",
1314a4fffe48SDenis Pauk "PRIME H610M-F D4",
1315a4fffe48SDenis Pauk "PRIME H610M-K D4",
13165dcd53e3SDenis Pauk "PRIME H610M-R D4",
13175dcd53e3SDenis Pauk "PRIME H670-PLUS D4",
13185dcd53e3SDenis Pauk "PRIME H770-PLUS D4",
1319e2e09989SDenis Pauk "PRIME X670-P",
1320e2e09989SDenis Pauk "PRIME X670-P WIFI",
1321e2e09989SDenis Pauk "PRIME X670E-PRO WIFI",
132290b86248SErik Ekman "PRIME Z590-A",
132390b86248SErik Ekman "PRIME Z590-P",
1324bcd2fbecSDenis Pauk "PRIME Z590-P WIFI",
1325bcd2fbecSDenis Pauk "PRIME Z590-V",
132690b86248SErik Ekman "PRIME Z590M-PLUS",
1327a4fffe48SDenis Pauk "PRIME Z690-A",
1328a4fffe48SDenis Pauk "PRIME Z690-P",
1329a4fffe48SDenis Pauk "PRIME Z690-P D4",
1330a4fffe48SDenis Pauk "PRIME Z690-P WIFI",
1331a4fffe48SDenis Pauk "PRIME Z690-P WIFI D4",
1332a4fffe48SDenis Pauk "PRIME Z690M-PLUS D4",
1333a4fffe48SDenis Pauk "PRIME Z790-A WIFI",
1334a4fffe48SDenis Pauk "PRIME Z790-P",
1335a4fffe48SDenis Pauk "PRIME Z790-P D4",
1336a4fffe48SDenis Pauk "PRIME Z790-P WIFI",
1337a4fffe48SDenis Pauk "PRIME Z790-P WIFI D4",
1338a4fffe48SDenis Pauk "PRIME Z790M-PLUS",
1339a4fffe48SDenis Pauk "PRIME Z790M-PLUS D4",
1340a4fffe48SDenis Pauk "Pro B560M-C",
1341a4fffe48SDenis Pauk "Pro B560M-CT",
1342bcd2fbecSDenis Pauk "Pro B660M-C",
1343c05403e6SDenis Pauk "Pro B660M-C D4",
13445dcd53e3SDenis Pauk "Pro B760M-C",
13455dcd53e3SDenis Pauk "Pro B760M-CT",
1346a4fffe48SDenis Pauk "Pro H510M-C",
1347a4fffe48SDenis Pauk "Pro H510M-CT",
1348a4fffe48SDenis Pauk "Pro H610M-C",
1349a4fffe48SDenis Pauk "Pro H610M-C D4",
1350a4fffe48SDenis Pauk "Pro H610M-CT D4",
1351a4fffe48SDenis Pauk "Pro H610T D4",
13525dcd53e3SDenis Pauk "Pro Q670M-C",
1353bcd2fbecSDenis Pauk "Pro WS W680-ACE",
1354bcd2fbecSDenis Pauk "Pro WS W680-ACE IPMI",
13555dcd53e3SDenis Pauk "Pro WS W790-ACE",
13565dcd53e3SDenis Pauk "Pro WS W790E-SAGE SE",
1357bcd2fbecSDenis Pauk "ProArt B650-CREATOR",
1358e2e09989SDenis Pauk "ProArt B660-CREATOR D4",
13595dcd53e3SDenis Pauk "ProArt B760-CREATOR D4",
1360e2e09989SDenis Pauk "ProArt X670E-CREATOR WIFI",
1361a4fffe48SDenis Pauk "ProArt Z690-CREATOR WIFI",
1362bcd2fbecSDenis Pauk "ProArt Z790-CREATOR WIFI",
1363e2e09989SDenis Pauk "ROG CROSSHAIR X670E EXTREME",
1364e2e09989SDenis Pauk "ROG CROSSHAIR X670E GENE",
1365e2e09989SDenis Pauk "ROG CROSSHAIR X670E HERO",
1366bcd2fbecSDenis Pauk "ROG MAXIMUS XIII APEX",
1367bcd2fbecSDenis Pauk "ROG MAXIMUS XIII EXTREME",
1368e2e09989SDenis Pauk "ROG MAXIMUS XIII EXTREME GLACIAL",
1369bcd2fbecSDenis Pauk "ROG MAXIMUS XIII HERO",
1370bcd2fbecSDenis Pauk "ROG MAXIMUS Z690 APEX",
1371e2e09989SDenis Pauk "ROG MAXIMUS Z690 EXTREME",
1372e2e09989SDenis Pauk "ROG MAXIMUS Z690 EXTREME GLACIAL",
13735dcd53e3SDenis Pauk "ROG MAXIMUS Z690 FORMULA",
13745dcd53e3SDenis Pauk "ROG MAXIMUS Z690 HERO",
1375a4fffe48SDenis Pauk "ROG MAXIMUS Z690 HERO EVA",
1376a4fffe48SDenis Pauk "ROG MAXIMUS Z790 APEX",
1377bcd2fbecSDenis Pauk "ROG MAXIMUS Z790 EXTREME",
1378a4fffe48SDenis Pauk "ROG MAXIMUS Z790 HERO",
1379a4fffe48SDenis Pauk "ROG STRIX B560-A GAMING WIFI",
1380a4fffe48SDenis Pauk "ROG STRIX B560-E GAMING WIFI",
1381a4fffe48SDenis Pauk "ROG STRIX B560-F GAMING WIFI",
1382a4fffe48SDenis Pauk "ROG STRIX B560-G GAMING WIFI",
1383a4fffe48SDenis Pauk "ROG STRIX B560-I GAMING WIFI",
1384e2e09989SDenis Pauk "ROG STRIX B650-A GAMING WIFI",
1385e2e09989SDenis Pauk "ROG STRIX B650E-E GAMING WIFI",
1386e2e09989SDenis Pauk "ROG STRIX B650E-F GAMING WIFI",
1387e2e09989SDenis Pauk "ROG STRIX B650E-I GAMING WIFI",
1388bcd2fbecSDenis Pauk "ROG STRIX B660-A GAMING WIFI",
1389e2e09989SDenis Pauk "ROG STRIX B660-A GAMING WIFI D4",
1390e2e09989SDenis Pauk "ROG STRIX B660-F GAMING WIFI",
1391e2e09989SDenis Pauk "ROG STRIX B660-G GAMING WIFI",
1392e2e09989SDenis Pauk "ROG STRIX B660-I GAMING WIFI",
13935dcd53e3SDenis Pauk "ROG STRIX B760-A GAMING WIFI",
13945dcd53e3SDenis Pauk "ROG STRIX B760-A GAMING WIFI D4",
13955dcd53e3SDenis Pauk "ROG STRIX B760-F GAMING WIFI",
13965dcd53e3SDenis Pauk "ROG STRIX B760-G GAMING WIFI",
13975dcd53e3SDenis Pauk "ROG STRIX B760-G GAMING WIFI D4",
13985dcd53e3SDenis Pauk "ROG STRIX B760-I GAMING WIFI",
1399e2e09989SDenis Pauk "ROG STRIX X670E-A GAMING WIFI",
1400e2e09989SDenis Pauk "ROG STRIX X670E-E GAMING WIFI",
1401e2e09989SDenis Pauk "ROG STRIX X670E-F GAMING WIFI",
1402e2e09989SDenis Pauk "ROG STRIX X670E-I GAMING WIFI",
1403bcd2fbecSDenis Pauk "ROG STRIX Z590-A GAMING WIFI",
1404e2e09989SDenis Pauk "ROG STRIX Z590-A GAMING WIFI II",
1405bcd2fbecSDenis Pauk "ROG STRIX Z590-E GAMING WIFI",
1406bcd2fbecSDenis Pauk "ROG STRIX Z590-F GAMING WIFI",
1407bcd2fbecSDenis Pauk "ROG STRIX Z590-I GAMING WIFI",
1408a4fffe48SDenis Pauk "ROG STRIX Z690-A GAMING WIFI",
1409e2e09989SDenis Pauk "ROG STRIX Z690-A GAMING WIFI D4",
14105dcd53e3SDenis Pauk "ROG STRIX Z690-E GAMING WIFI",
14115dcd53e3SDenis Pauk "ROG STRIX Z690-F GAMING WIFI",
14125dcd53e3SDenis Pauk "ROG STRIX Z690-G GAMING WIFI",
1413a4fffe48SDenis Pauk "ROG STRIX Z690-I GAMING WIFI",
1414a4fffe48SDenis Pauk "ROG STRIX Z790-A GAMING WIFI",
1415a4fffe48SDenis Pauk "ROG STRIX Z790-A GAMING WIFI D4",
1416a4fffe48SDenis Pauk "ROG STRIX Z790-E GAMING WIFI",
1417a4fffe48SDenis Pauk "ROG STRIX Z790-F GAMING WIFI",
1418a4fffe48SDenis Pauk "ROG STRIX Z790-H GAMING WIFI",
1419a4fffe48SDenis Pauk "ROG STRIX Z790-I GAMING WIFI",
14205dcd53e3SDenis Pauk "TUF GAMING A620M-PLUS",
14215dcd53e3SDenis Pauk "TUF GAMING A620M-PLUS WIFI",
1422a4fffe48SDenis Pauk "TUF GAMING B560-PLUS WIFI",
1423a4fffe48SDenis Pauk "TUF GAMING B560M-E",
1424a4fffe48SDenis Pauk "TUF GAMING B560M-PLUS",
1425a4fffe48SDenis Pauk "TUF GAMING B560M-PLUS WIFI",
1426e2e09989SDenis Pauk "TUF GAMING B650-PLUS",
1427e2e09989SDenis Pauk "TUF GAMING B650-PLUS WIFI",
1428e2e09989SDenis Pauk "TUF GAMING B650M-PLUS",
1429e2e09989SDenis Pauk "TUF GAMING B650M-PLUS WIFI",
1430bcd2fbecSDenis Pauk "TUF GAMING B660-PLUS WIFI D4",
1431bcd2fbecSDenis Pauk "TUF GAMING B660M-E D4",
14325dcd53e3SDenis Pauk "TUF GAMING B660M-PLUS D4",
1433e2e09989SDenis Pauk "TUF GAMING B660M-PLUS WIFI",
14345dcd53e3SDenis Pauk "TUF GAMING B660M-PLUS WIFI D4",
14355dcd53e3SDenis Pauk "TUF GAMING B760-PLUS WIFI",
14365dcd53e3SDenis Pauk "TUF GAMING B760-PLUS WIFI D4",
14375dcd53e3SDenis Pauk "TUF GAMING B760M-BTF WIFI D4",
14385dcd53e3SDenis Pauk "TUF GAMING B760M-E D4",
14395dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS",
14405dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS D4",
14415dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS WIFI",
14425dcd53e3SDenis Pauk "TUF GAMING B760M-PLUS WIFI D4",
14435dcd53e3SDenis Pauk "TUF GAMING H570-PRO",
14445dcd53e3SDenis Pauk "TUF GAMING H570-PRO WIFI",
14455dcd53e3SDenis Pauk "TUF GAMING H670-PRO WIFI D4",
14465dcd53e3SDenis Pauk "TUF GAMING H770-PRO WIFI",
1447e2e09989SDenis Pauk "TUF GAMING X670E-PLUS",
1448e2e09989SDenis Pauk "TUF GAMING X670E-PLUS WIFI",
1449bcd2fbecSDenis Pauk "TUF GAMING Z590-PLUS",
1450e2e09989SDenis Pauk "TUF GAMING Z590-PLUS WIFI",
1451a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS",
1452a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS D4",
1453a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS WIFI",
1454a4fffe48SDenis Pauk "TUF GAMING Z690-PLUS WIFI D4",
1455a4fffe48SDenis Pauk "TUF GAMING Z790-PLUS D4",
1456a4fffe48SDenis Pauk "TUF GAMING Z790-PLUS WIFI",
1457a4fffe48SDenis Pauk "TUF GAMING Z790-PLUS WIFI D4",
1458bcd2fbecSDenis Pauk "Z590 WIFI GUNDAM EDITION",
1459e2e09989SDenis Pauk };
1460e2e09989SDenis Pauk
1461c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI)
1462c3b3747dSDenis Pauk /*
1463c3b3747dSDenis Pauk * Callback for acpi_bus_for_each_dev() to find the right device
1464c3b3747dSDenis Pauk * by _UID and _HID and return 1 to stop iteration.
1465c3b3747dSDenis Pauk */
nct6775_asuswmi_device_match(struct device * dev,void * data)1466c3b3747dSDenis Pauk static int nct6775_asuswmi_device_match(struct device *dev, void *data)
1467c3b3747dSDenis Pauk {
1468c3b3747dSDenis Pauk struct acpi_device *adev = to_acpi_device(dev);
1469c3b3747dSDenis Pauk
14701b515cfeSRaag Jadav if (acpi_dev_hid_uid_match(adev, ASUSWMI_DEVICE_HID, data)) {
1471c3b3747dSDenis Pauk asus_acpi_dev = adev;
1472c3b3747dSDenis Pauk return 1;
1473c3b3747dSDenis Pauk }
1474c3b3747dSDenis Pauk
1475c3b3747dSDenis Pauk return 0;
1476c3b3747dSDenis Pauk }
1477c3b3747dSDenis Pauk #endif
1478c3b3747dSDenis Pauk
nct6775_determine_access(const char * device_uid)1479c3b3747dSDenis Pauk static enum sensor_access nct6775_determine_access(const char *device_uid)
1480c3b3747dSDenis Pauk {
1481c3b3747dSDenis Pauk #if IS_ENABLED(CONFIG_ACPI)
1482c3b3747dSDenis Pauk u8 tmp;
1483c3b3747dSDenis Pauk
1484c3b3747dSDenis Pauk acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid);
1485c3b3747dSDenis Pauk if (!asus_acpi_dev)
1486c3b3747dSDenis Pauk return access_direct;
1487c3b3747dSDenis Pauk
1488c3b3747dSDenis Pauk /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */
1489c3b3747dSDenis Pauk if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
1490c3b3747dSDenis Pauk pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp);
1491c3b3747dSDenis Pauk return access_asuswmi;
1492c3b3747dSDenis Pauk }
1493c3b3747dSDenis Pauk #endif
1494c3b3747dSDenis Pauk
1495c3b3747dSDenis Pauk return access_direct;
1496c3b3747dSDenis Pauk }
1497c3b3747dSDenis Pauk
sensors_nct6775_platform_init(void)1498c3963bc0SZev Weiss static int __init sensors_nct6775_platform_init(void)
1499c3963bc0SZev Weiss {
1500c3963bc0SZev Weiss int i, err;
1501c3963bc0SZev Weiss bool found = false;
1502c3963bc0SZev Weiss int address;
1503c3963bc0SZev Weiss struct resource res;
1504c3963bc0SZev Weiss struct nct6775_sio_data sio_data;
1505c3963bc0SZev Weiss int sioaddr[2] = { 0x2e, 0x4e };
1506c3963bc0SZev Weiss enum sensor_access access = access_direct;
1507c3963bc0SZev Weiss const char *board_vendor, *board_name;
1508c3963bc0SZev Weiss
1509c3963bc0SZev Weiss err = platform_driver_register(&nct6775_driver);
1510c3963bc0SZev Weiss if (err)
1511c3963bc0SZev Weiss return err;
1512c3963bc0SZev Weiss
1513c3963bc0SZev Weiss board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
1514c3963bc0SZev Weiss board_name = dmi_get_system_info(DMI_BOARD_NAME);
1515c3963bc0SZev Weiss
1516c3963bc0SZev Weiss if (board_name && board_vendor &&
1517c3963bc0SZev Weiss !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) {
1518c3963bc0SZev Weiss err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards),
1519c3963bc0SZev Weiss board_name);
1520c3b3747dSDenis Pauk if (err >= 0)
1521c3b3747dSDenis Pauk access = nct6775_determine_access(ASUSWMI_DEVICE_UID);
1522e2e09989SDenis Pauk
1523e2e09989SDenis Pauk err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards),
1524e2e09989SDenis Pauk board_name);
1525e2e09989SDenis Pauk if (err >= 0)
1526e2e09989SDenis Pauk access = nct6775_determine_access(ASUSMSI_DEVICE_UID);
1527c3963bc0SZev Weiss }
1528c3963bc0SZev Weiss
1529c3963bc0SZev Weiss /*
1530c3963bc0SZev Weiss * initialize sio_data->kind and sio_data->sioreg.
1531c3963bc0SZev Weiss *
1532c3963bc0SZev Weiss * when Super-I/O functions move to a separate file, the Super-I/O
1533c3963bc0SZev Weiss * driver will probe 0x2e and 0x4e and auto-detect the presence of a
1534c3963bc0SZev Weiss * nct6775 hardware monitor, and call probe()
1535c3963bc0SZev Weiss */
1536c3963bc0SZev Weiss for (i = 0; i < ARRAY_SIZE(pdev); i++) {
1537c3963bc0SZev Weiss sio_data.sio_outb = superio_outb;
1538c3963bc0SZev Weiss sio_data.sio_inb = superio_inb;
1539c3963bc0SZev Weiss sio_data.sio_select = superio_select;
1540c3963bc0SZev Weiss sio_data.sio_enter = superio_enter;
1541c3963bc0SZev Weiss sio_data.sio_exit = superio_exit;
1542c3963bc0SZev Weiss
1543c3963bc0SZev Weiss address = nct6775_find(sioaddr[i], &sio_data);
1544c3963bc0SZev Weiss if (address <= 0)
1545c3963bc0SZev Weiss continue;
1546c3963bc0SZev Weiss
1547c3963bc0SZev Weiss found = true;
1548c3963bc0SZev Weiss
1549c3963bc0SZev Weiss sio_data.access = access;
1550c3963bc0SZev Weiss
1551c3963bc0SZev Weiss if (access == access_asuswmi) {
1552c3963bc0SZev Weiss sio_data.sio_outb = superio_wmi_outb;
1553c3963bc0SZev Weiss sio_data.sio_inb = superio_wmi_inb;
1554c3963bc0SZev Weiss sio_data.sio_select = superio_wmi_select;
1555c3963bc0SZev Weiss sio_data.sio_enter = superio_wmi_enter;
1556c3963bc0SZev Weiss sio_data.sio_exit = superio_wmi_exit;
1557c3963bc0SZev Weiss }
1558c3963bc0SZev Weiss
1559c3963bc0SZev Weiss pdev[i] = platform_device_alloc(DRVNAME, address);
1560c3963bc0SZev Weiss if (!pdev[i]) {
1561c3963bc0SZev Weiss err = -ENOMEM;
1562c3963bc0SZev Weiss goto exit_device_unregister;
1563c3963bc0SZev Weiss }
1564c3963bc0SZev Weiss
1565c3963bc0SZev Weiss err = platform_device_add_data(pdev[i], &sio_data,
1566c3963bc0SZev Weiss sizeof(struct nct6775_sio_data));
1567c3963bc0SZev Weiss if (err)
1568c3963bc0SZev Weiss goto exit_device_put;
1569c3963bc0SZev Weiss
1570c3963bc0SZev Weiss if (sio_data.access == access_direct) {
1571c3963bc0SZev Weiss memset(&res, 0, sizeof(res));
1572c3963bc0SZev Weiss res.name = DRVNAME;
1573c3963bc0SZev Weiss res.start = address + IOREGION_OFFSET;
1574c3963bc0SZev Weiss res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
1575c3963bc0SZev Weiss res.flags = IORESOURCE_IO;
1576c3963bc0SZev Weiss
1577c3963bc0SZev Weiss err = acpi_check_resource_conflict(&res);
1578c3963bc0SZev Weiss if (err) {
1579c3963bc0SZev Weiss platform_device_put(pdev[i]);
1580c3963bc0SZev Weiss pdev[i] = NULL;
1581c3963bc0SZev Weiss continue;
1582c3963bc0SZev Weiss }
1583c3963bc0SZev Weiss
1584c3963bc0SZev Weiss err = platform_device_add_resources(pdev[i], &res, 1);
1585c3963bc0SZev Weiss if (err)
1586c3963bc0SZev Weiss goto exit_device_put;
1587c3963bc0SZev Weiss }
1588c3963bc0SZev Weiss
1589c3963bc0SZev Weiss /* platform_device_add calls probe() */
1590c3963bc0SZev Weiss err = platform_device_add(pdev[i]);
1591c3963bc0SZev Weiss if (err)
1592c3963bc0SZev Weiss goto exit_device_put;
1593c3963bc0SZev Weiss }
1594c3963bc0SZev Weiss if (!found) {
1595c3963bc0SZev Weiss err = -ENODEV;
1596c3963bc0SZev Weiss goto exit_unregister;
1597c3963bc0SZev Weiss }
1598c3963bc0SZev Weiss
1599c3963bc0SZev Weiss return 0;
1600c3963bc0SZev Weiss
1601c3963bc0SZev Weiss exit_device_put:
1602c3963bc0SZev Weiss platform_device_put(pdev[i]);
1603c3963bc0SZev Weiss exit_device_unregister:
1604452d5e29SAndy Shevchenko while (i--)
1605c3963bc0SZev Weiss platform_device_unregister(pdev[i]);
1606c3963bc0SZev Weiss exit_unregister:
1607c3963bc0SZev Weiss platform_driver_unregister(&nct6775_driver);
1608c3963bc0SZev Weiss return err;
1609c3963bc0SZev Weiss }
1610c3963bc0SZev Weiss
sensors_nct6775_platform_exit(void)1611c3963bc0SZev Weiss static void __exit sensors_nct6775_platform_exit(void)
1612c3963bc0SZev Weiss {
1613c3963bc0SZev Weiss int i;
1614c3963bc0SZev Weiss
1615452d5e29SAndy Shevchenko for (i = 0; i < ARRAY_SIZE(pdev); i++)
1616c3963bc0SZev Weiss platform_device_unregister(pdev[i]);
1617c3963bc0SZev Weiss platform_driver_unregister(&nct6775_driver);
1618c3963bc0SZev Weiss }
1619c3963bc0SZev Weiss
1620c3963bc0SZev Weiss MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
1621c3963bc0SZev Weiss MODULE_DESCRIPTION("Platform driver for NCT6775F and compatible chips");
1622c3963bc0SZev Weiss MODULE_LICENSE("GPL");
1623c3963bc0SZev Weiss MODULE_IMPORT_NS(HWMON_NCT6775);
1624c3963bc0SZev Weiss
1625c3963bc0SZev Weiss module_init(sensors_nct6775_platform_init);
1626c3963bc0SZev Weiss module_exit(sensors_nct6775_platform_exit);
1627