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