1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * nct7904.c - driver for Nuvoton NCT7904D. |
4 | * |
5 | * Copyright (c) 2015 Kontron |
6 | * Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru> |
7 | * |
8 | * Copyright (c) 2019 Advantech |
9 | * Author: Amy.Shih <amy.shih@advantech.com.tw> |
10 | * |
11 | * Copyright (c) 2020 Advantech |
12 | * Author: Yuechao Zhao <yuechao.zhao@advantech.com.cn> |
13 | * |
14 | * Supports the following chips: |
15 | * |
16 | * Chip #vin #fan #pwm #temp #dts chip ID |
17 | * nct7904d 20 12 4 5 8 0xc5 |
18 | */ |
19 | |
20 | #include <linux/module.h> |
21 | #include <linux/device.h> |
22 | #include <linux/init.h> |
23 | #include <linux/i2c.h> |
24 | #include <linux/mutex.h> |
25 | #include <linux/hwmon.h> |
26 | #include <linux/watchdog.h> |
27 | |
28 | #define VENDOR_ID_REG 0x7A /* Any bank */ |
29 | #define NUVOTON_ID 0x50 |
30 | #define CHIP_ID_REG 0x7B /* Any bank */ |
31 | #define NCT7904_ID 0xC5 |
32 | #define DEVICE_ID_REG 0x7C /* Any bank */ |
33 | |
34 | #define BANK_SEL_REG 0xFF |
35 | #define BANK_0 0x00 |
36 | #define BANK_1 0x01 |
37 | #define BANK_2 0x02 |
38 | #define BANK_3 0x03 |
39 | #define BANK_4 0x04 |
40 | #define BANK_MAX 0x04 |
41 | |
42 | #define FANIN_MAX 12 /* Counted from 1 */ |
43 | #define VSEN_MAX 21 /* VSEN1..14, 3VDD, VBAT, V3VSB, |
44 | LTD (not a voltage), VSEN17..19 */ |
45 | #define FANCTL_MAX 4 /* Counted from 1 */ |
46 | #define TCPU_MAX 8 /* Counted from 1 */ |
47 | #define TEMP_MAX 4 /* Counted from 1 */ |
48 | #define SMI_STS_MAX 10 /* Counted from 1 */ |
49 | |
50 | #define VT_ADC_CTRL0_REG 0x20 /* Bank 0 */ |
51 | #define VT_ADC_CTRL1_REG 0x21 /* Bank 0 */ |
52 | #define VT_ADC_CTRL2_REG 0x22 /* Bank 0 */ |
53 | #define FANIN_CTRL0_REG 0x24 |
54 | #define FANIN_CTRL1_REG 0x25 |
55 | #define DTS_T_CTRL0_REG 0x26 |
56 | #define DTS_T_CTRL1_REG 0x27 |
57 | #define VT_ADC_MD_REG 0x2E |
58 | |
59 | #define VSEN1_HV_LL_REG 0x02 /* Bank 1; 2 regs (HV/LV) per sensor */ |
60 | #define VSEN1_LV_LL_REG 0x03 /* Bank 1; 2 regs (HV/LV) per sensor */ |
61 | #define VSEN1_HV_HL_REG 0x00 /* Bank 1; 2 regs (HV/LV) per sensor */ |
62 | #define VSEN1_LV_HL_REG 0x01 /* Bank 1; 2 regs (HV/LV) per sensor */ |
63 | #define SMI_STS1_REG 0xC1 /* Bank 0; SMI Status Register */ |
64 | #define SMI_STS3_REG 0xC3 /* Bank 0; SMI Status Register */ |
65 | #define SMI_STS5_REG 0xC5 /* Bank 0; SMI Status Register */ |
66 | #define SMI_STS7_REG 0xC7 /* Bank 0; SMI Status Register */ |
67 | #define SMI_STS8_REG 0xC8 /* Bank 0; SMI Status Register */ |
68 | |
69 | #define VSEN1_HV_REG 0x40 /* Bank 0; 2 regs (HV/LV) per sensor */ |
70 | #define TEMP_CH1_HV_REG 0x42 /* Bank 0; same as VSEN2_HV */ |
71 | #define LTD_HV_REG 0x62 /* Bank 0; 2 regs in VSEN range */ |
72 | #define LTD_HV_HL_REG 0x44 /* Bank 1; 1 reg for LTD */ |
73 | #define LTD_LV_HL_REG 0x45 /* Bank 1; 1 reg for LTD */ |
74 | #define LTD_HV_LL_REG 0x46 /* Bank 1; 1 reg for LTD */ |
75 | #define LTD_LV_LL_REG 0x47 /* Bank 1; 1 reg for LTD */ |
76 | #define TEMP_CH1_CH_REG 0x05 /* Bank 1; 1 reg for LTD */ |
77 | #define TEMP_CH1_W_REG 0x06 /* Bank 1; 1 reg for LTD */ |
78 | #define TEMP_CH1_WH_REG 0x07 /* Bank 1; 1 reg for LTD */ |
79 | #define TEMP_CH1_C_REG 0x04 /* Bank 1; 1 reg per sensor */ |
80 | #define DTS_T_CPU1_C_REG 0x90 /* Bank 1; 1 reg per sensor */ |
81 | #define DTS_T_CPU1_CH_REG 0x91 /* Bank 1; 1 reg per sensor */ |
82 | #define DTS_T_CPU1_W_REG 0x92 /* Bank 1; 1 reg per sensor */ |
83 | #define DTS_T_CPU1_WH_REG 0x93 /* Bank 1; 1 reg per sensor */ |
84 | #define FANIN1_HV_REG 0x80 /* Bank 0; 2 regs (HV/LV) per sensor */ |
85 | #define FANIN1_HV_HL_REG 0x60 /* Bank 1; 2 regs (HV/LV) per sensor */ |
86 | #define FANIN1_LV_HL_REG 0x61 /* Bank 1; 2 regs (HV/LV) per sensor */ |
87 | #define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */ |
88 | |
89 | #define PRTS_REG 0x03 /* Bank 2 */ |
90 | #define PFE_REG 0x00 /* Bank 2; PECI Function Enable */ |
91 | #define TSI_CTRL_REG 0x50 /* Bank 2; TSI Control Register */ |
92 | #define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */ |
93 | #define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */ |
94 | |
95 | #define WDT_LOCK_REG 0xE0 /* W/O Lock Watchdog Register */ |
96 | #define WDT_EN_REG 0xE1 /* R/O Watchdog Enable Register */ |
97 | #define WDT_STS_REG 0xE2 /* R/O Watchdog Status Register */ |
98 | #define WDT_TIMER_REG 0xE3 /* R/W Watchdog Timer Register */ |
99 | #define WDT_SOFT_EN 0x55 /* Enable soft watchdog timer */ |
100 | #define WDT_SOFT_DIS 0xAA /* Disable soft watchdog timer */ |
101 | |
102 | #define VOLT_MONITOR_MODE 0x0 |
103 | #define THERMAL_DIODE_MODE 0x1 |
104 | #define THERMISTOR_MODE 0x3 |
105 | |
106 | #define ENABLE_TSI BIT(1) |
107 | |
108 | #define WATCHDOG_TIMEOUT 1 /* 1 minute default timeout */ |
109 | |
110 | /*The timeout range is 1-255 minutes*/ |
111 | #define MIN_TIMEOUT (1 * 60) |
112 | #define MAX_TIMEOUT (255 * 60) |
113 | |
114 | static int timeout; |
115 | module_param(timeout, int, 0); |
116 | MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes. 1 <= timeout <= 255, default=" |
117 | __MODULE_STRING(WATCHDOG_TIMEOUT) "." ); |
118 | |
119 | static bool nowayout = WATCHDOG_NOWAYOUT; |
120 | module_param(nowayout, bool, 0); |
121 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
122 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")" ); |
123 | |
124 | static const unsigned short normal_i2c[] = { |
125 | 0x2d, 0x2e, I2C_CLIENT_END |
126 | }; |
127 | |
128 | struct nct7904_data { |
129 | struct i2c_client *client; |
130 | struct watchdog_device wdt; |
131 | struct mutex bank_lock; |
132 | int bank_sel; |
133 | u32 fanin_mask; |
134 | u32 vsen_mask; |
135 | u32 tcpu_mask; |
136 | u8 fan_mode[FANCTL_MAX]; |
137 | u8 enable_dts; |
138 | u8 has_dts; |
139 | u8 temp_mode; /* 0: TR mode, 1: TD mode */ |
140 | u8 fan_alarm[2]; |
141 | u8 vsen_alarm[3]; |
142 | }; |
143 | |
144 | /* Access functions */ |
145 | static int nct7904_bank_lock(struct nct7904_data *data, unsigned int bank) |
146 | { |
147 | int ret; |
148 | |
149 | mutex_lock(&data->bank_lock); |
150 | if (data->bank_sel == bank) |
151 | return 0; |
152 | ret = i2c_smbus_write_byte_data(client: data->client, BANK_SEL_REG, value: bank); |
153 | if (ret == 0) |
154 | data->bank_sel = bank; |
155 | else |
156 | data->bank_sel = -1; |
157 | return ret; |
158 | } |
159 | |
160 | static inline void nct7904_bank_release(struct nct7904_data *data) |
161 | { |
162 | mutex_unlock(lock: &data->bank_lock); |
163 | } |
164 | |
165 | /* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */ |
166 | static int nct7904_read_reg(struct nct7904_data *data, |
167 | unsigned int bank, unsigned int reg) |
168 | { |
169 | struct i2c_client *client = data->client; |
170 | int ret; |
171 | |
172 | ret = nct7904_bank_lock(data, bank); |
173 | if (ret == 0) |
174 | ret = i2c_smbus_read_byte_data(client, command: reg); |
175 | |
176 | nct7904_bank_release(data); |
177 | return ret; |
178 | } |
179 | |
180 | /* |
181 | * Read 2-byte register. Returns register in big-endian format or |
182 | * -ERRNO on error. |
183 | */ |
184 | static int nct7904_read_reg16(struct nct7904_data *data, |
185 | unsigned int bank, unsigned int reg) |
186 | { |
187 | struct i2c_client *client = data->client; |
188 | int ret, hi; |
189 | |
190 | ret = nct7904_bank_lock(data, bank); |
191 | if (ret == 0) { |
192 | ret = i2c_smbus_read_byte_data(client, command: reg); |
193 | if (ret >= 0) { |
194 | hi = ret; |
195 | ret = i2c_smbus_read_byte_data(client, command: reg + 1); |
196 | if (ret >= 0) |
197 | ret |= hi << 8; |
198 | } |
199 | } |
200 | |
201 | nct7904_bank_release(data); |
202 | return ret; |
203 | } |
204 | |
205 | /* Write 1-byte register. Returns 0 or -ERRNO on error. */ |
206 | static int nct7904_write_reg(struct nct7904_data *data, |
207 | unsigned int bank, unsigned int reg, u8 val) |
208 | { |
209 | struct i2c_client *client = data->client; |
210 | int ret; |
211 | |
212 | ret = nct7904_bank_lock(data, bank); |
213 | if (ret == 0) |
214 | ret = i2c_smbus_write_byte_data(client, command: reg, value: val); |
215 | |
216 | nct7904_bank_release(data); |
217 | return ret; |
218 | } |
219 | |
220 | static int nct7904_read_fan(struct device *dev, u32 attr, int channel, |
221 | long *val) |
222 | { |
223 | struct nct7904_data *data = dev_get_drvdata(dev); |
224 | unsigned int cnt, rpm; |
225 | int ret; |
226 | |
227 | switch (attr) { |
228 | case hwmon_fan_input: |
229 | ret = nct7904_read_reg16(data, BANK_0, |
230 | FANIN1_HV_REG + channel * 2); |
231 | if (ret < 0) |
232 | return ret; |
233 | cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); |
234 | if (cnt == 0 || cnt == 0x1fff) |
235 | rpm = 0; |
236 | else |
237 | rpm = 1350000 / cnt; |
238 | *val = rpm; |
239 | return 0; |
240 | case hwmon_fan_min: |
241 | ret = nct7904_read_reg16(data, BANK_1, |
242 | FANIN1_HV_HL_REG + channel * 2); |
243 | if (ret < 0) |
244 | return ret; |
245 | cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); |
246 | if (cnt == 0 || cnt == 0x1fff) |
247 | rpm = 0; |
248 | else |
249 | rpm = 1350000 / cnt; |
250 | *val = rpm; |
251 | return 0; |
252 | case hwmon_fan_alarm: |
253 | ret = nct7904_read_reg(data, BANK_0, |
254 | SMI_STS5_REG + (channel >> 3)); |
255 | if (ret < 0) |
256 | return ret; |
257 | if (!data->fan_alarm[channel >> 3]) |
258 | data->fan_alarm[channel >> 3] = ret & 0xff; |
259 | else |
260 | /* If there is new alarm showing up */ |
261 | data->fan_alarm[channel >> 3] |= (ret & 0xff); |
262 | *val = (data->fan_alarm[channel >> 3] >> (channel & 0x07)) & 1; |
263 | /* Needs to clean the alarm if alarm existing */ |
264 | if (*val) |
265 | data->fan_alarm[channel >> 3] ^= 1 << (channel & 0x07); |
266 | return 0; |
267 | default: |
268 | return -EOPNOTSUPP; |
269 | } |
270 | } |
271 | |
272 | static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel) |
273 | { |
274 | const struct nct7904_data *data = _data; |
275 | |
276 | switch (attr) { |
277 | case hwmon_fan_input: |
278 | case hwmon_fan_alarm: |
279 | if (data->fanin_mask & (1 << channel)) |
280 | return 0444; |
281 | break; |
282 | case hwmon_fan_min: |
283 | if (data->fanin_mask & (1 << channel)) |
284 | return 0644; |
285 | break; |
286 | default: |
287 | break; |
288 | } |
289 | |
290 | return 0; |
291 | } |
292 | |
293 | static u8 nct7904_chan_to_index[] = { |
294 | 0, /* Not used */ |
295 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
296 | 18, 19, 20, 16 |
297 | }; |
298 | |
299 | static int nct7904_read_in(struct device *dev, u32 attr, int channel, |
300 | long *val) |
301 | { |
302 | struct nct7904_data *data = dev_get_drvdata(dev); |
303 | int ret, volt, index; |
304 | |
305 | index = nct7904_chan_to_index[channel]; |
306 | |
307 | switch (attr) { |
308 | case hwmon_in_input: |
309 | ret = nct7904_read_reg16(data, BANK_0, |
310 | VSEN1_HV_REG + index * 2); |
311 | if (ret < 0) |
312 | return ret; |
313 | volt = ((ret & 0xff00) >> 5) | (ret & 0x7); |
314 | if (index < 14) |
315 | volt *= 2; /* 0.002V scale */ |
316 | else |
317 | volt *= 6; /* 0.006V scale */ |
318 | *val = volt; |
319 | return 0; |
320 | case hwmon_in_min: |
321 | ret = nct7904_read_reg16(data, BANK_1, |
322 | VSEN1_HV_LL_REG + index * 4); |
323 | if (ret < 0) |
324 | return ret; |
325 | volt = ((ret & 0xff00) >> 5) | (ret & 0x7); |
326 | if (index < 14) |
327 | volt *= 2; /* 0.002V scale */ |
328 | else |
329 | volt *= 6; /* 0.006V scale */ |
330 | *val = volt; |
331 | return 0; |
332 | case hwmon_in_max: |
333 | ret = nct7904_read_reg16(data, BANK_1, |
334 | VSEN1_HV_HL_REG + index * 4); |
335 | if (ret < 0) |
336 | return ret; |
337 | volt = ((ret & 0xff00) >> 5) | (ret & 0x7); |
338 | if (index < 14) |
339 | volt *= 2; /* 0.002V scale */ |
340 | else |
341 | volt *= 6; /* 0.006V scale */ |
342 | *val = volt; |
343 | return 0; |
344 | case hwmon_in_alarm: |
345 | ret = nct7904_read_reg(data, BANK_0, |
346 | SMI_STS1_REG + (index >> 3)); |
347 | if (ret < 0) |
348 | return ret; |
349 | if (!data->vsen_alarm[index >> 3]) |
350 | data->vsen_alarm[index >> 3] = ret & 0xff; |
351 | else |
352 | /* If there is new alarm showing up */ |
353 | data->vsen_alarm[index >> 3] |= (ret & 0xff); |
354 | *val = (data->vsen_alarm[index >> 3] >> (index & 0x07)) & 1; |
355 | /* Needs to clean the alarm if alarm existing */ |
356 | if (*val) |
357 | data->vsen_alarm[index >> 3] ^= 1 << (index & 0x07); |
358 | return 0; |
359 | default: |
360 | return -EOPNOTSUPP; |
361 | } |
362 | } |
363 | |
364 | static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel) |
365 | { |
366 | const struct nct7904_data *data = _data; |
367 | int index = nct7904_chan_to_index[channel]; |
368 | |
369 | switch (attr) { |
370 | case hwmon_in_input: |
371 | case hwmon_in_alarm: |
372 | if (channel > 0 && (data->vsen_mask & BIT(index))) |
373 | return 0444; |
374 | break; |
375 | case hwmon_in_min: |
376 | case hwmon_in_max: |
377 | if (channel > 0 && (data->vsen_mask & BIT(index))) |
378 | return 0644; |
379 | break; |
380 | default: |
381 | break; |
382 | } |
383 | |
384 | return 0; |
385 | } |
386 | |
387 | static int nct7904_read_temp(struct device *dev, u32 attr, int channel, |
388 | long *val) |
389 | { |
390 | struct nct7904_data *data = dev_get_drvdata(dev); |
391 | int ret, temp; |
392 | unsigned int reg1, reg2, reg3; |
393 | s8 temps; |
394 | |
395 | switch (attr) { |
396 | case hwmon_temp_input: |
397 | if (channel == 4) |
398 | ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG); |
399 | else if (channel < 5) |
400 | ret = nct7904_read_reg16(data, BANK_0, |
401 | TEMP_CH1_HV_REG + channel * 4); |
402 | else |
403 | ret = nct7904_read_reg16(data, BANK_0, |
404 | T_CPU1_HV_REG + (channel - 5) |
405 | * 2); |
406 | if (ret < 0) |
407 | return ret; |
408 | temp = ((ret & 0xff00) >> 5) | (ret & 0x7); |
409 | *val = sign_extend32(value: temp, index: 10) * 125; |
410 | return 0; |
411 | case hwmon_temp_alarm: |
412 | if (channel == 4) { |
413 | ret = nct7904_read_reg(data, BANK_0, |
414 | SMI_STS3_REG); |
415 | if (ret < 0) |
416 | return ret; |
417 | *val = (ret >> 1) & 1; |
418 | } else if (channel < 4) { |
419 | ret = nct7904_read_reg(data, BANK_0, |
420 | SMI_STS1_REG); |
421 | if (ret < 0) |
422 | return ret; |
423 | *val = (ret >> (((channel * 2) + 1) & 0x07)) & 1; |
424 | } else { |
425 | if ((channel - 5) < 4) { |
426 | ret = nct7904_read_reg(data, BANK_0, |
427 | SMI_STS7_REG + |
428 | ((channel - 5) >> 3)); |
429 | if (ret < 0) |
430 | return ret; |
431 | *val = (ret >> ((channel - 5) & 0x07)) & 1; |
432 | } else { |
433 | ret = nct7904_read_reg(data, BANK_0, |
434 | SMI_STS8_REG + |
435 | ((channel - 5) >> 3)); |
436 | if (ret < 0) |
437 | return ret; |
438 | *val = (ret >> (((channel - 5) & 0x07) - 4)) |
439 | & 1; |
440 | } |
441 | } |
442 | return 0; |
443 | case hwmon_temp_type: |
444 | if (channel < 5) { |
445 | if ((data->tcpu_mask >> channel) & 0x01) { |
446 | if ((data->temp_mode >> channel) & 0x01) |
447 | *val = 3; /* TD */ |
448 | else |
449 | *val = 4; /* TR */ |
450 | } else { |
451 | *val = 0; |
452 | } |
453 | } else { |
454 | if ((data->has_dts >> (channel - 5)) & 0x01) { |
455 | if (data->enable_dts & ENABLE_TSI) |
456 | *val = 5; /* TSI */ |
457 | else |
458 | *val = 6; /* PECI */ |
459 | } else { |
460 | *val = 0; |
461 | } |
462 | } |
463 | return 0; |
464 | case hwmon_temp_max: |
465 | reg1 = LTD_HV_LL_REG; |
466 | reg2 = TEMP_CH1_W_REG; |
467 | reg3 = DTS_T_CPU1_W_REG; |
468 | break; |
469 | case hwmon_temp_max_hyst: |
470 | reg1 = LTD_LV_LL_REG; |
471 | reg2 = TEMP_CH1_WH_REG; |
472 | reg3 = DTS_T_CPU1_WH_REG; |
473 | break; |
474 | case hwmon_temp_crit: |
475 | reg1 = LTD_HV_HL_REG; |
476 | reg2 = TEMP_CH1_C_REG; |
477 | reg3 = DTS_T_CPU1_C_REG; |
478 | break; |
479 | case hwmon_temp_crit_hyst: |
480 | reg1 = LTD_LV_HL_REG; |
481 | reg2 = TEMP_CH1_CH_REG; |
482 | reg3 = DTS_T_CPU1_CH_REG; |
483 | break; |
484 | default: |
485 | return -EOPNOTSUPP; |
486 | } |
487 | |
488 | if (channel == 4) |
489 | ret = nct7904_read_reg(data, BANK_1, reg: reg1); |
490 | else if (channel < 5) |
491 | ret = nct7904_read_reg(data, BANK_1, |
492 | reg: reg2 + channel * 8); |
493 | else |
494 | ret = nct7904_read_reg(data, BANK_1, |
495 | reg: reg3 + (channel - 5) * 4); |
496 | |
497 | if (ret < 0) |
498 | return ret; |
499 | temps = ret; |
500 | *val = temps * 1000; |
501 | return 0; |
502 | } |
503 | |
504 | static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel) |
505 | { |
506 | const struct nct7904_data *data = _data; |
507 | |
508 | switch (attr) { |
509 | case hwmon_temp_input: |
510 | case hwmon_temp_alarm: |
511 | case hwmon_temp_type: |
512 | if (channel < 5) { |
513 | if (data->tcpu_mask & BIT(channel)) |
514 | return 0444; |
515 | } else { |
516 | if (data->has_dts & BIT(channel - 5)) |
517 | return 0444; |
518 | } |
519 | break; |
520 | case hwmon_temp_max: |
521 | case hwmon_temp_max_hyst: |
522 | case hwmon_temp_crit: |
523 | case hwmon_temp_crit_hyst: |
524 | if (channel < 5) { |
525 | if (data->tcpu_mask & BIT(channel)) |
526 | return 0644; |
527 | } else { |
528 | if (data->has_dts & BIT(channel - 5)) |
529 | return 0644; |
530 | } |
531 | break; |
532 | default: |
533 | break; |
534 | } |
535 | |
536 | return 0; |
537 | } |
538 | |
539 | static int nct7904_read_pwm(struct device *dev, u32 attr, int channel, |
540 | long *val) |
541 | { |
542 | struct nct7904_data *data = dev_get_drvdata(dev); |
543 | int ret; |
544 | |
545 | switch (attr) { |
546 | case hwmon_pwm_input: |
547 | ret = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + channel); |
548 | if (ret < 0) |
549 | return ret; |
550 | *val = ret; |
551 | return 0; |
552 | case hwmon_pwm_enable: |
553 | ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + channel); |
554 | if (ret < 0) |
555 | return ret; |
556 | |
557 | *val = ret ? 2 : 1; |
558 | return 0; |
559 | default: |
560 | return -EOPNOTSUPP; |
561 | } |
562 | } |
563 | |
564 | static int nct7904_write_temp(struct device *dev, u32 attr, int channel, |
565 | long val) |
566 | { |
567 | struct nct7904_data *data = dev_get_drvdata(dev); |
568 | int ret; |
569 | unsigned int reg1, reg2, reg3; |
570 | |
571 | val = clamp_val(val / 1000, -128, 127); |
572 | |
573 | switch (attr) { |
574 | case hwmon_temp_max: |
575 | reg1 = LTD_HV_LL_REG; |
576 | reg2 = TEMP_CH1_W_REG; |
577 | reg3 = DTS_T_CPU1_W_REG; |
578 | break; |
579 | case hwmon_temp_max_hyst: |
580 | reg1 = LTD_LV_LL_REG; |
581 | reg2 = TEMP_CH1_WH_REG; |
582 | reg3 = DTS_T_CPU1_WH_REG; |
583 | break; |
584 | case hwmon_temp_crit: |
585 | reg1 = LTD_HV_HL_REG; |
586 | reg2 = TEMP_CH1_C_REG; |
587 | reg3 = DTS_T_CPU1_C_REG; |
588 | break; |
589 | case hwmon_temp_crit_hyst: |
590 | reg1 = LTD_LV_HL_REG; |
591 | reg2 = TEMP_CH1_CH_REG; |
592 | reg3 = DTS_T_CPU1_CH_REG; |
593 | break; |
594 | default: |
595 | return -EOPNOTSUPP; |
596 | } |
597 | if (channel == 4) |
598 | ret = nct7904_write_reg(data, BANK_1, reg: reg1, val); |
599 | else if (channel < 5) |
600 | ret = nct7904_write_reg(data, BANK_1, |
601 | reg: reg2 + channel * 8, val); |
602 | else |
603 | ret = nct7904_write_reg(data, BANK_1, |
604 | reg: reg3 + (channel - 5) * 4, val); |
605 | |
606 | return ret; |
607 | } |
608 | |
609 | static int nct7904_write_fan(struct device *dev, u32 attr, int channel, |
610 | long val) |
611 | { |
612 | struct nct7904_data *data = dev_get_drvdata(dev); |
613 | int ret; |
614 | u8 tmp; |
615 | |
616 | switch (attr) { |
617 | case hwmon_fan_min: |
618 | if (val <= 0) |
619 | return -EINVAL; |
620 | |
621 | val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), 1, 0x1fff); |
622 | tmp = (val >> 5) & 0xff; |
623 | ret = nct7904_write_reg(data, BANK_1, |
624 | FANIN1_HV_HL_REG + channel * 2, val: tmp); |
625 | if (ret < 0) |
626 | return ret; |
627 | tmp = val & 0x1f; |
628 | ret = nct7904_write_reg(data, BANK_1, |
629 | FANIN1_LV_HL_REG + channel * 2, val: tmp); |
630 | return ret; |
631 | default: |
632 | return -EOPNOTSUPP; |
633 | } |
634 | } |
635 | |
636 | static int nct7904_write_in(struct device *dev, u32 attr, int channel, |
637 | long val) |
638 | { |
639 | struct nct7904_data *data = dev_get_drvdata(dev); |
640 | int ret, index, tmp; |
641 | |
642 | index = nct7904_chan_to_index[channel]; |
643 | |
644 | if (index < 14) |
645 | val = val / 2; /* 0.002V scale */ |
646 | else |
647 | val = val / 6; /* 0.006V scale */ |
648 | |
649 | val = clamp_val(val, 0, 0x7ff); |
650 | |
651 | switch (attr) { |
652 | case hwmon_in_min: |
653 | tmp = nct7904_read_reg(data, BANK_1, |
654 | VSEN1_LV_LL_REG + index * 4); |
655 | if (tmp < 0) |
656 | return tmp; |
657 | tmp &= ~0x7; |
658 | tmp |= val & 0x7; |
659 | ret = nct7904_write_reg(data, BANK_1, |
660 | VSEN1_LV_LL_REG + index * 4, val: tmp); |
661 | if (ret < 0) |
662 | return ret; |
663 | tmp = nct7904_read_reg(data, BANK_1, |
664 | VSEN1_HV_LL_REG + index * 4); |
665 | if (tmp < 0) |
666 | return tmp; |
667 | tmp = (val >> 3) & 0xff; |
668 | ret = nct7904_write_reg(data, BANK_1, |
669 | VSEN1_HV_LL_REG + index * 4, val: tmp); |
670 | return ret; |
671 | case hwmon_in_max: |
672 | tmp = nct7904_read_reg(data, BANK_1, |
673 | VSEN1_LV_HL_REG + index * 4); |
674 | if (tmp < 0) |
675 | return tmp; |
676 | tmp &= ~0x7; |
677 | tmp |= val & 0x7; |
678 | ret = nct7904_write_reg(data, BANK_1, |
679 | VSEN1_LV_HL_REG + index * 4, val: tmp); |
680 | if (ret < 0) |
681 | return ret; |
682 | tmp = nct7904_read_reg(data, BANK_1, |
683 | VSEN1_HV_HL_REG + index * 4); |
684 | if (tmp < 0) |
685 | return tmp; |
686 | tmp = (val >> 3) & 0xff; |
687 | ret = nct7904_write_reg(data, BANK_1, |
688 | VSEN1_HV_HL_REG + index * 4, val: tmp); |
689 | return ret; |
690 | default: |
691 | return -EOPNOTSUPP; |
692 | } |
693 | } |
694 | |
695 | static int nct7904_write_pwm(struct device *dev, u32 attr, int channel, |
696 | long val) |
697 | { |
698 | struct nct7904_data *data = dev_get_drvdata(dev); |
699 | int ret; |
700 | |
701 | switch (attr) { |
702 | case hwmon_pwm_input: |
703 | if (val < 0 || val > 255) |
704 | return -EINVAL; |
705 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + channel, |
706 | val); |
707 | return ret; |
708 | case hwmon_pwm_enable: |
709 | if (val < 1 || val > 2 || |
710 | (val == 2 && !data->fan_mode[channel])) |
711 | return -EINVAL; |
712 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + channel, |
713 | val: val == 2 ? data->fan_mode[channel] : 0); |
714 | return ret; |
715 | default: |
716 | return -EOPNOTSUPP; |
717 | } |
718 | } |
719 | |
720 | static umode_t nct7904_pwm_is_visible(const void *_data, u32 attr, int channel) |
721 | { |
722 | switch (attr) { |
723 | case hwmon_pwm_input: |
724 | case hwmon_pwm_enable: |
725 | return 0644; |
726 | default: |
727 | return 0; |
728 | } |
729 | } |
730 | |
731 | static int nct7904_read(struct device *dev, enum hwmon_sensor_types type, |
732 | u32 attr, int channel, long *val) |
733 | { |
734 | switch (type) { |
735 | case hwmon_in: |
736 | return nct7904_read_in(dev, attr, channel, val); |
737 | case hwmon_fan: |
738 | return nct7904_read_fan(dev, attr, channel, val); |
739 | case hwmon_pwm: |
740 | return nct7904_read_pwm(dev, attr, channel, val); |
741 | case hwmon_temp: |
742 | return nct7904_read_temp(dev, attr, channel, val); |
743 | default: |
744 | return -EOPNOTSUPP; |
745 | } |
746 | } |
747 | |
748 | static int nct7904_write(struct device *dev, enum hwmon_sensor_types type, |
749 | u32 attr, int channel, long val) |
750 | { |
751 | switch (type) { |
752 | case hwmon_in: |
753 | return nct7904_write_in(dev, attr, channel, val); |
754 | case hwmon_fan: |
755 | return nct7904_write_fan(dev, attr, channel, val); |
756 | case hwmon_pwm: |
757 | return nct7904_write_pwm(dev, attr, channel, val); |
758 | case hwmon_temp: |
759 | return nct7904_write_temp(dev, attr, channel, val); |
760 | default: |
761 | return -EOPNOTSUPP; |
762 | } |
763 | } |
764 | |
765 | static umode_t nct7904_is_visible(const void *data, |
766 | enum hwmon_sensor_types type, |
767 | u32 attr, int channel) |
768 | { |
769 | switch (type) { |
770 | case hwmon_in: |
771 | return nct7904_in_is_visible(data: data, attr, channel); |
772 | case hwmon_fan: |
773 | return nct7904_fan_is_visible(data: data, attr, channel); |
774 | case hwmon_pwm: |
775 | return nct7904_pwm_is_visible(data: data, attr, channel); |
776 | case hwmon_temp: |
777 | return nct7904_temp_is_visible(data: data, attr, channel); |
778 | default: |
779 | return 0; |
780 | } |
781 | } |
782 | |
783 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
784 | static int nct7904_detect(struct i2c_client *client, |
785 | struct i2c_board_info *info) |
786 | { |
787 | struct i2c_adapter *adapter = client->adapter; |
788 | |
789 | if (!i2c_check_functionality(adap: adapter, |
790 | I2C_FUNC_SMBUS_READ_BYTE | |
791 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) |
792 | return -ENODEV; |
793 | |
794 | /* Determine the chip type. */ |
795 | if (i2c_smbus_read_byte_data(client, VENDOR_ID_REG) != NUVOTON_ID || |
796 | i2c_smbus_read_byte_data(client, CHIP_ID_REG) != NCT7904_ID || |
797 | (i2c_smbus_read_byte_data(client, DEVICE_ID_REG) & 0xf0) != 0x50 || |
798 | (i2c_smbus_read_byte_data(client, BANK_SEL_REG) & 0xf8) != 0x00) |
799 | return -ENODEV; |
800 | |
801 | strscpy(info->type, "nct7904" , I2C_NAME_SIZE); |
802 | |
803 | return 0; |
804 | } |
805 | |
806 | static const struct hwmon_channel_info * const nct7904_info[] = { |
807 | HWMON_CHANNEL_INFO(in, |
808 | /* dummy, skipped in is_visible */ |
809 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
810 | HWMON_I_ALARM, |
811 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
812 | HWMON_I_ALARM, |
813 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
814 | HWMON_I_ALARM, |
815 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
816 | HWMON_I_ALARM, |
817 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
818 | HWMON_I_ALARM, |
819 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
820 | HWMON_I_ALARM, |
821 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
822 | HWMON_I_ALARM, |
823 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
824 | HWMON_I_ALARM, |
825 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
826 | HWMON_I_ALARM, |
827 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
828 | HWMON_I_ALARM, |
829 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
830 | HWMON_I_ALARM, |
831 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
832 | HWMON_I_ALARM, |
833 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
834 | HWMON_I_ALARM, |
835 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
836 | HWMON_I_ALARM, |
837 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
838 | HWMON_I_ALARM, |
839 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
840 | HWMON_I_ALARM, |
841 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
842 | HWMON_I_ALARM, |
843 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
844 | HWMON_I_ALARM, |
845 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
846 | HWMON_I_ALARM, |
847 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
848 | HWMON_I_ALARM, |
849 | HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | |
850 | HWMON_I_ALARM), |
851 | HWMON_CHANNEL_INFO(fan, |
852 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
853 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
854 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
855 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
856 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
857 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
858 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
859 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
860 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
861 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
862 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, |
863 | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM), |
864 | HWMON_CHANNEL_INFO(pwm, |
865 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
866 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
867 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
868 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE), |
869 | HWMON_CHANNEL_INFO(temp, |
870 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
871 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
872 | HWMON_T_CRIT_HYST, |
873 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
874 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
875 | HWMON_T_CRIT_HYST, |
876 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
877 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
878 | HWMON_T_CRIT_HYST, |
879 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
880 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
881 | HWMON_T_CRIT_HYST, |
882 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
883 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
884 | HWMON_T_CRIT_HYST, |
885 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
886 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
887 | HWMON_T_CRIT_HYST, |
888 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
889 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
890 | HWMON_T_CRIT_HYST, |
891 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
892 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
893 | HWMON_T_CRIT_HYST, |
894 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
895 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
896 | HWMON_T_CRIT_HYST, |
897 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
898 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
899 | HWMON_T_CRIT_HYST, |
900 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
901 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
902 | HWMON_T_CRIT_HYST, |
903 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
904 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
905 | HWMON_T_CRIT_HYST, |
906 | HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX | |
907 | HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT | |
908 | HWMON_T_CRIT_HYST), |
909 | NULL |
910 | }; |
911 | |
912 | static const struct hwmon_ops nct7904_hwmon_ops = { |
913 | .is_visible = nct7904_is_visible, |
914 | .read = nct7904_read, |
915 | .write = nct7904_write, |
916 | }; |
917 | |
918 | static const struct hwmon_chip_info nct7904_chip_info = { |
919 | .ops = &nct7904_hwmon_ops, |
920 | .info = nct7904_info, |
921 | }; |
922 | |
923 | /* |
924 | * Watchdog Function |
925 | */ |
926 | static int nct7904_wdt_start(struct watchdog_device *wdt) |
927 | { |
928 | struct nct7904_data *data = watchdog_get_drvdata(wdd: wdt); |
929 | |
930 | /* Enable soft watchdog timer */ |
931 | return nct7904_write_reg(data, BANK_0, WDT_LOCK_REG, WDT_SOFT_EN); |
932 | } |
933 | |
934 | static int nct7904_wdt_stop(struct watchdog_device *wdt) |
935 | { |
936 | struct nct7904_data *data = watchdog_get_drvdata(wdd: wdt); |
937 | |
938 | return nct7904_write_reg(data, BANK_0, WDT_LOCK_REG, WDT_SOFT_DIS); |
939 | } |
940 | |
941 | static int nct7904_wdt_set_timeout(struct watchdog_device *wdt, |
942 | unsigned int timeout) |
943 | { |
944 | struct nct7904_data *data = watchdog_get_drvdata(wdd: wdt); |
945 | /* |
946 | * The NCT7904 is very special in watchdog function. |
947 | * Its minimum unit is minutes. And wdt->timeout needs |
948 | * to match the actual timeout selected. So, this needs |
949 | * to be: wdt->timeout = timeout / 60 * 60. |
950 | * For example, if the user configures a timeout of |
951 | * 119 seconds, the actual timeout will be 60 seconds. |
952 | * So, wdt->timeout must then be set to 60 seconds. |
953 | */ |
954 | wdt->timeout = timeout / 60 * 60; |
955 | |
956 | return nct7904_write_reg(data, BANK_0, WDT_TIMER_REG, |
957 | val: wdt->timeout / 60); |
958 | } |
959 | |
960 | static int nct7904_wdt_ping(struct watchdog_device *wdt) |
961 | { |
962 | /* |
963 | * Note: |
964 | * NCT7904 does not support refreshing WDT_TIMER_REG register when |
965 | * the watchdog is active. Please disable watchdog before feeding |
966 | * the watchdog and enable it again. |
967 | */ |
968 | struct nct7904_data *data = watchdog_get_drvdata(wdd: wdt); |
969 | int ret; |
970 | |
971 | /* Disable soft watchdog timer */ |
972 | ret = nct7904_write_reg(data, BANK_0, WDT_LOCK_REG, WDT_SOFT_DIS); |
973 | if (ret < 0) |
974 | return ret; |
975 | |
976 | /* feed watchdog */ |
977 | ret = nct7904_write_reg(data, BANK_0, WDT_TIMER_REG, val: wdt->timeout / 60); |
978 | if (ret < 0) |
979 | return ret; |
980 | |
981 | /* Enable soft watchdog timer */ |
982 | return nct7904_write_reg(data, BANK_0, WDT_LOCK_REG, WDT_SOFT_EN); |
983 | } |
984 | |
985 | static unsigned int nct7904_wdt_get_timeleft(struct watchdog_device *wdt) |
986 | { |
987 | struct nct7904_data *data = watchdog_get_drvdata(wdd: wdt); |
988 | int ret; |
989 | |
990 | ret = nct7904_read_reg(data, BANK_0, WDT_TIMER_REG); |
991 | if (ret < 0) |
992 | return 0; |
993 | |
994 | return ret * 60; |
995 | } |
996 | |
997 | static const struct watchdog_info nct7904_wdt_info = { |
998 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | |
999 | WDIOF_MAGICCLOSE, |
1000 | .identity = "nct7904 watchdog" , |
1001 | }; |
1002 | |
1003 | static const struct watchdog_ops nct7904_wdt_ops = { |
1004 | .owner = THIS_MODULE, |
1005 | .start = nct7904_wdt_start, |
1006 | .stop = nct7904_wdt_stop, |
1007 | .ping = nct7904_wdt_ping, |
1008 | .set_timeout = nct7904_wdt_set_timeout, |
1009 | .get_timeleft = nct7904_wdt_get_timeleft, |
1010 | }; |
1011 | |
1012 | static int nct7904_probe(struct i2c_client *client) |
1013 | { |
1014 | struct nct7904_data *data; |
1015 | struct device *hwmon_dev; |
1016 | struct device *dev = &client->dev; |
1017 | int ret, i; |
1018 | u32 mask; |
1019 | u8 val, bit; |
1020 | |
1021 | data = devm_kzalloc(dev, size: sizeof(struct nct7904_data), GFP_KERNEL); |
1022 | if (!data) |
1023 | return -ENOMEM; |
1024 | |
1025 | data->client = client; |
1026 | mutex_init(&data->bank_lock); |
1027 | data->bank_sel = -1; |
1028 | |
1029 | /* Setup sensor groups. */ |
1030 | /* FANIN attributes */ |
1031 | ret = nct7904_read_reg16(data, BANK_0, FANIN_CTRL0_REG); |
1032 | if (ret < 0) |
1033 | return ret; |
1034 | data->fanin_mask = (ret >> 8) | ((ret & 0xff) << 8); |
1035 | |
1036 | /* |
1037 | * VSEN attributes |
1038 | * |
1039 | * Note: voltage sensors overlap with external temperature |
1040 | * sensors. So, if we ever decide to support the latter |
1041 | * we will have to adjust 'vsen_mask' accordingly. |
1042 | */ |
1043 | mask = 0; |
1044 | ret = nct7904_read_reg16(data, BANK_0, VT_ADC_CTRL0_REG); |
1045 | if (ret >= 0) |
1046 | mask = (ret >> 8) | ((ret & 0xff) << 8); |
1047 | ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG); |
1048 | if (ret >= 0) |
1049 | mask |= (ret << 16); |
1050 | data->vsen_mask = mask; |
1051 | |
1052 | /* CPU_TEMP attributes */ |
1053 | ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL0_REG); |
1054 | if (ret < 0) |
1055 | return ret; |
1056 | |
1057 | if ((ret & 0x6) == 0x6) |
1058 | data->tcpu_mask |= 1; /* TR1 */ |
1059 | if ((ret & 0x18) == 0x18) |
1060 | data->tcpu_mask |= 2; /* TR2 */ |
1061 | if ((ret & 0x20) == 0x20) |
1062 | data->tcpu_mask |= 4; /* TR3 */ |
1063 | if ((ret & 0x80) == 0x80) |
1064 | data->tcpu_mask |= 8; /* TR4 */ |
1065 | |
1066 | /* LTD */ |
1067 | ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG); |
1068 | if (ret < 0) |
1069 | return ret; |
1070 | if ((ret & 0x02) == 0x02) |
1071 | data->tcpu_mask |= 0x10; |
1072 | |
1073 | /* Multi-Function detecting for Volt and TR/TD */ |
1074 | ret = nct7904_read_reg(data, BANK_0, VT_ADC_MD_REG); |
1075 | if (ret < 0) |
1076 | return ret; |
1077 | |
1078 | data->temp_mode = 0; |
1079 | for (i = 0; i < 4; i++) { |
1080 | val = (ret >> (i * 2)) & 0x03; |
1081 | bit = (1 << i); |
1082 | if (val == VOLT_MONITOR_MODE) { |
1083 | data->tcpu_mask &= ~bit; |
1084 | } else if (val == THERMAL_DIODE_MODE && i < 2) { |
1085 | data->temp_mode |= bit; |
1086 | data->vsen_mask &= ~(0x06 << (i * 2)); |
1087 | } else if (val == THERMISTOR_MODE) { |
1088 | data->vsen_mask &= ~(0x02 << (i * 2)); |
1089 | } else { |
1090 | /* Reserved */ |
1091 | data->tcpu_mask &= ~bit; |
1092 | data->vsen_mask &= ~(0x06 << (i * 2)); |
1093 | } |
1094 | } |
1095 | |
1096 | /* PECI */ |
1097 | ret = nct7904_read_reg(data, BANK_2, PFE_REG); |
1098 | if (ret < 0) |
1099 | return ret; |
1100 | if (ret & 0x80) { |
1101 | data->enable_dts = 1; /* Enable DTS & PECI */ |
1102 | } else { |
1103 | ret = nct7904_read_reg(data, BANK_2, TSI_CTRL_REG); |
1104 | if (ret < 0) |
1105 | return ret; |
1106 | if (ret & 0x80) |
1107 | data->enable_dts = 0x3; /* Enable DTS & TSI */ |
1108 | } |
1109 | |
1110 | /* Check DTS enable status */ |
1111 | if (data->enable_dts) { |
1112 | ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL0_REG); |
1113 | if (ret < 0) |
1114 | return ret; |
1115 | data->has_dts = ret & 0xF; |
1116 | if (data->enable_dts & ENABLE_TSI) { |
1117 | ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG); |
1118 | if (ret < 0) |
1119 | return ret; |
1120 | data->has_dts |= (ret & 0xF) << 4; |
1121 | } |
1122 | } |
1123 | |
1124 | for (i = 0; i < FANCTL_MAX; i++) { |
1125 | ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i); |
1126 | if (ret < 0) |
1127 | return ret; |
1128 | data->fan_mode[i] = ret; |
1129 | } |
1130 | |
1131 | /* Read all of SMI status register to clear alarms */ |
1132 | for (i = 0; i < SMI_STS_MAX; i++) { |
1133 | ret = nct7904_read_reg(data, BANK_0, SMI_STS1_REG + i); |
1134 | if (ret < 0) |
1135 | return ret; |
1136 | } |
1137 | |
1138 | hwmon_dev = |
1139 | devm_hwmon_device_register_with_info(dev, name: client->name, drvdata: data, |
1140 | info: &nct7904_chip_info, NULL); |
1141 | ret = PTR_ERR_OR_ZERO(ptr: hwmon_dev); |
1142 | if (ret) |
1143 | return ret; |
1144 | |
1145 | /* Watchdog initialization */ |
1146 | data->wdt.ops = &nct7904_wdt_ops; |
1147 | data->wdt.info = &nct7904_wdt_info; |
1148 | |
1149 | data->wdt.timeout = WATCHDOG_TIMEOUT * 60; /* Set default timeout */ |
1150 | data->wdt.min_timeout = MIN_TIMEOUT; |
1151 | data->wdt.max_timeout = MAX_TIMEOUT; |
1152 | data->wdt.parent = &client->dev; |
1153 | |
1154 | watchdog_init_timeout(wdd: &data->wdt, timeout_parm: timeout * 60, dev: &client->dev); |
1155 | watchdog_set_nowayout(wdd: &data->wdt, nowayout); |
1156 | watchdog_set_drvdata(wdd: &data->wdt, data); |
1157 | |
1158 | watchdog_stop_on_unregister(wdd: &data->wdt); |
1159 | |
1160 | return devm_watchdog_register_device(dev, &data->wdt); |
1161 | } |
1162 | |
1163 | static const struct i2c_device_id nct7904_id[] = { |
1164 | {"nct7904" , 0}, |
1165 | {} |
1166 | }; |
1167 | MODULE_DEVICE_TABLE(i2c, nct7904_id); |
1168 | |
1169 | static struct i2c_driver nct7904_driver = { |
1170 | .class = I2C_CLASS_HWMON, |
1171 | .driver = { |
1172 | .name = "nct7904" , |
1173 | }, |
1174 | .probe = nct7904_probe, |
1175 | .id_table = nct7904_id, |
1176 | .detect = nct7904_detect, |
1177 | .address_list = normal_i2c, |
1178 | }; |
1179 | |
1180 | module_i2c_driver(nct7904_driver); |
1181 | |
1182 | MODULE_AUTHOR("Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>" ); |
1183 | MODULE_DESCRIPTION("Hwmon driver for NUVOTON NCT7904" ); |
1184 | MODULE_LICENSE("GPL" ); |
1185 | |