blob: 098d12b9ecdad7e621e87cb82f434a2c3916a906 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002/*
3 * nct6775 - Driver for the hardware monitoring functionality of
4 * Nuvoton NCT677x Super-I/O chips
5 *
6 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
7 *
8 * Derived from w83627ehf driver
Jean Delvare7c81c60f2014-01-29 20:40:08 +01009 * Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070010 * Copyright (C) 2006 Yuan Mu (Winbond),
11 * Rudolf Marek <r.marek@assembler.cz>
12 * David Hubbard <david.c.hubbard@gmail.com>
13 * Daniel J Blueman <daniel.blueman@gmail.com>
14 * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
15 *
16 * Shamelessly ripped from the w83627hf driver
17 * Copyright (C) 2003 Mark Studebaker
18 *
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070019 * Supports the following chips:
20 *
21 * Chip #vin #fan #pwm #temp chip IDs man ID
Guenter Roeck6c009502012-07-01 08:23:15 -070022 * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
Björn Gerhart29c7cb42019-07-23 18:06:46 +020023 * nct6116d 9 5 5 3+3 0xd280 0xc1 0x5ca3
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070024 * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
25 * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
26 * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
David Bartley578ab5f2013-06-24 22:28:28 -070027 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
Guenter Roeck8aefb932014-11-16 09:50:04 -080028 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070029 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
Guenter Roeck419220d2017-05-17 18:19:18 -070030 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
Guenter Roeck81820052018-02-21 13:09:39 -080031 * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
Guenter Roecke41da282018-09-18 20:48:29 -070032 * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3
Guenter Roeck05996822018-09-19 20:26:16 -070033 * (0xd451)
Guenter Roeck264142b2018-12-26 07:34:31 -080034 * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3
35 * (0xd429)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070036 *
37 * #temp lists the number of monitored temperature sources (first value) plus
38 * the number of directly connectable temperature sensors (second value).
39 */
40
41#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
42
43#include <linux/module.h>
44#include <linux/init.h>
45#include <linux/slab.h>
46#include <linux/jiffies.h>
47#include <linux/platform_device.h>
48#include <linux/hwmon.h>
49#include <linux/hwmon-sysfs.h>
50#include <linux/hwmon-vid.h>
51#include <linux/err.h>
52#include <linux/mutex.h>
53#include <linux/acpi.h>
Guenter Roeckd1bb21862017-05-17 18:40:10 -070054#include <linux/bitops.h>
Guenter Roeck25cdd992015-02-06 18:55:36 -080055#include <linux/dmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070056#include <linux/io.h>
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -050057#include <linux/nospec.h>
Denis Pauk3fbbfc22021-09-18 01:02:40 +030058#include <linux/wmi.h>
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070059#include "lm75.h"
60
Guenter Roeckaa136e52012-12-04 03:26:05 -080061#define USE_ALTERNATE
62
Björn Gerhart29c7cb42019-07-23 18:06:46 +020063enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
64 nct6793, nct6795, nct6796, nct6797, nct6798 };
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070065
66/* used to set data->name = nct6775_device_names[data->sio_kind] */
67static const char * const nct6775_device_names[] = {
Guenter Roeck6c009502012-07-01 08:23:15 -070068 "nct6106",
Björn Gerhart29c7cb42019-07-23 18:06:46 +020069 "nct6116",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070070 "nct6775",
71 "nct6776",
72 "nct6779",
David Bartley578ab5f2013-06-24 22:28:28 -070073 "nct6791",
Guenter Roeck8aefb932014-11-16 09:50:04 -080074 "nct6792",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070075 "nct6793",
Guenter Roeck419220d2017-05-17 18:19:18 -070076 "nct6795",
Guenter Roeck81820052018-02-21 13:09:39 -080077 "nct6796",
Guenter Roecke41da282018-09-18 20:48:29 -070078 "nct6797",
Guenter Roeck05996822018-09-19 20:26:16 -070079 "nct6798",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070080};
81
82static const char * const nct6775_sio_names[] __initconst = {
83 "NCT6106D",
Björn Gerhart29c7cb42019-07-23 18:06:46 +020084 "NCT6116D",
Guenter Roeckcd1faefa2015-08-30 19:45:19 -070085 "NCT6775F",
86 "NCT6776D/F",
87 "NCT6779D",
88 "NCT6791D",
89 "NCT6792D",
90 "NCT6793D",
Guenter Roeck419220d2017-05-17 18:19:18 -070091 "NCT6795D",
Guenter Roeck81820052018-02-21 13:09:39 -080092 "NCT6796D",
Guenter Roecke41da282018-09-18 20:48:29 -070093 "NCT6797D",
Guenter Roeck05996822018-09-19 20:26:16 -070094 "NCT6798D",
Guenter Roeck9de2e2e2012-05-20 19:29:48 -070095};
96
97static unsigned short force_id;
98module_param(force_id, ushort, 0);
99MODULE_PARM_DESC(force_id, "Override the detected device ID");
100
Guenter Roeck47ece962012-12-04 07:59:32 -0800101static unsigned short fan_debounce;
102module_param(fan_debounce, ushort, 0);
103MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
104
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700105#define DRVNAME "nct6775"
106
107/*
108 * Super-I/O constants and functions
109 */
110
Guenter Roecka6bd5872012-12-04 03:13:34 -0800111#define NCT6775_LD_ACPI 0x0a
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700112#define NCT6775_LD_HWM 0x0b
113#define NCT6775_LD_VID 0x0d
Guenter Roecke5c85222017-05-17 18:09:41 -0700114#define NCT6775_LD_12 0x12
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700115
116#define SIO_REG_LDSEL 0x07 /* Logical device select */
117#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
118#define SIO_REG_ENABLE 0x30 /* Logical device enable */
119#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
120
Guenter Roeck6c009502012-07-01 08:23:15 -0700121#define SIO_NCT6106_ID 0xc450
Björn Gerhart29c7cb42019-07-23 18:06:46 +0200122#define SIO_NCT6116_ID 0xd280
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700123#define SIO_NCT6775_ID 0xb470
124#define SIO_NCT6776_ID 0xc330
125#define SIO_NCT6779_ID 0xc560
David Bartley578ab5f2013-06-24 22:28:28 -0700126#define SIO_NCT6791_ID 0xc800
Guenter Roeck8aefb932014-11-16 09:50:04 -0800127#define SIO_NCT6792_ID 0xc910
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700128#define SIO_NCT6793_ID 0xd120
Guenter Roeck419220d2017-05-17 18:19:18 -0700129#define SIO_NCT6795_ID 0xd350
Guenter Roeck81820052018-02-21 13:09:39 -0800130#define SIO_NCT6796_ID 0xd420
Guenter Roecke41da282018-09-18 20:48:29 -0700131#define SIO_NCT6797_ID 0xd450
Guenter Roeck264142b2018-12-26 07:34:31 -0800132#define SIO_NCT6798_ID 0xd428
Guenter Roeck05996822018-09-19 20:26:16 -0700133#define SIO_ID_MASK 0xFFF8
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700134
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800135enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
Denis Pauk3fbbfc22021-09-18 01:02:40 +0300136enum sensor_access { access_direct, access_asuswmi };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800137
Denis Pauk2e7b9882021-09-18 01:02:38 +0300138struct nct6775_sio_data {
139 int sioreg;
Denis Pauk3fbbfc22021-09-18 01:02:40 +0300140 int ld;
Denis Pauk2e7b9882021-09-18 01:02:38 +0300141 enum kinds kind;
Denis Pauk3fbbfc22021-09-18 01:02:40 +0300142 enum sensor_access access;
Denis Pauk2e7b9882021-09-18 01:02:38 +0300143
144 /* superio_() callbacks */
145 void (*sio_outb)(struct nct6775_sio_data *sio_data, int reg, int val);
146 int (*sio_inb)(struct nct6775_sio_data *sio_data, int reg);
147 void (*sio_select)(struct nct6775_sio_data *sio_data, int ld);
148 int (*sio_enter)(struct nct6775_sio_data *sio_data);
149 void (*sio_exit)(struct nct6775_sio_data *sio_data);
150};
151
Denis Pauk3fbbfc22021-09-18 01:02:40 +0300152#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66"
153#define ASUSWMI_METHODID_RSIO 0x5253494F
154#define ASUSWMI_METHODID_WSIO 0x5753494F
155#define ASUSWMI_METHODID_RHWM 0x5248574D
156#define ASUSWMI_METHODID_WHWM 0x5748574D
157#define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE
158
159static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval)
160{
161#if IS_ENABLED(CONFIG_ACPI_WMI)
162 u32 args = bank | (reg << 8) | (val << 16);
163 struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
164 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
165 acpi_status status;
166 union acpi_object *obj;
167 u32 tmp = ASUSWMI_UNSUPPORTED_METHOD;
168
169 status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0,
170 method_id, &input, &output);
171
172 if (ACPI_FAILURE(status))
173 return -EIO;
174
175 obj = output.pointer;
176 if (obj && obj->type == ACPI_TYPE_INTEGER)
177 tmp = obj->integer.value;
178
179 if (retval)
180 *retval = tmp;
181
182 kfree(obj);
183
184 if (tmp == ASUSWMI_UNSUPPORTED_METHOD)
185 return -ENODEV;
186 return 0;
187#else
188 return -EOPNOTSUPP;
189#endif
190}
191
192static inline int nct6775_asuswmi_write(u8 bank, u8 reg, u8 val)
193{
194 return nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_WHWM, bank,
195 reg, val, NULL);
196}
197
198static inline int nct6775_asuswmi_read(u8 bank, u8 reg, u8 *val)
199{
200 u32 ret, tmp = 0;
201
202 ret = nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RHWM, bank,
203 reg, 0, &tmp);
204 *val = tmp;
205 return ret;
206}
207
208static int superio_wmi_inb(struct nct6775_sio_data *sio_data, int reg)
209{
210 int tmp = 0;
211
212 nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RSIO, sio_data->ld,
213 reg, 0, &tmp);
214 return tmp;
215}
216
217static void superio_wmi_outb(struct nct6775_sio_data *sio_data, int reg, int val)
218{
219 nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_WSIO, sio_data->ld,
220 reg, val, NULL);
221}
222
223static void superio_wmi_select(struct nct6775_sio_data *sio_data, int ld)
224{
225 sio_data->ld = ld;
226}
227
228static int superio_wmi_enter(struct nct6775_sio_data *sio_data)
229{
230 return 0;
231}
232
233static void superio_wmi_exit(struct nct6775_sio_data *sio_data)
234{
235}
236
Denis Pauk2e7b9882021-09-18 01:02:38 +0300237static void superio_outb(struct nct6775_sio_data *sio_data, int reg, int val)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700238{
Denis Pauk2e7b9882021-09-18 01:02:38 +0300239 int ioreg = sio_data->sioreg;
240
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700241 outb(reg, ioreg);
242 outb(val, ioreg + 1);
243}
244
Denis Pauk2e7b9882021-09-18 01:02:38 +0300245static int superio_inb(struct nct6775_sio_data *sio_data, int reg)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700246{
Denis Pauk2e7b9882021-09-18 01:02:38 +0300247 int ioreg = sio_data->sioreg;
248
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700249 outb(reg, ioreg);
250 return inb(ioreg + 1);
251}
252
Denis Pauk2e7b9882021-09-18 01:02:38 +0300253static void superio_select(struct nct6775_sio_data *sio_data, int ld)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700254{
Denis Pauk2e7b9882021-09-18 01:02:38 +0300255 int ioreg = sio_data->sioreg;
256
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700257 outb(SIO_REG_LDSEL, ioreg);
258 outb(ld, ioreg + 1);
259}
260
Denis Pauk2e7b9882021-09-18 01:02:38 +0300261static int superio_enter(struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700262{
Denis Pauk2e7b9882021-09-18 01:02:38 +0300263 int ioreg = sio_data->sioreg;
264
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700265 /*
266 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
267 */
268 if (!request_muxed_region(ioreg, 2, DRVNAME))
269 return -EBUSY;
270
271 outb(0x87, ioreg);
272 outb(0x87, ioreg);
273
274 return 0;
275}
276
Denis Pauk2e7b9882021-09-18 01:02:38 +0300277static void superio_exit(struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700278{
Denis Pauk2e7b9882021-09-18 01:02:38 +0300279 int ioreg = sio_data->sioreg;
280
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700281 outb(0xaa, ioreg);
282 outb(0x02, ioreg);
283 outb(0x02, ioreg + 1);
284 release_region(ioreg, 2);
285}
286
287/*
288 * ISA constants
289 */
290
291#define IOREGION_ALIGNMENT (~7)
292#define IOREGION_OFFSET 5
293#define IOREGION_LENGTH 2
294#define ADDR_REG_OFFSET 0
295#define DATA_REG_OFFSET 1
296
297#define NCT6775_REG_BANK 0x4E
298#define NCT6775_REG_CONFIG 0x40
Denis Pauk3fbbfc22021-09-18 01:02:40 +0300299#define NCT6775_PORT_CHIPID 0x58
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700300
301/*
302 * Not currently used:
303 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
304 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
305 * REG_MAN_ID is at port 0x4f
306 * REG_CHIP_ID is at port 0x58
307 */
308
Guenter Roeckaa136e52012-12-04 03:26:05 -0800309#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
310#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
311
Guenter Roeck6c009502012-07-01 08:23:15 -0700312#define NUM_REG_ALARM 7 /* Max number of alarm registers */
Guenter Roeck30846992013-06-24 22:21:59 -0700313#define NUM_REG_BEEP 5 /* Max number of beep registers */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700314
Guenter Roeck81820052018-02-21 13:09:39 -0800315#define NUM_FAN 7
David Bartley578ab5f2013-06-24 22:28:28 -0700316
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700317/* Common and NCT6775 specific data */
318
319/* Voltage min/max registers for nr=7..14 are in bank 5 */
320
321static const u16 NCT6775_REG_IN_MAX[] = {
322 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
323 0x55c, 0x55e, 0x560, 0x562 };
324static const u16 NCT6775_REG_IN_MIN[] = {
325 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
326 0x55d, 0x55f, 0x561, 0x563 };
327static const u16 NCT6775_REG_IN[] = {
328 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
329};
330
331#define NCT6775_REG_VBAT 0x5D
Guenter Roeckaa136e52012-12-04 03:26:05 -0800332#define NCT6775_REG_DIODE 0x5E
Guenter Roeck6c009502012-07-01 08:23:15 -0700333#define NCT6775_DIODE_MASK 0x02
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700334
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800335#define NCT6775_REG_FANDIV1 0x506
336#define NCT6775_REG_FANDIV2 0x507
337
Guenter Roeck47ece962012-12-04 07:59:32 -0800338#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
339
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700340static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
341
Guenter Roeck30846992013-06-24 22:21:59 -0700342/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700343
344static const s8 NCT6775_ALARM_BITS[] = {
345 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
346 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
347 -1, /* unused */
Guenter Roeck41fa9a92013-06-23 13:04:04 -0700348 6, 7, 11, -1, -1, /* fan1..fan5 */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700349 -1, -1, -1, /* unused */
350 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
351 12, -1 }; /* intrusion0, intrusion1 */
352
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800353#define FAN_ALARM_BASE 16
Guenter Roeckaa136e52012-12-04 03:26:05 -0800354#define TEMP_ALARM_BASE 24
Guenter Roecka6bd5872012-12-04 03:13:34 -0800355#define INTRUSION_ALARM_BASE 30
356
Guenter Roeck30846992013-06-24 22:21:59 -0700357static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
358
359/*
360 * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
361 * 30..31 intrusion
362 */
363static const s8 NCT6775_BEEP_BITS[] = {
364 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
365 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
366 21, /* global beep enable */
367 6, 7, 11, 28, -1, /* fan1..fan5 */
368 -1, -1, -1, /* unused */
369 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
370 12, -1 }; /* intrusion0, intrusion1 */
371
372#define BEEP_ENABLE_BASE 15
373
Guenter Roecka6bd5872012-12-04 03:13:34 -0800374static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
375static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
376
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800377/* DC or PWM output fan configuration */
378static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
379static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
380
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800381/* Advanced Fan control, some values are common for all fans */
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800382
David Bartley578ab5f2013-06-24 22:28:28 -0700383static const u16 NCT6775_REG_TARGET[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800384 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
David Bartley578ab5f2013-06-24 22:28:28 -0700385static const u16 NCT6775_REG_FAN_MODE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800386 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800387static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800388 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800389static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800390 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800391static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800392 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
David Bartley578ab5f2013-06-24 22:28:28 -0700393static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800394 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800395static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
396static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
397
398static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800399 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
David Bartley578ab5f2013-06-24 22:28:28 -0700400static const u16 NCT6775_REG_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800401 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
David Bartley578ab5f2013-06-24 22:28:28 -0700402static const u16 NCT6775_REG_PWM_READ[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800403 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800404
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800405static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
406static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
Guenter Roeckc7932792018-09-06 09:47:51 -0700407static const u16 NCT6775_REG_FAN_PULSES[NUM_FAN] = {
408 0x641, 0x642, 0x643, 0x644 };
409static const u16 NCT6775_FAN_PULSE_SHIFT[NUM_FAN] = { };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800410
Guenter Roeckaa136e52012-12-04 03:26:05 -0800411static const u16 NCT6775_REG_TEMP[] = {
412 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
413
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800414static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 };
415
Guenter Roeckaa136e52012-12-04 03:26:05 -0800416static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
417 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
418static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
419 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
420static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
421 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
422
423static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
424 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
425
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800426static const u16 NCT6775_REG_TEMP_SEL[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800427 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800428
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800429static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700430 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800431static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700432 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800433static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700434 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800435static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700436 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800437static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700438 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800439
Guenter Roeckaa136e52012-12-04 03:26:05 -0800440static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
441
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800442static const u16 NCT6775_REG_AUTO_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800443 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800444static const u16 NCT6775_REG_AUTO_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800445 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800446
447#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
448#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
449
450static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
451
452static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800453 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800454static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800455 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800456
Guenter Roeckaa136e52012-12-04 03:26:05 -0800457static const char *const nct6775_temp_label[] = {
458 "",
459 "SYSTIN",
460 "CPUTIN",
461 "AUXTIN",
462 "AMD SB-TSI",
463 "PECI Agent 0",
464 "PECI Agent 1",
465 "PECI Agent 2",
466 "PECI Agent 3",
467 "PECI Agent 4",
468 "PECI Agent 5",
469 "PECI Agent 6",
470 "PECI Agent 7",
471 "PCH_CHIP_CPU_MAX_TEMP",
472 "PCH_CHIP_TEMP",
473 "PCH_CPU_TEMP",
474 "PCH_MCH_TEMP",
475 "PCH_DIM0_TEMP",
476 "PCH_DIM1_TEMP",
477 "PCH_DIM2_TEMP",
478 "PCH_DIM3_TEMP"
479};
480
Guenter Roeckcc66b302017-05-17 18:05:06 -0700481#define NCT6775_TEMP_MASK 0x001ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700482#define NCT6775_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800483
Guenter Roeckcc66b302017-05-17 18:05:06 -0700484static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
485 [13] = 0x661,
486 [14] = 0x662,
487 [15] = 0x664,
488};
489
490static const u16 NCT6775_REG_TEMP_CRIT[32] = {
491 [4] = 0xa00,
492 [5] = 0xa01,
493 [6] = 0xa02,
494 [7] = 0xa03,
495 [8] = 0xa04,
496 [9] = 0xa05,
497 [10] = 0xa06,
498 [11] = 0xa07
499};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800500
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700501/* NCT6776 specific data */
502
Guenter Roeck728d2942015-08-31 16:13:47 -0700503/* STEP_UP_TIME and STEP_DOWN_TIME regs are swapped for all chips but NCT6775 */
504#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
505#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
506
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700507static const s8 NCT6776_ALARM_BITS[] = {
508 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
509 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
510 -1, /* unused */
511 6, 7, 11, 10, 23, /* fan1..fan5 */
512 -1, -1, -1, /* unused */
513 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
514 12, 9 }; /* intrusion0, intrusion1 */
515
Guenter Roeck30846992013-06-24 22:21:59 -0700516static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
517
518static const s8 NCT6776_BEEP_BITS[] = {
519 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
520 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
521 24, /* global beep enable */
522 25, 26, 27, 28, 29, /* fan1..fan5 */
523 -1, -1, -1, /* unused */
524 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
525 30, 31 }; /* intrusion0, intrusion1 */
526
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800527static const u16 NCT6776_REG_TOLERANCE_H[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800528 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800529
David Bartley578ab5f2013-06-24 22:28:28 -0700530static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
531static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -0800532
Guenter Roeck00fd4cf2018-02-21 13:09:37 -0800533static const u16 NCT6776_REG_FAN_MIN[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800534 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
Guenter Roeckc7932792018-09-06 09:47:51 -0700535static const u16 NCT6776_REG_FAN_PULSES[NUM_FAN] = {
536 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800537
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800538static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
David Bartley578ab5f2013-06-24 22:28:28 -0700539 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
Guenter Roeckbbd8dec2012-12-04 09:08:29 -0800540
Guenter Roeckaa136e52012-12-04 03:26:05 -0800541static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
542 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
543
544static const char *const nct6776_temp_label[] = {
545 "",
546 "SYSTIN",
547 "CPUTIN",
548 "AUXTIN",
549 "SMBUSMASTER 0",
550 "SMBUSMASTER 1",
551 "SMBUSMASTER 2",
552 "SMBUSMASTER 3",
553 "SMBUSMASTER 4",
554 "SMBUSMASTER 5",
555 "SMBUSMASTER 6",
556 "SMBUSMASTER 7",
557 "PECI Agent 0",
558 "PECI Agent 1",
559 "PCH_CHIP_CPU_MAX_TEMP",
560 "PCH_CHIP_TEMP",
561 "PCH_CPU_TEMP",
562 "PCH_MCH_TEMP",
563 "PCH_DIM0_TEMP",
564 "PCH_DIM1_TEMP",
565 "PCH_DIM2_TEMP",
566 "PCH_DIM3_TEMP",
567 "BYTE_TEMP"
568};
569
Guenter Roeckcc66b302017-05-17 18:05:06 -0700570#define NCT6776_TEMP_MASK 0x007ffffe
Guenter Roeck37196ba2018-09-13 19:43:58 -0700571#define NCT6776_VIRT_TEMP_MASK 0x00000000
Guenter Roeckaa136e52012-12-04 03:26:05 -0800572
Guenter Roeckcc66b302017-05-17 18:05:06 -0700573static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
574 [14] = 0x401,
575 [15] = 0x402,
576 [16] = 0x404,
577};
578
579static const u16 NCT6776_REG_TEMP_CRIT[32] = {
580 [11] = 0x709,
581 [12] = 0x70a,
582};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800583
Guenter Roeck9de2e2e2012-05-20 19:29:48 -0700584/* NCT6779 specific data */
585
586static const u16 NCT6779_REG_IN[] = {
587 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
588 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
589
590static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
591 0x459, 0x45A, 0x45B, 0x568 };
592
593static const s8 NCT6779_ALARM_BITS[] = {
594 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
595 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
596 -1, /* unused */
597 6, 7, 11, 10, 23, /* fan1..fan5 */
598 -1, -1, -1, /* unused */
599 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
600 12, 9 }; /* intrusion0, intrusion1 */
601
Guenter Roeck30846992013-06-24 22:21:59 -0700602static const s8 NCT6779_BEEP_BITS[] = {
603 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
604 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
605 24, /* global beep enable */
606 25, 26, 27, 28, 29, /* fan1..fan5 */
607 -1, -1, -1, /* unused */
608 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
609 30, 31 }; /* intrusion0, intrusion1 */
610
David Bartley578ab5f2013-06-24 22:28:28 -0700611static const u16 NCT6779_REG_FAN[] = {
Guenter Roeck55066352018-09-17 05:23:58 -0700612 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
Guenter Roeckc7932792018-09-06 09:47:51 -0700613static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
Guenter Roecke41da282018-09-18 20:48:29 -0700614 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f };
Guenter Roeck1c65dc32012-12-04 07:56:24 -0800615
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800616static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800617 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700618#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800619static const u16 NCT6779_REG_CRITICAL_PWM[] = {
Guenter Roeck81820052018-02-21 13:09:39 -0800620 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 };
Guenter Roeckcdcaece2012-12-04 09:04:52 -0800621
Guenter Roeckaa136e52012-12-04 03:26:05 -0800622static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800623static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
Guenter Roeckaa136e52012-12-04 03:26:05 -0800624static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
625 0x18, 0x152 };
626static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
627 0x3a, 0x153 };
628static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
629 0x39, 0x155 };
630
631static const u16 NCT6779_REG_TEMP_OFFSET[] = {
632 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
633
634static const char *const nct6779_temp_label[] = {
635 "",
636 "SYSTIN",
637 "CPUTIN",
638 "AUXTIN0",
639 "AUXTIN1",
640 "AUXTIN2",
641 "AUXTIN3",
642 "",
643 "SMBUSMASTER 0",
644 "SMBUSMASTER 1",
645 "SMBUSMASTER 2",
646 "SMBUSMASTER 3",
647 "SMBUSMASTER 4",
648 "SMBUSMASTER 5",
649 "SMBUSMASTER 6",
650 "SMBUSMASTER 7",
651 "PECI Agent 0",
652 "PECI Agent 1",
653 "PCH_CHIP_CPU_MAX_TEMP",
654 "PCH_CHIP_TEMP",
655 "PCH_CPU_TEMP",
656 "PCH_MCH_TEMP",
657 "PCH_DIM0_TEMP",
658 "PCH_DIM1_TEMP",
659 "PCH_DIM2_TEMP",
660 "PCH_DIM3_TEMP",
Guenter Roeck9a383712015-08-29 15:29:25 -0700661 "BYTE_TEMP",
662 "",
663 "",
664 "",
665 "",
666 "Virtual_TEMP"
Guenter Roeckaa136e52012-12-04 03:26:05 -0800667};
668
Guenter Roeckcc66b302017-05-17 18:05:06 -0700669#define NCT6779_TEMP_MASK 0x07ffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700670#define NCT6779_VIRT_TEMP_MASK 0x00000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700671#define NCT6791_TEMP_MASK 0x87ffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700672#define NCT6791_VIRT_TEMP_MASK 0x80000000
Guenter Roeck9a383712015-08-29 15:29:25 -0700673
Guenter Roeckcc66b302017-05-17 18:05:06 -0700674static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
Guenter Roeckaa136e52012-12-04 03:26:05 -0800675 = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
676 0, 0, 0, 0, 0, 0, 0, 0,
677 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
678 0x408, 0 };
679
Guenter Roeckcc66b302017-05-17 18:05:06 -0700680static const u16 NCT6779_REG_TEMP_CRIT[32] = {
681 [15] = 0x709,
682 [16] = 0x70a,
683};
Guenter Roeckaa136e52012-12-04 03:26:05 -0800684
David Bartley578ab5f2013-06-24 22:28:28 -0700685/* NCT6791 specific data */
686
687#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
688
Guenter Roecke2617262018-02-21 13:09:36 -0800689static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
690static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
691static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
692static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
693static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
694static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
Guenter Roeckcc76dee2013-11-13 12:47:17 -0800695
David Bartley578ab5f2013-06-24 22:28:28 -0700696static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
697 0x459, 0x45A, 0x45B, 0x568, 0x45D };
698
699static const s8 NCT6791_ALARM_BITS[] = {
700 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
701 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
702 -1, /* unused */
703 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
704 -1, -1, /* unused */
705 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
706 12, 9 }; /* intrusion0, intrusion1 */
707
Guenter Roeckcd1faefa2015-08-30 19:45:19 -0700708/* NCT6792/NCT6793 specific data */
Guenter Roeck8aefb932014-11-16 09:50:04 -0800709
710static const u16 NCT6792_REG_TEMP_MON[] = {
711 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
712static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
713 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
David Bartley578ab5f2013-06-24 22:28:28 -0700714
Guenter Roeck50224f42015-10-30 07:52:39 -0700715static const char *const nct6792_temp_label[] = {
716 "",
717 "SYSTIN",
718 "CPUTIN",
719 "AUXTIN0",
720 "AUXTIN1",
721 "AUXTIN2",
722 "AUXTIN3",
723 "",
724 "SMBUSMASTER 0",
725 "SMBUSMASTER 1",
726 "SMBUSMASTER 2",
727 "SMBUSMASTER 3",
728 "SMBUSMASTER 4",
729 "SMBUSMASTER 5",
730 "SMBUSMASTER 6",
731 "SMBUSMASTER 7",
732 "PECI Agent 0",
733 "PECI Agent 1",
734 "PCH_CHIP_CPU_MAX_TEMP",
735 "PCH_CHIP_TEMP",
736 "PCH_CPU_TEMP",
737 "PCH_MCH_TEMP",
738 "PCH_DIM0_TEMP",
739 "PCH_DIM1_TEMP",
740 "PCH_DIM2_TEMP",
741 "PCH_DIM3_TEMP",
742 "BYTE_TEMP",
743 "PECI Agent 0 Calibration",
744 "PECI Agent 1 Calibration",
745 "",
746 "",
747 "Virtual_TEMP"
748};
749
Guenter Roeckcc66b302017-05-17 18:05:06 -0700750#define NCT6792_TEMP_MASK 0x9fffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700751#define NCT6792_VIRT_TEMP_MASK 0x80000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700752
Guenter Roeck50224f42015-10-30 07:52:39 -0700753static const char *const nct6793_temp_label[] = {
754 "",
755 "SYSTIN",
756 "CPUTIN",
757 "AUXTIN0",
758 "AUXTIN1",
759 "AUXTIN2",
760 "AUXTIN3",
761 "",
762 "SMBUSMASTER 0",
763 "SMBUSMASTER 1",
764 "",
765 "",
766 "",
767 "",
768 "",
769 "",
770 "PECI Agent 0",
771 "PECI Agent 1",
772 "PCH_CHIP_CPU_MAX_TEMP",
773 "PCH_CHIP_TEMP",
774 "PCH_CPU_TEMP",
775 "PCH_MCH_TEMP",
776 "Agent0 Dimm0 ",
777 "Agent0 Dimm1",
778 "Agent1 Dimm0",
779 "Agent1 Dimm1",
780 "BYTE_TEMP0",
781 "BYTE_TEMP1",
782 "PECI Agent 0 Calibration",
783 "PECI Agent 1 Calibration",
784 "",
785 "Virtual_TEMP"
786};
787
Guenter Roeckcc66b302017-05-17 18:05:06 -0700788#define NCT6793_TEMP_MASK 0xbfff037e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700789#define NCT6793_VIRT_TEMP_MASK 0x80000000
Guenter Roeckcc66b302017-05-17 18:05:06 -0700790
Guenter Roeck419220d2017-05-17 18:19:18 -0700791static const char *const nct6795_temp_label[] = {
792 "",
793 "SYSTIN",
794 "CPUTIN",
795 "AUXTIN0",
796 "AUXTIN1",
797 "AUXTIN2",
798 "AUXTIN3",
799 "",
800 "SMBUSMASTER 0",
801 "SMBUSMASTER 1",
802 "SMBUSMASTER 2",
803 "SMBUSMASTER 3",
804 "SMBUSMASTER 4",
805 "SMBUSMASTER 5",
806 "SMBUSMASTER 6",
807 "SMBUSMASTER 7",
808 "PECI Agent 0",
809 "PECI Agent 1",
810 "PCH_CHIP_CPU_MAX_TEMP",
811 "PCH_CHIP_TEMP",
812 "PCH_CPU_TEMP",
813 "PCH_MCH_TEMP",
Guenter Roeck3be8c9d2018-09-19 21:52:49 -0700814 "Agent0 Dimm0",
815 "Agent0 Dimm1",
816 "Agent1 Dimm0",
817 "Agent1 Dimm1",
Guenter Roeck419220d2017-05-17 18:19:18 -0700818 "BYTE_TEMP0",
819 "BYTE_TEMP1",
820 "PECI Agent 0 Calibration",
821 "PECI Agent 1 Calibration",
822 "",
823 "Virtual_TEMP"
824};
825
826#define NCT6795_TEMP_MASK 0xbfffff7e
Guenter Roeck37196ba2018-09-13 19:43:58 -0700827#define NCT6795_VIRT_TEMP_MASK 0x80000000
Guenter Roeck419220d2017-05-17 18:19:18 -0700828
Guenter Roeck81820052018-02-21 13:09:39 -0800829static const char *const nct6796_temp_label[] = {
830 "",
831 "SYSTIN",
832 "CPUTIN",
833 "AUXTIN0",
834 "AUXTIN1",
835 "AUXTIN2",
836 "AUXTIN3",
837 "AUXTIN4",
838 "SMBUSMASTER 0",
839 "SMBUSMASTER 1",
Guenter Roeck37196ba2018-09-13 19:43:58 -0700840 "Virtual_TEMP",
841 "Virtual_TEMP",
Guenter Roeck81820052018-02-21 13:09:39 -0800842 "",
843 "",
844 "",
845 "",
846 "PECI Agent 0",
847 "PECI Agent 1",
848 "PCH_CHIP_CPU_MAX_TEMP",
849 "PCH_CHIP_TEMP",
850 "PCH_CPU_TEMP",
851 "PCH_MCH_TEMP",
Guenter Roeck3be8c9d2018-09-19 21:52:49 -0700852 "Agent0 Dimm0",
853 "Agent0 Dimm1",
854 "Agent1 Dimm0",
855 "Agent1 Dimm1",
Guenter Roeck81820052018-02-21 13:09:39 -0800856 "BYTE_TEMP0",
857 "BYTE_TEMP1",
858 "PECI Agent 0 Calibration",
859 "PECI Agent 1 Calibration",
860 "",
861 "Virtual_TEMP"
862};
863
Guenter Roeck37196ba2018-09-13 19:43:58 -0700864#define NCT6796_TEMP_MASK 0xbfff0ffe
865#define NCT6796_VIRT_TEMP_MASK 0x80000c00
Guenter Roeck81820052018-02-21 13:09:39 -0800866
Guenter Roeck05996822018-09-19 20:26:16 -0700867static const char *const nct6798_temp_label[] = {
868 "",
869 "SYSTIN",
870 "CPUTIN",
871 "AUXTIN0",
872 "AUXTIN1",
873 "AUXTIN2",
874 "AUXTIN3",
875 "AUXTIN4",
876 "SMBUSMASTER 0",
877 "SMBUSMASTER 1",
878 "Virtual_TEMP",
879 "Virtual_TEMP",
880 "",
881 "",
882 "",
883 "",
884 "PECI Agent 0",
885 "PECI Agent 1",
886 "PCH_CHIP_CPU_MAX_TEMP",
887 "PCH_CHIP_TEMP",
888 "PCH_CPU_TEMP",
889 "PCH_MCH_TEMP",
890 "Agent0 Dimm0",
891 "Agent0 Dimm1",
892 "Agent1 Dimm0",
893 "Agent1 Dimm1",
894 "BYTE_TEMP0",
895 "BYTE_TEMP1",
Guenter Roeck8a037462020-07-14 14:31:11 -0700896 "PECI Agent 0 Calibration", /* undocumented */
897 "PECI Agent 1 Calibration", /* undocumented */
Guenter Roeck05996822018-09-19 20:26:16 -0700898 "",
899 "Virtual_TEMP"
900};
901
Guenter Roeck8a037462020-07-14 14:31:11 -0700902#define NCT6798_TEMP_MASK 0xbfff0ffe
Guenter Roeck05996822018-09-19 20:26:16 -0700903#define NCT6798_VIRT_TEMP_MASK 0x80000c00
904
Guenter Roeck6c009502012-07-01 08:23:15 -0700905/* NCT6102D/NCT6106D specific data */
906
907#define NCT6106_REG_VBAT 0x318
908#define NCT6106_REG_DIODE 0x319
909#define NCT6106_DIODE_MASK 0x01
910
911static const u16 NCT6106_REG_IN_MAX[] = {
912 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
913static const u16 NCT6106_REG_IN_MIN[] = {
914 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
915static const u16 NCT6106_REG_IN[] = {
916 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
917
918static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
Guenter Roeckd1a284b2013-11-13 12:46:20 -0800919static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a };
Guenter Roeck6c009502012-07-01 08:23:15 -0700920static const u16 NCT6106_REG_TEMP_HYST[] = {
921 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
922static const u16 NCT6106_REG_TEMP_OVER[] = {
Guenter Roeckb7a61352013-04-02 22:14:06 -0700923 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
924static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
925 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
926static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
927 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700928static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
929static const u16 NCT6106_REG_TEMP_CONFIG[] = {
930 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
931
932static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
933static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
Guenter Roeckc7932792018-09-06 09:47:51 -0700934static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6 };
935static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700936
937static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
938static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700939static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
940static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
Guenter Roeck6c009502012-07-01 08:23:15 -0700941static const u16 NCT6106_REG_TEMP_SOURCE[] = {
942 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
943
944static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
945static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
946 0x11b, 0x12b, 0x13b };
947
948static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
949#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
950static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
951
952static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
953static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
954static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
955static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
956static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
957static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
958
959static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
960
961static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
962static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
963static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
Björn Gerhartf3d43e22019-07-15 18:33:55 +0200964static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x18b };
Guenter Roeck6c009502012-07-01 08:23:15 -0700965static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
966static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
967
968static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
969static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
970
971static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
972 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
973
974static const s8 NCT6106_ALARM_BITS[] = {
975 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
976 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
977 -1, /* unused */
978 32, 33, 34, -1, -1, /* fan1..fan5 */
979 -1, -1, -1, /* unused */
980 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
981 48, -1 /* intrusion0, intrusion1 */
982};
983
Guenter Roeck30846992013-06-24 22:21:59 -0700984static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
985 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
986
987static const s8 NCT6106_BEEP_BITS[] = {
988 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
989 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
990 32, /* global beep enable */
991 24, 25, 26, 27, 28, /* fan1..fan5 */
992 -1, -1, -1, /* unused */
993 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
994 34, -1 /* intrusion0, intrusion1 */
995};
996
Guenter Roeckcc66b302017-05-17 18:05:06 -0700997static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
998 [14] = 0x51,
999 [15] = 0x52,
1000 [16] = 0x54,
1001};
Guenter Roeck6c009502012-07-01 08:23:15 -07001002
Guenter Roeckcc66b302017-05-17 18:05:06 -07001003static const u16 NCT6106_REG_TEMP_CRIT[32] = {
1004 [11] = 0x204,
1005 [12] = 0x205,
1006};
Guenter Roeck6c009502012-07-01 08:23:15 -07001007
Björn Gerhart29c7cb42019-07-23 18:06:46 +02001008/* NCT6112D/NCT6114D/NCT6116D specific data */
1009
1010static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
1011static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 };
1012static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 };
1013static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
1014
1015static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
1016static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
1017static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
1018static const u16 NCT6116_REG_TEMP_SOURCE[] = {
1019 0xb0, 0xb1, 0xb2 };
1020
1021static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
1022 0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
1023static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = {
1024 0x11b, 0x12b, 0x13b, 0x19b, 0x1ab };
1025
1026static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = {
1027 0x11c, 0x12c, 0x13c, 0x19c, 0x1ac };
1028static const u16 NCT6116_REG_CRITICAL_PWM[] = {
1029 0x11d, 0x12d, 0x13d, 0x19d, 0x1ad };
1030
1031static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = {
1032 0x114, 0x124, 0x134, 0x194, 0x1a4 };
1033static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = {
1034 0x115, 0x125, 0x135, 0x195, 0x1a5 };
1035static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = {
1036 0x116, 0x126, 0x136, 0x196, 0x1a6 };
1037static const u16 NCT6116_REG_FAN_START_OUTPUT[] = {
1038 0x117, 0x127, 0x137, 0x197, 0x1a7 };
1039static const u16 NCT6116_REG_FAN_STOP_TIME[] = {
1040 0x118, 0x128, 0x138, 0x198, 0x1a8 };
1041static const u16 NCT6116_REG_TOLERANCE_H[] = {
1042 0x112, 0x122, 0x132, 0x192, 0x1a2 };
1043
1044static const u16 NCT6116_REG_TARGET[] = {
1045 0x111, 0x121, 0x131, 0x191, 0x1a1 };
1046
1047static const u16 NCT6116_REG_AUTO_TEMP[] = {
1048 0x160, 0x170, 0x180, 0x1d0, 0x1e0 };
1049static const u16 NCT6116_REG_AUTO_PWM[] = {
1050 0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
1051
1052static const s8 NCT6116_ALARM_BITS[] = {
1053 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
1054 9, -1, -1, -1, -1, -1, -1, /* in8..in9 */
1055 -1, /* unused */
1056 32, 33, 34, 35, 36, /* fan1..fan5 */
1057 -1, -1, -1, /* unused */
1058 16, 17, 18, -1, -1, -1, /* temp1..temp6 */
1059 48, -1 /* intrusion0, intrusion1 */
1060};
1061
1062static const s8 NCT6116_BEEP_BITS[] = {
1063 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
1064 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
1065 32, /* global beep enable */
1066 24, 25, 26, 27, 28, /* fan1..fan5 */
1067 -1, -1, -1, /* unused */
1068 16, 17, 18, -1, -1, -1, /* temp1..temp6 */
1069 34, -1 /* intrusion0, intrusion1 */
1070};
1071
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001072static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
1073{
1074 if (mode == 0 && pwm == 255)
1075 return off;
1076 return mode + 1;
1077}
1078
1079static int pwm_enable_to_reg(enum pwm_enable mode)
1080{
1081 if (mode == off)
1082 return 0;
1083 return mode - 1;
1084}
1085
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001086/*
1087 * Conversions
1088 */
1089
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001090/* 1 is DC mode, output in ms */
1091static unsigned int step_time_from_reg(u8 reg, u8 mode)
1092{
1093 return mode ? 400 * reg : 100 * reg;
1094}
1095
1096static u8 step_time_to_reg(unsigned int msec, u8 mode)
1097{
1098 return clamp_val((mode ? (msec + 200) / 400 :
1099 (msec + 50) / 100), 1, 255);
1100}
1101
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001102static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
1103{
1104 if (reg == 0 || reg == 255)
1105 return 0;
1106 return 1350000U / (reg << divreg);
1107}
1108
1109static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
1110{
1111 if ((reg & 0xff1f) == 0xff1f)
1112 return 0;
1113
1114 reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
1115
1116 if (reg == 0)
1117 return 0;
1118
1119 return 1350000U / reg;
1120}
1121
1122static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
1123{
1124 if (reg == 0 || reg == 0xffff)
1125 return 0;
1126
1127 /*
1128 * Even though the registers are 16 bit wide, the fan divisor
1129 * still applies.
1130 */
1131 return 1350000U / (reg << divreg);
1132}
1133
Guenter Roeckf6de2982018-09-13 20:01:12 -07001134static unsigned int fan_from_reg_rpm(u16 reg, unsigned int divreg)
1135{
1136 return reg;
1137}
1138
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001139static u16 fan_to_reg(u32 fan, unsigned int divreg)
1140{
1141 if (!fan)
1142 return 0;
1143
1144 return (1350000U / fan) >> divreg;
1145}
1146
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001147static inline unsigned int
1148div_from_reg(u8 reg)
1149{
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001150 return BIT(reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001151}
1152
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001153/*
1154 * Some of the voltage inputs have internal scaling, the tables below
1155 * contain 8 (the ADC LSB in mV) * scaling factor * 100
1156 */
1157static const u16 scale_in[15] = {
1158 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
1159 800, 800
1160};
1161
1162static inline long in_from_reg(u8 reg, u8 nr)
1163{
1164 return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
1165}
1166
1167static inline u8 in_to_reg(u32 val, u8 nr)
1168{
1169 return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
1170}
1171
1172/*
1173 * Data structures and manipulation thereof
1174 */
1175
1176struct nct6775_data {
1177 int addr; /* IO base of hw monitor block */
Guenter Roeck79da5332022-01-23 18:23:22 -08001178 struct nct6775_sio_data *sio_data;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001179 enum kinds kind;
1180 const char *name;
1181
Guenter Roeck615fc8c2013-07-06 09:43:30 -07001182 const struct attribute_group *groups[6];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001183
Guenter Roeckb7a61352013-04-02 22:14:06 -07001184 u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1185 * 3=temp_crit, 4=temp_lcrit
Guenter Roeckaa136e52012-12-04 03:26:05 -08001186 */
1187 u8 temp_src[NUM_TEMP];
1188 u16 reg_temp_config[NUM_TEMP];
1189 const char * const *temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07001190 u32 temp_mask;
Guenter Roeck37196ba2018-09-13 19:43:58 -07001191 u32 virt_temp_mask;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001192
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001193 u16 REG_CONFIG;
1194 u16 REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001195 u16 REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07001196 u8 DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001197
1198 const s8 *ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07001199 const s8 *BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001200
1201 const u16 *REG_VIN;
1202 const u16 *REG_IN_MINMAX[2];
1203
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001204 const u16 *REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001205 const u16 *REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001206 const u16 *REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001207 const u16 *REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08001208 const u16 *REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07001209 const u16 *FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001210 const u16 *REG_FAN_TIME[3];
1211
1212 const u16 *REG_TOLERANCE_H;
Guenter Roeckaa136e52012-12-04 03:26:05 -08001213
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001214 const u8 *REG_PWM_MODE;
1215 const u8 *PWM_MODE_MASK;
1216
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001217 const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1218 * [3]=pwm_max, [4]=pwm_step,
1219 * [5]=weight_duty_step, [6]=weight_duty_base
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001220 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001221 const u16 *REG_PWM_READ;
1222
Guenter Roeck6c009502012-07-01 08:23:15 -07001223 const u16 *REG_CRITICAL_PWM_ENABLE;
1224 u8 CRITICAL_PWM_ENABLE_MASK;
1225 const u16 *REG_CRITICAL_PWM;
1226
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001227 const u16 *REG_AUTO_TEMP;
1228 const u16 *REG_AUTO_PWM;
1229
1230 const u16 *REG_CRITICAL_TEMP;
1231 const u16 *REG_CRITICAL_TEMP_TOLERANCE;
1232
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001233 const u16 *REG_TEMP_SOURCE; /* temp register sources */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001234 const u16 *REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001235 const u16 *REG_WEIGHT_TEMP_SEL;
1236 const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
1237
Guenter Roeckaa136e52012-12-04 03:26:05 -08001238 const u16 *REG_TEMP_OFFSET;
1239
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001240 const u16 *REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07001241 const u16 *REG_BEEP;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001242
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001243 unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
1244 unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
1245
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001246 struct mutex update_lock;
1247 bool valid; /* true if following fields are valid */
1248 unsigned long last_updated; /* In jiffies */
1249
1250 /* Register values */
1251 u8 bank; /* current register bank */
1252 u8 in_num; /* number of in inputs we have */
1253 u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
David Bartley578ab5f2013-06-24 22:28:28 -07001254 unsigned int rpm[NUM_FAN];
1255 u16 fan_min[NUM_FAN];
1256 u8 fan_pulses[NUM_FAN];
1257 u8 fan_div[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001258 u8 has_pwm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001259 u8 has_fan; /* some fan inputs can be disabled */
1260 u8 has_fan_min; /* some fans don't have min register */
1261 bool has_fan_div;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001262
Guenter Roeck6c009502012-07-01 08:23:15 -07001263 u8 num_temp_alarms; /* 2, 3, or 6 */
Guenter Roeck30846992013-06-24 22:21:59 -07001264 u8 num_temp_beeps; /* 2, 3, or 6 */
Guenter Roeckaa136e52012-12-04 03:26:05 -08001265 u8 temp_fixed_num; /* 3 or 6 */
1266 u8 temp_type[NUM_TEMP_FIXED];
1267 s8 temp_offset[NUM_TEMP_FIXED];
Dan Carpenterf58876a2013-07-18 18:01:11 +03001268 s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
1269 * 3=temp_crit, 4=temp_lcrit */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001270 u64 alarms;
Guenter Roeck30846992013-06-24 22:21:59 -07001271 u64 beeps;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001272
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001273 u8 pwm_num; /* number of pwm */
Guenter Roeck57fec3a2018-06-18 09:21:46 -07001274 u8 pwm_mode[NUM_FAN]; /* 0->DC variable voltage,
1275 * 1->PWM variable duty cycle
David Bartley578ab5f2013-06-24 22:28:28 -07001276 */
1277 enum pwm_enable pwm_enable[NUM_FAN];
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001278 /* 0->off
1279 * 1->manual
1280 * 2->thermal cruise mode (also called SmartFan I)
1281 * 3->fan speed cruise mode
1282 * 4->SmartFan III
1283 * 5->enhanced variable thermal cruise (SmartFan IV)
1284 */
David Bartley578ab5f2013-06-24 22:28:28 -07001285 u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
1286 * [3]=pwm_max, [4]=pwm_step,
1287 * [5]=weight_duty_step, [6]=weight_duty_base
1288 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001289
David Bartley578ab5f2013-06-24 22:28:28 -07001290 u8 target_temp[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001291 u8 target_temp_mask;
David Bartley578ab5f2013-06-24 22:28:28 -07001292 u32 target_speed[NUM_FAN];
1293 u32 target_speed_tolerance[NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001294 u8 speed_tolerance_limit;
1295
David Bartley578ab5f2013-06-24 22:28:28 -07001296 u8 temp_tolerance[2][NUM_FAN];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001297 u8 tolerance_mask;
1298
David Bartley578ab5f2013-06-24 22:28:28 -07001299 u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001300
1301 /* Automatic fan speed control registers */
1302 int auto_pwm_num;
David Bartley578ab5f2013-06-24 22:28:28 -07001303 u8 auto_pwm[NUM_FAN][7];
1304 u8 auto_temp[NUM_FAN][7];
1305 u8 pwm_temp_sel[NUM_FAN];
1306 u8 pwm_weight_temp_sel[NUM_FAN];
1307 u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
1308 * 2->temp_base
1309 */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001310
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001311 u8 vid;
1312 u8 vrm;
1313
Guenter Roeckf73cf632013-03-18 09:22:50 -07001314 bool have_vid;
1315
Guenter Roeckaa136e52012-12-04 03:26:05 -08001316 u16 have_temp;
1317 u16 have_temp_fixed;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001318 u16 have_in;
Guenter Roeck48e93182015-02-07 08:48:49 -08001319
Guenter Roeck84d19d92012-12-04 08:01:39 -08001320 /* Remember extra register values over suspend/resume */
1321 u8 vbat;
1322 u8 fandiv1;
1323 u8 fandiv2;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08001324 u8 sio_reg_enable;
Denis Pauk49140362021-09-18 01:02:39 +03001325
1326 /* nct6775_*() callbacks */
1327 u16 (*read_value)(struct nct6775_data *data, u16 reg);
1328 int (*write_value)(struct nct6775_data *data, u16 reg, u16 value);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001329};
1330
Guenter Roeckf73cf632013-03-18 09:22:50 -07001331struct sensor_device_template {
1332 struct device_attribute dev_attr;
1333 union {
1334 struct {
1335 u8 nr;
1336 u8 index;
1337 } s;
1338 int index;
1339 } u;
1340 bool s2; /* true if both index and nr are used */
1341};
1342
1343struct sensor_device_attr_u {
1344 union {
1345 struct sensor_device_attribute a1;
1346 struct sensor_device_attribute_2 a2;
1347 } u;
1348 char name[32];
1349};
1350
1351#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
1352 .attr = {.name = _template, .mode = _mode }, \
1353 .show = _show, \
1354 .store = _store, \
1355}
1356
1357#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
1358 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1359 .u.index = _index, \
1360 .s2 = false }
1361
1362#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1363 _nr, _index) \
1364 { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
1365 .u.s.index = _index, \
1366 .u.s.nr = _nr, \
1367 .s2 = true }
1368
1369#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
1370static struct sensor_device_template sensor_dev_template_##_name \
1371 = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
1372 _index)
1373
1374#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
1375 _nr, _index) \
1376static struct sensor_device_template sensor_dev_template_##_name \
1377 = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
1378 _nr, _index)
1379
1380struct sensor_template_group {
1381 struct sensor_device_template **templates;
1382 umode_t (*is_visible)(struct kobject *, struct attribute *, int);
1383 int base;
1384};
1385
1386static struct attribute_group *
Julia Lawallc60fdf82015-12-12 17:36:39 +01001387nct6775_create_attr_group(struct device *dev,
1388 const struct sensor_template_group *tg,
Guenter Roeckf73cf632013-03-18 09:22:50 -07001389 int repeat)
1390{
1391 struct attribute_group *group;
1392 struct sensor_device_attr_u *su;
1393 struct sensor_device_attribute *a;
1394 struct sensor_device_attribute_2 *a2;
1395 struct attribute **attrs;
1396 struct sensor_device_template **t;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001397 int i, count;
Guenter Roeckf73cf632013-03-18 09:22:50 -07001398
1399 if (repeat <= 0)
1400 return ERR_PTR(-EINVAL);
1401
1402 t = tg->templates;
1403 for (count = 0; *t; t++, count++)
1404 ;
1405
1406 if (count == 0)
1407 return ERR_PTR(-EINVAL);
1408
1409 group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
1410 if (group == NULL)
1411 return ERR_PTR(-ENOMEM);
1412
Kees Cooka86854d2018-06-12 14:07:58 -07001413 attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001414 GFP_KERNEL);
1415 if (attrs == NULL)
1416 return ERR_PTR(-ENOMEM);
1417
Kees Cooka86854d2018-06-12 14:07:58 -07001418 su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)),
Guenter Roeckf73cf632013-03-18 09:22:50 -07001419 GFP_KERNEL);
1420 if (su == NULL)
1421 return ERR_PTR(-ENOMEM);
1422
1423 group->attrs = attrs;
1424 group->is_visible = tg->is_visible;
1425
1426 for (i = 0; i < repeat; i++) {
1427 t = tg->templates;
Dan Carpenter1e687e82013-10-19 11:55:15 +03001428 while (*t != NULL) {
Guenter Roeckf73cf632013-03-18 09:22:50 -07001429 snprintf(su->name, sizeof(su->name),
1430 (*t)->dev_attr.attr.name, tg->base + i);
1431 if ((*t)->s2) {
1432 a2 = &su->u.a2;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001433 sysfs_attr_init(&a2->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001434 a2->dev_attr.attr.name = su->name;
1435 a2->nr = (*t)->u.s.nr + i;
1436 a2->index = (*t)->u.s.index;
1437 a2->dev_attr.attr.mode =
1438 (*t)->dev_attr.attr.mode;
1439 a2->dev_attr.show = (*t)->dev_attr.show;
1440 a2->dev_attr.store = (*t)->dev_attr.store;
1441 *attrs = &a2->dev_attr.attr;
1442 } else {
1443 a = &su->u.a1;
Guenter Roeck1b63bf62015-05-28 09:08:09 -07001444 sysfs_attr_init(&a->dev_attr.attr);
Guenter Roeckf73cf632013-03-18 09:22:50 -07001445 a->dev_attr.attr.name = su->name;
1446 a->index = (*t)->u.index + i;
1447 a->dev_attr.attr.mode =
1448 (*t)->dev_attr.attr.mode;
1449 a->dev_attr.show = (*t)->dev_attr.show;
1450 a->dev_attr.store = (*t)->dev_attr.store;
1451 *attrs = &a->dev_attr.attr;
1452 }
1453 attrs++;
1454 su++;
1455 t++;
1456 }
1457 }
1458
Guenter Roeckf73cf632013-03-18 09:22:50 -07001459 return group;
1460}
1461
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001462static bool is_word_sized(struct nct6775_data *data, u16 reg)
1463{
1464 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07001465 case nct6106:
1466 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1467 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
1468 reg == 0x111 || reg == 0x121 || reg == 0x131;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02001469 case nct6116:
1470 return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
1471 reg == 0x26 || reg == 0x28 || reg == 0xe0 || reg == 0xe2 ||
1472 reg == 0xe4 || reg == 0xe6 || reg == 0xe8 || reg == 0x111 ||
1473 reg == 0x121 || reg == 0x131 || reg == 0x191 || reg == 0x1a1;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001474 case nct6775:
1475 return (((reg & 0xff00) == 0x100 ||
1476 (reg & 0xff00) == 0x200) &&
1477 ((reg & 0x00ff) == 0x50 ||
1478 (reg & 0x00ff) == 0x53 ||
1479 (reg & 0x00ff) == 0x55)) ||
1480 (reg & 0xfff0) == 0x630 ||
1481 reg == 0x640 || reg == 0x642 ||
1482 reg == 0x662 ||
1483 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1484 reg == 0x73 || reg == 0x75 || reg == 0x77;
1485 case nct6776:
1486 return (((reg & 0xff00) == 0x100 ||
1487 (reg & 0xff00) == 0x200) &&
1488 ((reg & 0x00ff) == 0x50 ||
1489 (reg & 0x00ff) == 0x53 ||
1490 (reg & 0x00ff) == 0x55)) ||
1491 (reg & 0xfff0) == 0x630 ||
1492 reg == 0x402 ||
1493 reg == 0x640 || reg == 0x642 ||
1494 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
1495 reg == 0x73 || reg == 0x75 || reg == 0x77;
1496 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001497 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001498 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001499 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001500 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001501 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07001502 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07001503 case nct6798:
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001504 return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
Guenter Roeckf6de2982018-09-13 20:01:12 -07001505 (reg & 0xfff0) == 0x4c0 ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001506 reg == 0x402 ||
1507 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
Guenter Roeck00fd4cf2018-02-21 13:09:37 -08001508 reg == 0x640 || reg == 0x642 || reg == 0x64a ||
Guenter Roeck55066352018-09-17 05:23:58 -07001509 reg == 0x64c ||
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001510 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
Guenter Roeck8aefb932014-11-16 09:50:04 -08001511 reg == 0x7b || reg == 0x7d;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001512 }
1513 return false;
1514}
1515
Denis Pauk3fbbfc22021-09-18 01:02:40 +03001516static inline void nct6775_wmi_set_bank(struct nct6775_data *data, u16 reg)
1517{
1518 u8 bank = reg >> 8;
1519
1520 data->bank = bank;
1521}
1522
1523static u16 nct6775_wmi_read_value(struct nct6775_data *data, u16 reg)
1524{
1525 int res, err, word_sized = is_word_sized(data, reg);
1526 u8 tmp = 0;
1527
1528 nct6775_wmi_set_bank(data, reg);
1529
Zev Weiss214f5252021-11-10 18:53:38 -08001530 err = nct6775_asuswmi_read(data->bank, reg & 0xff, &tmp);
Denis Pauk3fbbfc22021-09-18 01:02:40 +03001531 if (err)
1532 return 0;
1533
1534 res = tmp;
1535 if (word_sized) {
1536 err = nct6775_asuswmi_read(data->bank, (reg & 0xff) + 1, &tmp);
1537 if (err)
1538 return 0;
1539
1540 res = (res << 8) + tmp;
1541 }
1542 return res;
1543}
1544
1545static int nct6775_wmi_write_value(struct nct6775_data *data, u16 reg, u16 value)
1546{
1547 int res, word_sized = is_word_sized(data, reg);
1548
1549 nct6775_wmi_set_bank(data, reg);
1550
1551 if (word_sized) {
1552 res = nct6775_asuswmi_write(data->bank, reg & 0xff, value >> 8);
1553 if (res)
1554 return res;
1555
1556 res = nct6775_asuswmi_write(data->bank, (reg & 0xff) + 1, value);
1557 } else {
1558 res = nct6775_asuswmi_write(data->bank, reg & 0xff, value);
1559 }
1560
1561 return res;
1562}
1563
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001564/*
1565 * On older chips, only registers 0x50-0x5f are banked.
1566 * On more recent chips, all registers are banked.
1567 * Assume that is the case and set the bank number for each access.
1568 * Cache the bank number so it only needs to be set if it changes.
1569 */
1570static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
1571{
1572 u8 bank = reg >> 8;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001573
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001574 if (data->bank != bank) {
1575 outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
1576 outb_p(bank, data->addr + DATA_REG_OFFSET);
1577 data->bank = bank;
1578 }
1579}
1580
1581static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
1582{
1583 int res, word_sized = is_word_sized(data, reg);
1584
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001585 nct6775_set_bank(data, reg);
1586 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1587 res = inb_p(data->addr + DATA_REG_OFFSET);
1588 if (word_sized) {
1589 outb_p((reg & 0xff) + 1,
1590 data->addr + ADDR_REG_OFFSET);
1591 res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
1592 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001593 return res;
1594}
1595
1596static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
1597{
1598 int word_sized = is_word_sized(data, reg);
1599
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001600 nct6775_set_bank(data, reg);
1601 outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
1602 if (word_sized) {
1603 outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
1604 outb_p((reg & 0xff) + 1,
1605 data->addr + ADDR_REG_OFFSET);
1606 }
1607 outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001608 return 0;
1609}
1610
Guenter Roeckaa136e52012-12-04 03:26:05 -08001611/* We left-align 8-bit temperature values to make the code simpler */
1612static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
1613{
1614 u16 res;
1615
Denis Pauk49140362021-09-18 01:02:39 +03001616 res = data->read_value(data, reg);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001617 if (!is_word_sized(data, reg))
1618 res <<= 8;
1619
1620 return res;
1621}
1622
1623static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
1624{
1625 if (!is_word_sized(data, reg))
1626 value >>= 8;
Denis Pauk49140362021-09-18 01:02:39 +03001627 return data->write_value(data, reg, value);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001628}
1629
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001630/* This function assumes that the caller holds data->update_lock */
1631static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
1632{
1633 u8 reg;
1634
1635 switch (nr) {
1636 case 0:
Denis Pauk49140362021-09-18 01:02:39 +03001637 reg = (data->read_value(data, NCT6775_REG_FANDIV1) & 0x70)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001638 | (data->fan_div[0] & 0x7);
Denis Pauk49140362021-09-18 01:02:39 +03001639 data->write_value(data, NCT6775_REG_FANDIV1, reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001640 break;
1641 case 1:
Denis Pauk49140362021-09-18 01:02:39 +03001642 reg = (data->read_value(data, NCT6775_REG_FANDIV1) & 0x7)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001643 | ((data->fan_div[1] << 4) & 0x70);
Denis Pauk49140362021-09-18 01:02:39 +03001644 data->write_value(data, NCT6775_REG_FANDIV1, reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001645 break;
1646 case 2:
Denis Pauk49140362021-09-18 01:02:39 +03001647 reg = (data->read_value(data, NCT6775_REG_FANDIV2) & 0x70)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001648 | (data->fan_div[2] & 0x7);
Denis Pauk49140362021-09-18 01:02:39 +03001649 data->write_value(data, NCT6775_REG_FANDIV2, reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001650 break;
1651 case 3:
Denis Pauk49140362021-09-18 01:02:39 +03001652 reg = (data->read_value(data, NCT6775_REG_FANDIV2) & 0x7)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001653 | ((data->fan_div[3] << 4) & 0x70);
Denis Pauk49140362021-09-18 01:02:39 +03001654 data->write_value(data, NCT6775_REG_FANDIV2, reg);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001655 break;
1656 }
1657}
1658
1659static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
1660{
1661 if (data->kind == nct6775)
1662 nct6775_write_fan_div(data, nr);
1663}
1664
1665static void nct6775_update_fan_div(struct nct6775_data *data)
1666{
1667 u8 i;
1668
Denis Pauk49140362021-09-18 01:02:39 +03001669 i = data->read_value(data, NCT6775_REG_FANDIV1);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001670 data->fan_div[0] = i & 0x7;
1671 data->fan_div[1] = (i & 0x70) >> 4;
Denis Pauk49140362021-09-18 01:02:39 +03001672 i = data->read_value(data, NCT6775_REG_FANDIV2);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001673 data->fan_div[2] = i & 0x7;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001674 if (data->has_fan & BIT(3))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001675 data->fan_div[3] = (i & 0x70) >> 4;
1676}
1677
1678static void nct6775_update_fan_div_common(struct nct6775_data *data)
1679{
1680 if (data->kind == nct6775)
1681 nct6775_update_fan_div(data);
1682}
1683
1684static void nct6775_init_fan_div(struct nct6775_data *data)
1685{
1686 int i;
1687
1688 nct6775_update_fan_div_common(data);
1689 /*
1690 * For all fans, start with highest divider value if the divider
1691 * register is not initialized. This ensures that we get a
1692 * reading from the fan count register, even if it is not optimal.
1693 * We'll compute a better divider later on.
1694 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001695 for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001696 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001697 continue;
1698 if (data->fan_div[i] == 0) {
1699 data->fan_div[i] = 7;
1700 nct6775_write_fan_div_common(data, i);
1701 }
1702 }
1703}
1704
1705static void nct6775_init_fan_common(struct device *dev,
1706 struct nct6775_data *data)
1707{
1708 int i;
1709 u8 reg;
1710
1711 if (data->has_fan_div)
1712 nct6775_init_fan_div(data);
1713
1714 /*
1715 * If fan_min is not set (0), set it to 0xff to disable it. This
1716 * prevents the unnecessary warning when fanX_min is reported as 0.
1717 */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001718 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001719 if (data->has_fan_min & BIT(i)) {
Denis Pauk49140362021-09-18 01:02:39 +03001720 reg = data->read_value(data, data->REG_FAN_MIN[i]);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001721 if (!reg)
Denis Pauk49140362021-09-18 01:02:39 +03001722 data->write_value(data, data->REG_FAN_MIN[i],
1723 data->has_fan_div ? 0xff
1724 : 0xff1f);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001725 }
1726 }
1727}
1728
1729static void nct6775_select_fan_div(struct device *dev,
1730 struct nct6775_data *data, int nr, u16 reg)
1731{
1732 u8 fan_div = data->fan_div[nr];
1733 u16 fan_min;
1734
1735 if (!data->has_fan_div)
1736 return;
1737
1738 /*
1739 * If we failed to measure the fan speed, or the reported value is not
1740 * in the optimal range, and the clock divider can be modified,
1741 * let's try that for next time.
1742 */
1743 if (reg == 0x00 && fan_div < 0x07)
1744 fan_div++;
1745 else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
1746 fan_div--;
1747
1748 if (fan_div != data->fan_div[nr]) {
1749 dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
1750 nr + 1, div_from_reg(data->fan_div[nr]),
1751 div_from_reg(fan_div));
1752
1753 /* Preserve min limit if possible */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001754 if (data->has_fan_min & BIT(nr)) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001755 fan_min = data->fan_min[nr];
1756 if (fan_div > data->fan_div[nr]) {
1757 if (fan_min != 255 && fan_min > 1)
1758 fan_min >>= 1;
1759 } else {
1760 if (fan_min != 255) {
1761 fan_min <<= 1;
1762 if (fan_min > 254)
1763 fan_min = 254;
1764 }
1765 }
1766 if (fan_min != data->fan_min[nr]) {
1767 data->fan_min[nr] = fan_min;
Denis Pauk49140362021-09-18 01:02:39 +03001768 data->write_value(data, data->REG_FAN_MIN[nr],
1769 fan_min);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001770 }
1771 }
1772 data->fan_div[nr] = fan_div;
1773 nct6775_write_fan_div_common(data, nr);
1774 }
1775}
1776
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001777static void nct6775_update_pwm(struct device *dev)
1778{
1779 struct nct6775_data *data = dev_get_drvdata(dev);
1780 int i, j;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001781 int fanmodecfg, reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001782 bool duty_is_dc;
1783
1784 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001785 if (!(data->has_pwm & BIT(i)))
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001786 continue;
1787
1788 duty_is_dc = data->REG_PWM_MODE[i] &&
Denis Pauk49140362021-09-18 01:02:39 +03001789 (data->read_value(data, data->REG_PWM_MODE[i])
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001790 & data->PWM_MODE_MASK[i]);
Guenter Roeck415eb2a2018-03-26 19:50:31 -07001791 data->pwm_mode[i] = !duty_is_dc;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001792
Denis Pauk49140362021-09-18 01:02:39 +03001793 fanmodecfg = data->read_value(data, data->REG_FAN_MODE[i]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001794 for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
1795 if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
Denis Pauk49140362021-09-18 01:02:39 +03001796 data->pwm[j][i] = data->read_value(data,
1797 data->REG_PWM[j][i]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001798 }
1799 }
1800
1801 data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
1802 (fanmodecfg >> 4) & 7);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001803
1804 if (!data->temp_tolerance[0][i] ||
1805 data->pwm_enable[i] != speed_cruise)
1806 data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
1807 if (!data->target_speed_tolerance[i] ||
1808 data->pwm_enable[i] == speed_cruise) {
1809 u8 t = fanmodecfg & 0x0f;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001810
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001811 if (data->REG_TOLERANCE_H) {
Denis Pauk49140362021-09-18 01:02:39 +03001812 t |= (data->read_value(data,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001813 data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
1814 }
1815 data->target_speed_tolerance[i] = t;
1816 }
1817
1818 data->temp_tolerance[1][i] =
Denis Pauk49140362021-09-18 01:02:39 +03001819 data->read_value(data,
1820 data->REG_CRITICAL_TEMP_TOLERANCE[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001821
Denis Pauk49140362021-09-18 01:02:39 +03001822 reg = data->read_value(data, data->REG_TEMP_SEL[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001823 data->pwm_temp_sel[i] = reg & 0x1f;
1824 /* If fan can stop, report floor as 0 */
1825 if (reg & 0x80)
1826 data->pwm[2][i] = 0;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001827
Guenter Roeckcc76dee2013-11-13 12:47:17 -08001828 if (!data->REG_WEIGHT_TEMP_SEL[i])
1829 continue;
1830
Denis Pauk49140362021-09-18 01:02:39 +03001831 reg = data->read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001832 data->pwm_weight_temp_sel[i] = reg & 0x1f;
1833 /* If weight is disabled, report weight source as 0 */
Dan Carpentere3f3d7a2018-09-05 10:46:27 +03001834 if (!(reg & 0x80))
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001835 data->pwm_weight_temp_sel[i] = 0;
1836
1837 /* Weight temp data */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001838 for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
Denis Pauk49140362021-09-18 01:02:39 +03001839 data->weight_temp[j][i] = data->read_value(data,
1840 data->REG_WEIGHT_TEMP[j][i]);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08001841 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001842 }
1843}
1844
1845static void nct6775_update_pwm_limits(struct device *dev)
1846{
1847 struct nct6775_data *data = dev_get_drvdata(dev);
1848 int i, j;
1849 u8 reg;
1850 u16 reg_t;
1851
1852 for (i = 0; i < data->pwm_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001853 if (!(data->has_pwm & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001854 continue;
1855
Guenter Roeckc409fd42013-04-09 05:04:00 -07001856 for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001857 data->fan_time[j][i] =
Denis Pauk49140362021-09-18 01:02:39 +03001858 data->read_value(data, data->REG_FAN_TIME[j][i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001859 }
1860
Denis Pauk49140362021-09-18 01:02:39 +03001861 reg_t = data->read_value(data, data->REG_TARGET[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001862 /* Update only in matching mode or if never updated */
1863 if (!data->target_temp[i] ||
1864 data->pwm_enable[i] == thermal_cruise)
1865 data->target_temp[i] = reg_t & data->target_temp_mask;
1866 if (!data->target_speed[i] ||
1867 data->pwm_enable[i] == speed_cruise) {
1868 if (data->REG_TOLERANCE_H) {
Denis Pauk49140362021-09-18 01:02:39 +03001869 reg_t |= (data->read_value(data,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001870 data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
1871 }
1872 data->target_speed[i] = reg_t;
1873 }
1874
1875 for (j = 0; j < data->auto_pwm_num; j++) {
1876 data->auto_pwm[i][j] =
Denis Pauk49140362021-09-18 01:02:39 +03001877 data->read_value(data,
1878 NCT6775_AUTO_PWM(data, i, j));
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001879 data->auto_temp[i][j] =
Denis Pauk49140362021-09-18 01:02:39 +03001880 data->read_value(data,
1881 NCT6775_AUTO_TEMP(data, i, j));
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001882 }
1883
1884 /* critical auto_pwm temperature data */
1885 data->auto_temp[i][data->auto_pwm_num] =
Denis Pauk49140362021-09-18 01:02:39 +03001886 data->read_value(data, data->REG_CRITICAL_TEMP[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001887
1888 switch (data->kind) {
1889 case nct6775:
Denis Pauk49140362021-09-18 01:02:39 +03001890 reg = data->read_value(data,
1891 NCT6775_REG_CRITICAL_ENAB[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001892 data->auto_pwm[i][data->auto_pwm_num] =
1893 (reg & 0x02) ? 0xff : 0x00;
1894 break;
1895 case nct6776:
1896 data->auto_pwm[i][data->auto_pwm_num] = 0xff;
1897 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07001898 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02001899 case nct6116:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001900 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07001901 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08001902 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07001903 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07001904 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08001905 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07001906 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07001907 case nct6798:
Denis Pauk49140362021-09-18 01:02:39 +03001908 reg = data->read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001909 data->REG_CRITICAL_PWM_ENABLE[i]);
1910 if (reg & data->CRITICAL_PWM_ENABLE_MASK)
Denis Pauk49140362021-09-18 01:02:39 +03001911 reg = data->read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07001912 data->REG_CRITICAL_PWM[i]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001913 else
Guenter Roeck6c009502012-07-01 08:23:15 -07001914 reg = 0xff;
1915 data->auto_pwm[i][data->auto_pwm_num] = reg;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001916 break;
1917 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001918 }
1919}
1920
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001921static struct nct6775_data *nct6775_update_device(struct device *dev)
1922{
1923 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001924 int i, j;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001925
1926 mutex_lock(&data->update_lock);
1927
Guenter Roeck6445e662013-04-21 09:13:28 -07001928 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001929 || !data->valid) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001930 /* Fan clock dividers */
1931 nct6775_update_fan_div_common(data);
1932
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001933 /* Measured voltages and limits */
1934 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001935 if (!(data->have_in & BIT(i)))
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001936 continue;
1937
Denis Pauk49140362021-09-18 01:02:39 +03001938 data->in[i][0] = data->read_value(data,
1939 data->REG_VIN[i]);
1940 data->in[i][1] = data->read_value(data,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001941 data->REG_IN_MINMAX[0][i]);
Denis Pauk49140362021-09-18 01:02:39 +03001942 data->in[i][2] = data->read_value(data,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001943 data->REG_IN_MINMAX[1][i]);
1944 }
1945
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001946 /* Measured fan speeds and limits */
Guenter Roeckc409fd42013-04-09 05:04:00 -07001947 for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001948 u16 reg;
1949
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001950 if (!(data->has_fan & BIT(i)))
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001951 continue;
1952
Denis Pauk49140362021-09-18 01:02:39 +03001953 reg = data->read_value(data, data->REG_FAN[i]);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001954 data->rpm[i] = data->fan_from_reg(reg,
1955 data->fan_div[i]);
1956
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001957 if (data->has_fan_min & BIT(i))
Denis Pauk49140362021-09-18 01:02:39 +03001958 data->fan_min[i] = data->read_value(data,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001959 data->REG_FAN_MIN[i]);
Guenter Roeckc7932792018-09-06 09:47:51 -07001960
1961 if (data->REG_FAN_PULSES[i]) {
1962 data->fan_pulses[i] =
Denis Pauk49140362021-09-18 01:02:39 +03001963 (data->read_value(data,
1964 data->REG_FAN_PULSES[i])
Guenter Roeckc7932792018-09-06 09:47:51 -07001965 >> data->FAN_PULSE_SHIFT[i]) & 0x03;
1966 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08001967
1968 nct6775_select_fan_div(dev, data, i, reg);
1969 }
1970
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001971 nct6775_update_pwm(dev);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08001972 nct6775_update_pwm_limits(dev);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08001973
Guenter Roeckaa136e52012-12-04 03:26:05 -08001974 /* Measured temperatures and limits */
1975 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001976 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001977 continue;
Guenter Roeckc409fd42013-04-09 05:04:00 -07001978 for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08001979 if (data->reg_temp[j][i])
Denis Pauk49140362021-09-18 01:02:39 +03001980 data->temp[j][i] = nct6775_read_temp(data,
1981 data->reg_temp[j][i]);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001982 }
Guenter Roeck45a5b3a2013-09-11 10:35:47 -07001983 if (i >= NUM_TEMP_FIXED ||
Guenter Roeckd1bb21862017-05-17 18:40:10 -07001984 !(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08001985 continue;
Denis Pauk49140362021-09-18 01:02:39 +03001986 data->temp_offset[i] = data->read_value(data,
1987 data->REG_TEMP_OFFSET[i]);
Guenter Roeckaa136e52012-12-04 03:26:05 -08001988 }
1989
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001990 data->alarms = 0;
1991 for (i = 0; i < NUM_REG_ALARM; i++) {
1992 u8 alarm;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08001993
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001994 if (!data->REG_ALARM[i])
1995 continue;
Denis Pauk49140362021-09-18 01:02:39 +03001996 alarm = data->read_value(data, data->REG_ALARM[i]);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07001997 data->alarms |= ((u64)alarm) << (i << 3);
1998 }
1999
Guenter Roeck30846992013-06-24 22:21:59 -07002000 data->beeps = 0;
2001 for (i = 0; i < NUM_REG_BEEP; i++) {
2002 u8 beep;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002003
Guenter Roeck30846992013-06-24 22:21:59 -07002004 if (!data->REG_BEEP[i])
2005 continue;
Denis Pauk49140362021-09-18 01:02:39 +03002006 beep = data->read_value(data, data->REG_BEEP[i]);
Guenter Roeck30846992013-06-24 22:21:59 -07002007 data->beeps |= ((u64)beep) << (i << 3);
2008 }
2009
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002010 data->last_updated = jiffies;
2011 data->valid = true;
2012 }
2013
2014 mutex_unlock(&data->update_lock);
2015 return data;
2016}
2017
2018/*
2019 * Sysfs callback functions
2020 */
2021static ssize_t
2022show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
2023{
2024 struct nct6775_data *data = nct6775_update_device(dev);
2025 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002026 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002027 int nr = sattr->nr;
2028
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002029 return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
2030}
2031
2032static ssize_t
2033store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
2034 size_t count)
2035{
2036 struct nct6775_data *data = dev_get_drvdata(dev);
2037 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002038 int index = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002039 int nr = sattr->nr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002040 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002041 int err;
2042
2043 err = kstrtoul(buf, 10, &val);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002044 if (err < 0)
2045 return err;
2046 mutex_lock(&data->update_lock);
2047 data->in[nr][index] = in_to_reg(val, nr);
Denis Pauk49140362021-09-18 01:02:39 +03002048 data->write_value(data, data->REG_IN_MINMAX[index - 1][nr],
2049 data->in[nr][index]);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002050 mutex_unlock(&data->update_lock);
2051 return count;
2052}
2053
2054static ssize_t
2055show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
2056{
2057 struct nct6775_data *data = nct6775_update_device(dev);
2058 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2059 int nr = data->ALARM_BITS[sattr->index];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002060
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002061 return sprintf(buf, "%u\n",
2062 (unsigned int)((data->alarms >> nr) & 0x01));
2063}
2064
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07002065static int find_temp_source(struct nct6775_data *data, int index, int count)
2066{
2067 int source = data->temp_src[index];
2068 int nr;
2069
2070 for (nr = 0; nr < count; nr++) {
2071 int src;
2072
Denis Pauk49140362021-09-18 01:02:39 +03002073 src = data->read_value(data,
2074 data->REG_TEMP_SOURCE[nr]) & 0x1f;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07002075 if (src == source)
2076 return nr;
2077 }
Guenter Roecke8ab5082013-09-11 10:32:18 -07002078 return -ENODEV;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07002079}
2080
2081static ssize_t
2082show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
2083{
2084 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2085 struct nct6775_data *data = nct6775_update_device(dev);
2086 unsigned int alarm = 0;
2087 int nr;
2088
2089 /*
2090 * For temperatures, there is no fixed mapping from registers to alarm
2091 * bits. Alarm bits are determined by the temperature source mapping.
2092 */
2093 nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
2094 if (nr >= 0) {
2095 int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002096
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07002097 alarm = (data->alarms >> bit) & 0x01;
2098 }
2099 return sprintf(buf, "%u\n", alarm);
2100}
2101
Guenter Roeck30846992013-06-24 22:21:59 -07002102static ssize_t
2103show_beep(struct device *dev, struct device_attribute *attr, char *buf)
2104{
2105 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2106 struct nct6775_data *data = nct6775_update_device(dev);
2107 int nr = data->BEEP_BITS[sattr->index];
2108
2109 return sprintf(buf, "%u\n",
2110 (unsigned int)((data->beeps >> nr) & 0x01));
2111}
2112
2113static ssize_t
2114store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
2115 size_t count)
2116{
2117 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2118 struct nct6775_data *data = dev_get_drvdata(dev);
2119 int nr = data->BEEP_BITS[sattr->index];
2120 int regindex = nr >> 3;
2121 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002122 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07002123
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002124 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07002125 if (err < 0)
2126 return err;
2127 if (val > 1)
2128 return -EINVAL;
2129
2130 mutex_lock(&data->update_lock);
2131 if (val)
2132 data->beeps |= (1ULL << nr);
2133 else
2134 data->beeps &= ~(1ULL << nr);
Denis Pauk49140362021-09-18 01:02:39 +03002135 data->write_value(data, data->REG_BEEP[regindex],
2136 (data->beeps >> (regindex << 3)) & 0xff);
Guenter Roeck30846992013-06-24 22:21:59 -07002137 mutex_unlock(&data->update_lock);
2138 return count;
2139}
2140
2141static ssize_t
2142show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
2143{
2144 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2145 struct nct6775_data *data = nct6775_update_device(dev);
2146 unsigned int beep = 0;
2147 int nr;
2148
2149 /*
2150 * For temperatures, there is no fixed mapping from registers to beep
2151 * enable bits. Beep enable bits are determined by the temperature
2152 * source mapping.
2153 */
2154 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
2155 if (nr >= 0) {
2156 int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002157
Guenter Roeck30846992013-06-24 22:21:59 -07002158 beep = (data->beeps >> bit) & 0x01;
2159 }
2160 return sprintf(buf, "%u\n", beep);
2161}
2162
2163static ssize_t
2164store_temp_beep(struct device *dev, struct device_attribute *attr,
2165 const char *buf, size_t count)
2166{
2167 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2168 struct nct6775_data *data = dev_get_drvdata(dev);
2169 int nr, bit, regindex;
2170 unsigned long val;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002171 int err;
Guenter Roeck30846992013-06-24 22:21:59 -07002172
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002173 err = kstrtoul(buf, 10, &val);
Guenter Roeck30846992013-06-24 22:21:59 -07002174 if (err < 0)
2175 return err;
2176 if (val > 1)
2177 return -EINVAL;
2178
2179 nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
2180 if (nr < 0)
Guenter Roecke8ab5082013-09-11 10:32:18 -07002181 return nr;
Guenter Roeck30846992013-06-24 22:21:59 -07002182
2183 bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
2184 regindex = bit >> 3;
2185
2186 mutex_lock(&data->update_lock);
2187 if (val)
2188 data->beeps |= (1ULL << bit);
2189 else
2190 data->beeps &= ~(1ULL << bit);
Denis Pauk49140362021-09-18 01:02:39 +03002191 data->write_value(data, data->REG_BEEP[regindex],
2192 (data->beeps >> (regindex << 3)) & 0xff);
Guenter Roeck30846992013-06-24 22:21:59 -07002193 mutex_unlock(&data->update_lock);
2194
2195 return count;
2196}
2197
Guenter Roeckf73cf632013-03-18 09:22:50 -07002198static umode_t nct6775_in_is_visible(struct kobject *kobj,
2199 struct attribute *attr, int index)
2200{
zhouchuangao036855a2020-05-11 11:43:06 +08002201 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002202 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002203 int in = index / 5; /* voltage index */
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002204
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002205 if (!(data->have_in & BIT(in)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002206 return 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002207
Guenter Roeckf73cf632013-03-18 09:22:50 -07002208 return attr->mode;
2209}
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002210
Guenter Roeckf73cf632013-03-18 09:22:50 -07002211SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
2212SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002213SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
2214 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002215SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
2216 store_in_reg, 0, 1);
2217SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
2218 store_in_reg, 0, 2);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002219
Guenter Roeckf73cf632013-03-18 09:22:50 -07002220/*
2221 * nct6775_in_is_visible uses the index into the following array
2222 * to determine if attributes should be created or not.
2223 * Any change in order or content must be matched.
2224 */
2225static struct sensor_device_template *nct6775_attributes_in_template[] = {
2226 &sensor_dev_template_in_input,
2227 &sensor_dev_template_in_alarm,
Guenter Roeck30846992013-06-24 22:21:59 -07002228 &sensor_dev_template_in_beep,
Guenter Roeckf73cf632013-03-18 09:22:50 -07002229 &sensor_dev_template_in_min,
2230 &sensor_dev_template_in_max,
2231 NULL
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002232};
2233
Julia Lawallc60fdf82015-12-12 17:36:39 +01002234static const struct sensor_template_group nct6775_in_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002235 .templates = nct6775_attributes_in_template,
2236 .is_visible = nct6775_in_is_visible,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07002237};
2238
2239static ssize_t
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002240show_fan(struct device *dev, struct device_attribute *attr, char *buf)
2241{
2242 struct nct6775_data *data = nct6775_update_device(dev);
2243 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2244 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002245
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002246 return sprintf(buf, "%d\n", data->rpm[nr]);
2247}
2248
2249static ssize_t
2250show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
2251{
2252 struct nct6775_data *data = nct6775_update_device(dev);
2253 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2254 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002255
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002256 return sprintf(buf, "%d\n",
2257 data->fan_from_reg_min(data->fan_min[nr],
2258 data->fan_div[nr]));
2259}
2260
2261static ssize_t
2262show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
2263{
2264 struct nct6775_data *data = nct6775_update_device(dev);
2265 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2266 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002267
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002268 return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
2269}
2270
2271static ssize_t
2272store_fan_min(struct device *dev, struct device_attribute *attr,
2273 const char *buf, size_t count)
2274{
2275 struct nct6775_data *data = dev_get_drvdata(dev);
2276 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2277 int nr = sattr->index;
2278 unsigned long val;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002279 unsigned int reg;
2280 u8 new_div;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002281 int err;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002282
2283 err = kstrtoul(buf, 10, &val);
2284 if (err < 0)
2285 return err;
2286
2287 mutex_lock(&data->update_lock);
2288 if (!data->has_fan_div) {
2289 /* NCT6776F or NCT6779D; we know this is a 13 bit register */
2290 if (!val) {
2291 val = 0xff1f;
2292 } else {
2293 if (val > 1350000U)
2294 val = 135000U;
2295 val = 1350000U / val;
2296 val = (val & 0x1f) | ((val << 3) & 0xff00);
2297 }
2298 data->fan_min[nr] = val;
2299 goto write_min; /* Leave fan divider alone */
2300 }
2301 if (!val) {
2302 /* No min limit, alarm disabled */
2303 data->fan_min[nr] = 255;
2304 new_div = data->fan_div[nr]; /* No change */
2305 dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
2306 goto write_div;
2307 }
2308 reg = 1350000U / val;
2309 if (reg >= 128 * 255) {
2310 /*
2311 * Speed below this value cannot possibly be represented,
2312 * even with the highest divider (128)
2313 */
2314 data->fan_min[nr] = 254;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002315 new_div = 7; /* 128 == BIT(7) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002316 dev_warn(dev,
2317 "fan%u low limit %lu below minimum %u, set to minimum\n",
2318 nr + 1, val, data->fan_from_reg_min(254, 7));
2319 } else if (!reg) {
2320 /*
2321 * Speed above this value cannot possibly be represented,
2322 * even with the lowest divider (1)
2323 */
2324 data->fan_min[nr] = 1;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002325 new_div = 0; /* 1 == BIT(0) */
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002326 dev_warn(dev,
2327 "fan%u low limit %lu above maximum %u, set to maximum\n",
2328 nr + 1, val, data->fan_from_reg_min(1, 0));
2329 } else {
2330 /*
2331 * Automatically pick the best divider, i.e. the one such
2332 * that the min limit will correspond to a register value
2333 * in the 96..192 range
2334 */
2335 new_div = 0;
2336 while (reg > 192 && new_div < 7) {
2337 reg >>= 1;
2338 new_div++;
2339 }
2340 data->fan_min[nr] = reg;
2341 }
2342
2343write_div:
2344 /*
2345 * Write both the fan clock divider (if it changed) and the new
2346 * fan min (unconditionally)
2347 */
2348 if (new_div != data->fan_div[nr]) {
2349 dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
2350 nr + 1, div_from_reg(data->fan_div[nr]),
2351 div_from_reg(new_div));
2352 data->fan_div[nr] = new_div;
2353 nct6775_write_fan_div_common(data, nr);
2354 /* Give the chip time to sample a new speed value */
2355 data->last_updated = jiffies;
2356 }
2357
2358write_min:
Denis Pauk49140362021-09-18 01:02:39 +03002359 data->write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002360 mutex_unlock(&data->update_lock);
2361
2362 return count;
2363}
2364
Guenter Roeck5c25d952012-12-11 07:29:06 -08002365static ssize_t
2366show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
2367{
2368 struct nct6775_data *data = nct6775_update_device(dev);
2369 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2370 int p = data->fan_pulses[sattr->index];
2371
2372 return sprintf(buf, "%d\n", p ? : 4);
2373}
2374
2375static ssize_t
2376store_fan_pulses(struct device *dev, struct device_attribute *attr,
2377 const char *buf, size_t count)
2378{
2379 struct nct6775_data *data = dev_get_drvdata(dev);
2380 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2381 int nr = sattr->index;
2382 unsigned long val;
2383 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002384 u8 reg;
Guenter Roeck5c25d952012-12-11 07:29:06 -08002385
2386 err = kstrtoul(buf, 10, &val);
2387 if (err < 0)
2388 return err;
2389
2390 if (val > 4)
2391 return -EINVAL;
2392
2393 mutex_lock(&data->update_lock);
2394 data->fan_pulses[nr] = val & 3;
Denis Pauk49140362021-09-18 01:02:39 +03002395 reg = data->read_value(data, data->REG_FAN_PULSES[nr]);
Guenter Roeck6c009502012-07-01 08:23:15 -07002396 reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
2397 reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
Denis Pauk49140362021-09-18 01:02:39 +03002398 data->write_value(data, data->REG_FAN_PULSES[nr], reg);
Guenter Roeck5c25d952012-12-11 07:29:06 -08002399 mutex_unlock(&data->update_lock);
2400
2401 return count;
2402}
2403
Guenter Roeckf73cf632013-03-18 09:22:50 -07002404static umode_t nct6775_fan_is_visible(struct kobject *kobj,
2405 struct attribute *attr, int index)
2406{
zhouchuangao036855a2020-05-11 11:43:06 +08002407 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002408 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002409 int fan = index / 6; /* fan index */
2410 int nr = index % 6; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002411
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002412 if (!(data->has_fan & BIT(fan)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002413 return 0;
2414
2415 if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
2416 return 0;
Guenter Roeck30846992013-06-24 22:21:59 -07002417 if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002418 return 0;
Guenter Roeck81820052018-02-21 13:09:39 -08002419 if (nr == 3 && !data->REG_FAN_PULSES[fan])
2420 return 0;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002421 if (nr == 4 && !(data->has_fan_min & BIT(fan)))
Guenter Roeck30846992013-06-24 22:21:59 -07002422 return 0;
2423 if (nr == 5 && data->kind != nct6775)
Guenter Roeckf73cf632013-03-18 09:22:50 -07002424 return 0;
2425
2426 return attr->mode;
2427}
2428
2429SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
2430SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
2431 FAN_ALARM_BASE);
Guenter Roeck30846992013-06-24 22:21:59 -07002432SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
2433 store_beep, FAN_ALARM_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002434SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
2435 store_fan_pulses, 0);
2436SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
2437 store_fan_min, 0);
2438SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
2439
2440/*
2441 * nct6775_fan_is_visible uses the index into the following array
2442 * to determine if attributes should be created or not.
2443 * Any change in order or content must be matched.
2444 */
2445static struct sensor_device_template *nct6775_attributes_fan_template[] = {
2446 &sensor_dev_template_fan_input,
2447 &sensor_dev_template_fan_alarm, /* 1 */
Guenter Roeck30846992013-06-24 22:21:59 -07002448 &sensor_dev_template_fan_beep, /* 2 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002449 &sensor_dev_template_fan_pulses,
Guenter Roeck30846992013-06-24 22:21:59 -07002450 &sensor_dev_template_fan_min, /* 4 */
2451 &sensor_dev_template_fan_div, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002452 NULL
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002453};
2454
Julia Lawallc60fdf82015-12-12 17:36:39 +01002455static const struct sensor_template_group nct6775_fan_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002456 .templates = nct6775_attributes_fan_template,
2457 .is_visible = nct6775_fan_is_visible,
2458 .base = 1,
Guenter Roeck1c65dc32012-12-04 07:56:24 -08002459};
2460
2461static ssize_t
Guenter Roeckaa136e52012-12-04 03:26:05 -08002462show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
2463{
2464 struct nct6775_data *data = nct6775_update_device(dev);
2465 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2466 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002467
Guenter Roeckaa136e52012-12-04 03:26:05 -08002468 return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
2469}
2470
2471static ssize_t
2472show_temp(struct device *dev, struct device_attribute *attr, char *buf)
2473{
2474 struct nct6775_data *data = nct6775_update_device(dev);
2475 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2476 int nr = sattr->nr;
2477 int index = sattr->index;
2478
2479 return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
2480}
2481
2482static ssize_t
2483store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
2484 size_t count)
2485{
2486 struct nct6775_data *data = dev_get_drvdata(dev);
2487 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2488 int nr = sattr->nr;
2489 int index = sattr->index;
2490 int err;
2491 long val;
2492
2493 err = kstrtol(buf, 10, &val);
2494 if (err < 0)
2495 return err;
2496
2497 mutex_lock(&data->update_lock);
2498 data->temp[index][nr] = LM75_TEMP_TO_REG(val);
2499 nct6775_write_temp(data, data->reg_temp[index][nr],
2500 data->temp[index][nr]);
2501 mutex_unlock(&data->update_lock);
2502 return count;
2503}
2504
2505static ssize_t
2506show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
2507{
2508 struct nct6775_data *data = nct6775_update_device(dev);
2509 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2510
2511 return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
2512}
2513
2514static ssize_t
2515store_temp_offset(struct device *dev, struct device_attribute *attr,
2516 const char *buf, size_t count)
2517{
2518 struct nct6775_data *data = dev_get_drvdata(dev);
2519 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2520 int nr = sattr->index;
2521 long val;
2522 int err;
2523
2524 err = kstrtol(buf, 10, &val);
2525 if (err < 0)
2526 return err;
2527
2528 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
2529
2530 mutex_lock(&data->update_lock);
2531 data->temp_offset[nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03002532 data->write_value(data, data->REG_TEMP_OFFSET[nr], val);
Guenter Roeckaa136e52012-12-04 03:26:05 -08002533 mutex_unlock(&data->update_lock);
2534
2535 return count;
2536}
2537
2538static ssize_t
2539show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
2540{
2541 struct nct6775_data *data = nct6775_update_device(dev);
2542 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2543 int nr = sattr->index;
Guenter Roeck9cd892b2014-11-16 10:00:06 -08002544
Guenter Roeckaa136e52012-12-04 03:26:05 -08002545 return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
2546}
2547
2548static ssize_t
2549store_temp_type(struct device *dev, struct device_attribute *attr,
2550 const char *buf, size_t count)
2551{
2552 struct nct6775_data *data = nct6775_update_device(dev);
2553 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2554 int nr = sattr->index;
2555 unsigned long val;
2556 int err;
Guenter Roeck6c009502012-07-01 08:23:15 -07002557 u8 vbat, diode, vbit, dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002558
2559 err = kstrtoul(buf, 10, &val);
2560 if (err < 0)
2561 return err;
2562
2563 if (val != 1 && val != 3 && val != 4)
2564 return -EINVAL;
2565
2566 mutex_lock(&data->update_lock);
2567
2568 data->temp_type[nr] = val;
Guenter Roeck6c009502012-07-01 08:23:15 -07002569 vbit = 0x02 << nr;
2570 dbit = data->DIODE_MASK << nr;
Denis Pauk49140362021-09-18 01:02:39 +03002571 vbat = data->read_value(data, data->REG_VBAT) & ~vbit;
2572 diode = data->read_value(data, data->REG_DIODE) & ~dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002573 switch (val) {
2574 case 1: /* CPU diode (diode, current mode) */
Guenter Roeck6c009502012-07-01 08:23:15 -07002575 vbat |= vbit;
2576 diode |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002577 break;
2578 case 3: /* diode, voltage mode */
Guenter Roeck6c009502012-07-01 08:23:15 -07002579 vbat |= dbit;
Guenter Roeckaa136e52012-12-04 03:26:05 -08002580 break;
2581 case 4: /* thermistor */
2582 break;
2583 }
Denis Pauk49140362021-09-18 01:02:39 +03002584 data->write_value(data, data->REG_VBAT, vbat);
2585 data->write_value(data, data->REG_DIODE, diode);
Guenter Roeckaa136e52012-12-04 03:26:05 -08002586
2587 mutex_unlock(&data->update_lock);
2588 return count;
2589}
2590
Guenter Roeckf73cf632013-03-18 09:22:50 -07002591static umode_t nct6775_temp_is_visible(struct kobject *kobj,
2592 struct attribute *attr, int index)
2593{
zhouchuangao036855a2020-05-11 11:43:06 +08002594 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002595 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck30846992013-06-24 22:21:59 -07002596 int temp = index / 10; /* temp index */
2597 int nr = index % 10; /* attribute index */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002598
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002599 if (!(data->have_temp & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002600 return 0;
2601
Guenter Roeckcc66b302017-05-17 18:05:06 -07002602 if (nr == 1 && !data->temp_label)
2603 return 0;
2604
Guenter Roeckf73cf632013-03-18 09:22:50 -07002605 if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
2606 return 0; /* alarm */
2607
Guenter Roeck30846992013-06-24 22:21:59 -07002608 if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
2609 return 0; /* beep */
2610
2611 if (nr == 4 && !data->reg_temp[1][temp]) /* max */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002612 return 0;
2613
Guenter Roeck30846992013-06-24 22:21:59 -07002614 if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002615 return 0;
2616
Guenter Roeck30846992013-06-24 22:21:59 -07002617 if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002618 return 0;
2619
Guenter Roeck30846992013-06-24 22:21:59 -07002620 if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
Guenter Roeckb7a61352013-04-02 22:14:06 -07002621 return 0;
2622
2623 /* offset and type only apply to fixed sensors */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002624 if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07002625 return 0;
2626
2627 return attr->mode;
2628}
2629
2630SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
2631SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
2632SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
2633 store_temp, 0, 1);
2634SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
2635 show_temp, store_temp, 0, 2);
2636SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
2637 store_temp, 0, 3);
Guenter Roeckb7a61352013-04-02 22:14:06 -07002638SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
2639 store_temp, 0, 4);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002640SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
2641 show_temp_offset, store_temp_offset, 0);
2642SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
2643 store_temp_type, 0);
2644SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
Guenter Roeck30846992013-06-24 22:21:59 -07002645SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
2646 store_temp_beep, 0);
Guenter Roeckf73cf632013-03-18 09:22:50 -07002647
2648/*
2649 * nct6775_temp_is_visible uses the index into the following array
2650 * to determine if attributes should be created or not.
2651 * Any change in order or content must be matched.
2652 */
2653static struct sensor_device_template *nct6775_attributes_temp_template[] = {
2654 &sensor_dev_template_temp_input,
2655 &sensor_dev_template_temp_label,
2656 &sensor_dev_template_temp_alarm, /* 2 */
Guenter Roeck30846992013-06-24 22:21:59 -07002657 &sensor_dev_template_temp_beep, /* 3 */
2658 &sensor_dev_template_temp_max, /* 4 */
2659 &sensor_dev_template_temp_max_hyst, /* 5 */
2660 &sensor_dev_template_temp_crit, /* 6 */
2661 &sensor_dev_template_temp_lcrit, /* 7 */
2662 &sensor_dev_template_temp_offset, /* 8 */
2663 &sensor_dev_template_temp_type, /* 9 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07002664 NULL
Guenter Roeckaa136e52012-12-04 03:26:05 -08002665};
2666
Julia Lawallc60fdf82015-12-12 17:36:39 +01002667static const struct sensor_template_group nct6775_temp_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07002668 .templates = nct6775_attributes_temp_template,
2669 .is_visible = nct6775_temp_is_visible,
2670 .base = 1,
Guenter Roeckaa136e52012-12-04 03:26:05 -08002671};
2672
Guenter Roeckaa136e52012-12-04 03:26:05 -08002673static ssize_t
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002674show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
2675{
2676 struct nct6775_data *data = nct6775_update_device(dev);
2677 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2678
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002679 return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002680}
2681
2682static ssize_t
2683store_pwm_mode(struct device *dev, struct device_attribute *attr,
2684 const char *buf, size_t count)
2685{
2686 struct nct6775_data *data = dev_get_drvdata(dev);
2687 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2688 int nr = sattr->index;
2689 unsigned long val;
2690 int err;
2691 u8 reg;
2692
2693 err = kstrtoul(buf, 10, &val);
2694 if (err < 0)
2695 return err;
2696
2697 if (val > 1)
2698 return -EINVAL;
2699
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002700 /* Setting DC mode (0) is not supported for all chips/channels */
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002701 if (data->REG_PWM_MODE[nr] == 0) {
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002702 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002703 return -EINVAL;
2704 return count;
2705 }
2706
2707 mutex_lock(&data->update_lock);
2708 data->pwm_mode[nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03002709 reg = data->read_value(data, data->REG_PWM_MODE[nr]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002710 reg &= ~data->PWM_MODE_MASK[nr];
Guenter Roeck415eb2a2018-03-26 19:50:31 -07002711 if (!val)
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002712 reg |= data->PWM_MODE_MASK[nr];
Denis Pauk49140362021-09-18 01:02:39 +03002713 data->write_value(data, data->REG_PWM_MODE[nr], reg);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002714 mutex_unlock(&data->update_lock);
2715 return count;
2716}
2717
2718static ssize_t
2719show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
2720{
2721 struct nct6775_data *data = nct6775_update_device(dev);
2722 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2723 int nr = sattr->nr;
2724 int index = sattr->index;
2725 int pwm;
2726
2727 /*
2728 * For automatic fan control modes, show current pwm readings.
2729 * Otherwise, show the configured value.
2730 */
2731 if (index == 0 && data->pwm_enable[nr] > manual)
Denis Pauk49140362021-09-18 01:02:39 +03002732 pwm = data->read_value(data, data->REG_PWM_READ[nr]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002733 else
2734 pwm = data->pwm[index][nr];
2735
2736 return sprintf(buf, "%d\n", pwm);
2737}
2738
2739static ssize_t
2740store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
2741 size_t count)
2742{
2743 struct nct6775_data *data = dev_get_drvdata(dev);
2744 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
2745 int nr = sattr->nr;
2746 int index = sattr->index;
2747 unsigned long val;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002748 int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
2749 int maxval[7]
2750 = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002751 int err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002752 u8 reg;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002753
2754 err = kstrtoul(buf, 10, &val);
2755 if (err < 0)
2756 return err;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002757 val = clamp_val(val, minval[index], maxval[index]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002758
2759 mutex_lock(&data->update_lock);
2760 data->pwm[index][nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03002761 data->write_value(data, data->REG_PWM[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002762 if (index == 2) { /* floor: disable if val == 0 */
Denis Pauk49140362021-09-18 01:02:39 +03002763 reg = data->read_value(data, data->REG_TEMP_SEL[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002764 reg &= 0x7f;
2765 if (val)
2766 reg |= 0x80;
Denis Pauk49140362021-09-18 01:02:39 +03002767 data->write_value(data, data->REG_TEMP_SEL[nr], reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002768 }
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002769 mutex_unlock(&data->update_lock);
2770 return count;
2771}
2772
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002773/* Returns 0 if OK, -EINVAL otherwise */
2774static int check_trip_points(struct nct6775_data *data, int nr)
2775{
2776 int i;
2777
2778 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2779 if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
2780 return -EINVAL;
2781 }
2782 for (i = 0; i < data->auto_pwm_num - 1; i++) {
2783 if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
2784 return -EINVAL;
2785 }
2786 /* validate critical temperature and pwm if enabled (pwm > 0) */
2787 if (data->auto_pwm[nr][data->auto_pwm_num]) {
2788 if (data->auto_temp[nr][data->auto_pwm_num - 1] >
2789 data->auto_temp[nr][data->auto_pwm_num] ||
2790 data->auto_pwm[nr][data->auto_pwm_num - 1] >
2791 data->auto_pwm[nr][data->auto_pwm_num])
2792 return -EINVAL;
2793 }
2794 return 0;
2795}
2796
2797static void pwm_update_registers(struct nct6775_data *data, int nr)
2798{
2799 u8 reg;
2800
2801 switch (data->pwm_enable[nr]) {
2802 case off:
2803 case manual:
2804 break;
2805 case speed_cruise:
Denis Pauk49140362021-09-18 01:02:39 +03002806 reg = data->read_value(data, data->REG_FAN_MODE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002807 reg = (reg & ~data->tolerance_mask) |
2808 (data->target_speed_tolerance[nr] & data->tolerance_mask);
Denis Pauk49140362021-09-18 01:02:39 +03002809 data->write_value(data, data->REG_FAN_MODE[nr], reg);
2810 data->write_value(data, data->REG_TARGET[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002811 data->target_speed[nr] & 0xff);
2812 if (data->REG_TOLERANCE_H) {
2813 reg = (data->target_speed[nr] >> 8) & 0x0f;
2814 reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
Denis Pauk49140362021-09-18 01:02:39 +03002815 data->write_value(data,
2816 data->REG_TOLERANCE_H[nr],
2817 reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002818 }
2819 break;
2820 case thermal_cruise:
Denis Pauk49140362021-09-18 01:02:39 +03002821 data->write_value(data, data->REG_TARGET[nr],
2822 data->target_temp[nr]);
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05002823 fallthrough;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002824 default:
Denis Pauk49140362021-09-18 01:02:39 +03002825 reg = data->read_value(data, data->REG_FAN_MODE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002826 reg = (reg & ~data->tolerance_mask) |
2827 data->temp_tolerance[0][nr];
Denis Pauk49140362021-09-18 01:02:39 +03002828 data->write_value(data, data->REG_FAN_MODE[nr], reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002829 break;
2830 }
2831}
2832
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002833static ssize_t
2834show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
2835{
2836 struct nct6775_data *data = nct6775_update_device(dev);
2837 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2838
2839 return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
2840}
2841
2842static ssize_t
2843store_pwm_enable(struct device *dev, struct device_attribute *attr,
2844 const char *buf, size_t count)
2845{
2846 struct nct6775_data *data = dev_get_drvdata(dev);
2847 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2848 int nr = sattr->index;
2849 unsigned long val;
2850 int err;
2851 u16 reg;
2852
2853 err = kstrtoul(buf, 10, &val);
2854 if (err < 0)
2855 return err;
2856
2857 if (val > sf4)
2858 return -EINVAL;
2859
2860 if (val == sf3 && data->kind != nct6775)
2861 return -EINVAL;
2862
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002863 if (val == sf4 && check_trip_points(data, nr)) {
2864 dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
2865 dev_err(dev, "Adjust trip points and try again\n");
2866 return -EINVAL;
2867 }
2868
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002869 mutex_lock(&data->update_lock);
2870 data->pwm_enable[nr] = val;
2871 if (val == off) {
2872 /*
2873 * turn off pwm control: select manual mode, set pwm to maximum
2874 */
2875 data->pwm[0][nr] = 255;
Denis Pauk49140362021-09-18 01:02:39 +03002876 data->write_value(data, data->REG_PWM[0][nr], 255);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002877 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002878 pwm_update_registers(data, nr);
Denis Pauk49140362021-09-18 01:02:39 +03002879 reg = data->read_value(data, data->REG_FAN_MODE[nr]);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002880 reg &= 0x0f;
2881 reg |= pwm_enable_to_reg(val) << 4;
Denis Pauk49140362021-09-18 01:02:39 +03002882 data->write_value(data, data->REG_FAN_MODE[nr], reg);
Guenter Roeck77eb5b32012-12-04 08:30:54 -08002883 mutex_unlock(&data->update_lock);
2884 return count;
2885}
2886
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002887static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002888show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002889{
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002890 int i, sel = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002891
2892 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002893 if (!(data->have_temp & BIT(i)))
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002894 continue;
2895 if (src == data->temp_src[i]) {
2896 sel = i + 1;
2897 break;
2898 }
2899 }
2900
2901 return sprintf(buf, "%d\n", sel);
2902}
2903
2904static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002905show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
2906{
2907 struct nct6775_data *data = nct6775_update_device(dev);
2908 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2909 int index = sattr->index;
2910
2911 return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
2912}
2913
2914static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002915store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
2916 const char *buf, size_t count)
2917{
2918 struct nct6775_data *data = nct6775_update_device(dev);
2919 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2920 int nr = sattr->index;
2921 unsigned long val;
2922 int err, reg, src;
2923
2924 err = kstrtoul(buf, 10, &val);
2925 if (err < 0)
2926 return err;
2927 if (val == 0 || val > NUM_TEMP)
2928 return -EINVAL;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002929 if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002930 return -EINVAL;
2931
2932 mutex_lock(&data->update_lock);
2933 src = data->temp_src[val - 1];
2934 data->pwm_temp_sel[nr] = src;
Denis Pauk49140362021-09-18 01:02:39 +03002935 reg = data->read_value(data, data->REG_TEMP_SEL[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002936 reg &= 0xe0;
2937 reg |= src;
Denis Pauk49140362021-09-18 01:02:39 +03002938 data->write_value(data, data->REG_TEMP_SEL[nr], reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002939 mutex_unlock(&data->update_lock);
2940
2941 return count;
2942}
2943
2944static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002945show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2946 char *buf)
2947{
2948 struct nct6775_data *data = nct6775_update_device(dev);
2949 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2950 int index = sattr->index;
2951
2952 return show_pwm_temp_sel_common(data, buf,
2953 data->pwm_weight_temp_sel[index]);
2954}
2955
2956static ssize_t
2957store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
2958 const char *buf, size_t count)
2959{
2960 struct nct6775_data *data = nct6775_update_device(dev);
2961 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
2962 int nr = sattr->index;
2963 unsigned long val;
2964 int err, reg, src;
2965
2966 err = kstrtoul(buf, 10, &val);
2967 if (err < 0)
2968 return err;
2969 if (val > NUM_TEMP)
2970 return -EINVAL;
Gustavo A. R. Silvad49dbfa2018-08-15 08:14:37 -05002971 val = array_index_nospec(val, NUM_TEMP + 1);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07002972 if (val && (!(data->have_temp & BIT(val - 1)) ||
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002973 !data->temp_src[val - 1]))
2974 return -EINVAL;
2975
2976 mutex_lock(&data->update_lock);
2977 if (val) {
2978 src = data->temp_src[val - 1];
2979 data->pwm_weight_temp_sel[nr] = src;
Denis Pauk49140362021-09-18 01:02:39 +03002980 reg = data->read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002981 reg &= 0xe0;
2982 reg |= (src | 0x80);
Denis Pauk49140362021-09-18 01:02:39 +03002983 data->write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002984 } else {
2985 data->pwm_weight_temp_sel[nr] = 0;
Denis Pauk49140362021-09-18 01:02:39 +03002986 reg = data->read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002987 reg &= 0x7f;
Denis Pauk49140362021-09-18 01:02:39 +03002988 data->write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08002989 }
2990 mutex_unlock(&data->update_lock);
2991
2992 return count;
2993}
2994
2995static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08002996show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
2997{
2998 struct nct6775_data *data = nct6775_update_device(dev);
2999 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
3000
3001 return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
3002}
3003
3004static ssize_t
3005store_target_temp(struct device *dev, struct device_attribute *attr,
3006 const char *buf, size_t count)
3007{
3008 struct nct6775_data *data = dev_get_drvdata(dev);
3009 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
3010 int nr = sattr->index;
3011 unsigned long val;
3012 int err;
3013
3014 err = kstrtoul(buf, 10, &val);
3015 if (err < 0)
3016 return err;
3017
3018 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
3019 data->target_temp_mask);
3020
3021 mutex_lock(&data->update_lock);
3022 data->target_temp[nr] = val;
3023 pwm_update_registers(data, nr);
3024 mutex_unlock(&data->update_lock);
3025 return count;
3026}
3027
3028static ssize_t
3029show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
3030{
3031 struct nct6775_data *data = nct6775_update_device(dev);
3032 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
3033 int nr = sattr->index;
3034
3035 return sprintf(buf, "%d\n",
3036 fan_from_reg16(data->target_speed[nr],
3037 data->fan_div[nr]));
3038}
3039
3040static ssize_t
3041store_target_speed(struct device *dev, struct device_attribute *attr,
3042 const char *buf, size_t count)
3043{
3044 struct nct6775_data *data = dev_get_drvdata(dev);
3045 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
3046 int nr = sattr->index;
3047 unsigned long val;
3048 int err;
3049 u16 speed;
3050
3051 err = kstrtoul(buf, 10, &val);
3052 if (err < 0)
3053 return err;
3054
3055 val = clamp_val(val, 0, 1350000U);
3056 speed = fan_to_reg(val, data->fan_div[nr]);
3057
3058 mutex_lock(&data->update_lock);
3059 data->target_speed[nr] = speed;
3060 pwm_update_registers(data, nr);
3061 mutex_unlock(&data->update_lock);
3062 return count;
3063}
3064
3065static ssize_t
3066show_temp_tolerance(struct device *dev, struct device_attribute *attr,
3067 char *buf)
3068{
3069 struct nct6775_data *data = nct6775_update_device(dev);
3070 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3071 int nr = sattr->nr;
3072 int index = sattr->index;
3073
3074 return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
3075}
3076
3077static ssize_t
3078store_temp_tolerance(struct device *dev, struct device_attribute *attr,
3079 const char *buf, size_t count)
3080{
3081 struct nct6775_data *data = dev_get_drvdata(dev);
3082 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3083 int nr = sattr->nr;
3084 int index = sattr->index;
3085 unsigned long val;
3086 int err;
3087
3088 err = kstrtoul(buf, 10, &val);
3089 if (err < 0)
3090 return err;
3091
3092 /* Limit tolerance as needed */
3093 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
3094
3095 mutex_lock(&data->update_lock);
3096 data->temp_tolerance[index][nr] = val;
3097 if (index)
3098 pwm_update_registers(data, nr);
3099 else
Denis Pauk49140362021-09-18 01:02:39 +03003100 data->write_value(data,
3101 data->REG_CRITICAL_TEMP_TOLERANCE[nr],
3102 val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003103 mutex_unlock(&data->update_lock);
3104 return count;
3105}
3106
3107/*
3108 * Fan speed tolerance is a tricky beast, since the associated register is
3109 * a tick counter, but the value is reported and configured as rpm.
3110 * Compute resulting low and high rpm values and report the difference.
Guenter Roeck61b6c662018-09-17 09:24:11 -07003111 * A fan speed tolerance only makes sense if a fan target speed has been
3112 * configured, so only display values other than 0 if that is the case.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003113 */
3114static ssize_t
3115show_speed_tolerance(struct device *dev, struct device_attribute *attr,
3116 char *buf)
3117{
3118 struct nct6775_data *data = nct6775_update_device(dev);
3119 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
3120 int nr = sattr->index;
Guenter Roeck61b6c662018-09-17 09:24:11 -07003121 int target = data->target_speed[nr];
3122 int tolerance = 0;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003123
Guenter Roeck61b6c662018-09-17 09:24:11 -07003124 if (target) {
3125 int low = target - data->target_speed_tolerance[nr];
3126 int high = target + data->target_speed_tolerance[nr];
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003127
Guenter Roeck61b6c662018-09-17 09:24:11 -07003128 if (low <= 0)
3129 low = 1;
3130 if (high > 0xffff)
3131 high = 0xffff;
3132 if (high < low)
3133 high = low;
3134
3135 tolerance = (fan_from_reg16(low, data->fan_div[nr])
3136 - fan_from_reg16(high, data->fan_div[nr])) / 2;
3137 }
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003138
3139 return sprintf(buf, "%d\n", tolerance);
3140}
3141
3142static ssize_t
3143store_speed_tolerance(struct device *dev, struct device_attribute *attr,
3144 const char *buf, size_t count)
3145{
3146 struct nct6775_data *data = dev_get_drvdata(dev);
3147 struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
3148 int nr = sattr->index;
3149 unsigned long val;
3150 int err;
3151 int low, high;
3152
3153 err = kstrtoul(buf, 10, &val);
3154 if (err < 0)
3155 return err;
3156
Dan Carpenterc2fe0f62021-12-15 14:40:50 +03003157 high = fan_from_reg16(data->target_speed[nr], data->fan_div[nr]) + val;
3158 low = fan_from_reg16(data->target_speed[nr], data->fan_div[nr]) - val;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003159 if (low <= 0)
3160 low = 1;
3161 if (high < low)
3162 high = low;
3163
3164 val = (fan_to_reg(low, data->fan_div[nr]) -
3165 fan_to_reg(high, data->fan_div[nr])) / 2;
3166
3167 /* Limit tolerance as needed */
3168 val = clamp_val(val, 0, data->speed_tolerance_limit);
3169
3170 mutex_lock(&data->update_lock);
3171 data->target_speed_tolerance[nr] = val;
3172 pwm_update_registers(data, nr);
3173 mutex_unlock(&data->update_lock);
3174 return count;
3175}
3176
Guenter Roeckf73cf632013-03-18 09:22:50 -07003177SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
3178SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
3179 store_pwm_mode, 0);
3180SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
3181 store_pwm_enable, 0);
3182SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
3183 show_pwm_temp_sel, store_pwm_temp_sel, 0);
3184SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
3185 show_target_temp, store_target_temp, 0);
3186SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
3187 show_target_speed, store_target_speed, 0);
3188SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
3189 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003190
3191/* Smart Fan registers */
3192
3193static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003194show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
3195{
3196 struct nct6775_data *data = nct6775_update_device(dev);
3197 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3198 int nr = sattr->nr;
3199 int index = sattr->index;
3200
3201 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
3202}
3203
3204static ssize_t
3205store_weight_temp(struct device *dev, struct device_attribute *attr,
3206 const char *buf, size_t count)
3207{
3208 struct nct6775_data *data = dev_get_drvdata(dev);
3209 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3210 int nr = sattr->nr;
3211 int index = sattr->index;
3212 unsigned long val;
3213 int err;
3214
3215 err = kstrtoul(buf, 10, &val);
3216 if (err < 0)
3217 return err;
3218
3219 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
3220
3221 mutex_lock(&data->update_lock);
3222 data->weight_temp[index][nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03003223 data->write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003224 mutex_unlock(&data->update_lock);
3225 return count;
3226}
3227
Guenter Roeckf73cf632013-03-18 09:22:50 -07003228SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
3229 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
3230SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
3231 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
3232SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
3233 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
3234SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
3235 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
3236SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
3237 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
3238SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
3239 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003240
3241static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003242show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
3243{
3244 struct nct6775_data *data = nct6775_update_device(dev);
3245 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3246 int nr = sattr->nr;
3247 int index = sattr->index;
3248
3249 return sprintf(buf, "%d\n",
3250 step_time_from_reg(data->fan_time[index][nr],
3251 data->pwm_mode[nr]));
3252}
3253
3254static ssize_t
3255store_fan_time(struct device *dev, struct device_attribute *attr,
3256 const char *buf, size_t count)
3257{
3258 struct nct6775_data *data = dev_get_drvdata(dev);
3259 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3260 int nr = sattr->nr;
3261 int index = sattr->index;
3262 unsigned long val;
3263 int err;
3264
3265 err = kstrtoul(buf, 10, &val);
3266 if (err < 0)
3267 return err;
3268
3269 val = step_time_to_reg(val, data->pwm_mode[nr]);
3270 mutex_lock(&data->update_lock);
3271 data->fan_time[index][nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03003272 data->write_value(data, data->REG_FAN_TIME[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003273 mutex_unlock(&data->update_lock);
3274 return count;
3275}
3276
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003277static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003278show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3279{
3280 struct nct6775_data *data = nct6775_update_device(dev);
3281 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3282
3283 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3284}
3285
3286static ssize_t
3287store_auto_pwm(struct device *dev, struct device_attribute *attr,
3288 const char *buf, size_t count)
3289{
3290 struct nct6775_data *data = dev_get_drvdata(dev);
3291 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3292 int nr = sattr->nr;
3293 int point = sattr->index;
3294 unsigned long val;
3295 int err;
3296 u8 reg;
3297
3298 err = kstrtoul(buf, 10, &val);
3299 if (err < 0)
3300 return err;
3301 if (val > 255)
3302 return -EINVAL;
3303
3304 if (point == data->auto_pwm_num) {
3305 if (data->kind != nct6775 && !val)
3306 return -EINVAL;
3307 if (data->kind != nct6779 && val)
3308 val = 0xff;
3309 }
3310
3311 mutex_lock(&data->update_lock);
3312 data->auto_pwm[nr][point] = val;
3313 if (point < data->auto_pwm_num) {
Denis Pauk49140362021-09-18 01:02:39 +03003314 data->write_value(data,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003315 NCT6775_AUTO_PWM(data, nr, point),
3316 data->auto_pwm[nr][point]);
3317 } else {
3318 switch (data->kind) {
3319 case nct6775:
3320 /* disable if needed (pwm == 0) */
Denis Pauk49140362021-09-18 01:02:39 +03003321 reg = data->read_value(data,
3322 NCT6775_REG_CRITICAL_ENAB[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003323 if (val)
3324 reg |= 0x02;
3325 else
3326 reg &= ~0x02;
Denis Pauk49140362021-09-18 01:02:39 +03003327 data->write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3328 reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003329 break;
3330 case nct6776:
3331 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003332 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003333 case nct6116:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003334 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003335 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003336 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003337 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003338 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003339 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07003340 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07003341 case nct6798:
Denis Pauk49140362021-09-18 01:02:39 +03003342 data->write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003343 val);
Denis Pauk49140362021-09-18 01:02:39 +03003344 reg = data->read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003345 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003346 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003347 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003348 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003349 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Denis Pauk49140362021-09-18 01:02:39 +03003350 data->write_value(data,
3351 data->REG_CRITICAL_PWM_ENABLE[nr],
3352 reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003353 break;
3354 }
3355 }
3356 mutex_unlock(&data->update_lock);
3357 return count;
3358}
3359
3360static ssize_t
3361show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3362{
3363 struct nct6775_data *data = nct6775_update_device(dev);
3364 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3365 int nr = sattr->nr;
3366 int point = sattr->index;
3367
3368 /*
3369 * We don't know for sure if the temperature is signed or unsigned.
3370 * Assume it is unsigned.
3371 */
3372 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3373}
3374
3375static ssize_t
3376store_auto_temp(struct device *dev, struct device_attribute *attr,
3377 const char *buf, size_t count)
3378{
3379 struct nct6775_data *data = dev_get_drvdata(dev);
3380 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3381 int nr = sattr->nr;
3382 int point = sattr->index;
3383 unsigned long val;
3384 int err;
3385
3386 err = kstrtoul(buf, 10, &val);
3387 if (err)
3388 return err;
3389 if (val > 255000)
3390 return -EINVAL;
3391
3392 mutex_lock(&data->update_lock);
3393 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3394 if (point < data->auto_pwm_num) {
Denis Pauk49140362021-09-18 01:02:39 +03003395 data->write_value(data,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003396 NCT6775_AUTO_TEMP(data, nr, point),
3397 data->auto_temp[nr][point]);
3398 } else {
Denis Pauk49140362021-09-18 01:02:39 +03003399 data->write_value(data, data->REG_CRITICAL_TEMP[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003400 data->auto_temp[nr][point]);
3401 }
3402 mutex_unlock(&data->update_lock);
3403 return count;
3404}
3405
Guenter Roeckf73cf632013-03-18 09:22:50 -07003406static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3407 struct attribute *attr, int index)
3408{
zhouchuangao036855a2020-05-11 11:43:06 +08003409 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003410 struct nct6775_data *data = dev_get_drvdata(dev);
3411 int pwm = index / 36; /* pwm index */
3412 int nr = index % 36; /* attribute index */
3413
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003414 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003415 return 0;
3416
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003417 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3418 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3419 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003420 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3421 return 0;
3422 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3423 return 0;
3424 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3425 return 0;
3426
3427 if (nr >= 22 && nr <= 35) { /* auto point */
3428 int api = (nr - 22) / 2; /* auto point index */
3429
3430 if (api > data->auto_pwm_num)
3431 return 0;
3432 }
3433 return attr->mode;
3434}
3435
3436SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3437 show_fan_time, store_fan_time, 0, 0);
3438SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3439 show_fan_time, store_fan_time, 0, 1);
3440SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3441 show_fan_time, store_fan_time, 0, 2);
3442SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3443 store_pwm, 0, 1);
3444SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3445 store_pwm, 0, 2);
3446SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3447 show_temp_tolerance, store_temp_tolerance, 0, 0);
3448SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3449 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3450 0, 1);
3451
3452SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3453 0, 3);
3454
3455SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3456 store_pwm, 0, 4);
3457
3458SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3459 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3460SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3461 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3462
3463SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3464 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3465SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3466 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3467
3468SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3469 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3470SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3471 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3472
3473SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3474 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3475SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3476 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3477
3478SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3479 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3480SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3481 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3482
3483SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3484 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3485SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3486 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3487
3488SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3489 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3490SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3491 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3492
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003493/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003494 * nct6775_pwm_is_visible uses the index into the following array
3495 * to determine if attributes should be created or not.
3496 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003497 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003498static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3499 &sensor_dev_template_pwm,
3500 &sensor_dev_template_pwm_mode,
3501 &sensor_dev_template_pwm_enable,
3502 &sensor_dev_template_pwm_temp_sel,
3503 &sensor_dev_template_pwm_temp_tolerance,
3504 &sensor_dev_template_pwm_crit_temp_tolerance,
3505 &sensor_dev_template_pwm_target_temp,
3506 &sensor_dev_template_fan_target,
3507 &sensor_dev_template_fan_tolerance,
3508 &sensor_dev_template_pwm_stop_time,
3509 &sensor_dev_template_pwm_step_up_time,
3510 &sensor_dev_template_pwm_step_down_time,
3511 &sensor_dev_template_pwm_start,
3512 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003513 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003514 &sensor_dev_template_pwm_weight_temp_step,
3515 &sensor_dev_template_pwm_weight_temp_step_tol,
3516 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003517 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003518 &sensor_dev_template_pwm_max, /* 19 */
3519 &sensor_dev_template_pwm_step, /* 20 */
3520 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3521 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3522 &sensor_dev_template_pwm_auto_point1_temp,
3523 &sensor_dev_template_pwm_auto_point2_pwm,
3524 &sensor_dev_template_pwm_auto_point2_temp,
3525 &sensor_dev_template_pwm_auto_point3_pwm,
3526 &sensor_dev_template_pwm_auto_point3_temp,
3527 &sensor_dev_template_pwm_auto_point4_pwm,
3528 &sensor_dev_template_pwm_auto_point4_temp,
3529 &sensor_dev_template_pwm_auto_point5_pwm,
3530 &sensor_dev_template_pwm_auto_point5_temp,
3531 &sensor_dev_template_pwm_auto_point6_pwm,
3532 &sensor_dev_template_pwm_auto_point6_temp,
3533 &sensor_dev_template_pwm_auto_point7_pwm,
3534 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003535
Guenter Roeckf73cf632013-03-18 09:22:50 -07003536 NULL
3537};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003538
Julia Lawallc60fdf82015-12-12 17:36:39 +01003539static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003540 .templates = nct6775_attributes_pwm_template,
3541 .is_visible = nct6775_pwm_is_visible,
3542 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003543};
3544
3545static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003546cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003547{
3548 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003549
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003550 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3551}
3552
Julia Lawall93d72ac2016-12-22 13:05:23 +01003553static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003554
Guenter Roecka6bd5872012-12-04 03:13:34 -08003555/* Case open detection */
3556
3557static ssize_t
3558clear_caseopen(struct device *dev, struct device_attribute *attr,
3559 const char *buf, size_t count)
3560{
3561 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck79da5332022-01-23 18:23:22 -08003562 struct nct6775_sio_data *sio_data = data->sio_data;
Guenter Roecka6bd5872012-12-04 03:13:34 -08003563 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3564 unsigned long val;
3565 u8 reg;
3566 int ret;
3567
3568 if (kstrtoul(buf, 10, &val) || val != 0)
3569 return -EINVAL;
3570
3571 mutex_lock(&data->update_lock);
3572
3573 /*
3574 * Use CR registers to clear caseopen status.
3575 * The CR registers are the same for all chips, and not all chips
3576 * support clearing the caseopen status through "regular" registers.
3577 */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003578 ret = sio_data->sio_enter(sio_data);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003579 if (ret) {
3580 count = ret;
3581 goto error;
3582 }
3583
Denis Pauk2e7b9882021-09-18 01:02:38 +03003584 sio_data->sio_select(sio_data, NCT6775_LD_ACPI);
3585 reg = sio_data->sio_inb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003586 reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Denis Pauk2e7b9882021-09-18 01:02:38 +03003587 sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003588 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Denis Pauk2e7b9882021-09-18 01:02:38 +03003589 sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3590 sio_data->sio_exit(sio_data);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003591
3592 data->valid = false; /* Force cache refresh */
3593error:
3594 mutex_unlock(&data->update_lock);
3595 return count;
3596}
3597
Guenter Roeckf73cf632013-03-18 09:22:50 -07003598static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3599 clear_caseopen, INTRUSION_ALARM_BASE);
3600static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3601 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003602static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3603 store_beep, INTRUSION_ALARM_BASE);
3604static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3605 store_beep, INTRUSION_ALARM_BASE + 1);
3606static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3607 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003608
3609static umode_t nct6775_other_is_visible(struct kobject *kobj,
3610 struct attribute *attr, int index)
3611{
zhouchuangao036855a2020-05-11 11:43:06 +08003612 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003613 struct nct6775_data *data = dev_get_drvdata(dev);
3614
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003615 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003616 return 0;
3617
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003618 if (index == 1 || index == 2) {
3619 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003620 return 0;
3621 }
3622
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003623 if (index == 3 || index == 4) {
3624 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003625 return 0;
3626 }
3627
Guenter Roeckf73cf632013-03-18 09:22:50 -07003628 return attr->mode;
3629}
3630
3631/*
3632 * nct6775_other_is_visible uses the index into the following array
3633 * to determine if attributes should be created or not.
3634 * Any change in order or content must be matched.
3635 */
3636static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003637 &dev_attr_cpu0_vid.attr, /* 0 */
3638 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3639 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3640 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3641 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3642 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003643
3644 NULL
3645};
3646
3647static const struct attribute_group nct6775_group_other = {
3648 .attrs = nct6775_attributes_other,
3649 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003650};
3651
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003652static inline void nct6775_init_device(struct nct6775_data *data)
3653{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003654 int i;
3655 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003656
3657 /* Start monitoring if needed */
3658 if (data->REG_CONFIG) {
Denis Pauk49140362021-09-18 01:02:39 +03003659 tmp = data->read_value(data, data->REG_CONFIG);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003660 if (!(tmp & 0x01))
Denis Pauk49140362021-09-18 01:02:39 +03003661 data->write_value(data, data->REG_CONFIG, tmp | 0x01);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003662 }
3663
Guenter Roeckaa136e52012-12-04 03:26:05 -08003664 /* Enable temperature sensors if needed */
3665 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003666 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003667 continue;
3668 if (!data->reg_temp_config[i])
3669 continue;
Denis Pauk49140362021-09-18 01:02:39 +03003670 tmp = data->read_value(data, data->reg_temp_config[i]);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003671 if (tmp & 0x01)
Denis Pauk49140362021-09-18 01:02:39 +03003672 data->write_value(data, data->reg_temp_config[i],
Guenter Roeckaa136e52012-12-04 03:26:05 -08003673 tmp & 0xfe);
3674 }
3675
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003676 /* Enable VBAT monitoring if needed */
Denis Pauk49140362021-09-18 01:02:39 +03003677 tmp = data->read_value(data, data->REG_VBAT);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003678 if (!(tmp & 0x01))
Denis Pauk49140362021-09-18 01:02:39 +03003679 data->write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003680
Denis Pauk49140362021-09-18 01:02:39 +03003681 diode = data->read_value(data, data->REG_DIODE);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003682
3683 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003684 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003685 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003686 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3687 data->temp_type[i]
3688 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003689 else /* thermistor */
3690 data->temp_type[i] = 4;
3691 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003692}
3693
Guenter Roeckf73cf632013-03-18 09:22:50 -07003694static void
Denis Pauk2e7b9882021-09-18 01:02:38 +03003695nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio_data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003696{
Guenter Roeck1b206242018-02-21 13:09:38 -08003697 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003698 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003699 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003700 bool pwm6pin = false, pwm7pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003701
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003702 /* Store SIO_REG_ENABLE for use during resume */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003703 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
3704 data->sio_reg_enable = sio_data->sio_inb(sio_data, SIO_REG_ENABLE);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003705
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003706 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3707 if (data->kind == nct6775) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003708 int cr2c = sio_data->sio_inb(sio_data, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003709
Guenter Roecka6c54f22018-09-18 09:34:06 -07003710 fan3pin = cr2c & BIT(6);
3711 pwm3pin = cr2c & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003712
3713 /* On NCT6775, fan4 shares pins with the fdc interface */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003714 fan4pin = !(sio_data->sio_inb(sio_data, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003715 } else if (data->kind == nct6776) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003716 bool gpok = sio_data->sio_inb(sio_data, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003717 const char *board_vendor, *board_name;
3718
3719 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3720 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3721
3722 if (board_name && board_vendor &&
3723 !strcmp(board_vendor, "ASRock")) {
3724 /*
3725 * Auxiliary fan monitoring is not enabled on ASRock
3726 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3727 * Observed with BIOS version 2.00.
3728 */
3729 if (!strcmp(board_name, "Z77 Pro4-M")) {
3730 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3731 data->sio_reg_enable |= 0xe0;
Denis Pauk2e7b9882021-09-18 01:02:38 +03003732 sio_data->sio_outb(sio_data, SIO_REG_ENABLE,
Guenter Roeck25cdd992015-02-06 18:55:36 -08003733 data->sio_reg_enable);
3734 }
3735 }
3736 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003737
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003738 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003739 fan3pin = gpok;
3740 else
Denis Pauk2e7b9882021-09-18 01:02:38 +03003741 fan3pin = !(sio_data->sio_inb(sio_data, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003742
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003743 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003744 fan4pin = gpok;
3745 else
Denis Pauk2e7b9882021-09-18 01:02:38 +03003746 fan4pin = sio_data->sio_inb(sio_data, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003747
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003748 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003749 fan5pin = gpok;
3750 else
Denis Pauk2e7b9882021-09-18 01:02:38 +03003751 fan5pin = sio_data->sio_inb(sio_data, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003752
3753 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003754 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003755 } else if (data->kind == nct6106) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003756 int cr24 = sio_data->sio_inb(sio_data, 0x24);
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003757
Guenter Roecka6c54f22018-09-18 09:34:06 -07003758 fan3pin = !(cr24 & 0x80);
3759 pwm3pin = cr24 & 0x08;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003760 } else if (data->kind == nct6116) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003761 int cr1a = sio_data->sio_inb(sio_data, 0x1a);
3762 int cr1b = sio_data->sio_inb(sio_data, 0x1b);
3763 int cr24 = sio_data->sio_inb(sio_data, 0x24);
3764 int cr2a = sio_data->sio_inb(sio_data, 0x2a);
3765 int cr2b = sio_data->sio_inb(sio_data, 0x2b);
3766 int cr2f = sio_data->sio_inb(sio_data, 0x2f);
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003767
3768 fan3pin = !(cr2b & 0x10);
3769 fan4pin = (cr2b & 0x80) || // pin 1(2)
3770 (!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66)
3771 fan5pin = (cr2b & 0x80) || // pin 126(127)
3772 (!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96)
3773
3774 pwm3pin = fan3pin && (cr24 & 0x08);
3775 pwm4pin = fan4pin;
3776 pwm5pin = fan5pin;
Guenter Roeck81820052018-02-21 13:09:39 -08003777 } else {
Guenter Roecke41da282018-09-18 20:48:29 -07003778 /*
3779 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
Guenter Roeck05996822018-09-19 20:26:16 -07003780 * NCT6797D, NCT6798D
Guenter Roecke41da282018-09-18 20:48:29 -07003781 */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003782 int cr1a = sio_data->sio_inb(sio_data, 0x1a);
3783 int cr1b = sio_data->sio_inb(sio_data, 0x1b);
3784 int cr1c = sio_data->sio_inb(sio_data, 0x1c);
3785 int cr1d = sio_data->sio_inb(sio_data, 0x1d);
3786 int cr2a = sio_data->sio_inb(sio_data, 0x2a);
3787 int cr2b = sio_data->sio_inb(sio_data, 0x2b);
3788 int cr2d = sio_data->sio_inb(sio_data, 0x2d);
3789 int cr2f = sio_data->sio_inb(sio_data, 0x2f);
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003790 bool dsw_en = cr2f & BIT(3);
Guenter Roecke41da282018-09-18 20:48:29 -07003791 bool ddr4_en = cr2f & BIT(4);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003792 int cre0;
Guenter Roeck2d888c52018-09-18 09:49:29 -07003793 int creb;
3794 int cred;
3795
Denis Pauk2e7b9882021-09-18 01:02:38 +03003796 sio_data->sio_select(sio_data, NCT6775_LD_12);
3797 cre0 = sio_data->sio_inb(sio_data, 0xe0);
3798 creb = sio_data->sio_inb(sio_data, 0xeb);
3799 cred = sio_data->sio_inb(sio_data, 0xed);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003800
Guenter Roecka6c54f22018-09-18 09:34:06 -07003801 fan3pin = !(cr1c & BIT(5));
3802 fan4pin = !(cr1c & BIT(6));
3803 fan5pin = !(cr1c & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003804
Guenter Roecka6c54f22018-09-18 09:34:06 -07003805 pwm3pin = !(cr1c & BIT(0));
3806 pwm4pin = !(cr1c & BIT(1));
3807 pwm5pin = !(cr1c & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003808
Guenter Roecke5c85222017-05-17 18:09:41 -07003809 switch (data->kind) {
3810 case nct6791:
Guenter Roecka6c54f22018-09-18 09:34:06 -07003811 fan6pin = cr2d & BIT(1);
3812 pwm6pin = cr2d & BIT(0);
Guenter Roecke5c85222017-05-17 18:09:41 -07003813 break;
Guenter Roeck7dcdbde2018-09-18 10:52:55 -07003814 case nct6792:
3815 fan6pin = !dsw_en && (cr2d & BIT(1));
3816 pwm6pin = !dsw_en && (cr2d & BIT(0));
3817 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003818 case nct6793:
Guenter Roeck2d999252018-09-18 11:03:25 -07003819 fan5pin |= cr1b & BIT(5);
3820 fan5pin |= creb & BIT(5);
3821
Guenter Roeck2a2ec4a2019-01-27 16:08:00 -08003822 fan6pin = !dsw_en && (cr2d & BIT(1));
3823 fan6pin |= creb & BIT(3);
Guenter Roeck2d999252018-09-18 11:03:25 -07003824
3825 pwm5pin |= cr2d & BIT(7);
3826 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3827
3828 pwm6pin = !dsw_en && (cr2d & BIT(0));
3829 pwm6pin |= creb & BIT(2);
3830 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003831 case nct6795:
Guenter Roeckb75a8062018-09-18 11:18:30 -07003832 fan5pin |= cr1b & BIT(5);
3833 fan5pin |= creb & BIT(5);
3834
3835 fan6pin = (cr2a & BIT(4)) &&
3836 (!dsw_en || (cred & BIT(4)));
3837 fan6pin |= creb & BIT(3);
3838
3839 pwm5pin |= cr2d & BIT(7);
3840 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3841
3842 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3843 pwm6pin |= creb & BIT(2);
3844 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003845 case nct6796:
Guenter Roecka4e0a082018-09-18 09:53:06 -07003846 fan5pin |= cr1b & BIT(5);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003847 fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
3848 fan5pin |= creb & BIT(5);
Guenter Roecke5c85222017-05-17 18:09:41 -07003849
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003850 fan6pin = (cr2a & BIT(4)) &&
Guenter Roeck2d999252018-09-18 11:03:25 -07003851 (!dsw_en || (cred & BIT(4)));
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003852 fan6pin |= creb & BIT(3);
Guenter Roeck81820052018-02-21 13:09:39 -08003853
Guenter Roeckb75a8062018-09-18 11:18:30 -07003854 fan7pin = !(cr2b & BIT(2));
Guenter Roeck81820052018-02-21 13:09:39 -08003855
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003856 pwm5pin |= cr2d & BIT(7);
3857 pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
3858 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3859
3860 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3861 pwm6pin |= creb & BIT(2);
3862
3863 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
Guenter Roecke5c85222017-05-17 18:09:41 -07003864 break;
Guenter Roecke41da282018-09-18 20:48:29 -07003865 case nct6797:
3866 fan5pin |= !ddr4_en && (cr1b & BIT(5));
3867 fan5pin |= creb & BIT(5);
3868
3869 fan6pin = cr2a & BIT(4);
3870 fan6pin |= creb & BIT(3);
3871
3872 fan7pin = cr1a & BIT(1);
3873
3874 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3875 pwm5pin |= !ddr4_en && (cr2d & BIT(7));
3876
3877 pwm6pin = creb & BIT(2);
3878 pwm6pin |= cred & BIT(2);
3879
3880 pwm7pin = cr1d & BIT(4);
3881 break;
Guenter Roeck05996822018-09-19 20:26:16 -07003882 case nct6798:
3883 fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
3884 fan6pin |= cr2a & BIT(4);
3885 fan6pin |= creb & BIT(5);
3886
3887 fan7pin = cr1b & BIT(5);
3888 fan7pin |= !(cr2b & BIT(2));
3889 fan7pin |= creb & BIT(3);
3890
3891 pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
3892 pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3));
3893 pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3894
3895 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
3896 pwm7pin |= cr2d & BIT(7);
3897 pwm7pin |= creb & BIT(2);
3898 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003899 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003900 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003901 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003902
3903 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003904 }
3905
David Bartley578ab5f2013-06-24 22:28:28 -07003906 /* fan 1 and 2 (0x03) are always present */
3907 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003908 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003909 data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003910 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003911 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003912 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003913}
3914
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003915static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3916 int *available, int *mask)
3917{
3918 int i;
3919 u8 src;
3920
3921 for (i = 0; i < data->pwm_num && *available; i++) {
3922 int index;
3923
3924 if (!regp[i])
3925 continue;
Denis Pauk49140362021-09-18 01:02:39 +03003926 src = data->read_value(data, regp[i]);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003927 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003928 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003929 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003930 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003931 continue;
3932
3933 index = __ffs(*available);
Denis Pauk49140362021-09-18 01:02:39 +03003934 data->write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003935 *available &= ~BIT(index);
3936 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003937 }
3938}
3939
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003940static int nct6775_probe(struct platform_device *pdev)
3941{
3942 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003943 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003944 struct nct6775_data *data;
3945 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003946 int i, s, err = 0;
3947 int src, mask, available;
3948 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003949 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003950 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003951 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003952 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003953 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003954 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003955 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003956
Denis Pauk3fbbfc22021-09-18 01:02:40 +03003957 if (sio_data->access == access_direct) {
3958 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3959 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3960 DRVNAME))
3961 return -EBUSY;
3962 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003963
3964 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3965 GFP_KERNEL);
3966 if (!data)
3967 return -ENOMEM;
3968
3969 data->kind = sio_data->kind;
Guenter Roeck79da5332022-01-23 18:23:22 -08003970 data->sio_data = sio_data;
Denis Pauk3fbbfc22021-09-18 01:02:40 +03003971
3972 if (sio_data->access == access_direct) {
3973 data->addr = res->start;
3974 data->read_value = nct6775_read_value;
3975 data->write_value = nct6775_write_value;
3976 } else {
3977 data->read_value = nct6775_wmi_read_value;
3978 data->write_value = nct6775_wmi_write_value;
3979 }
3980
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003981 mutex_init(&data->update_lock);
3982 data->name = nct6775_device_names[data->kind];
3983 data->bank = 0xff; /* Force initial bank selection */
3984 platform_set_drvdata(pdev, data);
3985
3986 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003987 case nct6106:
3988 data->in_num = 9;
3989 data->pwm_num = 3;
3990 data->auto_pwm_num = 4;
3991 data->temp_fixed_num = 3;
3992 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003993 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003994
3995 data->fan_from_reg = fan_from_reg13;
3996 data->fan_from_reg_min = fan_from_reg13;
3997
3998 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003999 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004000 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07004001
4002 data->REG_VBAT = NCT6106_REG_VBAT;
4003 data->REG_DIODE = NCT6106_REG_DIODE;
4004 data->DIODE_MASK = NCT6106_DIODE_MASK;
4005 data->REG_VIN = NCT6106_REG_IN;
4006 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
4007 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
4008 data->REG_TARGET = NCT6106_REG_TARGET;
4009 data->REG_FAN = NCT6106_REG_FAN;
4010 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
4011 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
4012 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
4013 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
4014 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
4015 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
4016 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
Björn Gerhartf3d43e22019-07-15 18:33:55 +02004017 data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004018 data->REG_PWM[0] = NCT6116_REG_PWM;
Guenter Roeck6c009502012-07-01 08:23:15 -07004019 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
4020 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
4021 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
4022 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
4023 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
4024 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
4025 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
4026 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
4027 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
4028 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
4029 data->REG_CRITICAL_TEMP_TOLERANCE
4030 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
4031 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
4032 data->CRITICAL_PWM_ENABLE_MASK
4033 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
4034 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
4035 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
4036 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004037 data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
Guenter Roeck6c009502012-07-01 08:23:15 -07004038 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
4039 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
4040 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
4041 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
4042 data->REG_ALARM = NCT6106_REG_ALARM;
4043 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004044 data->REG_BEEP = NCT6106_REG_BEEP;
4045 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07004046
4047 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004048 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07004049 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004050 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07004051 reg_temp_over = NCT6106_REG_TEMP_OVER;
4052 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
4053 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
4054 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
4055 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07004056 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
4057 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07004058
4059 break;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004060 case nct6116:
4061 data->in_num = 9;
4062 data->pwm_num = 3;
4063 data->auto_pwm_num = 4;
4064 data->temp_fixed_num = 3;
4065 data->num_temp_alarms = 3;
4066 data->num_temp_beeps = 3;
4067
4068 data->fan_from_reg = fan_from_reg13;
4069 data->fan_from_reg_min = fan_from_reg13;
4070
4071 data->temp_label = nct6776_temp_label;
4072 data->temp_mask = NCT6776_TEMP_MASK;
4073 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
4074
4075 data->REG_VBAT = NCT6106_REG_VBAT;
4076 data->REG_DIODE = NCT6106_REG_DIODE;
4077 data->DIODE_MASK = NCT6106_DIODE_MASK;
4078 data->REG_VIN = NCT6106_REG_IN;
4079 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
4080 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
4081 data->REG_TARGET = NCT6116_REG_TARGET;
4082 data->REG_FAN = NCT6116_REG_FAN;
4083 data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
4084 data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
4085 data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
4086 data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
4087 data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
4088 data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
4089 data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
4090 data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
4091 data->REG_PWM[0] = NCT6116_REG_PWM;
4092 data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
4093 data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
4094 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
4095 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
4096 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
4097 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
4098 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
4099 data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
4100 data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
4101 data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
4102 data->REG_CRITICAL_TEMP_TOLERANCE
4103 = NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
4104 data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
4105 data->CRITICAL_PWM_ENABLE_MASK
4106 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
4107 data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
4108 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
4109 data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
4110 data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
4111 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
4112 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
4113 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
4114 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
4115 data->REG_ALARM = NCT6106_REG_ALARM;
4116 data->ALARM_BITS = NCT6116_ALARM_BITS;
4117 data->REG_BEEP = NCT6106_REG_BEEP;
4118 data->BEEP_BITS = NCT6116_BEEP_BITS;
4119
4120 reg_temp = NCT6106_REG_TEMP;
4121 reg_temp_mon = NCT6106_REG_TEMP_MON;
4122 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
4123 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
4124 reg_temp_over = NCT6106_REG_TEMP_OVER;
4125 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
4126 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
4127 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
4128 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
4129 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
4130 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
4131
4132 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004133 case nct6775:
4134 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004135 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004136 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004137 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004138 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004139 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07004140 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004141
4142 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004143 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004144
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004145 data->fan_from_reg = fan_from_reg16;
4146 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004147 data->target_temp_mask = 0x7f;
4148 data->tolerance_mask = 0x0f;
4149 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004150
Guenter Roeckaa136e52012-12-04 03:26:05 -08004151 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004152 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004153 data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004154
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004155 data->REG_CONFIG = NCT6775_REG_CONFIG;
4156 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004157 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004158 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004159 data->REG_VIN = NCT6775_REG_IN;
4160 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4161 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004162 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004163 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004164 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004165 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004166 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004167 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004168 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
4169 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
4170 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004171 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004172 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4173 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
4174 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
4175 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004176 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004177 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4178 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
4179 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004180 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4181 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4182 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4183 data->REG_CRITICAL_TEMP_TOLERANCE
4184 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004185 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
4186 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004187 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004188 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4189 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4190 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4191 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004192 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004193 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004194
4195 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004196 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004197 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004198 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004199 reg_temp_over = NCT6775_REG_TEMP_OVER;
4200 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
4201 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
4202 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
4203 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
4204
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004205 break;
4206 case nct6776:
4207 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004208 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004209 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004210 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004211 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004212 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07004213 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004214
4215 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004216 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004217
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004218 data->fan_from_reg = fan_from_reg13;
4219 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004220 data->target_temp_mask = 0xff;
4221 data->tolerance_mask = 0x07;
4222 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004223
Guenter Roeckaa136e52012-12-04 03:26:05 -08004224 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004225 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004226 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004227
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004228 data->REG_CONFIG = NCT6775_REG_CONFIG;
4229 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004230 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004231 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004232 data->REG_VIN = NCT6775_REG_IN;
4233 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4234 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004235 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004236 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004237 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004238 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004239 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004240 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004241 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004242 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4243 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004244 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004245 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004246 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4247 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004248 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4249 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004250 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4251 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4252 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004253 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4254 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4255 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4256 data->REG_CRITICAL_TEMP_TOLERANCE
4257 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004258 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
4259 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004260 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004261 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4262 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4263 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4264 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004265 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004266 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004267
4268 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004269 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004270 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004271 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004272 reg_temp_over = NCT6775_REG_TEMP_OVER;
4273 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
4274 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
4275 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
4276 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
4277
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004278 break;
4279 case nct6779:
4280 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004281 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004282 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004283 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004284 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004285 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07004286 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004287
4288 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004289 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004290
Guenter Roeckf6de2982018-09-13 20:01:12 -07004291 data->fan_from_reg = fan_from_reg_rpm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004292 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004293 data->target_temp_mask = 0xff;
4294 data->tolerance_mask = 0x07;
4295 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004296
Guenter Roeckaa136e52012-12-04 03:26:05 -08004297 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004298 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004299 data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004300
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004301 data->REG_CONFIG = NCT6775_REG_CONFIG;
4302 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004303 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004304 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004305 data->REG_VIN = NCT6779_REG_IN;
4306 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4307 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004308 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004309 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004310 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004311 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004312 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004313 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004314 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004315 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4316 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004317 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004318 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004319 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4320 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004321 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4322 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004323 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4324 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4325 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004326 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4327 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4328 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4329 data->REG_CRITICAL_TEMP_TOLERANCE
4330 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004331 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4332 data->CRITICAL_PWM_ENABLE_MASK
4333 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4334 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004335 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4336 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004337 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004338 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4339 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4340 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4341 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004342 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004343 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004344
4345 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004346 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004347 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004348 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004349 reg_temp_over = NCT6779_REG_TEMP_OVER;
4350 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4351 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4352 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4353 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4354
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004355 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004356 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004357 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004358 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004359 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004360 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004361 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004362 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004363 data->in_num = 15;
Guenter Roecke41da282018-09-18 20:48:29 -07004364 data->pwm_num = (data->kind == nct6796 ||
Guenter Roeck05996822018-09-19 20:26:16 -07004365 data->kind == nct6797 ||
4366 data->kind == nct6798) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07004367 data->auto_pwm_num = 4;
4368 data->has_fan_div = false;
4369 data->temp_fixed_num = 6;
4370 data->num_temp_alarms = 2;
4371 data->num_temp_beeps = 2;
4372
4373 data->ALARM_BITS = NCT6791_ALARM_BITS;
4374 data->BEEP_BITS = NCT6779_BEEP_BITS;
4375
Guenter Roeckf6de2982018-09-13 20:01:12 -07004376 data->fan_from_reg = fan_from_reg_rpm;
David Bartley578ab5f2013-06-24 22:28:28 -07004377 data->fan_from_reg_min = fan_from_reg13;
4378 data->target_temp_mask = 0xff;
4379 data->tolerance_mask = 0x07;
4380 data->speed_tolerance_limit = 63;
4381
Guenter Roeck50224f42015-10-30 07:52:39 -07004382 switch (data->kind) {
4383 default:
4384 case nct6791:
4385 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004386 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004387 data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004388 break;
4389 case nct6792:
4390 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004391 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004392 data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004393 break;
4394 case nct6793:
4395 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004396 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004397 data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004398 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004399 case nct6795:
Guenter Roecke41da282018-09-18 20:48:29 -07004400 case nct6797:
Guenter Roeck419220d2017-05-17 18:19:18 -07004401 data->temp_label = nct6795_temp_label;
4402 data->temp_mask = NCT6795_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004403 data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
Guenter Roeck419220d2017-05-17 18:19:18 -07004404 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004405 case nct6796:
4406 data->temp_label = nct6796_temp_label;
4407 data->temp_mask = NCT6796_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004408 data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
Guenter Roeck81820052018-02-21 13:09:39 -08004409 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004410 case nct6798:
4411 data->temp_label = nct6798_temp_label;
4412 data->temp_mask = NCT6798_TEMP_MASK;
4413 data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
4414 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07004415 }
David Bartley578ab5f2013-06-24 22:28:28 -07004416
4417 data->REG_CONFIG = NCT6775_REG_CONFIG;
4418 data->REG_VBAT = NCT6775_REG_VBAT;
4419 data->REG_DIODE = NCT6775_REG_DIODE;
4420 data->DIODE_MASK = NCT6775_DIODE_MASK;
4421 data->REG_VIN = NCT6779_REG_IN;
4422 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4423 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
4424 data->REG_TARGET = NCT6775_REG_TARGET;
4425 data->REG_FAN = NCT6779_REG_FAN;
4426 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
4427 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
4428 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
4429 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
4430 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004431 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4432 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07004433 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
4434 data->REG_PWM[0] = NCT6775_REG_PWM;
4435 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4436 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004437 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
4438 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004439 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4440 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4441 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
4442 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4443 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4444 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4445 data->REG_CRITICAL_TEMP_TOLERANCE
4446 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
4447 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4448 data->CRITICAL_PWM_ENABLE_MASK
4449 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4450 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
4451 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4452 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4453 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004454 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4455 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4456 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4457 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004458 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004459 if (data->kind == nct6791)
4460 data->REG_BEEP = NCT6776_REG_BEEP;
4461 else
4462 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004463
4464 reg_temp = NCT6779_REG_TEMP;
4465 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004466 if (data->kind == nct6791) {
4467 reg_temp_mon = NCT6779_REG_TEMP_MON;
4468 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4469 } else {
4470 reg_temp_mon = NCT6792_REG_TEMP_MON;
4471 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4472 }
David Bartley578ab5f2013-06-24 22:28:28 -07004473 reg_temp_over = NCT6779_REG_TEMP_OVER;
4474 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4475 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4476 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4477 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4478
4479 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004480 default:
4481 return -ENODEV;
4482 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004483 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004484 data->have_temp = 0;
4485
4486 /*
4487 * On some boards, not all available temperature sources are monitored,
4488 * even though some of the monitoring registers are unused.
4489 * Get list of unused monitoring registers, then detect if any fan
4490 * controls are configured to use unmonitored temperature sources.
4491 * If so, assign the unmonitored temperature sources to available
4492 * monitoring registers.
4493 */
4494 mask = 0;
4495 available = 0;
4496 for (i = 0; i < num_reg_temp; i++) {
4497 if (reg_temp[i] == 0)
4498 continue;
4499
Denis Pauk49140362021-09-18 01:02:39 +03004500 src = data->read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004501 if (!src || (mask & BIT(src)))
4502 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004503
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004504 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004505 }
4506
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004507 /*
4508 * Now find unmonitored temperature registers and enable monitoring
4509 * if additional monitoring registers are available.
4510 */
4511 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4512 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4513
Guenter Roeckaa136e52012-12-04 03:26:05 -08004514 mask = 0;
4515 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4516 for (i = 0; i < num_reg_temp; i++) {
4517 if (reg_temp[i] == 0)
4518 continue;
4519
Denis Pauk49140362021-09-18 01:02:39 +03004520 src = data->read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004521 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004522 continue;
4523
Guenter Roeckcc66b302017-05-17 18:05:06 -07004524 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004525 dev_info(dev,
4526 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4527 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4528 continue;
4529 }
4530
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004531 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004532
4533 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4534 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004535 data->have_temp |= BIT(src - 1);
4536 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004537 data->reg_temp[0][src - 1] = reg_temp[i];
4538 data->reg_temp[1][src - 1] = reg_temp_over[i];
4539 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004540 if (reg_temp_crit_h && reg_temp_crit_h[i])
4541 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4542 else if (reg_temp_crit[src - 1])
4543 data->reg_temp[3][src - 1]
4544 = reg_temp_crit[src - 1];
4545 if (reg_temp_crit_l && reg_temp_crit_l[i])
4546 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004547 data->reg_temp_config[src - 1] = reg_temp_config[i];
4548 data->temp_src[src - 1] = src;
4549 continue;
4550 }
4551
4552 if (s >= NUM_TEMP)
4553 continue;
4554
4555 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004556 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004557 data->reg_temp[0][s] = reg_temp[i];
4558 data->reg_temp[1][s] = reg_temp_over[i];
4559 data->reg_temp[2][s] = reg_temp_hyst[i];
4560 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004561 if (reg_temp_crit_h && reg_temp_crit_h[i])
4562 data->reg_temp[3][s] = reg_temp_crit_h[i];
4563 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004564 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004565 if (reg_temp_crit_l && reg_temp_crit_l[i])
4566 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004567
4568 data->temp_src[s] = src;
4569 s++;
4570 }
4571
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004572 /*
4573 * Repeat with temperatures used for fan control.
4574 * This set of registers does not support limits.
4575 */
4576 for (i = 0; i < num_reg_temp_mon; i++) {
4577 if (reg_temp_mon[i] == 0)
4578 continue;
4579
Denis Pauk49140362021-09-18 01:02:39 +03004580 src = data->read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004581 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004582 continue;
4583
Guenter Roeckcc66b302017-05-17 18:05:06 -07004584 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004585 dev_info(dev,
4586 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4587 src, i, data->REG_TEMP_SEL[i],
4588 reg_temp_mon[i]);
4589 continue;
4590 }
4591
Guenter Roeck7ce41902016-09-11 12:42:52 -07004592 /*
4593 * For virtual temperature sources, the 'virtual' temperature
4594 * for each fan reflects a different temperature, and there
4595 * are no duplicates.
4596 */
Guenter Roeck37196ba2018-09-13 19:43:58 -07004597 if (!(data->virt_temp_mask & BIT(src))) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004598 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004599 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004600 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004601 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004602
4603 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4604 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004605 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004606 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004607 data->have_temp |= BIT(src - 1);
4608 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004609 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4610 data->temp_src[src - 1] = src;
4611 continue;
4612 }
4613
4614 if (s >= NUM_TEMP)
4615 continue;
4616
4617 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004618 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004619 data->reg_temp[0][s] = reg_temp_mon[i];
4620 data->temp_src[s] = src;
4621 s++;
4622 }
4623
Guenter Roeckaa136e52012-12-04 03:26:05 -08004624#ifdef USE_ALTERNATE
4625 /*
4626 * Go through the list of alternate temp registers and enable
4627 * if possible.
4628 * The temperature is already monitored if the respective bit in <mask>
4629 * is set.
4630 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004631 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004632 if (!(data->temp_mask & BIT(i + 1)))
4633 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004634 if (!reg_temp_alternate[i])
4635 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004636 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004637 continue;
4638 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004639 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004640 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004641 data->have_temp |= BIT(i);
4642 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004643 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004644 if (i < num_reg_temp) {
4645 data->reg_temp[1][i] = reg_temp_over[i];
4646 data->reg_temp[2][i] = reg_temp_hyst[i];
4647 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004648 data->temp_src[i] = i + 1;
4649 continue;
4650 }
4651
4652 if (s >= NUM_TEMP) /* Abort if no more space */
4653 break;
4654
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004655 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004656 data->reg_temp[0][s] = reg_temp_alternate[i];
4657 data->temp_src[s] = i + 1;
4658 s++;
4659 }
4660#endif /* USE_ALTERNATE */
4661
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004662 /* Initialize the chip */
4663 nct6775_init_device(data);
4664
Denis Pauk2e7b9882021-09-18 01:02:38 +03004665 err = sio_data->sio_enter(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004666 if (err)
4667 return err;
4668
Denis Pauk2e7b9882021-09-18 01:02:38 +03004669 cr2a = sio_data->sio_inb(sio_data, 0x2a);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004670 switch (data->kind) {
4671 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004672 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004673 break;
4674 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004675 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004676 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004677 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004678 case nct6116:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004679 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004680 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004681 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004682 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004683 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004684 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004685 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004686 case nct6798:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004687 break;
4688 }
4689
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004690 /*
4691 * Read VID value
4692 * We can get the VID input values directly at logical device D 0xe3.
4693 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004694 if (data->have_vid) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03004695 sio_data->sio_select(sio_data, NCT6775_LD_VID);
4696 data->vid = sio_data->sio_inb(sio_data, 0xe3);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004697 data->vrm = vid_which_vrm();
4698 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004699
4700 if (fan_debounce) {
4701 u8 tmp;
4702
Denis Pauk2e7b9882021-09-18 01:02:38 +03004703 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
4704 tmp = sio_data->sio_inb(sio_data,
4705 NCT6775_REG_CR_FAN_DEBOUNCE);
Guenter Roeck47ece962012-12-04 07:59:32 -08004706 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004707 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004708 case nct6116:
Guenter Roeck6c009502012-07-01 08:23:15 -07004709 tmp |= 0xe0;
4710 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004711 case nct6775:
4712 tmp |= 0x1e;
4713 break;
4714 case nct6776:
4715 case nct6779:
4716 tmp |= 0x3e;
4717 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004718 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004719 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004720 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004721 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004722 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004723 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004724 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004725 tmp |= 0x7e;
4726 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004727 }
Denis Pauk2e7b9882021-09-18 01:02:38 +03004728 sio_data->sio_outb(sio_data, NCT6775_REG_CR_FAN_DEBOUNCE,
Guenter Roeck47ece962012-12-04 07:59:32 -08004729 tmp);
4730 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4731 data->name);
4732 }
4733
Denis Pauk2e7b9882021-09-18 01:02:38 +03004734 nct6775_check_fan_inputs(data, sio_data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004735
Denis Pauk2e7b9882021-09-18 01:02:38 +03004736 sio_data->sio_exit(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004737
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004738 /* Read fan clock dividers immediately */
4739 nct6775_init_fan_common(dev, data);
4740
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004741 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004742 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4743 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004744 if (IS_ERR(group))
4745 return PTR_ERR(group);
4746
Axel Lin55bdee62014-07-24 08:59:34 +08004747 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004748
Guenter Roeckf73cf632013-03-18 09:22:50 -07004749 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4750 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004751 if (IS_ERR(group))
4752 return PTR_ERR(group);
4753
Axel Lin55bdee62014-07-24 08:59:34 +08004754 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004755
Guenter Roeckf73cf632013-03-18 09:22:50 -07004756 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4757 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004758 if (IS_ERR(group))
4759 return PTR_ERR(group);
4760
Axel Lin55bdee62014-07-24 08:59:34 +08004761 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004762
Guenter Roeckf73cf632013-03-18 09:22:50 -07004763 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4764 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004765 if (IS_ERR(group))
4766 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004767
Axel Lin55bdee62014-07-24 08:59:34 +08004768 data->groups[num_attr_groups++] = group;
4769 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004770
Guenter Roecka150d952013-07-11 22:55:22 -07004771 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4772 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004773 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004774}
4775
Denis Pauk2e7b9882021-09-18 01:02:38 +03004776static void nct6791_enable_io_mapping(struct nct6775_sio_data *sio_data)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004777{
4778 int val;
4779
Denis Pauk2e7b9882021-09-18 01:02:38 +03004780 val = sio_data->sio_inb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004781 if (val & 0x10) {
4782 pr_info("Enabling hardware monitor logical device mappings.\n");
Denis Pauk2e7b9882021-09-18 01:02:38 +03004783 sio_data->sio_outb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4784 val & ~0x10);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004785 }
4786}
4787
Guenter Roeck48e93182015-02-07 08:48:49 -08004788static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004789{
4790 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004791
4792 mutex_lock(&data->update_lock);
Denis Pauk49140362021-09-18 01:02:39 +03004793 data->vbat = data->read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004794 if (data->kind == nct6775) {
Denis Pauk49140362021-09-18 01:02:39 +03004795 data->fandiv1 = data->read_value(data, NCT6775_REG_FANDIV1);
4796 data->fandiv2 = data->read_value(data, NCT6775_REG_FANDIV2);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004797 }
4798 mutex_unlock(&data->update_lock);
4799
4800 return 0;
4801}
4802
Guenter Roeck48e93182015-02-07 08:48:49 -08004803static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004804{
4805 struct nct6775_data *data = dev_get_drvdata(dev);
Denis Pauk2e7b9882021-09-18 01:02:38 +03004806 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004807 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004808 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004809
4810 mutex_lock(&data->update_lock);
4811 data->bank = 0xff; /* Force initial bank selection */
4812
Denis Pauk2e7b9882021-09-18 01:02:38 +03004813 err = sio_data->sio_enter(sio_data);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004814 if (err)
4815 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004816
Denis Pauk2e7b9882021-09-18 01:02:38 +03004817 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
4818 reg = sio_data->sio_inb(sio_data, SIO_REG_ENABLE);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004819 if (reg != data->sio_reg_enable)
Denis Pauk2e7b9882021-09-18 01:02:38 +03004820 sio_data->sio_outb(sio_data, SIO_REG_ENABLE, data->sio_reg_enable);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004821
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004822 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004823 data->kind == nct6793 || data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004824 data->kind == nct6796 || data->kind == nct6797 ||
4825 data->kind == nct6798)
Denis Pauk2e7b9882021-09-18 01:02:38 +03004826 nct6791_enable_io_mapping(sio_data);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004827
Denis Pauk2e7b9882021-09-18 01:02:38 +03004828 sio_data->sio_exit(sio_data);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004829
Guenter Roeck84d19d92012-12-04 08:01:39 -08004830 /* Restore limits */
4831 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004832 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004833 continue;
4834
Denis Pauk49140362021-09-18 01:02:39 +03004835 data->write_value(data, data->REG_IN_MINMAX[0][i],
4836 data->in[i][1]);
4837 data->write_value(data, data->REG_IN_MINMAX[1][i],
4838 data->in[i][2]);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004839 }
4840
Guenter Roeckc409fd42013-04-09 05:04:00 -07004841 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004842 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004843 continue;
4844
Denis Pauk49140362021-09-18 01:02:39 +03004845 data->write_value(data, data->REG_FAN_MIN[i],
4846 data->fan_min[i]);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004847 }
4848
4849 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004850 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004851 continue;
4852
Guenter Roeckc409fd42013-04-09 05:04:00 -07004853 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004854 if (data->reg_temp[j][i])
4855 nct6775_write_temp(data, data->reg_temp[j][i],
4856 data->temp[j][i]);
4857 }
4858
4859 /* Restore other settings */
Denis Pauk49140362021-09-18 01:02:39 +03004860 data->write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004861 if (data->kind == nct6775) {
Denis Pauk49140362021-09-18 01:02:39 +03004862 data->write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4863 data->write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004864 }
4865
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004866abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004867 /* Force re-reading all values */
4868 data->valid = false;
4869 mutex_unlock(&data->update_lock);
4870
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004871 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004872}
4873
Guenter Roeck48e93182015-02-07 08:48:49 -08004874static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004875
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004876static struct platform_driver nct6775_driver = {
4877 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004878 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004879 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004880 },
4881 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004882};
4883
4884/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004885static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004886{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004887 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004888 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004889 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004890
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004891 sio_data->access = access_direct;
Denis Pauk2e7b9882021-09-18 01:02:38 +03004892 sio_data->sioreg = sioaddr;
4893
4894 err = sio_data->sio_enter(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004895 if (err)
4896 return err;
4897
Denis Pauk2e7b9882021-09-18 01:02:38 +03004898 val = (sio_data->sio_inb(sio_data, SIO_REG_DEVID) << 8) |
4899 sio_data->sio_inb(sio_data, SIO_REG_DEVID + 1);
Guenter Roeckfc72af32016-08-03 22:07:18 -07004900 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004901 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004902
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004903 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004904 case SIO_NCT6106_ID:
4905 sio_data->kind = nct6106;
4906 break;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004907 case SIO_NCT6116_ID:
4908 sio_data->kind = nct6116;
4909 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004910 case SIO_NCT6775_ID:
4911 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004912 break;
4913 case SIO_NCT6776_ID:
4914 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004915 break;
4916 case SIO_NCT6779_ID:
4917 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004918 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004919 case SIO_NCT6791_ID:
4920 sio_data->kind = nct6791;
4921 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004922 case SIO_NCT6792_ID:
4923 sio_data->kind = nct6792;
4924 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004925 case SIO_NCT6793_ID:
4926 sio_data->kind = nct6793;
4927 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004928 case SIO_NCT6795_ID:
4929 sio_data->kind = nct6795;
4930 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004931 case SIO_NCT6796_ID:
4932 sio_data->kind = nct6796;
4933 break;
Guenter Roecke41da282018-09-18 20:48:29 -07004934 case SIO_NCT6797_ID:
4935 sio_data->kind = nct6797;
4936 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004937 case SIO_NCT6798_ID:
4938 sio_data->kind = nct6798;
4939 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004940 default:
4941 if (val != 0xffff)
4942 pr_debug("unsupported chip ID: 0x%04x\n", val);
Denis Pauk2e7b9882021-09-18 01:02:38 +03004943 sio_data->sio_exit(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004944 return -ENODEV;
4945 }
4946
4947 /* We have a known chip, find the HWM I/O address */
Denis Pauk2e7b9882021-09-18 01:02:38 +03004948 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
4949 val = (sio_data->sio_inb(sio_data, SIO_REG_ADDR) << 8)
4950 | sio_data->sio_inb(sio_data, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004951 addr = val & IOREGION_ALIGNMENT;
4952 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004953 pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
Denis Pauk2e7b9882021-09-18 01:02:38 +03004954 sio_data->sio_exit(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004955 return -ENODEV;
4956 }
4957
4958 /* Activate logical device if needed */
Denis Pauk2e7b9882021-09-18 01:02:38 +03004959 val = sio_data->sio_inb(sio_data, SIO_REG_ENABLE);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004960 if (!(val & 0x01)) {
4961 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
Denis Pauk2e7b9882021-09-18 01:02:38 +03004962 sio_data->sio_outb(sio_data, SIO_REG_ENABLE, val | 0x01);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004963 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004964
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004965 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004966 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004967 sio_data->kind == nct6796 || sio_data->kind == nct6797 ||
4968 sio_data->kind == nct6798)
Denis Pauk2e7b9882021-09-18 01:02:38 +03004969 nct6791_enable_io_mapping(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004970
Denis Pauk2e7b9882021-09-18 01:02:38 +03004971 sio_data->sio_exit(sio_data);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004972 pr_info("Found %s or compatible chip at %#x:%#x\n",
4973 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004974
Guenter Roeck698a7c22013-04-05 07:35:25 -07004975 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004976}
4977
4978/*
4979 * when Super-I/O functions move to a separate file, the Super-I/O
4980 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004981 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004982 * must keep track of the device
4983 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004984static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004985
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004986static const char * const asus_wmi_boards[] = {
Denis Paukf4cbba72021-10-25 22:47:48 +03004987 "ProArt X570-CREATOR WIFI",
Oleksandr Natalenko1508fb22021-10-03 15:33:42 +02004988 "Pro WS X570-ACE",
Denis Pauk6e2baac2021-10-03 00:08:54 +03004989 "PRIME B360-PLUS",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004990 "PRIME B460-PLUS",
Denis Pauk6e2baac2021-10-03 00:08:54 +03004991 "PRIME X570-PRO",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004992 "ROG CROSSHAIR VIII DARK HERO",
Denis Pauk6e2baac2021-10-03 00:08:54 +03004993 "ROG CROSSHAIR VIII FORMULA",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004994 "ROG CROSSHAIR VIII HERO",
4995 "ROG CROSSHAIR VIII IMPACT",
Denis Pauk1e7c94b2021-12-11 20:00:36 +02004996 "ROG STRIX B550-A GAMING",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004997 "ROG STRIX B550-E GAMING",
4998 "ROG STRIX B550-F GAMING",
4999 "ROG STRIX B550-F GAMING (WI-FI)",
Denis Pauk6e2baac2021-10-03 00:08:54 +03005000 "ROG STRIX B550-I GAMING",
5001 "ROG STRIX X570-F GAMING",
Denis Pauk1e7c94b2021-12-11 20:00:36 +02005002 "ROG STRIX X570-I GAMING",
Denis Pauk6e2baac2021-10-03 00:08:54 +03005003 "ROG STRIX Z390-E GAMING",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005004 "ROG STRIX Z490-I GAMING",
5005 "TUF GAMING B550M-PLUS",
5006 "TUF GAMING B550M-PLUS (WI-FI)",
5007 "TUF GAMING B550-PLUS",
Denis Pauk6e2baac2021-10-03 00:08:54 +03005008 "TUF GAMING B550-PRO",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005009 "TUF GAMING X570-PLUS",
5010 "TUF GAMING X570-PLUS (WI-FI)",
5011 "TUF GAMING X570-PRO (WI-FI)",
Denis Pauk6e2baac2021-10-03 00:08:54 +03005012 "TUF GAMING Z490-PLUS",
5013 "TUF GAMING Z490-PLUS (WI-FI)",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005014};
5015
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005016static int __init sensors_nct6775_init(void)
5017{
Guenter Roeck698a7c22013-04-05 07:35:25 -07005018 int i, err;
5019 bool found = false;
5020 int address;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005021 struct resource res;
5022 struct nct6775_sio_data sio_data;
Guenter Roeck698a7c22013-04-05 07:35:25 -07005023 int sioaddr[2] = { 0x2e, 0x4e };
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005024 enum sensor_access access = access_direct;
5025 const char *board_vendor, *board_name;
5026 u8 tmp;
Guenter Roeck698a7c22013-04-05 07:35:25 -07005027
5028 err = platform_driver_register(&nct6775_driver);
5029 if (err)
5030 return err;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005031
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005032 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
5033 board_name = dmi_get_system_info(DMI_BOARD_NAME);
5034
5035 if (board_name && board_vendor &&
5036 !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) {
5037 err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards),
5038 board_name);
5039 if (err >= 0) {
5040 /* if reading chip id via WMI succeeds, use WMI */
Denis Pauk20f2e672021-12-18 22:52:06 +02005041 if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005042 pr_info("Using Asus WMI to access %#x chip.\n", tmp);
5043 access = access_asuswmi;
5044 } else {
5045 pr_err("Can't read ChipID by Asus WMI.\n");
5046 }
5047 }
5048 }
5049
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005050 /*
5051 * initialize sio_data->kind and sio_data->sioreg.
5052 *
5053 * when Super-I/O functions move to a separate file, the Super-I/O
5054 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
5055 * nct6775 hardware monitor, and call probe()
5056 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07005057 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03005058 sio_data.sio_outb = superio_outb;
5059 sio_data.sio_inb = superio_inb;
5060 sio_data.sio_select = superio_select;
5061 sio_data.sio_enter = superio_enter;
5062 sio_data.sio_exit = superio_exit;
5063
Guenter Roeck698a7c22013-04-05 07:35:25 -07005064 address = nct6775_find(sioaddr[i], &sio_data);
5065 if (address <= 0)
5066 continue;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005067
Guenter Roeck698a7c22013-04-05 07:35:25 -07005068 found = true;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005069
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005070 sio_data.access = access;
5071
5072 if (access == access_asuswmi) {
5073 sio_data.sio_outb = superio_wmi_outb;
5074 sio_data.sio_inb = superio_wmi_inb;
5075 sio_data.sio_select = superio_wmi_select;
5076 sio_data.sio_enter = superio_wmi_enter;
5077 sio_data.sio_exit = superio_wmi_exit;
5078 }
5079
Guenter Roeck698a7c22013-04-05 07:35:25 -07005080 pdev[i] = platform_device_alloc(DRVNAME, address);
5081 if (!pdev[i]) {
5082 err = -ENOMEM;
Axel Lin9d311ed2014-05-24 23:21:23 +08005083 goto exit_device_unregister;
Guenter Roeck698a7c22013-04-05 07:35:25 -07005084 }
5085
5086 err = platform_device_add_data(pdev[i], &sio_data,
5087 sizeof(struct nct6775_sio_data));
5088 if (err)
5089 goto exit_device_put;
5090
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005091 if (sio_data.access == access_direct) {
5092 memset(&res, 0, sizeof(res));
5093 res.name = DRVNAME;
5094 res.start = address + IOREGION_OFFSET;
5095 res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
5096 res.flags = IORESOURCE_IO;
Guenter Roeck698a7c22013-04-05 07:35:25 -07005097
Denis Pauk3fbbfc22021-09-18 01:02:40 +03005098 err = acpi_check_resource_conflict(&res);
5099 if (err) {
5100 platform_device_put(pdev[i]);
5101 pdev[i] = NULL;
5102 continue;
5103 }
5104
5105 err = platform_device_add_resources(pdev[i], &res, 1);
5106 if (err)
5107 goto exit_device_put;
Guenter Roeck698a7c22013-04-05 07:35:25 -07005108 }
5109
Guenter Roeck698a7c22013-04-05 07:35:25 -07005110 /* platform_device_add calls probe() */
5111 err = platform_device_add(pdev[i]);
5112 if (err)
5113 goto exit_device_put;
5114 }
5115 if (!found) {
5116 err = -ENODEV;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005117 goto exit_unregister;
5118 }
5119
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005120 return 0;
5121
5122exit_device_put:
Axel Lin9d311ed2014-05-24 23:21:23 +08005123 platform_device_put(pdev[i]);
5124exit_device_unregister:
5125 while (--i >= 0) {
Guenter Roeck698a7c22013-04-05 07:35:25 -07005126 if (pdev[i])
Axel Lin9d311ed2014-05-24 23:21:23 +08005127 platform_device_unregister(pdev[i]);
Guenter Roeck698a7c22013-04-05 07:35:25 -07005128 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005129exit_unregister:
5130 platform_driver_unregister(&nct6775_driver);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005131 return err;
5132}
5133
5134static void __exit sensors_nct6775_exit(void)
5135{
Guenter Roeck698a7c22013-04-05 07:35:25 -07005136 int i;
5137
5138 for (i = 0; i < ARRAY_SIZE(pdev); i++) {
5139 if (pdev[i])
5140 platform_device_unregister(pdev[i]);
5141 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005142 platform_driver_unregister(&nct6775_driver);
5143}
5144
5145MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07005146MODULE_DESCRIPTION("Driver for NCT6775F and compatible chips");
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07005147MODULE_LICENSE("GPL");
5148
5149module_init(sensors_nct6775_init);
5150module_exit(sensors_nct6775_exit);