blob: 57ce8633a72561d2e126e868c3aede44e6f7478e [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 Roeckdf612d52013-07-08 13:15:04 -07001178 int sioreg; /* SIO register address */
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
3157 high = fan_from_reg16(data->target_speed[nr],
3158 data->fan_div[nr]) + val;
3159 low = fan_from_reg16(data->target_speed[nr],
3160 data->fan_div[nr]) - val;
3161 if (low <= 0)
3162 low = 1;
3163 if (high < low)
3164 high = low;
3165
3166 val = (fan_to_reg(low, data->fan_div[nr]) -
3167 fan_to_reg(high, data->fan_div[nr])) / 2;
3168
3169 /* Limit tolerance as needed */
3170 val = clamp_val(val, 0, data->speed_tolerance_limit);
3171
3172 mutex_lock(&data->update_lock);
3173 data->target_speed_tolerance[nr] = val;
3174 pwm_update_registers(data, nr);
3175 mutex_unlock(&data->update_lock);
3176 return count;
3177}
3178
Guenter Roeckf73cf632013-03-18 09:22:50 -07003179SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
3180SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
3181 store_pwm_mode, 0);
3182SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
3183 store_pwm_enable, 0);
3184SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
3185 show_pwm_temp_sel, store_pwm_temp_sel, 0);
3186SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
3187 show_target_temp, store_target_temp, 0);
3188SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
3189 show_target_speed, store_target_speed, 0);
3190SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
3191 show_speed_tolerance, store_speed_tolerance, 0);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003192
3193/* Smart Fan registers */
3194
3195static ssize_t
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003196show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
3197{
3198 struct nct6775_data *data = nct6775_update_device(dev);
3199 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3200 int nr = sattr->nr;
3201 int index = sattr->index;
3202
3203 return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
3204}
3205
3206static ssize_t
3207store_weight_temp(struct device *dev, struct device_attribute *attr,
3208 const char *buf, size_t count)
3209{
3210 struct nct6775_data *data = dev_get_drvdata(dev);
3211 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3212 int nr = sattr->nr;
3213 int index = sattr->index;
3214 unsigned long val;
3215 int err;
3216
3217 err = kstrtoul(buf, 10, &val);
3218 if (err < 0)
3219 return err;
3220
3221 val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
3222
3223 mutex_lock(&data->update_lock);
3224 data->weight_temp[index][nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03003225 data->write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003226 mutex_unlock(&data->update_lock);
3227 return count;
3228}
3229
Guenter Roeckf73cf632013-03-18 09:22:50 -07003230SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
3231 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
3232SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
3233 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
3234SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
3235 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
3236SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
3237 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
3238SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
3239 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
3240SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
3241 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08003242
3243static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003244show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
3245{
3246 struct nct6775_data *data = nct6775_update_device(dev);
3247 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3248 int nr = sattr->nr;
3249 int index = sattr->index;
3250
3251 return sprintf(buf, "%d\n",
3252 step_time_from_reg(data->fan_time[index][nr],
3253 data->pwm_mode[nr]));
3254}
3255
3256static ssize_t
3257store_fan_time(struct device *dev, struct device_attribute *attr,
3258 const char *buf, size_t count)
3259{
3260 struct nct6775_data *data = dev_get_drvdata(dev);
3261 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3262 int nr = sattr->nr;
3263 int index = sattr->index;
3264 unsigned long val;
3265 int err;
3266
3267 err = kstrtoul(buf, 10, &val);
3268 if (err < 0)
3269 return err;
3270
3271 val = step_time_to_reg(val, data->pwm_mode[nr]);
3272 mutex_lock(&data->update_lock);
3273 data->fan_time[index][nr] = val;
Denis Pauk49140362021-09-18 01:02:39 +03003274 data->write_value(data, data->REG_FAN_TIME[index][nr], val);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003275 mutex_unlock(&data->update_lock);
3276 return count;
3277}
3278
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003279static ssize_t
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003280show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
3281{
3282 struct nct6775_data *data = nct6775_update_device(dev);
3283 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3284
3285 return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
3286}
3287
3288static ssize_t
3289store_auto_pwm(struct device *dev, struct device_attribute *attr,
3290 const char *buf, size_t count)
3291{
3292 struct nct6775_data *data = dev_get_drvdata(dev);
3293 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3294 int nr = sattr->nr;
3295 int point = sattr->index;
3296 unsigned long val;
3297 int err;
3298 u8 reg;
3299
3300 err = kstrtoul(buf, 10, &val);
3301 if (err < 0)
3302 return err;
3303 if (val > 255)
3304 return -EINVAL;
3305
3306 if (point == data->auto_pwm_num) {
3307 if (data->kind != nct6775 && !val)
3308 return -EINVAL;
3309 if (data->kind != nct6779 && val)
3310 val = 0xff;
3311 }
3312
3313 mutex_lock(&data->update_lock);
3314 data->auto_pwm[nr][point] = val;
3315 if (point < data->auto_pwm_num) {
Denis Pauk49140362021-09-18 01:02:39 +03003316 data->write_value(data,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003317 NCT6775_AUTO_PWM(data, nr, point),
3318 data->auto_pwm[nr][point]);
3319 } else {
3320 switch (data->kind) {
3321 case nct6775:
3322 /* disable if needed (pwm == 0) */
Denis Pauk49140362021-09-18 01:02:39 +03003323 reg = data->read_value(data,
3324 NCT6775_REG_CRITICAL_ENAB[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003325 if (val)
3326 reg |= 0x02;
3327 else
3328 reg &= ~0x02;
Denis Pauk49140362021-09-18 01:02:39 +03003329 data->write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
3330 reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003331 break;
3332 case nct6776:
3333 break; /* always enabled, nothing to do */
Guenter Roeck6c009502012-07-01 08:23:15 -07003334 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003335 case nct6116:
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003336 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07003337 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08003338 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07003339 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07003340 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08003341 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07003342 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07003343 case nct6798:
Denis Pauk49140362021-09-18 01:02:39 +03003344 data->write_value(data, data->REG_CRITICAL_PWM[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003345 val);
Denis Pauk49140362021-09-18 01:02:39 +03003346 reg = data->read_value(data,
Guenter Roeck6c009502012-07-01 08:23:15 -07003347 data->REG_CRITICAL_PWM_ENABLE[nr]);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003348 if (val == 255)
Guenter Roeck6c009502012-07-01 08:23:15 -07003349 reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003350 else
Guenter Roeck6c009502012-07-01 08:23:15 -07003351 reg |= data->CRITICAL_PWM_ENABLE_MASK;
Denis Pauk49140362021-09-18 01:02:39 +03003352 data->write_value(data,
3353 data->REG_CRITICAL_PWM_ENABLE[nr],
3354 reg);
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003355 break;
3356 }
3357 }
3358 mutex_unlock(&data->update_lock);
3359 return count;
3360}
3361
3362static ssize_t
3363show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
3364{
3365 struct nct6775_data *data = nct6775_update_device(dev);
3366 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3367 int nr = sattr->nr;
3368 int point = sattr->index;
3369
3370 /*
3371 * We don't know for sure if the temperature is signed or unsigned.
3372 * Assume it is unsigned.
3373 */
3374 return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
3375}
3376
3377static ssize_t
3378store_auto_temp(struct device *dev, struct device_attribute *attr,
3379 const char *buf, size_t count)
3380{
3381 struct nct6775_data *data = dev_get_drvdata(dev);
3382 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
3383 int nr = sattr->nr;
3384 int point = sattr->index;
3385 unsigned long val;
3386 int err;
3387
3388 err = kstrtoul(buf, 10, &val);
3389 if (err)
3390 return err;
3391 if (val > 255000)
3392 return -EINVAL;
3393
3394 mutex_lock(&data->update_lock);
3395 data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
3396 if (point < data->auto_pwm_num) {
Denis Pauk49140362021-09-18 01:02:39 +03003397 data->write_value(data,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003398 NCT6775_AUTO_TEMP(data, nr, point),
3399 data->auto_temp[nr][point]);
3400 } else {
Denis Pauk49140362021-09-18 01:02:39 +03003401 data->write_value(data, data->REG_CRITICAL_TEMP[nr],
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003402 data->auto_temp[nr][point]);
3403 }
3404 mutex_unlock(&data->update_lock);
3405 return count;
3406}
3407
Guenter Roeckf73cf632013-03-18 09:22:50 -07003408static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
3409 struct attribute *attr, int index)
3410{
zhouchuangao036855a2020-05-11 11:43:06 +08003411 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003412 struct nct6775_data *data = dev_get_drvdata(dev);
3413 int pwm = index / 36; /* pwm index */
3414 int nr = index % 36; /* attribute index */
3415
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003416 if (!(data->has_pwm & BIT(pwm)))
Guenter Roeckf73cf632013-03-18 09:22:50 -07003417 return 0;
3418
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003419 if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
3420 if (!data->REG_WEIGHT_TEMP_SEL[pwm])
3421 return 0;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003422 if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
3423 return 0;
3424 if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
3425 return 0;
3426 if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
3427 return 0;
3428
3429 if (nr >= 22 && nr <= 35) { /* auto point */
3430 int api = (nr - 22) / 2; /* auto point index */
3431
3432 if (api > data->auto_pwm_num)
3433 return 0;
3434 }
3435 return attr->mode;
3436}
3437
3438SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
3439 show_fan_time, store_fan_time, 0, 0);
3440SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
3441 show_fan_time, store_fan_time, 0, 1);
3442SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
3443 show_fan_time, store_fan_time, 0, 2);
3444SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
3445 store_pwm, 0, 1);
3446SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
3447 store_pwm, 0, 2);
3448SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
3449 show_temp_tolerance, store_temp_tolerance, 0, 0);
3450SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
3451 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
3452 0, 1);
3453
3454SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
3455 0, 3);
3456
3457SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
3458 store_pwm, 0, 4);
3459
3460SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
3461 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
3462SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
3463 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
3464
3465SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
3466 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
3467SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
3468 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
3469
3470SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
3471 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
3472SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
3473 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
3474
3475SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
3476 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
3477SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
3478 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
3479
3480SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
3481 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
3482SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
3483 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
3484
3485SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
3486 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
3487SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
3488 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
3489
3490SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
3491 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
3492SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
3493 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
3494
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003495/*
Guenter Roeckf73cf632013-03-18 09:22:50 -07003496 * nct6775_pwm_is_visible uses the index into the following array
3497 * to determine if attributes should be created or not.
3498 * Any change in order or content must be matched.
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003499 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003500static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
3501 &sensor_dev_template_pwm,
3502 &sensor_dev_template_pwm_mode,
3503 &sensor_dev_template_pwm_enable,
3504 &sensor_dev_template_pwm_temp_sel,
3505 &sensor_dev_template_pwm_temp_tolerance,
3506 &sensor_dev_template_pwm_crit_temp_tolerance,
3507 &sensor_dev_template_pwm_target_temp,
3508 &sensor_dev_template_fan_target,
3509 &sensor_dev_template_fan_tolerance,
3510 &sensor_dev_template_pwm_stop_time,
3511 &sensor_dev_template_pwm_step_up_time,
3512 &sensor_dev_template_pwm_step_down_time,
3513 &sensor_dev_template_pwm_start,
3514 &sensor_dev_template_pwm_floor,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003515 &sensor_dev_template_pwm_weight_temp_sel, /* 14 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003516 &sensor_dev_template_pwm_weight_temp_step,
3517 &sensor_dev_template_pwm_weight_temp_step_tol,
3518 &sensor_dev_template_pwm_weight_temp_step_base,
Guenter Roeckcc76dee2013-11-13 12:47:17 -08003519 &sensor_dev_template_pwm_weight_duty_step, /* 18 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003520 &sensor_dev_template_pwm_max, /* 19 */
3521 &sensor_dev_template_pwm_step, /* 20 */
3522 &sensor_dev_template_pwm_weight_duty_base, /* 21 */
3523 &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
3524 &sensor_dev_template_pwm_auto_point1_temp,
3525 &sensor_dev_template_pwm_auto_point2_pwm,
3526 &sensor_dev_template_pwm_auto_point2_temp,
3527 &sensor_dev_template_pwm_auto_point3_pwm,
3528 &sensor_dev_template_pwm_auto_point3_temp,
3529 &sensor_dev_template_pwm_auto_point4_pwm,
3530 &sensor_dev_template_pwm_auto_point4_temp,
3531 &sensor_dev_template_pwm_auto_point5_pwm,
3532 &sensor_dev_template_pwm_auto_point5_temp,
3533 &sensor_dev_template_pwm_auto_point6_pwm,
3534 &sensor_dev_template_pwm_auto_point6_temp,
3535 &sensor_dev_template_pwm_auto_point7_pwm,
3536 &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003537
Guenter Roeckf73cf632013-03-18 09:22:50 -07003538 NULL
3539};
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003540
Julia Lawallc60fdf82015-12-12 17:36:39 +01003541static const struct sensor_template_group nct6775_pwm_template_group = {
Guenter Roeckf73cf632013-03-18 09:22:50 -07003542 .templates = nct6775_attributes_pwm_template,
3543 .is_visible = nct6775_pwm_is_visible,
3544 .base = 1,
Guenter Roeckcdcaece2012-12-04 09:04:52 -08003545};
3546
3547static ssize_t
Julia Lawall93d72ac2016-12-22 13:05:23 +01003548cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003549{
3550 struct nct6775_data *data = dev_get_drvdata(dev);
Guenter Roeck9cd892b2014-11-16 10:00:06 -08003551
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003552 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
3553}
3554
Julia Lawall93d72ac2016-12-22 13:05:23 +01003555static DEVICE_ATTR_RO(cpu0_vid);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003556
Guenter Roecka6bd5872012-12-04 03:13:34 -08003557/* Case open detection */
3558
3559static ssize_t
3560clear_caseopen(struct device *dev, struct device_attribute *attr,
3561 const char *buf, size_t count)
3562{
3563 struct nct6775_data *data = dev_get_drvdata(dev);
Denis Pauk2e7b9882021-09-18 01:02:38 +03003564 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003565 int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
3566 unsigned long val;
3567 u8 reg;
3568 int ret;
3569
3570 if (kstrtoul(buf, 10, &val) || val != 0)
3571 return -EINVAL;
3572
3573 mutex_lock(&data->update_lock);
3574
3575 /*
3576 * Use CR registers to clear caseopen status.
3577 * The CR registers are the same for all chips, and not all chips
3578 * support clearing the caseopen status through "regular" registers.
3579 */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003580 ret = sio_data->sio_enter(sio_data);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003581 if (ret) {
3582 count = ret;
3583 goto error;
3584 }
3585
Denis Pauk2e7b9882021-09-18 01:02:38 +03003586 sio_data->sio_select(sio_data, NCT6775_LD_ACPI);
3587 reg = sio_data->sio_inb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
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);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003590 reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
Denis Pauk2e7b9882021-09-18 01:02:38 +03003591 sio_data->sio_outb(sio_data, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
3592 sio_data->sio_exit(sio_data);
Guenter Roecka6bd5872012-12-04 03:13:34 -08003593
3594 data->valid = false; /* Force cache refresh */
3595error:
3596 mutex_unlock(&data->update_lock);
3597 return count;
3598}
3599
Guenter Roeckf73cf632013-03-18 09:22:50 -07003600static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
3601 clear_caseopen, INTRUSION_ALARM_BASE);
3602static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
3603 clear_caseopen, INTRUSION_ALARM_BASE + 1);
Guenter Roeck30846992013-06-24 22:21:59 -07003604static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
3605 store_beep, INTRUSION_ALARM_BASE);
3606static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
3607 store_beep, INTRUSION_ALARM_BASE + 1);
3608static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
3609 store_beep, BEEP_ENABLE_BASE);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003610
3611static umode_t nct6775_other_is_visible(struct kobject *kobj,
3612 struct attribute *attr, int index)
3613{
zhouchuangao036855a2020-05-11 11:43:06 +08003614 struct device *dev = kobj_to_dev(kobj);
Guenter Roeckf73cf632013-03-18 09:22:50 -07003615 struct nct6775_data *data = dev_get_drvdata(dev);
3616
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003617 if (index == 0 && !data->have_vid)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003618 return 0;
3619
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003620 if (index == 1 || index == 2) {
3621 if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0)
Guenter Roeckf73cf632013-03-18 09:22:50 -07003622 return 0;
3623 }
3624
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003625 if (index == 3 || index == 4) {
3626 if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
Guenter Roeck30846992013-06-24 22:21:59 -07003627 return 0;
3628 }
3629
Guenter Roeckf73cf632013-03-18 09:22:50 -07003630 return attr->mode;
3631}
3632
3633/*
3634 * nct6775_other_is_visible uses the index into the following array
3635 * to determine if attributes should be created or not.
3636 * Any change in order or content must be matched.
3637 */
3638static struct attribute *nct6775_attributes_other[] = {
Guenter Roeck615fc8c2013-07-06 09:43:30 -07003639 &dev_attr_cpu0_vid.attr, /* 0 */
3640 &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */
3641 &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */
3642 &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */
3643 &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */
3644 &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07003645
3646 NULL
3647};
3648
3649static const struct attribute_group nct6775_group_other = {
3650 .attrs = nct6775_attributes_other,
3651 .is_visible = nct6775_other_is_visible,
Guenter Roecka6bd5872012-12-04 03:13:34 -08003652};
3653
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003654static inline void nct6775_init_device(struct nct6775_data *data)
3655{
Guenter Roeckaa136e52012-12-04 03:26:05 -08003656 int i;
3657 u8 tmp, diode;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003658
3659 /* Start monitoring if needed */
3660 if (data->REG_CONFIG) {
Denis Pauk49140362021-09-18 01:02:39 +03003661 tmp = data->read_value(data, data->REG_CONFIG);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003662 if (!(tmp & 0x01))
Denis Pauk49140362021-09-18 01:02:39 +03003663 data->write_value(data, data->REG_CONFIG, tmp | 0x01);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003664 }
3665
Guenter Roeckaa136e52012-12-04 03:26:05 -08003666 /* Enable temperature sensors if needed */
3667 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003668 if (!(data->have_temp & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003669 continue;
3670 if (!data->reg_temp_config[i])
3671 continue;
Denis Pauk49140362021-09-18 01:02:39 +03003672 tmp = data->read_value(data, data->reg_temp_config[i]);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003673 if (tmp & 0x01)
Denis Pauk49140362021-09-18 01:02:39 +03003674 data->write_value(data, data->reg_temp_config[i],
Guenter Roeckaa136e52012-12-04 03:26:05 -08003675 tmp & 0xfe);
3676 }
3677
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003678 /* Enable VBAT monitoring if needed */
Denis Pauk49140362021-09-18 01:02:39 +03003679 tmp = data->read_value(data, data->REG_VBAT);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003680 if (!(tmp & 0x01))
Denis Pauk49140362021-09-18 01:02:39 +03003681 data->write_value(data, data->REG_VBAT, tmp | 0x01);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003682
Denis Pauk49140362021-09-18 01:02:39 +03003683 diode = data->read_value(data, data->REG_DIODE);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003684
3685 for (i = 0; i < data->temp_fixed_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003686 if (!(data->have_temp_fixed & BIT(i)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08003687 continue;
Guenter Roeck6c009502012-07-01 08:23:15 -07003688 if ((tmp & (data->DIODE_MASK << i))) /* diode */
3689 data->temp_type[i]
3690 = 3 - ((diode >> i) & data->DIODE_MASK);
Guenter Roeckaa136e52012-12-04 03:26:05 -08003691 else /* thermistor */
3692 data->temp_type[i] = 4;
3693 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003694}
3695
Guenter Roeckf73cf632013-03-18 09:22:50 -07003696static void
Denis Pauk2e7b9882021-09-18 01:02:38 +03003697nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio_data)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003698{
Guenter Roeck1b206242018-02-21 13:09:38 -08003699 bool fan3pin = false, fan4pin = false, fan4min = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003700 bool fan5pin = false, fan6pin = false, fan7pin = false;
Guenter Roeck1b206242018-02-21 13:09:38 -08003701 bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
Guenter Roeck81820052018-02-21 13:09:39 -08003702 bool pwm6pin = false, pwm7pin = false;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003703
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003704 /* Store SIO_REG_ENABLE for use during resume */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003705 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
3706 data->sio_reg_enable = sio_data->sio_inb(sio_data, SIO_REG_ENABLE);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003707
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003708 /* fan4 and fan5 share some pins with the GPIO and serial flash */
3709 if (data->kind == nct6775) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003710 int cr2c = sio_data->sio_inb(sio_data, 0x2c);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003711
Guenter Roecka6c54f22018-09-18 09:34:06 -07003712 fan3pin = cr2c & BIT(6);
3713 pwm3pin = cr2c & BIT(7);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003714
3715 /* On NCT6775, fan4 shares pins with the fdc interface */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003716 fan4pin = !(sio_data->sio_inb(sio_data, 0x2A) & 0x80);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003717 } else if (data->kind == nct6776) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003718 bool gpok = sio_data->sio_inb(sio_data, 0x27) & 0x80;
Guenter Roeck25cdd992015-02-06 18:55:36 -08003719 const char *board_vendor, *board_name;
3720
3721 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
3722 board_name = dmi_get_system_info(DMI_BOARD_NAME);
3723
3724 if (board_name && board_vendor &&
3725 !strcmp(board_vendor, "ASRock")) {
3726 /*
3727 * Auxiliary fan monitoring is not enabled on ASRock
3728 * Z77 Pro4-M if booted in UEFI Ultra-FastBoot mode.
3729 * Observed with BIOS version 2.00.
3730 */
3731 if (!strcmp(board_name, "Z77 Pro4-M")) {
3732 if ((data->sio_reg_enable & 0xe0) != 0xe0) {
3733 data->sio_reg_enable |= 0xe0;
Denis Pauk2e7b9882021-09-18 01:02:38 +03003734 sio_data->sio_outb(sio_data, SIO_REG_ENABLE,
Guenter Roeck25cdd992015-02-06 18:55:36 -08003735 data->sio_reg_enable);
3736 }
3737 }
3738 }
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003739
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003740 if (data->sio_reg_enable & 0x80)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003741 fan3pin = gpok;
3742 else
Denis Pauk2e7b9882021-09-18 01:02:38 +03003743 fan3pin = !(sio_data->sio_inb(sio_data, 0x24) & 0x40);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003744
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003745 if (data->sio_reg_enable & 0x40)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003746 fan4pin = gpok;
3747 else
Denis Pauk2e7b9882021-09-18 01:02:38 +03003748 fan4pin = sio_data->sio_inb(sio_data, 0x1C) & 0x01;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003749
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08003750 if (data->sio_reg_enable & 0x20)
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003751 fan5pin = gpok;
3752 else
Denis Pauk2e7b9882021-09-18 01:02:38 +03003753 fan5pin = sio_data->sio_inb(sio_data, 0x1C) & 0x02;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003754
3755 fan4min = fan4pin;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003756 pwm3pin = fan3pin;
Guenter Roeck6c009502012-07-01 08:23:15 -07003757 } else if (data->kind == nct6106) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003758 int cr24 = sio_data->sio_inb(sio_data, 0x24);
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003759
Guenter Roecka6c54f22018-09-18 09:34:06 -07003760 fan3pin = !(cr24 & 0x80);
3761 pwm3pin = cr24 & 0x08;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003762 } else if (data->kind == nct6116) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03003763 int cr1a = sio_data->sio_inb(sio_data, 0x1a);
3764 int cr1b = sio_data->sio_inb(sio_data, 0x1b);
3765 int cr24 = sio_data->sio_inb(sio_data, 0x24);
3766 int cr2a = sio_data->sio_inb(sio_data, 0x2a);
3767 int cr2b = sio_data->sio_inb(sio_data, 0x2b);
3768 int cr2f = sio_data->sio_inb(sio_data, 0x2f);
Björn Gerhart29c7cb42019-07-23 18:06:46 +02003769
3770 fan3pin = !(cr2b & 0x10);
3771 fan4pin = (cr2b & 0x80) || // pin 1(2)
3772 (!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66)
3773 fan5pin = (cr2b & 0x80) || // pin 126(127)
3774 (!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96)
3775
3776 pwm3pin = fan3pin && (cr24 & 0x08);
3777 pwm4pin = fan4pin;
3778 pwm5pin = fan5pin;
Guenter Roeck81820052018-02-21 13:09:39 -08003779 } else {
Guenter Roecke41da282018-09-18 20:48:29 -07003780 /*
3781 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
Guenter Roeck05996822018-09-19 20:26:16 -07003782 * NCT6797D, NCT6798D
Guenter Roecke41da282018-09-18 20:48:29 -07003783 */
Denis Pauk2e7b9882021-09-18 01:02:38 +03003784 int cr1a = sio_data->sio_inb(sio_data, 0x1a);
3785 int cr1b = sio_data->sio_inb(sio_data, 0x1b);
3786 int cr1c = sio_data->sio_inb(sio_data, 0x1c);
3787 int cr1d = sio_data->sio_inb(sio_data, 0x1d);
3788 int cr2a = sio_data->sio_inb(sio_data, 0x2a);
3789 int cr2b = sio_data->sio_inb(sio_data, 0x2b);
3790 int cr2d = sio_data->sio_inb(sio_data, 0x2d);
3791 int cr2f = sio_data->sio_inb(sio_data, 0x2f);
Guenter Roeck97ce6df2018-09-18 09:46:24 -07003792 bool dsw_en = cr2f & BIT(3);
Guenter Roecke41da282018-09-18 20:48:29 -07003793 bool ddr4_en = cr2f & BIT(4);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003794 int cre0;
Guenter Roeck2d888c52018-09-18 09:49:29 -07003795 int creb;
3796 int cred;
3797
Denis Pauk2e7b9882021-09-18 01:02:38 +03003798 sio_data->sio_select(sio_data, NCT6775_LD_12);
3799 cre0 = sio_data->sio_inb(sio_data, 0xe0);
3800 creb = sio_data->sio_inb(sio_data, 0xeb);
3801 cred = sio_data->sio_inb(sio_data, 0xed);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003802
Guenter Roecka6c54f22018-09-18 09:34:06 -07003803 fan3pin = !(cr1c & BIT(5));
3804 fan4pin = !(cr1c & BIT(6));
3805 fan5pin = !(cr1c & BIT(7));
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003806
Guenter Roecka6c54f22018-09-18 09:34:06 -07003807 pwm3pin = !(cr1c & BIT(0));
3808 pwm4pin = !(cr1c & BIT(1));
3809 pwm5pin = !(cr1c & BIT(2));
Guenter Roeck77eb5b32012-12-04 08:30:54 -08003810
Guenter Roecke5c85222017-05-17 18:09:41 -07003811 switch (data->kind) {
3812 case nct6791:
Guenter Roecka6c54f22018-09-18 09:34:06 -07003813 fan6pin = cr2d & BIT(1);
3814 pwm6pin = cr2d & BIT(0);
Guenter Roecke5c85222017-05-17 18:09:41 -07003815 break;
Guenter Roeck7dcdbde2018-09-18 10:52:55 -07003816 case nct6792:
3817 fan6pin = !dsw_en && (cr2d & BIT(1));
3818 pwm6pin = !dsw_en && (cr2d & BIT(0));
3819 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003820 case nct6793:
Guenter Roeck2d999252018-09-18 11:03:25 -07003821 fan5pin |= cr1b & BIT(5);
3822 fan5pin |= creb & BIT(5);
3823
Guenter Roeck2a2ec4a2019-01-27 16:08:00 -08003824 fan6pin = !dsw_en && (cr2d & BIT(1));
3825 fan6pin |= creb & BIT(3);
Guenter Roeck2d999252018-09-18 11:03:25 -07003826
3827 pwm5pin |= cr2d & BIT(7);
3828 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3829
3830 pwm6pin = !dsw_en && (cr2d & BIT(0));
3831 pwm6pin |= creb & BIT(2);
3832 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07003833 case nct6795:
Guenter Roeckb75a8062018-09-18 11:18:30 -07003834 fan5pin |= cr1b & BIT(5);
3835 fan5pin |= creb & BIT(5);
3836
3837 fan6pin = (cr2a & BIT(4)) &&
3838 (!dsw_en || (cred & BIT(4)));
3839 fan6pin |= creb & BIT(3);
3840
3841 pwm5pin |= cr2d & BIT(7);
3842 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3843
3844 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3845 pwm6pin |= creb & BIT(2);
3846 break;
Guenter Roeck81820052018-02-21 13:09:39 -08003847 case nct6796:
Guenter Roecka4e0a082018-09-18 09:53:06 -07003848 fan5pin |= cr1b & BIT(5);
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003849 fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
3850 fan5pin |= creb & BIT(5);
Guenter Roecke5c85222017-05-17 18:09:41 -07003851
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003852 fan6pin = (cr2a & BIT(4)) &&
Guenter Roeck2d999252018-09-18 11:03:25 -07003853 (!dsw_en || (cred & BIT(4)));
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003854 fan6pin |= creb & BIT(3);
Guenter Roeck81820052018-02-21 13:09:39 -08003855
Guenter Roeckb75a8062018-09-18 11:18:30 -07003856 fan7pin = !(cr2b & BIT(2));
Guenter Roeck81820052018-02-21 13:09:39 -08003857
Guenter Roeck3fdb06a2018-09-18 20:21:40 -07003858 pwm5pin |= cr2d & BIT(7);
3859 pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
3860 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3861
3862 pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
3863 pwm6pin |= creb & BIT(2);
3864
3865 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
Guenter Roecke5c85222017-05-17 18:09:41 -07003866 break;
Guenter Roecke41da282018-09-18 20:48:29 -07003867 case nct6797:
3868 fan5pin |= !ddr4_en && (cr1b & BIT(5));
3869 fan5pin |= creb & BIT(5);
3870
3871 fan6pin = cr2a & BIT(4);
3872 fan6pin |= creb & BIT(3);
3873
3874 fan7pin = cr1a & BIT(1);
3875
3876 pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3877 pwm5pin |= !ddr4_en && (cr2d & BIT(7));
3878
3879 pwm6pin = creb & BIT(2);
3880 pwm6pin |= cred & BIT(2);
3881
3882 pwm7pin = cr1d & BIT(4);
3883 break;
Guenter Roeck05996822018-09-19 20:26:16 -07003884 case nct6798:
3885 fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
3886 fan6pin |= cr2a & BIT(4);
3887 fan6pin |= creb & BIT(5);
3888
3889 fan7pin = cr1b & BIT(5);
3890 fan7pin |= !(cr2b & BIT(2));
3891 fan7pin |= creb & BIT(3);
3892
3893 pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
3894 pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3));
3895 pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
3896
3897 pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
3898 pwm7pin |= cr2d & BIT(7);
3899 pwm7pin |= creb & BIT(2);
3900 break;
Guenter Roecke5c85222017-05-17 18:09:41 -07003901 default: /* NCT6779D */
Guenter Roecke5c85222017-05-17 18:09:41 -07003902 break;
David Bartley578ab5f2013-06-24 22:28:28 -07003903 }
Guenter Roecke5c85222017-05-17 18:09:41 -07003904
3905 fan4min = fan4pin;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003906 }
3907
David Bartley578ab5f2013-06-24 22:28:28 -07003908 /* fan 1 and 2 (0x03) are always present */
3909 data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 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_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003912 (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
David Bartley578ab5f2013-06-24 22:28:28 -07003913 data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
Guenter Roeck81820052018-02-21 13:09:39 -08003914 (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08003915}
3916
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003917static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
3918 int *available, int *mask)
3919{
3920 int i;
3921 u8 src;
3922
3923 for (i = 0; i < data->pwm_num && *available; i++) {
3924 int index;
3925
3926 if (!regp[i])
3927 continue;
Denis Pauk49140362021-09-18 01:02:39 +03003928 src = data->read_value(data, regp[i]);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003929 src &= 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003930 if (!src || (*mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003931 continue;
Guenter Roeckcc66b302017-05-17 18:05:06 -07003932 if (!(data->temp_mask & BIT(src)))
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003933 continue;
3934
3935 index = __ffs(*available);
Denis Pauk49140362021-09-18 01:02:39 +03003936 data->write_value(data, data->REG_TEMP_SOURCE[index], src);
Guenter Roeckd1bb21862017-05-17 18:40:10 -07003937 *available &= ~BIT(index);
3938 *mask |= BIT(src);
Guenter Roeck8e9285b2012-12-04 08:03:37 -08003939 }
3940}
3941
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003942static int nct6775_probe(struct platform_device *pdev)
3943{
3944 struct device *dev = &pdev->dev;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09003945 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003946 struct nct6775_data *data;
3947 struct resource *res;
Guenter Roeckaa136e52012-12-04 03:26:05 -08003948 int i, s, err = 0;
3949 int src, mask, available;
3950 const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003951 const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
Guenter Roeckb7a61352013-04-02 22:14:06 -07003952 const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08003953 int num_reg_temp, num_reg_temp_mon;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08003954 u8 cr2a;
Guenter Roeckf73cf632013-03-18 09:22:50 -07003955 struct attribute_group *group;
Guenter Roecka150d952013-07-11 22:55:22 -07003956 struct device *hwmon_dev;
Axel Lin55bdee62014-07-24 08:59:34 +08003957 int num_attr_groups = 0;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003958
Denis Pauk3fbbfc22021-09-18 01:02:40 +03003959 if (sio_data->access == access_direct) {
3960 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
3961 if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
3962 DRVNAME))
3963 return -EBUSY;
3964 }
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003965
3966 data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
3967 GFP_KERNEL);
3968 if (!data)
3969 return -ENOMEM;
3970
3971 data->kind = sio_data->kind;
Guenter Roeckdf612d52013-07-08 13:15:04 -07003972 data->sioreg = sio_data->sioreg;
Denis Pauk3fbbfc22021-09-18 01:02:40 +03003973
3974 if (sio_data->access == access_direct) {
3975 data->addr = res->start;
3976 data->read_value = nct6775_read_value;
3977 data->write_value = nct6775_write_value;
3978 } else {
3979 data->read_value = nct6775_wmi_read_value;
3980 data->write_value = nct6775_wmi_write_value;
3981 }
3982
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07003983 mutex_init(&data->update_lock);
3984 data->name = nct6775_device_names[data->kind];
3985 data->bank = 0xff; /* Force initial bank selection */
3986 platform_set_drvdata(pdev, data);
3987
3988 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07003989 case nct6106:
3990 data->in_num = 9;
3991 data->pwm_num = 3;
3992 data->auto_pwm_num = 4;
3993 data->temp_fixed_num = 3;
3994 data->num_temp_alarms = 6;
Guenter Roeck30846992013-06-24 22:21:59 -07003995 data->num_temp_beeps = 6;
Guenter Roeck6c009502012-07-01 08:23:15 -07003996
3997 data->fan_from_reg = fan_from_reg13;
3998 data->fan_from_reg_min = fan_from_reg13;
3999
4000 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004001 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004002 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeck6c009502012-07-01 08:23:15 -07004003
4004 data->REG_VBAT = NCT6106_REG_VBAT;
4005 data->REG_DIODE = NCT6106_REG_DIODE;
4006 data->DIODE_MASK = NCT6106_DIODE_MASK;
4007 data->REG_VIN = NCT6106_REG_IN;
4008 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
4009 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
4010 data->REG_TARGET = NCT6106_REG_TARGET;
4011 data->REG_FAN = NCT6106_REG_FAN;
4012 data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
4013 data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
4014 data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
4015 data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
4016 data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
4017 data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
4018 data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
Björn Gerhartf3d43e22019-07-15 18:33:55 +02004019 data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004020 data->REG_PWM[0] = NCT6116_REG_PWM;
Guenter Roeck6c009502012-07-01 08:23:15 -07004021 data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
4022 data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
4023 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
4024 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
4025 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
4026 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
4027 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
4028 data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
4029 data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
4030 data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
4031 data->REG_CRITICAL_TEMP_TOLERANCE
4032 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
4033 data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
4034 data->CRITICAL_PWM_ENABLE_MASK
4035 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
4036 data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
4037 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
4038 data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004039 data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
Guenter Roeck6c009502012-07-01 08:23:15 -07004040 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
4041 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
4042 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
4043 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
4044 data->REG_ALARM = NCT6106_REG_ALARM;
4045 data->ALARM_BITS = NCT6106_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004046 data->REG_BEEP = NCT6106_REG_BEEP;
4047 data->BEEP_BITS = NCT6106_BEEP_BITS;
Guenter Roeck6c009502012-07-01 08:23:15 -07004048
4049 reg_temp = NCT6106_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004050 reg_temp_mon = NCT6106_REG_TEMP_MON;
Guenter Roeck6c009502012-07-01 08:23:15 -07004051 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004052 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
Guenter Roeck6c009502012-07-01 08:23:15 -07004053 reg_temp_over = NCT6106_REG_TEMP_OVER;
4054 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
4055 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
4056 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
4057 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
Guenter Roeckb7a61352013-04-02 22:14:06 -07004058 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
4059 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
Guenter Roeck6c009502012-07-01 08:23:15 -07004060
4061 break;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004062 case nct6116:
4063 data->in_num = 9;
4064 data->pwm_num = 3;
4065 data->auto_pwm_num = 4;
4066 data->temp_fixed_num = 3;
4067 data->num_temp_alarms = 3;
4068 data->num_temp_beeps = 3;
4069
4070 data->fan_from_reg = fan_from_reg13;
4071 data->fan_from_reg_min = fan_from_reg13;
4072
4073 data->temp_label = nct6776_temp_label;
4074 data->temp_mask = NCT6776_TEMP_MASK;
4075 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
4076
4077 data->REG_VBAT = NCT6106_REG_VBAT;
4078 data->REG_DIODE = NCT6106_REG_DIODE;
4079 data->DIODE_MASK = NCT6106_DIODE_MASK;
4080 data->REG_VIN = NCT6106_REG_IN;
4081 data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
4082 data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
4083 data->REG_TARGET = NCT6116_REG_TARGET;
4084 data->REG_FAN = NCT6116_REG_FAN;
4085 data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
4086 data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
4087 data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
4088 data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
4089 data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
4090 data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
4091 data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
4092 data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
4093 data->REG_PWM[0] = NCT6116_REG_PWM;
4094 data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
4095 data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
4096 data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
4097 data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
4098 data->REG_PWM_READ = NCT6106_REG_PWM_READ;
4099 data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
4100 data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
4101 data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
4102 data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
4103 data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
4104 data->REG_CRITICAL_TEMP_TOLERANCE
4105 = NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
4106 data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
4107 data->CRITICAL_PWM_ENABLE_MASK
4108 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
4109 data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
4110 data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
4111 data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
4112 data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
4113 data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
4114 data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
4115 data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
4116 data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
4117 data->REG_ALARM = NCT6106_REG_ALARM;
4118 data->ALARM_BITS = NCT6116_ALARM_BITS;
4119 data->REG_BEEP = NCT6106_REG_BEEP;
4120 data->BEEP_BITS = NCT6116_BEEP_BITS;
4121
4122 reg_temp = NCT6106_REG_TEMP;
4123 reg_temp_mon = NCT6106_REG_TEMP_MON;
4124 num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
4125 num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
4126 reg_temp_over = NCT6106_REG_TEMP_OVER;
4127 reg_temp_hyst = NCT6106_REG_TEMP_HYST;
4128 reg_temp_config = NCT6106_REG_TEMP_CONFIG;
4129 reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
4130 reg_temp_crit = NCT6106_REG_TEMP_CRIT;
4131 reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
4132 reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
4133
4134 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004135 case nct6775:
4136 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004137 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004138 data->auto_pwm_num = 6;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004139 data->has_fan_div = true;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004140 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004141 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07004142 data->num_temp_beeps = 3;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004143
4144 data->ALARM_BITS = NCT6775_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004145 data->BEEP_BITS = NCT6775_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004146
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004147 data->fan_from_reg = fan_from_reg16;
4148 data->fan_from_reg_min = fan_from_reg8;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004149 data->target_temp_mask = 0x7f;
4150 data->tolerance_mask = 0x0f;
4151 data->speed_tolerance_limit = 15;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004152
Guenter Roeckaa136e52012-12-04 03:26:05 -08004153 data->temp_label = nct6775_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004154 data->temp_mask = NCT6775_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004155 data->virt_temp_mask = NCT6775_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004156
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004157 data->REG_CONFIG = NCT6775_REG_CONFIG;
4158 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004159 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004160 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004161 data->REG_VIN = NCT6775_REG_IN;
4162 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4163 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004164 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004165 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004166 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004167 data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004168 data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004169 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004170 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
4171 data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
4172 data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004173 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004174 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4175 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
4176 data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
4177 data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004178 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004179 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4180 data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
4181 data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004182 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4183 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4184 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4185 data->REG_CRITICAL_TEMP_TOLERANCE
4186 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004187 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
4188 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004189 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004190 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4191 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4192 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4193 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004194 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004195 data->REG_BEEP = NCT6775_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004196
4197 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004198 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004199 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004200 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004201 reg_temp_over = NCT6775_REG_TEMP_OVER;
4202 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
4203 reg_temp_config = NCT6775_REG_TEMP_CONFIG;
4204 reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
4205 reg_temp_crit = NCT6775_REG_TEMP_CRIT;
4206
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004207 break;
4208 case nct6776:
4209 data->in_num = 9;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004210 data->pwm_num = 3;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004211 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004212 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004213 data->temp_fixed_num = 3;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004214 data->num_temp_alarms = 3;
Guenter Roeck30846992013-06-24 22:21:59 -07004215 data->num_temp_beeps = 6;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004216
4217 data->ALARM_BITS = NCT6776_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004218 data->BEEP_BITS = NCT6776_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004219
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004220 data->fan_from_reg = fan_from_reg13;
4221 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004222 data->target_temp_mask = 0xff;
4223 data->tolerance_mask = 0x07;
4224 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004225
Guenter Roeckaa136e52012-12-04 03:26:05 -08004226 data->temp_label = nct6776_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004227 data->temp_mask = NCT6776_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004228 data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004229
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004230 data->REG_CONFIG = NCT6775_REG_CONFIG;
4231 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004232 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004233 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004234 data->REG_VIN = NCT6775_REG_IN;
4235 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4236 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004237 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004238 data->REG_FAN = NCT6775_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004239 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004240 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004241 data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004242 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004243 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004244 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4245 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004246 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004247 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004248 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4249 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004250 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4251 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004252 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4253 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4254 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004255 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4256 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4257 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4258 data->REG_CRITICAL_TEMP_TOLERANCE
4259 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004260 data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
4261 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004262 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004263 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4264 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4265 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4266 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004267 data->REG_ALARM = NCT6775_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004268 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004269
4270 reg_temp = NCT6775_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004271 reg_temp_mon = NCT6775_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004272 num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004273 num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004274 reg_temp_over = NCT6775_REG_TEMP_OVER;
4275 reg_temp_hyst = NCT6775_REG_TEMP_HYST;
4276 reg_temp_config = NCT6776_REG_TEMP_CONFIG;
4277 reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
4278 reg_temp_crit = NCT6776_REG_TEMP_CRIT;
4279
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004280 break;
4281 case nct6779:
4282 data->in_num = 15;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004283 data->pwm_num = 5;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004284 data->auto_pwm_num = 4;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004285 data->has_fan_div = false;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004286 data->temp_fixed_num = 6;
Guenter Roeckb1d2bff2013-06-22 16:15:31 -07004287 data->num_temp_alarms = 2;
Guenter Roeck30846992013-06-24 22:21:59 -07004288 data->num_temp_beeps = 2;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004289
4290 data->ALARM_BITS = NCT6779_ALARM_BITS;
Guenter Roeck30846992013-06-24 22:21:59 -07004291 data->BEEP_BITS = NCT6779_BEEP_BITS;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004292
Guenter Roeckf6de2982018-09-13 20:01:12 -07004293 data->fan_from_reg = fan_from_reg_rpm;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004294 data->fan_from_reg_min = fan_from_reg13;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004295 data->target_temp_mask = 0xff;
4296 data->tolerance_mask = 0x07;
4297 data->speed_tolerance_limit = 63;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004298
Guenter Roeckaa136e52012-12-04 03:26:05 -08004299 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004300 data->temp_mask = NCT6779_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004301 data->virt_temp_mask = NCT6779_VIRT_TEMP_MASK;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004302
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004303 data->REG_CONFIG = NCT6775_REG_CONFIG;
4304 data->REG_VBAT = NCT6775_REG_VBAT;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004305 data->REG_DIODE = NCT6775_REG_DIODE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004306 data->DIODE_MASK = NCT6775_DIODE_MASK;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004307 data->REG_VIN = NCT6779_REG_IN;
4308 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4309 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004310 data->REG_TARGET = NCT6775_REG_TARGET;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004311 data->REG_FAN = NCT6779_REG_FAN;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004312 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004313 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
Guenter Roeck5c25d952012-12-11 07:29:06 -08004314 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
Guenter Roeck6c009502012-07-01 08:23:15 -07004315 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004316 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004317 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4318 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004319 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004320 data->REG_PWM[0] = NCT6775_REG_PWM;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004321 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4322 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004323 data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
4324 data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004325 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4326 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4327 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004328 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4329 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4330 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4331 data->REG_CRITICAL_TEMP_TOLERANCE
4332 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
Guenter Roeck6c009502012-07-01 08:23:15 -07004333 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4334 data->CRITICAL_PWM_ENABLE_MASK
4335 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4336 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004337 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4338 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004339 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckbbd8dec2012-12-04 09:08:29 -08004340 data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
4341 data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
4342 data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
4343 data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004344 data->REG_ALARM = NCT6779_REG_ALARM;
Guenter Roeck30846992013-06-24 22:21:59 -07004345 data->REG_BEEP = NCT6776_REG_BEEP;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004346
4347 reg_temp = NCT6779_REG_TEMP;
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004348 reg_temp_mon = NCT6779_REG_TEMP_MON;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004349 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004350 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004351 reg_temp_over = NCT6779_REG_TEMP_OVER;
4352 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4353 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4354 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4355 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4356
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004357 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004358 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004359 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004360 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004361 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004362 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004363 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004364 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004365 data->in_num = 15;
Guenter Roecke41da282018-09-18 20:48:29 -07004366 data->pwm_num = (data->kind == nct6796 ||
Guenter Roeck05996822018-09-19 20:26:16 -07004367 data->kind == nct6797 ||
4368 data->kind == nct6798) ? 7 : 6;
David Bartley578ab5f2013-06-24 22:28:28 -07004369 data->auto_pwm_num = 4;
4370 data->has_fan_div = false;
4371 data->temp_fixed_num = 6;
4372 data->num_temp_alarms = 2;
4373 data->num_temp_beeps = 2;
4374
4375 data->ALARM_BITS = NCT6791_ALARM_BITS;
4376 data->BEEP_BITS = NCT6779_BEEP_BITS;
4377
Guenter Roeckf6de2982018-09-13 20:01:12 -07004378 data->fan_from_reg = fan_from_reg_rpm;
David Bartley578ab5f2013-06-24 22:28:28 -07004379 data->fan_from_reg_min = fan_from_reg13;
4380 data->target_temp_mask = 0xff;
4381 data->tolerance_mask = 0x07;
4382 data->speed_tolerance_limit = 63;
4383
Guenter Roeck50224f42015-10-30 07:52:39 -07004384 switch (data->kind) {
4385 default:
4386 case nct6791:
4387 data->temp_label = nct6779_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004388 data->temp_mask = NCT6791_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004389 data->virt_temp_mask = NCT6791_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004390 break;
4391 case nct6792:
4392 data->temp_label = nct6792_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004393 data->temp_mask = NCT6792_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004394 data->virt_temp_mask = NCT6792_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004395 break;
4396 case nct6793:
4397 data->temp_label = nct6793_temp_label;
Guenter Roeckcc66b302017-05-17 18:05:06 -07004398 data->temp_mask = NCT6793_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004399 data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
Guenter Roeck50224f42015-10-30 07:52:39 -07004400 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004401 case nct6795:
Guenter Roecke41da282018-09-18 20:48:29 -07004402 case nct6797:
Guenter Roeck419220d2017-05-17 18:19:18 -07004403 data->temp_label = nct6795_temp_label;
4404 data->temp_mask = NCT6795_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004405 data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
Guenter Roeck419220d2017-05-17 18:19:18 -07004406 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004407 case nct6796:
4408 data->temp_label = nct6796_temp_label;
4409 data->temp_mask = NCT6796_TEMP_MASK;
Guenter Roeck37196ba2018-09-13 19:43:58 -07004410 data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
Guenter Roeck81820052018-02-21 13:09:39 -08004411 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004412 case nct6798:
4413 data->temp_label = nct6798_temp_label;
4414 data->temp_mask = NCT6798_TEMP_MASK;
4415 data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
4416 break;
Guenter Roeck50224f42015-10-30 07:52:39 -07004417 }
David Bartley578ab5f2013-06-24 22:28:28 -07004418
4419 data->REG_CONFIG = NCT6775_REG_CONFIG;
4420 data->REG_VBAT = NCT6775_REG_VBAT;
4421 data->REG_DIODE = NCT6775_REG_DIODE;
4422 data->DIODE_MASK = NCT6775_DIODE_MASK;
4423 data->REG_VIN = NCT6779_REG_IN;
4424 data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
4425 data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
4426 data->REG_TARGET = NCT6775_REG_TARGET;
4427 data->REG_FAN = NCT6779_REG_FAN;
4428 data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
4429 data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
4430 data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
4431 data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
4432 data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
Guenter Roeck728d2942015-08-31 16:13:47 -07004433 data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
4434 data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
David Bartley578ab5f2013-06-24 22:28:28 -07004435 data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
4436 data->REG_PWM[0] = NCT6775_REG_PWM;
4437 data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
4438 data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004439 data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
4440 data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004441 data->REG_PWM_READ = NCT6775_REG_PWM_READ;
4442 data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
4443 data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
4444 data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
4445 data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
4446 data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
4447 data->REG_CRITICAL_TEMP_TOLERANCE
4448 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
4449 data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
4450 data->CRITICAL_PWM_ENABLE_MASK
4451 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
4452 data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
4453 data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
4454 data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
4455 data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
Guenter Roeckcc76dee2013-11-13 12:47:17 -08004456 data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
4457 data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
4458 data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
4459 data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
David Bartley578ab5f2013-06-24 22:28:28 -07004460 data->REG_ALARM = NCT6791_REG_ALARM;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004461 if (data->kind == nct6791)
4462 data->REG_BEEP = NCT6776_REG_BEEP;
4463 else
4464 data->REG_BEEP = NCT6792_REG_BEEP;
David Bartley578ab5f2013-06-24 22:28:28 -07004465
4466 reg_temp = NCT6779_REG_TEMP;
4467 num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
Guenter Roeck8aefb932014-11-16 09:50:04 -08004468 if (data->kind == nct6791) {
4469 reg_temp_mon = NCT6779_REG_TEMP_MON;
4470 num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
4471 } else {
4472 reg_temp_mon = NCT6792_REG_TEMP_MON;
4473 num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
4474 }
David Bartley578ab5f2013-06-24 22:28:28 -07004475 reg_temp_over = NCT6779_REG_TEMP_OVER;
4476 reg_temp_hyst = NCT6779_REG_TEMP_HYST;
4477 reg_temp_config = NCT6779_REG_TEMP_CONFIG;
4478 reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
4479 reg_temp_crit = NCT6779_REG_TEMP_CRIT;
4480
4481 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004482 default:
4483 return -ENODEV;
4484 }
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004485 data->have_in = BIT(data->in_num) - 1;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004486 data->have_temp = 0;
4487
4488 /*
4489 * On some boards, not all available temperature sources are monitored,
4490 * even though some of the monitoring registers are unused.
4491 * Get list of unused monitoring registers, then detect if any fan
4492 * controls are configured to use unmonitored temperature sources.
4493 * If so, assign the unmonitored temperature sources to available
4494 * monitoring registers.
4495 */
4496 mask = 0;
4497 available = 0;
4498 for (i = 0; i < num_reg_temp; i++) {
4499 if (reg_temp[i] == 0)
4500 continue;
4501
Denis Pauk49140362021-09-18 01:02:39 +03004502 src = data->read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004503 if (!src || (mask & BIT(src)))
4504 available |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004505
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004506 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004507 }
4508
Guenter Roeck8e9285b2012-12-04 08:03:37 -08004509 /*
4510 * Now find unmonitored temperature registers and enable monitoring
4511 * if additional monitoring registers are available.
4512 */
4513 add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
4514 add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
4515
Guenter Roeckaa136e52012-12-04 03:26:05 -08004516 mask = 0;
4517 s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
4518 for (i = 0; i < num_reg_temp; i++) {
4519 if (reg_temp[i] == 0)
4520 continue;
4521
Denis Pauk49140362021-09-18 01:02:39 +03004522 src = data->read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004523 if (!src || (mask & BIT(src)))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004524 continue;
4525
Guenter Roeckcc66b302017-05-17 18:05:06 -07004526 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckaa136e52012-12-04 03:26:05 -08004527 dev_info(dev,
4528 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4529 src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
4530 continue;
4531 }
4532
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004533 mask |= BIT(src);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004534
4535 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4536 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004537 data->have_temp |= BIT(src - 1);
4538 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004539 data->reg_temp[0][src - 1] = reg_temp[i];
4540 data->reg_temp[1][src - 1] = reg_temp_over[i];
4541 data->reg_temp[2][src - 1] = reg_temp_hyst[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004542 if (reg_temp_crit_h && reg_temp_crit_h[i])
4543 data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
4544 else if (reg_temp_crit[src - 1])
4545 data->reg_temp[3][src - 1]
4546 = reg_temp_crit[src - 1];
4547 if (reg_temp_crit_l && reg_temp_crit_l[i])
4548 data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004549 data->reg_temp_config[src - 1] = reg_temp_config[i];
4550 data->temp_src[src - 1] = src;
4551 continue;
4552 }
4553
4554 if (s >= NUM_TEMP)
4555 continue;
4556
4557 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004558 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004559 data->reg_temp[0][s] = reg_temp[i];
4560 data->reg_temp[1][s] = reg_temp_over[i];
4561 data->reg_temp[2][s] = reg_temp_hyst[i];
4562 data->reg_temp_config[s] = reg_temp_config[i];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004563 if (reg_temp_crit_h && reg_temp_crit_h[i])
4564 data->reg_temp[3][s] = reg_temp_crit_h[i];
4565 else if (reg_temp_crit[src - 1])
Guenter Roeckaa136e52012-12-04 03:26:05 -08004566 data->reg_temp[3][s] = reg_temp_crit[src - 1];
Guenter Roeckb7a61352013-04-02 22:14:06 -07004567 if (reg_temp_crit_l && reg_temp_crit_l[i])
4568 data->reg_temp[4][s] = reg_temp_crit_l[i];
Guenter Roeckaa136e52012-12-04 03:26:05 -08004569
4570 data->temp_src[s] = src;
4571 s++;
4572 }
4573
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004574 /*
4575 * Repeat with temperatures used for fan control.
4576 * This set of registers does not support limits.
4577 */
4578 for (i = 0; i < num_reg_temp_mon; i++) {
4579 if (reg_temp_mon[i] == 0)
4580 continue;
4581
Denis Pauk49140362021-09-18 01:02:39 +03004582 src = data->read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
Guenter Roeck7ce41902016-09-11 12:42:52 -07004583 if (!src)
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004584 continue;
4585
Guenter Roeckcc66b302017-05-17 18:05:06 -07004586 if (!(data->temp_mask & BIT(src))) {
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004587 dev_info(dev,
4588 "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
4589 src, i, data->REG_TEMP_SEL[i],
4590 reg_temp_mon[i]);
4591 continue;
4592 }
4593
Guenter Roeck7ce41902016-09-11 12:42:52 -07004594 /*
4595 * For virtual temperature sources, the 'virtual' temperature
4596 * for each fan reflects a different temperature, and there
4597 * are no duplicates.
4598 */
Guenter Roeck37196ba2018-09-13 19:43:58 -07004599 if (!(data->virt_temp_mask & BIT(src))) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004600 if (mask & BIT(src))
Guenter Roeck7ce41902016-09-11 12:42:52 -07004601 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004602 mask |= BIT(src);
Guenter Roeck7ce41902016-09-11 12:42:52 -07004603 }
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004604
4605 /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
4606 if (src <= data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004607 if (data->have_temp & BIT(src - 1))
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004608 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004609 data->have_temp |= BIT(src - 1);
4610 data->have_temp_fixed |= BIT(src - 1);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004611 data->reg_temp[0][src - 1] = reg_temp_mon[i];
4612 data->temp_src[src - 1] = src;
4613 continue;
4614 }
4615
4616 if (s >= NUM_TEMP)
4617 continue;
4618
4619 /* Use dynamic index for other sources */
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004620 data->have_temp |= BIT(s);
Guenter Roeckd1a284b2013-11-13 12:46:20 -08004621 data->reg_temp[0][s] = reg_temp_mon[i];
4622 data->temp_src[s] = src;
4623 s++;
4624 }
4625
Guenter Roeckaa136e52012-12-04 03:26:05 -08004626#ifdef USE_ALTERNATE
4627 /*
4628 * Go through the list of alternate temp registers and enable
4629 * if possible.
4630 * The temperature is already monitored if the respective bit in <mask>
4631 * is set.
4632 */
Guenter Roeck91bb8f42018-06-12 15:19:35 -07004633 for (i = 0; i < 31; i++) {
Guenter Roeckcc66b302017-05-17 18:05:06 -07004634 if (!(data->temp_mask & BIT(i + 1)))
4635 continue;
Guenter Roeckaa136e52012-12-04 03:26:05 -08004636 if (!reg_temp_alternate[i])
4637 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004638 if (mask & BIT(i + 1))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004639 continue;
4640 if (i < data->temp_fixed_num) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004641 if (data->have_temp & BIT(i))
Guenter Roeckaa136e52012-12-04 03:26:05 -08004642 continue;
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004643 data->have_temp |= BIT(i);
4644 data->have_temp_fixed |= BIT(i);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004645 data->reg_temp[0][i] = reg_temp_alternate[i];
Guenter Roeck169c05cd2013-05-09 10:40:01 -07004646 if (i < num_reg_temp) {
4647 data->reg_temp[1][i] = reg_temp_over[i];
4648 data->reg_temp[2][i] = reg_temp_hyst[i];
4649 }
Guenter Roeckaa136e52012-12-04 03:26:05 -08004650 data->temp_src[i] = i + 1;
4651 continue;
4652 }
4653
4654 if (s >= NUM_TEMP) /* Abort if no more space */
4655 break;
4656
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004657 data->have_temp |= BIT(s);
Guenter Roeckaa136e52012-12-04 03:26:05 -08004658 data->reg_temp[0][s] = reg_temp_alternate[i];
4659 data->temp_src[s] = i + 1;
4660 s++;
4661 }
4662#endif /* USE_ALTERNATE */
4663
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004664 /* Initialize the chip */
4665 nct6775_init_device(data);
4666
Denis Pauk2e7b9882021-09-18 01:02:38 +03004667 err = sio_data->sio_enter(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004668 if (err)
4669 return err;
4670
Denis Pauk2e7b9882021-09-18 01:02:38 +03004671 cr2a = sio_data->sio_inb(sio_data, 0x2a);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004672 switch (data->kind) {
4673 case nct6775:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004674 data->have_vid = (cr2a & 0x40);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004675 break;
4676 case nct6776:
Guenter Roeckf73cf632013-03-18 09:22:50 -07004677 data->have_vid = (cr2a & 0x60) == 0x40;
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004678 break;
Guenter Roeck6c009502012-07-01 08:23:15 -07004679 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004680 case nct6116:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004681 case nct6779:
David Bartley578ab5f2013-06-24 22:28:28 -07004682 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004683 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004684 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004685 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004686 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004687 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004688 case nct6798:
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004689 break;
4690 }
4691
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004692 /*
4693 * Read VID value
4694 * We can get the VID input values directly at logical device D 0xe3.
4695 */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004696 if (data->have_vid) {
Denis Pauk2e7b9882021-09-18 01:02:38 +03004697 sio_data->sio_select(sio_data, NCT6775_LD_VID);
4698 data->vid = sio_data->sio_inb(sio_data, 0xe3);
Guenter Roeck0fc1f8f2013-02-26 09:43:50 -08004699 data->vrm = vid_which_vrm();
4700 }
Guenter Roeck47ece962012-12-04 07:59:32 -08004701
4702 if (fan_debounce) {
4703 u8 tmp;
4704
Denis Pauk2e7b9882021-09-18 01:02:38 +03004705 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
4706 tmp = sio_data->sio_inb(sio_data,
4707 NCT6775_REG_CR_FAN_DEBOUNCE);
Guenter Roeck47ece962012-12-04 07:59:32 -08004708 switch (data->kind) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004709 case nct6106:
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004710 case nct6116:
Guenter Roeck6c009502012-07-01 08:23:15 -07004711 tmp |= 0xe0;
4712 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004713 case nct6775:
4714 tmp |= 0x1e;
4715 break;
4716 case nct6776:
4717 case nct6779:
4718 tmp |= 0x3e;
4719 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004720 case nct6791:
Guenter Roeck8aefb932014-11-16 09:50:04 -08004721 case nct6792:
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004722 case nct6793:
Guenter Roeck419220d2017-05-17 18:19:18 -07004723 case nct6795:
Guenter Roeck81820052018-02-21 13:09:39 -08004724 case nct6796:
Guenter Roecke41da282018-09-18 20:48:29 -07004725 case nct6797:
Guenter Roeck05996822018-09-19 20:26:16 -07004726 case nct6798:
David Bartley578ab5f2013-06-24 22:28:28 -07004727 tmp |= 0x7e;
4728 break;
Guenter Roeck47ece962012-12-04 07:59:32 -08004729 }
Denis Pauk2e7b9882021-09-18 01:02:38 +03004730 sio_data->sio_outb(sio_data, NCT6775_REG_CR_FAN_DEBOUNCE,
Guenter Roeck47ece962012-12-04 07:59:32 -08004731 tmp);
4732 dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
4733 data->name);
4734 }
4735
Denis Pauk2e7b9882021-09-18 01:02:38 +03004736 nct6775_check_fan_inputs(data, sio_data);
Guenter Roeckf73cf632013-03-18 09:22:50 -07004737
Denis Pauk2e7b9882021-09-18 01:02:38 +03004738 sio_data->sio_exit(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004739
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004740 /* Read fan clock dividers immediately */
4741 nct6775_init_fan_common(dev, data);
4742
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004743 /* Register sysfs hooks */
Guenter Roeckf73cf632013-03-18 09:22:50 -07004744 group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
4745 data->pwm_num);
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004746 if (IS_ERR(group))
4747 return PTR_ERR(group);
4748
Axel Lin55bdee62014-07-24 08:59:34 +08004749 data->groups[num_attr_groups++] = group;
Guenter Roeckcdcaece2012-12-04 09:04:52 -08004750
Guenter Roeckf73cf632013-03-18 09:22:50 -07004751 group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
4752 fls(data->have_in));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004753 if (IS_ERR(group))
4754 return PTR_ERR(group);
4755
Axel Lin55bdee62014-07-24 08:59:34 +08004756 data->groups[num_attr_groups++] = group;
Guenter Roeck77eb5b32012-12-04 08:30:54 -08004757
Guenter Roeckf73cf632013-03-18 09:22:50 -07004758 group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
4759 fls(data->has_fan));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004760 if (IS_ERR(group))
4761 return PTR_ERR(group);
4762
Axel Lin55bdee62014-07-24 08:59:34 +08004763 data->groups[num_attr_groups++] = group;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004764
Guenter Roeckf73cf632013-03-18 09:22:50 -07004765 group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
4766 fls(data->have_temp));
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004767 if (IS_ERR(group))
4768 return PTR_ERR(group);
Guenter Roeck1c65dc32012-12-04 07:56:24 -08004769
Axel Lin55bdee62014-07-24 08:59:34 +08004770 data->groups[num_attr_groups++] = group;
4771 data->groups[num_attr_groups++] = &nct6775_group_other;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004772
Guenter Roecka150d952013-07-11 22:55:22 -07004773 hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
4774 data, data->groups);
Fengguang Wu9c09bd82013-09-17 06:43:42 -07004775 return PTR_ERR_OR_ZERO(hwmon_dev);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004776}
4777
Denis Pauk2e7b9882021-09-18 01:02:38 +03004778static void nct6791_enable_io_mapping(struct nct6775_sio_data *sio_data)
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004779{
4780 int val;
4781
Denis Pauk2e7b9882021-09-18 01:02:38 +03004782 val = sio_data->sio_inb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004783 if (val & 0x10) {
4784 pr_info("Enabling hardware monitor logical device mappings.\n");
Denis Pauk2e7b9882021-09-18 01:02:38 +03004785 sio_data->sio_outb(sio_data, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
4786 val & ~0x10);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004787 }
4788}
4789
Guenter Roeck48e93182015-02-07 08:48:49 -08004790static int __maybe_unused nct6775_suspend(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004791{
4792 struct nct6775_data *data = nct6775_update_device(dev);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004793
4794 mutex_lock(&data->update_lock);
Denis Pauk49140362021-09-18 01:02:39 +03004795 data->vbat = data->read_value(data, data->REG_VBAT);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004796 if (data->kind == nct6775) {
Denis Pauk49140362021-09-18 01:02:39 +03004797 data->fandiv1 = data->read_value(data, NCT6775_REG_FANDIV1);
4798 data->fandiv2 = data->read_value(data, NCT6775_REG_FANDIV2);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004799 }
4800 mutex_unlock(&data->update_lock);
4801
4802 return 0;
4803}
4804
Guenter Roeck48e93182015-02-07 08:48:49 -08004805static int __maybe_unused nct6775_resume(struct device *dev)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004806{
4807 struct nct6775_data *data = dev_get_drvdata(dev);
Denis Pauk2e7b9882021-09-18 01:02:38 +03004808 struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004809 int i, j, err = 0;
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004810 u8 reg;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004811
4812 mutex_lock(&data->update_lock);
4813 data->bank = 0xff; /* Force initial bank selection */
4814
Denis Pauk2e7b9882021-09-18 01:02:38 +03004815 err = sio_data->sio_enter(sio_data);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004816 if (err)
4817 goto abort;
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004818
Denis Pauk2e7b9882021-09-18 01:02:38 +03004819 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
4820 reg = sio_data->sio_inb(sio_data, SIO_REG_ENABLE);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004821 if (reg != data->sio_reg_enable)
Denis Pauk2e7b9882021-09-18 01:02:38 +03004822 sio_data->sio_outb(sio_data, SIO_REG_ENABLE, data->sio_reg_enable);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004823
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004824 if (data->kind == nct6791 || data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004825 data->kind == nct6793 || data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004826 data->kind == nct6796 || data->kind == nct6797 ||
4827 data->kind == nct6798)
Denis Pauk2e7b9882021-09-18 01:02:38 +03004828 nct6791_enable_io_mapping(sio_data);
Guenter Roeckd2a14ea2015-02-06 18:53:21 -08004829
Denis Pauk2e7b9882021-09-18 01:02:38 +03004830 sio_data->sio_exit(sio_data);
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004831
Guenter Roeck84d19d92012-12-04 08:01:39 -08004832 /* Restore limits */
4833 for (i = 0; i < data->in_num; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004834 if (!(data->have_in & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004835 continue;
4836
Denis Pauk49140362021-09-18 01:02:39 +03004837 data->write_value(data, data->REG_IN_MINMAX[0][i],
4838 data->in[i][1]);
4839 data->write_value(data, data->REG_IN_MINMAX[1][i],
4840 data->in[i][2]);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004841 }
4842
Guenter Roeckc409fd42013-04-09 05:04:00 -07004843 for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004844 if (!(data->has_fan_min & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004845 continue;
4846
Denis Pauk49140362021-09-18 01:02:39 +03004847 data->write_value(data, data->REG_FAN_MIN[i],
4848 data->fan_min[i]);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004849 }
4850
4851 for (i = 0; i < NUM_TEMP; i++) {
Guenter Roeckd1bb21862017-05-17 18:40:10 -07004852 if (!(data->have_temp & BIT(i)))
Guenter Roeck84d19d92012-12-04 08:01:39 -08004853 continue;
4854
Guenter Roeckc409fd42013-04-09 05:04:00 -07004855 for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
Guenter Roeck84d19d92012-12-04 08:01:39 -08004856 if (data->reg_temp[j][i])
4857 nct6775_write_temp(data, data->reg_temp[j][i],
4858 data->temp[j][i]);
4859 }
4860
4861 /* Restore other settings */
Denis Pauk49140362021-09-18 01:02:39 +03004862 data->write_value(data, data->REG_VBAT, data->vbat);
Guenter Roeckdf612d52013-07-08 13:15:04 -07004863 if (data->kind == nct6775) {
Denis Pauk49140362021-09-18 01:02:39 +03004864 data->write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
4865 data->write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004866 }
4867
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004868abort:
Guenter Roeck84d19d92012-12-04 08:01:39 -08004869 /* Force re-reading all values */
4870 data->valid = false;
4871 mutex_unlock(&data->update_lock);
4872
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004873 return err;
Guenter Roeck84d19d92012-12-04 08:01:39 -08004874}
4875
Guenter Roeck48e93182015-02-07 08:48:49 -08004876static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
Guenter Roeck84d19d92012-12-04 08:01:39 -08004877
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004878static struct platform_driver nct6775_driver = {
4879 .driver = {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004880 .name = DRVNAME,
Guenter Roeck48e93182015-02-07 08:48:49 -08004881 .pm = &nct6775_dev_pm_ops,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004882 },
4883 .probe = nct6775_probe,
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004884};
4885
4886/* nct6775_find() looks for a '627 in the Super-I/O config space */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004887static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004888{
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004889 u16 val;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004890 int err;
Guenter Roeck698a7c22013-04-05 07:35:25 -07004891 int addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004892
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004893 sio_data->access = access_direct;
Denis Pauk2e7b9882021-09-18 01:02:38 +03004894 sio_data->sioreg = sioaddr;
4895
4896 err = sio_data->sio_enter(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004897 if (err)
4898 return err;
4899
Denis Pauk2e7b9882021-09-18 01:02:38 +03004900 val = (sio_data->sio_inb(sio_data, SIO_REG_DEVID) << 8) |
4901 sio_data->sio_inb(sio_data, SIO_REG_DEVID + 1);
Guenter Roeckfc72af32016-08-03 22:07:18 -07004902 if (force_id && val != 0xffff)
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004903 val = force_id;
Guenter Roeckfc72af32016-08-03 22:07:18 -07004904
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004905 switch (val & SIO_ID_MASK) {
Guenter Roeck6c009502012-07-01 08:23:15 -07004906 case SIO_NCT6106_ID:
4907 sio_data->kind = nct6106;
4908 break;
Björn Gerhart29c7cb42019-07-23 18:06:46 +02004909 case SIO_NCT6116_ID:
4910 sio_data->kind = nct6116;
4911 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004912 case SIO_NCT6775_ID:
4913 sio_data->kind = nct6775;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004914 break;
4915 case SIO_NCT6776_ID:
4916 sio_data->kind = nct6776;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004917 break;
4918 case SIO_NCT6779_ID:
4919 sio_data->kind = nct6779;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004920 break;
David Bartley578ab5f2013-06-24 22:28:28 -07004921 case SIO_NCT6791_ID:
4922 sio_data->kind = nct6791;
4923 break;
Guenter Roeck8aefb932014-11-16 09:50:04 -08004924 case SIO_NCT6792_ID:
4925 sio_data->kind = nct6792;
4926 break;
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004927 case SIO_NCT6793_ID:
4928 sio_data->kind = nct6793;
4929 break;
Guenter Roeck419220d2017-05-17 18:19:18 -07004930 case SIO_NCT6795_ID:
4931 sio_data->kind = nct6795;
4932 break;
Guenter Roeck81820052018-02-21 13:09:39 -08004933 case SIO_NCT6796_ID:
4934 sio_data->kind = nct6796;
4935 break;
Guenter Roecke41da282018-09-18 20:48:29 -07004936 case SIO_NCT6797_ID:
4937 sio_data->kind = nct6797;
4938 break;
Guenter Roeck05996822018-09-19 20:26:16 -07004939 case SIO_NCT6798_ID:
4940 sio_data->kind = nct6798;
4941 break;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004942 default:
4943 if (val != 0xffff)
4944 pr_debug("unsupported chip ID: 0x%04x\n", val);
Denis Pauk2e7b9882021-09-18 01:02:38 +03004945 sio_data->sio_exit(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004946 return -ENODEV;
4947 }
4948
4949 /* We have a known chip, find the HWM I/O address */
Denis Pauk2e7b9882021-09-18 01:02:38 +03004950 sio_data->sio_select(sio_data, NCT6775_LD_HWM);
4951 val = (sio_data->sio_inb(sio_data, SIO_REG_ADDR) << 8)
4952 | sio_data->sio_inb(sio_data, SIO_REG_ADDR + 1);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004953 addr = val & IOREGION_ALIGNMENT;
4954 if (addr == 0) {
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004955 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 +03004956 sio_data->sio_exit(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004957 return -ENODEV;
4958 }
4959
4960 /* Activate logical device if needed */
Denis Pauk2e7b9882021-09-18 01:02:38 +03004961 val = sio_data->sio_inb(sio_data, SIO_REG_ENABLE);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004962 if (!(val & 0x01)) {
4963 pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
Denis Pauk2e7b9882021-09-18 01:02:38 +03004964 sio_data->sio_outb(sio_data, SIO_REG_ENABLE, val | 0x01);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004965 }
Guenter Roeckf5776cc2013-12-25 07:25:59 -08004966
Guenter Roeckcd1faefa2015-08-30 19:45:19 -07004967 if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
Guenter Roeck81820052018-02-21 13:09:39 -08004968 sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
Guenter Roeck9de15c92018-12-26 13:56:15 -08004969 sio_data->kind == nct6796 || sio_data->kind == nct6797 ||
4970 sio_data->kind == nct6798)
Denis Pauk2e7b9882021-09-18 01:02:38 +03004971 nct6791_enable_io_mapping(sio_data);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004972
Denis Pauk2e7b9882021-09-18 01:02:38 +03004973 sio_data->sio_exit(sio_data);
Guenter Roeck698a7c22013-04-05 07:35:25 -07004974 pr_info("Found %s or compatible chip at %#x:%#x\n",
4975 nct6775_sio_names[sio_data->kind], sioaddr, addr);
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004976
Guenter Roeck698a7c22013-04-05 07:35:25 -07004977 return addr;
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004978}
4979
4980/*
4981 * when Super-I/O functions move to a separate file, the Super-I/O
4982 * bus will manage the lifetime of the device and this module will only keep
Guenter Roeck615fc8c2013-07-06 09:43:30 -07004983 * track of the nct6775 driver. But since we use platform_device_alloc(), we
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004984 * must keep track of the device
4985 */
Guenter Roeck698a7c22013-04-05 07:35:25 -07004986static struct platform_device *pdev[2];
Guenter Roeck9de2e2e2012-05-20 19:29:48 -07004987
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004988static const char * const asus_wmi_boards[] = {
Denis Paukf4cbba72021-10-25 22:47:48 +03004989 "ProArt X570-CREATOR WIFI",
Oleksandr Natalenko1508fb22021-10-03 15:33:42 +02004990 "Pro WS X570-ACE",
Denis Pauk6e2baac2021-10-03 00:08:54 +03004991 "PRIME B360-PLUS",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004992 "PRIME B460-PLUS",
Denis Pauk6e2baac2021-10-03 00:08:54 +03004993 "PRIME X570-PRO",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004994 "ROG CROSSHAIR VIII DARK HERO",
Denis Pauk6e2baac2021-10-03 00:08:54 +03004995 "ROG CROSSHAIR VIII FORMULA",
Denis Pauk3fbbfc22021-09-18 01:02:40 +03004996 "ROG CROSSHAIR VIII HERO",
4997 "ROG CROSSHAIR VIII IMPACT",
4998 "ROG STRIX B550-E GAMING",
4999 "ROG STRIX B550-F GAMING",
5000 "ROG STRIX B550-F GAMING (WI-FI)",
Denis Pauk6e2baac2021-10-03 00:08:54 +03005001 "ROG STRIX B550-I GAMING",
5002 "ROG STRIX X570-F GAMING",
5003 "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 */
5041 if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp)) {
5042 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);