xref: /linux/drivers/hwmon/nct6694-hwmon.c (revision 68a052239fc4b351e961f698b824f7654a346091)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Nuvoton NCT6694 HWMON driver based on USB interface.
4  *
5  * Copyright (C) 2025 Nuvoton Technology Corp.
6  */
7 
8 #include <linux/bits.h>
9 #include <linux/bitfield.h>
10 #include <linux/hwmon.h>
11 #include <linux/kernel.h>
12 #include <linux/mfd/core.h>
13 #include <linux/mfd/nct6694.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17 
18 /*
19  * USB command module type for NCT6694 report channel
20  * This defines the module type used for communication with the NCT6694
21  * report channel over the USB interface.
22  */
23 #define NCT6694_RPT_MOD			0xFF
24 
25 /* Report channel */
26 /*
27  * The report channel is used to report the status of the hardware monitor
28  * devices, such as voltage, temperature, fan speed, and PWM.
29  */
30 #define NCT6694_VIN_IDX(x)		(0x00 + (x))
31 #define NCT6694_TIN_IDX(x)			\
32 	({ typeof(x) (_x) = (x);		\
33 	 ((_x) < 10) ? (0x10 + ((_x) * 2)) :	\
34 	 (0x30 + (((_x) - 10) * 2)); })
35 #define NCT6694_FIN_IDX(x)		(0x50 + ((x) * 2))
36 #define NCT6694_PWM_IDX(x)		(0x70 + (x))
37 #define NCT6694_VIN_STS(x)		(0x68 + (x))
38 #define NCT6694_TIN_STS(x)		(0x6A + (x))
39 #define NCT6694_FIN_STS(x)		(0x6E + (x))
40 
41 /*
42  * USB command module type for NCT6694 HWMON controller.
43  * This defines the module type used for communication with the NCT6694
44  * HWMON controller over the USB interface.
45  */
46 #define NCT6694_HWMON_MOD		0x00
47 
48 /* Command 00h - Hardware Monitor Control */
49 #define NCT6694_HWMON_CONTROL		0x00
50 #define NCT6694_HWMON_CONTROL_SEL	0x00
51 
52 /* Command 02h - Alarm Control */
53 #define NCT6694_HWMON_ALARM		0x02
54 #define NCT6694_HWMON_ALARM_SEL		0x00
55 
56 /*
57  * USB command module type for NCT6694 PWM controller.
58  * This defines the module type used for communication with the NCT6694
59  * PWM controller over the USB interface.
60  */
61 #define NCT6694_PWM_MOD			0x01
62 
63 /* PWM Command - Manual Control */
64 #define NCT6694_PWM_CONTROL		0x01
65 #define NCT6694_PWM_CONTROL_SEL		0x00
66 
67 #define NCT6694_FREQ_FROM_REG(reg)	((reg) * 25000 / 255)
68 #define NCT6694_FREQ_TO_REG(val)	\
69 	(DIV_ROUND_CLOSEST(clamp_val((val), 100, 25000) * 255, 25000))
70 
71 #define NCT6694_LSB_REG_MASK		GENMASK(7, 5)
72 #define NCT6694_TIN_HYST_MASK		GENMASK(7, 5)
73 
74 enum nct6694_hwmon_temp_mode {
75 	NCT6694_HWMON_TWOTIME_IRQ = 0,
76 	NCT6694_HWMON_ONETIME_IRQ,
77 	NCT6694_HWMON_REALTIME_IRQ,
78 	NCT6694_HWMON_COMPARE_IRQ,
79 };
80 
81 struct __packed nct6694_hwmon_control {
82 	u8 vin_en[2];
83 	u8 tin_en[2];
84 	u8 fin_en[2];
85 	u8 pwm_en[2];
86 	u8 reserved1[40];
87 	u8 pwm_freq[10];
88 	u8 reserved2[6];
89 };
90 
91 struct __packed nct6694_hwmon_alarm {
92 	u8 smi_ctrl;
93 	u8 reserved1[15];
94 	struct {
95 		u8 hl;
96 		u8 ll;
97 	} vin_limit[16];
98 	struct {
99 		u8 hyst;
100 		s8 hl;
101 	} tin_cfg[32];
102 	__be16 fin_ll[10];
103 	u8 reserved2[4];
104 };
105 
106 struct __packed nct6694_pwm_control {
107 	u8 mal_en[2];
108 	u8 mal_val[10];
109 	u8 reserved[12];
110 };
111 
112 union __packed nct6694_hwmon_rpt {
113 	u8 vin;
114 	struct {
115 		u8 msb;
116 		u8 lsb;
117 	} tin;
118 	__be16 fin;
119 	u8 pwm;
120 	u8 status;
121 };
122 
123 union __packed nct6694_hwmon_msg {
124 	struct nct6694_hwmon_alarm hwmon_alarm;
125 	struct nct6694_pwm_control pwm_ctrl;
126 };
127 
128 struct nct6694_hwmon_data {
129 	struct nct6694 *nct6694;
130 	struct mutex lock;
131 	struct nct6694_hwmon_control hwmon_en;
132 	union nct6694_hwmon_rpt *rpt;
133 	union nct6694_hwmon_msg *msg;
134 };
135 
136 static inline long in_from_reg(u8 reg)
137 {
138 	return reg * 16;
139 }
140 
141 static inline u8 in_to_reg(long val)
142 {
143 	return DIV_ROUND_CLOSEST(val, 16);
144 }
145 
146 static inline long temp_from_reg(s8 reg)
147 {
148 	return reg * 1000;
149 }
150 
151 static inline s8 temp_to_reg(long val)
152 {
153 	return DIV_ROUND_CLOSEST(val, 1000);
154 }
155 
156 #define NCT6694_HWMON_IN_CONFIG (HWMON_I_INPUT | HWMON_I_ENABLE |	\
157 				 HWMON_I_MAX | HWMON_I_MIN |		\
158 				 HWMON_I_ALARM)
159 #define NCT6694_HWMON_TEMP_CONFIG (HWMON_T_INPUT | HWMON_T_ENABLE |	\
160 				   HWMON_T_MAX | HWMON_T_MAX_HYST |	\
161 				   HWMON_T_MAX_ALARM)
162 #define NCT6694_HWMON_FAN_CONFIG (HWMON_F_INPUT | HWMON_F_ENABLE |	\
163 				  HWMON_F_MIN | HWMON_F_MIN_ALARM)
164 #define NCT6694_HWMON_PWM_CONFIG (HWMON_PWM_INPUT | HWMON_PWM_ENABLE |	\
165 				  HWMON_PWM_FREQ)
166 static const struct hwmon_channel_info *nct6694_info[] = {
167 	HWMON_CHANNEL_INFO(in,
168 			   NCT6694_HWMON_IN_CONFIG,	/* VIN0 */
169 			   NCT6694_HWMON_IN_CONFIG,	/* VIN1 */
170 			   NCT6694_HWMON_IN_CONFIG,	/* VIN2 */
171 			   NCT6694_HWMON_IN_CONFIG,	/* VIN3 */
172 			   NCT6694_HWMON_IN_CONFIG,	/* VIN5 */
173 			   NCT6694_HWMON_IN_CONFIG,	/* VIN6 */
174 			   NCT6694_HWMON_IN_CONFIG,	/* VIN7 */
175 			   NCT6694_HWMON_IN_CONFIG,	/* VIN14 */
176 			   NCT6694_HWMON_IN_CONFIG,	/* VIN15 */
177 			   NCT6694_HWMON_IN_CONFIG,	/* VIN16 */
178 			   NCT6694_HWMON_IN_CONFIG,	/* VBAT */
179 			   NCT6694_HWMON_IN_CONFIG,	/* VSB */
180 			   NCT6694_HWMON_IN_CONFIG,	/* AVSB */
181 			   NCT6694_HWMON_IN_CONFIG,	/* VCC */
182 			   NCT6694_HWMON_IN_CONFIG,	/* VHIF */
183 			   NCT6694_HWMON_IN_CONFIG),	/* VTT */
184 
185 	HWMON_CHANNEL_INFO(temp,
186 			   NCT6694_HWMON_TEMP_CONFIG,	/* THR1 */
187 			   NCT6694_HWMON_TEMP_CONFIG,	/* THR2 */
188 			   NCT6694_HWMON_TEMP_CONFIG,	/* THR14 */
189 			   NCT6694_HWMON_TEMP_CONFIG,	/* THR15 */
190 			   NCT6694_HWMON_TEMP_CONFIG,	/* THR16 */
191 			   NCT6694_HWMON_TEMP_CONFIG,	/* TDP0 */
192 			   NCT6694_HWMON_TEMP_CONFIG,	/* TDP1 */
193 			   NCT6694_HWMON_TEMP_CONFIG,	/* TDP2 */
194 			   NCT6694_HWMON_TEMP_CONFIG,	/* TDP3 */
195 			   NCT6694_HWMON_TEMP_CONFIG,	/* TDP4 */
196 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN0 */
197 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN1 */
198 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN2 */
199 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN3 */
200 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN4 */
201 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN5 */
202 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN6 */
203 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN7 */
204 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN8 */
205 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN9 */
206 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN10 */
207 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN11 */
208 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN12 */
209 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN13 */
210 			   NCT6694_HWMON_TEMP_CONFIG,	/* DTIN14 */
211 			   NCT6694_HWMON_TEMP_CONFIG),	/* DTIN15 */
212 
213 	HWMON_CHANNEL_INFO(fan,
214 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN0 */
215 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN1 */
216 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN2 */
217 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN3 */
218 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN4 */
219 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN5 */
220 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN6 */
221 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN7 */
222 			   NCT6694_HWMON_FAN_CONFIG,	/* FIN8 */
223 			   NCT6694_HWMON_FAN_CONFIG),	/* FIN9 */
224 
225 	HWMON_CHANNEL_INFO(pwm,
226 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM0 */
227 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM1 */
228 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM2 */
229 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM3 */
230 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM4 */
231 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM5 */
232 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM6 */
233 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM7 */
234 			   NCT6694_HWMON_PWM_CONFIG,	/* PWM8 */
235 			   NCT6694_HWMON_PWM_CONFIG),	/* PWM9 */
236 	NULL
237 };
238 
239 static int nct6694_in_read(struct device *dev, u32 attr, int channel,
240 			   long *val)
241 {
242 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
243 	struct nct6694_cmd_header cmd_hd;
244 	unsigned char vin_en;
245 	int ret;
246 
247 	guard(mutex)(&data->lock);
248 
249 	switch (attr) {
250 	case hwmon_in_enable:
251 		vin_en = data->hwmon_en.vin_en[(channel / 8)];
252 		*val = !!(vin_en & BIT(channel % 8));
253 
254 		return 0;
255 	case hwmon_in_input:
256 		cmd_hd = (struct nct6694_cmd_header) {
257 			.mod = NCT6694_RPT_MOD,
258 			.offset = cpu_to_le16(NCT6694_VIN_IDX(channel)),
259 			.len = cpu_to_le16(sizeof(data->rpt->vin))
260 		};
261 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
262 				       &data->rpt->vin);
263 		if (ret)
264 			return ret;
265 
266 		*val = in_from_reg(data->rpt->vin);
267 
268 		return 0;
269 	case hwmon_in_max:
270 		cmd_hd = (struct nct6694_cmd_header) {
271 			.mod = NCT6694_HWMON_MOD,
272 			.cmd = NCT6694_HWMON_ALARM,
273 			.sel = NCT6694_HWMON_ALARM_SEL,
274 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
275 		};
276 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
277 				       &data->msg->hwmon_alarm);
278 		if (ret)
279 			return ret;
280 
281 		*val = in_from_reg(data->msg->hwmon_alarm.vin_limit[channel].hl);
282 
283 		return 0;
284 	case hwmon_in_min:
285 		cmd_hd = (struct nct6694_cmd_header) {
286 			.mod = NCT6694_HWMON_MOD,
287 			.cmd = NCT6694_HWMON_ALARM,
288 			.sel = NCT6694_HWMON_ALARM_SEL,
289 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
290 		};
291 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
292 				       &data->msg->hwmon_alarm);
293 		if (ret)
294 			return ret;
295 
296 		*val = in_from_reg(data->msg->hwmon_alarm.vin_limit[channel].ll);
297 
298 		return 0;
299 	case hwmon_in_alarm:
300 		cmd_hd = (struct nct6694_cmd_header) {
301 			.mod = NCT6694_RPT_MOD,
302 			.offset = cpu_to_le16(NCT6694_VIN_STS(channel / 8)),
303 			.len = cpu_to_le16(sizeof(data->rpt->status))
304 		};
305 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
306 				       &data->rpt->status);
307 		if (ret)
308 			return ret;
309 
310 		*val = !!(data->rpt->status & BIT(channel % 8));
311 
312 		return 0;
313 	default:
314 		return -EOPNOTSUPP;
315 	}
316 }
317 
318 static int nct6694_temp_read(struct device *dev, u32 attr, int channel,
319 			     long *val)
320 {
321 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
322 	struct nct6694_cmd_header cmd_hd;
323 	unsigned char temp_en, temp_hyst;
324 	signed char temp_max;
325 	int ret, temp_raw;
326 
327 	guard(mutex)(&data->lock);
328 
329 	switch (attr) {
330 	case hwmon_temp_enable:
331 		temp_en = data->hwmon_en.tin_en[channel / 8];
332 		*val = !!(temp_en & BIT(channel % 8));
333 
334 		return 0;
335 	case hwmon_temp_input:
336 		cmd_hd = (struct nct6694_cmd_header) {
337 			.mod = NCT6694_RPT_MOD,
338 			.offset = cpu_to_le16(NCT6694_TIN_IDX(channel)),
339 			.len = cpu_to_le16(sizeof(data->rpt->tin))
340 		};
341 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
342 				       &data->rpt->tin);
343 		if (ret)
344 			return ret;
345 
346 		temp_raw = data->rpt->tin.msb << 3;
347 		temp_raw |= FIELD_GET(NCT6694_LSB_REG_MASK, data->rpt->tin.lsb);
348 
349 		/* Real temperature(milli degrees Celsius) = temp_raw * 1000 * 0.125 */
350 		*val = sign_extend32(temp_raw, 10) * 125;
351 
352 		return 0;
353 	case hwmon_temp_max:
354 		cmd_hd = (struct nct6694_cmd_header) {
355 			.mod = NCT6694_HWMON_MOD,
356 			.cmd = NCT6694_HWMON_ALARM,
357 			.sel = NCT6694_HWMON_ALARM_SEL,
358 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
359 		};
360 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
361 				       &data->msg->hwmon_alarm);
362 		if (ret)
363 			return ret;
364 
365 		*val = temp_from_reg(data->msg->hwmon_alarm.tin_cfg[channel].hl);
366 
367 		return 0;
368 	case hwmon_temp_max_hyst:
369 		cmd_hd = (struct nct6694_cmd_header) {
370 			.mod = NCT6694_HWMON_MOD,
371 			.cmd = NCT6694_HWMON_ALARM,
372 			.sel = NCT6694_HWMON_ALARM_SEL,
373 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
374 		};
375 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
376 				       &data->msg->hwmon_alarm);
377 		if (ret)
378 			return ret;
379 
380 		temp_max = data->msg->hwmon_alarm.tin_cfg[channel].hl;
381 		temp_hyst = FIELD_GET(NCT6694_TIN_HYST_MASK,
382 				      data->msg->hwmon_alarm.tin_cfg[channel].hyst);
383 		*val = temp_from_reg(temp_max - temp_hyst);
384 
385 		return 0;
386 	case hwmon_temp_max_alarm:
387 		cmd_hd = (struct nct6694_cmd_header) {
388 			.mod = NCT6694_RPT_MOD,
389 			.offset = cpu_to_le16(NCT6694_TIN_STS(channel / 8)),
390 			.len = cpu_to_le16(sizeof(data->rpt->status))
391 		};
392 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
393 				       &data->rpt->status);
394 		if (ret)
395 			return ret;
396 
397 		*val = !!(data->rpt->status & BIT(channel % 8));
398 
399 		return 0;
400 	default:
401 		return -EOPNOTSUPP;
402 	}
403 }
404 
405 static int nct6694_fan_read(struct device *dev, u32 attr, int channel,
406 			    long *val)
407 {
408 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
409 	struct nct6694_cmd_header cmd_hd;
410 	unsigned char fanin_en;
411 	int ret;
412 
413 	guard(mutex)(&data->lock);
414 
415 	switch (attr) {
416 	case hwmon_fan_enable:
417 		fanin_en = data->hwmon_en.fin_en[channel / 8];
418 		*val = !!(fanin_en & BIT(channel % 8));
419 
420 		return 0;
421 	case hwmon_fan_input:
422 		cmd_hd = (struct nct6694_cmd_header) {
423 			.mod = NCT6694_RPT_MOD,
424 			.offset = cpu_to_le16(NCT6694_FIN_IDX(channel)),
425 			.len = cpu_to_le16(sizeof(data->rpt->fin))
426 		};
427 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
428 				       &data->rpt->fin);
429 		if (ret)
430 			return ret;
431 
432 		*val = be16_to_cpu(data->rpt->fin);
433 
434 		return 0;
435 	case hwmon_fan_min:
436 		cmd_hd = (struct nct6694_cmd_header) {
437 			.mod = NCT6694_HWMON_MOD,
438 			.cmd = NCT6694_HWMON_ALARM,
439 			.sel = NCT6694_HWMON_ALARM_SEL,
440 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
441 		};
442 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
443 				       &data->msg->hwmon_alarm);
444 		if (ret)
445 			return ret;
446 
447 		*val = be16_to_cpu(data->msg->hwmon_alarm.fin_ll[channel]);
448 
449 		return 0;
450 	case hwmon_fan_min_alarm:
451 		cmd_hd = (struct nct6694_cmd_header) {
452 			.mod = NCT6694_RPT_MOD,
453 			.offset = cpu_to_le16(NCT6694_FIN_STS(channel / 8)),
454 			.len = cpu_to_le16(sizeof(data->rpt->status))
455 		};
456 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
457 				       &data->rpt->status);
458 		if (ret)
459 			return ret;
460 
461 		*val = !!(data->rpt->status & BIT(channel % 8));
462 
463 		return 0;
464 	default:
465 		return -EOPNOTSUPP;
466 	}
467 }
468 
469 static int nct6694_pwm_read(struct device *dev, u32 attr, int channel,
470 			    long *val)
471 {
472 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
473 	struct nct6694_cmd_header cmd_hd;
474 	unsigned char pwm_en;
475 	int ret;
476 
477 	guard(mutex)(&data->lock);
478 
479 	switch (attr) {
480 	case hwmon_pwm_enable:
481 		pwm_en = data->hwmon_en.pwm_en[channel / 8];
482 		*val = !!(pwm_en & BIT(channel % 8));
483 
484 		return 0;
485 	case hwmon_pwm_input:
486 		cmd_hd = (struct nct6694_cmd_header) {
487 			.mod = NCT6694_RPT_MOD,
488 			.offset = cpu_to_le16(NCT6694_PWM_IDX(channel)),
489 			.len = cpu_to_le16(sizeof(data->rpt->pwm))
490 		};
491 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
492 				       &data->rpt->pwm);
493 		if (ret)
494 			return ret;
495 
496 		*val = data->rpt->pwm;
497 
498 		return 0;
499 	case hwmon_pwm_freq:
500 		*val = NCT6694_FREQ_FROM_REG(data->hwmon_en.pwm_freq[channel]);
501 
502 		return 0;
503 	default:
504 		return -EOPNOTSUPP;
505 	}
506 }
507 
508 static int nct6694_in_write(struct device *dev, u32 attr, int channel,
509 			    long val)
510 {
511 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
512 	struct nct6694_cmd_header cmd_hd;
513 	int ret;
514 
515 	guard(mutex)(&data->lock);
516 
517 	switch (attr) {
518 	case hwmon_in_enable:
519 		if (val == 0)
520 			data->hwmon_en.vin_en[channel / 8] &= ~BIT(channel % 8);
521 		else if (val == 1)
522 			data->hwmon_en.vin_en[channel / 8] |= BIT(channel % 8);
523 		else
524 			return -EINVAL;
525 
526 		cmd_hd = (struct nct6694_cmd_header) {
527 			.mod = NCT6694_HWMON_MOD,
528 			.cmd = NCT6694_HWMON_CONTROL,
529 			.sel = NCT6694_HWMON_CONTROL_SEL,
530 			.len = cpu_to_le16(sizeof(data->hwmon_en))
531 		};
532 
533 		return nct6694_write_msg(data->nct6694, &cmd_hd,
534 					 &data->hwmon_en);
535 	case hwmon_in_max:
536 		cmd_hd = (struct nct6694_cmd_header) {
537 			.mod = NCT6694_HWMON_MOD,
538 			.cmd = NCT6694_HWMON_ALARM,
539 			.sel = NCT6694_HWMON_ALARM_SEL,
540 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
541 		};
542 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
543 				       &data->msg->hwmon_alarm);
544 		if (ret)
545 			return ret;
546 
547 		val = clamp_val(val, 0, 2032);
548 		data->msg->hwmon_alarm.vin_limit[channel].hl = in_to_reg(val);
549 
550 		return nct6694_write_msg(data->nct6694, &cmd_hd,
551 					 &data->msg->hwmon_alarm);
552 	case hwmon_in_min:
553 		cmd_hd = (struct nct6694_cmd_header) {
554 			.mod = NCT6694_HWMON_MOD,
555 			.cmd = NCT6694_HWMON_ALARM,
556 			.sel = NCT6694_HWMON_ALARM_SEL,
557 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
558 		};
559 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
560 				       &data->msg->hwmon_alarm);
561 		if (ret)
562 			return ret;
563 
564 		val = clamp_val(val, 0, 2032);
565 		data->msg->hwmon_alarm.vin_limit[channel].ll = in_to_reg(val);
566 
567 		return nct6694_write_msg(data->nct6694, &cmd_hd,
568 					 &data->msg->hwmon_alarm);
569 	default:
570 		return -EOPNOTSUPP;
571 	}
572 }
573 
574 static int nct6694_temp_write(struct device *dev, u32 attr, int channel,
575 			      long val)
576 {
577 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
578 	struct nct6694_cmd_header cmd_hd;
579 	unsigned char temp_hyst;
580 	signed char temp_max;
581 	int ret;
582 
583 	guard(mutex)(&data->lock);
584 
585 	switch (attr) {
586 	case hwmon_temp_enable:
587 		if (val == 0)
588 			data->hwmon_en.tin_en[channel / 8] &= ~BIT(channel % 8);
589 		else if (val == 1)
590 			data->hwmon_en.tin_en[channel / 8] |= BIT(channel % 8);
591 		else
592 			return -EINVAL;
593 
594 		cmd_hd = (struct nct6694_cmd_header) {
595 			.mod = NCT6694_HWMON_MOD,
596 			.cmd = NCT6694_HWMON_CONTROL,
597 			.sel = NCT6694_HWMON_CONTROL_SEL,
598 			.len = cpu_to_le16(sizeof(data->hwmon_en))
599 		};
600 
601 		return nct6694_write_msg(data->nct6694, &cmd_hd,
602 					 &data->hwmon_en);
603 	case hwmon_temp_max:
604 		cmd_hd = (struct nct6694_cmd_header) {
605 			.mod = NCT6694_HWMON_MOD,
606 			.cmd = NCT6694_HWMON_ALARM,
607 			.sel = NCT6694_HWMON_ALARM_SEL,
608 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
609 		};
610 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
611 				       &data->msg->hwmon_alarm);
612 		if (ret)
613 			return ret;
614 
615 		val = clamp_val(val, -127000, 127000);
616 		data->msg->hwmon_alarm.tin_cfg[channel].hl = temp_to_reg(val);
617 
618 		return nct6694_write_msg(data->nct6694, &cmd_hd,
619 					 &data->msg->hwmon_alarm);
620 	case hwmon_temp_max_hyst:
621 		cmd_hd = (struct nct6694_cmd_header) {
622 			.mod = NCT6694_HWMON_MOD,
623 			.cmd = NCT6694_HWMON_ALARM,
624 			.sel = NCT6694_HWMON_ALARM_SEL,
625 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
626 		};
627 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
628 				       &data->msg->hwmon_alarm);
629 
630 		val = clamp_val(val, -127000, 127000);
631 		temp_max = data->msg->hwmon_alarm.tin_cfg[channel].hl;
632 		temp_hyst = temp_max - temp_to_reg(val);
633 		temp_hyst = clamp_val(temp_hyst, 0, 7);
634 		data->msg->hwmon_alarm.tin_cfg[channel].hyst =
635 			(data->msg->hwmon_alarm.tin_cfg[channel].hyst & ~NCT6694_TIN_HYST_MASK) |
636 			FIELD_PREP(NCT6694_TIN_HYST_MASK, temp_hyst);
637 
638 		return nct6694_write_msg(data->nct6694, &cmd_hd,
639 					 &data->msg->hwmon_alarm);
640 	default:
641 		return -EOPNOTSUPP;
642 	}
643 }
644 
645 static int nct6694_fan_write(struct device *dev, u32 attr, int channel,
646 			     long val)
647 {
648 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
649 	struct nct6694_cmd_header cmd_hd;
650 	int ret;
651 
652 	guard(mutex)(&data->lock);
653 
654 	switch (attr) {
655 	case hwmon_fan_enable:
656 		if (val == 0)
657 			data->hwmon_en.fin_en[channel / 8] &= ~BIT(channel % 8);
658 		else if (val == 1)
659 			data->hwmon_en.fin_en[channel / 8] |= BIT(channel % 8);
660 		else
661 			return -EINVAL;
662 
663 		cmd_hd = (struct nct6694_cmd_header) {
664 			.mod = NCT6694_HWMON_MOD,
665 			.cmd = NCT6694_HWMON_CONTROL,
666 			.sel = NCT6694_HWMON_CONTROL_SEL,
667 			.len = cpu_to_le16(sizeof(data->hwmon_en))
668 		};
669 
670 		return nct6694_write_msg(data->nct6694, &cmd_hd,
671 					 &data->hwmon_en);
672 	case hwmon_fan_min:
673 		cmd_hd = (struct nct6694_cmd_header) {
674 			.mod = NCT6694_HWMON_MOD,
675 			.cmd = NCT6694_HWMON_ALARM,
676 			.sel = NCT6694_HWMON_ALARM_SEL,
677 			.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
678 		};
679 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
680 				       &data->msg->hwmon_alarm);
681 		if (ret)
682 			return ret;
683 
684 		val = clamp_val(val, 1, 65535);
685 		data->msg->hwmon_alarm.fin_ll[channel] = cpu_to_be16(val);
686 
687 		return nct6694_write_msg(data->nct6694, &cmd_hd,
688 					 &data->msg->hwmon_alarm);
689 	default:
690 		return -EOPNOTSUPP;
691 	}
692 }
693 
694 static int nct6694_pwm_write(struct device *dev, u32 attr, int channel,
695 			     long val)
696 {
697 	struct nct6694_hwmon_data *data = dev_get_drvdata(dev);
698 	struct nct6694_cmd_header cmd_hd;
699 	int ret;
700 
701 	guard(mutex)(&data->lock);
702 
703 	switch (attr) {
704 	case hwmon_pwm_enable:
705 		if (val == 0)
706 			data->hwmon_en.pwm_en[channel / 8] &= ~BIT(channel % 8);
707 		else if (val == 1)
708 			data->hwmon_en.pwm_en[channel / 8] |= BIT(channel % 8);
709 		else
710 			return -EINVAL;
711 
712 		cmd_hd = (struct nct6694_cmd_header) {
713 			.mod = NCT6694_HWMON_MOD,
714 			.cmd = NCT6694_HWMON_CONTROL,
715 			.sel = NCT6694_HWMON_CONTROL_SEL,
716 			.len = cpu_to_le16(sizeof(data->hwmon_en))
717 		};
718 
719 		return nct6694_write_msg(data->nct6694, &cmd_hd,
720 					 &data->hwmon_en);
721 	case hwmon_pwm_input:
722 		if (val < 0 || val > 255)
723 			return -EINVAL;
724 
725 		cmd_hd = (struct nct6694_cmd_header) {
726 			.mod = NCT6694_PWM_MOD,
727 			.cmd = NCT6694_PWM_CONTROL,
728 			.sel = NCT6694_PWM_CONTROL_SEL,
729 			.len = cpu_to_le16(sizeof(data->msg->pwm_ctrl))
730 		};
731 
732 		ret = nct6694_read_msg(data->nct6694, &cmd_hd,
733 				       &data->msg->pwm_ctrl);
734 		if (ret)
735 			return ret;
736 
737 		data->msg->pwm_ctrl.mal_val[channel] = val;
738 
739 		return nct6694_write_msg(data->nct6694, &cmd_hd,
740 					 &data->msg->pwm_ctrl);
741 	case hwmon_pwm_freq:
742 		cmd_hd = (struct nct6694_cmd_header) {
743 			.mod = NCT6694_HWMON_MOD,
744 			.cmd = NCT6694_HWMON_CONTROL,
745 			.sel = NCT6694_HWMON_CONTROL_SEL,
746 			.len = cpu_to_le16(sizeof(data->hwmon_en))
747 		};
748 
749 		data->hwmon_en.pwm_freq[channel] = NCT6694_FREQ_TO_REG(val);
750 
751 		return nct6694_write_msg(data->nct6694, &cmd_hd,
752 					 &data->hwmon_en);
753 	default:
754 		return -EOPNOTSUPP;
755 	}
756 }
757 
758 static int nct6694_read(struct device *dev, enum hwmon_sensor_types type,
759 			u32 attr, int channel, long *val)
760 {
761 	switch (type) {
762 	case hwmon_in:
763 		/* in mV */
764 		return nct6694_in_read(dev, attr, channel, val);
765 	case hwmon_temp:
766 		/* in mC */
767 		return nct6694_temp_read(dev, attr, channel, val);
768 	case hwmon_fan:
769 		/* in RPM */
770 		return nct6694_fan_read(dev, attr, channel, val);
771 	case hwmon_pwm:
772 		/* in value 0~255 */
773 		return nct6694_pwm_read(dev, attr, channel, val);
774 	default:
775 		return -EOPNOTSUPP;
776 	}
777 }
778 
779 static int nct6694_write(struct device *dev, enum hwmon_sensor_types type,
780 			 u32 attr, int channel, long val)
781 {
782 	switch (type) {
783 	case hwmon_in:
784 		return nct6694_in_write(dev, attr, channel, val);
785 	case hwmon_temp:
786 		return nct6694_temp_write(dev, attr, channel, val);
787 	case hwmon_fan:
788 		return nct6694_fan_write(dev, attr, channel, val);
789 	case hwmon_pwm:
790 		return nct6694_pwm_write(dev, attr, channel, val);
791 	default:
792 		return -EOPNOTSUPP;
793 	}
794 }
795 
796 static umode_t nct6694_is_visible(const void *data,
797 				  enum hwmon_sensor_types type,
798 				  u32 attr, int channel)
799 {
800 	switch (type) {
801 	case hwmon_in:
802 		switch (attr) {
803 		case hwmon_in_enable:
804 		case hwmon_in_max:
805 		case hwmon_in_min:
806 			return 0644;
807 		case hwmon_in_alarm:
808 		case hwmon_in_input:
809 			return 0444;
810 		default:
811 			return 0;
812 		}
813 	case hwmon_temp:
814 		switch (attr) {
815 		case hwmon_temp_enable:
816 		case hwmon_temp_max:
817 		case hwmon_temp_max_hyst:
818 			return 0644;
819 		case hwmon_temp_input:
820 		case hwmon_temp_max_alarm:
821 			return 0444;
822 		default:
823 			return 0;
824 		}
825 	case hwmon_fan:
826 		switch (attr) {
827 		case hwmon_fan_enable:
828 		case hwmon_fan_min:
829 			return 0644;
830 		case hwmon_fan_input:
831 		case hwmon_fan_min_alarm:
832 			return 0444;
833 		default:
834 			return 0;
835 		}
836 	case hwmon_pwm:
837 		switch (attr) {
838 		case hwmon_pwm_enable:
839 		case hwmon_pwm_freq:
840 		case hwmon_pwm_input:
841 			return 0644;
842 		default:
843 			return 0;
844 		}
845 	default:
846 		return 0;
847 	}
848 }
849 
850 static const struct hwmon_ops nct6694_hwmon_ops = {
851 	.is_visible = nct6694_is_visible,
852 	.read = nct6694_read,
853 	.write = nct6694_write,
854 };
855 
856 static const struct hwmon_chip_info nct6694_chip_info = {
857 	.ops = &nct6694_hwmon_ops,
858 	.info = nct6694_info,
859 };
860 
861 static int nct6694_hwmon_init(struct nct6694_hwmon_data *data)
862 {
863 	struct nct6694_cmd_header cmd_hd = {
864 		.mod = NCT6694_HWMON_MOD,
865 		.cmd = NCT6694_HWMON_CONTROL,
866 		.sel = NCT6694_HWMON_CONTROL_SEL,
867 		.len = cpu_to_le16(sizeof(data->hwmon_en))
868 	};
869 	int ret;
870 
871 	/*
872 	 * Record each Hardware Monitor Channel enable status
873 	 * and PWM frequency register
874 	 */
875 	ret = nct6694_read_msg(data->nct6694, &cmd_hd,
876 			       &data->hwmon_en);
877 	if (ret)
878 		return ret;
879 
880 	cmd_hd = (struct nct6694_cmd_header) {
881 		.mod = NCT6694_HWMON_MOD,
882 		.cmd = NCT6694_HWMON_ALARM,
883 		.sel = NCT6694_HWMON_ALARM_SEL,
884 		.len = cpu_to_le16(sizeof(data->msg->hwmon_alarm))
885 	};
886 
887 	/* Select hwmon device alarm mode */
888 	ret = nct6694_read_msg(data->nct6694, &cmd_hd,
889 			       &data->msg->hwmon_alarm);
890 	if (ret)
891 		return ret;
892 
893 	data->msg->hwmon_alarm.smi_ctrl = NCT6694_HWMON_REALTIME_IRQ;
894 
895 	return nct6694_write_msg(data->nct6694, &cmd_hd,
896 				 &data->msg->hwmon_alarm);
897 }
898 
899 static int nct6694_hwmon_probe(struct platform_device *pdev)
900 {
901 	struct nct6694_hwmon_data *data;
902 	struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent);
903 	struct device *hwmon_dev;
904 	int ret;
905 
906 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
907 	if (!data)
908 		return -ENOMEM;
909 
910 	data->rpt = devm_kzalloc(&pdev->dev, sizeof(union nct6694_hwmon_rpt),
911 				 GFP_KERNEL);
912 	if (!data->rpt)
913 		return -ENOMEM;
914 
915 	data->msg = devm_kzalloc(&pdev->dev, sizeof(union nct6694_hwmon_msg),
916 				 GFP_KERNEL);
917 	if (!data->msg)
918 		return -ENOMEM;
919 
920 	data->nct6694 = nct6694;
921 	ret = devm_mutex_init(&pdev->dev, &data->lock);
922 	if (ret)
923 		return ret;
924 
925 	ret = nct6694_hwmon_init(data);
926 	if (ret)
927 		return ret;
928 
929 	/* Register hwmon device to HWMON framework */
930 	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
931 							 "nct6694", data,
932 							 &nct6694_chip_info,
933 							 NULL);
934 	return PTR_ERR_OR_ZERO(hwmon_dev);
935 }
936 
937 static struct platform_driver nct6694_hwmon_driver = {
938 	.driver = {
939 		.name	= "nct6694-hwmon",
940 	},
941 	.probe		= nct6694_hwmon_probe,
942 };
943 
944 module_platform_driver(nct6694_hwmon_driver);
945 
946 MODULE_DESCRIPTION("USB-HWMON driver for NCT6694");
947 MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
948 MODULE_LICENSE("GPL");
949 MODULE_ALIAS("platform:nct6694-hwmon");
950