xref: /freebsd/sys/dev/iicbus/sensor/w83793g.c (revision cd3cc6e910c0f739925c57e42fae6781d693db02)
1 /*
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2026 Justin Hibbits
5  */
6 
7 #include <sys/param.h>
8 #include <sys/bus.h>
9 #include <sys/kernel.h>
10 #include <sys/module.h>
11 #include <sys/sysctl.h>
12 
13 #include <dev/iicbus/iicbus.h>
14 #include <dev/iicbus/iiconf.h>
15 
16 #include <dev/ofw/ofw_bus.h>
17 #include <dev/ofw/ofw_bus_subr.h>
18 
19 /*
20  * Driver for the Winbond W83793G hardware monitor.
21  *
22  * The hardware monitor supports the following sensors:
23  * - 6 temperature sensors
24  *   - 4 with 1/4 integer precision
25  *   - 2 with integer precision
26  * - 11 voltage sensors
27  * - 12 fan sensors
28  *   - FanIn 6-12 are on multifunction pins, so may not be enabled.
29  *   8 DC/PWM fan outputs for fan speed control
30  * - Case open detection
31  */
32 
33 #define	WB_TD_BASE	0x1c
34 #define	WB_TLOW		0x22
35 
36 #define	WB_VCORE_A	0x10
37 #define	WB_VCORE_B	0x11
38 #define	WB_VTT		0x12
39 #define	WB_VSEN1	0x14
40 #define	WB_VSEN2	0x15
41 #define	WB_VSEN3	0x16
42 #define	WB_VSEN4	0x17
43 #define	WB_5VDD		0x18
44 #define	WB_5VSB		0x19
45 #define	WB_VBAT		0x1a
46 #define	WB_VLOW		0x1b
47 #define	WB_FAN_BASE	0x23
48 
49 #define	INT_STS1	0x41
50 #define	INT_STS2	0x42
51 #define	INT_STS3	0x43
52 #define	INT_STS4	0x44
53 #define	  CHASSIS	  0x40
54 #define	INT_STS5	0x45
55 #define	INT_MASK1	0x46
56 #define	INT_MASK2	0x47
57 #define	INT_MASK3	0x48
58 #define	INT_MASK4	0x49
59 #define	  CLR_CHS	  0x80
60 #define	INT_MASK5	0x4a
61 
62 #define	WB_MFC		0x58	/* Multi-function pin control */
63 #define	  MFC_VIDBSEL	  0x80
64 #define	  MFC_SIB_SEL	  0x40
65 #define	  MFC_SID_SEL_M	  0x30
66 #define	  MFC_SID_VID	  0x00
67 #define	  MFC_SID_FANIN	  0x20
68 #define	  MFC_SIC_SEL_M	  0x0c
69 #define	  MFC_SIC_VID	  0x00
70 #define	  MFC_SIC_FANIN	  0x08
71 #define	  MFC_SIA_SEL	  0x02
72 #define	  MFC_FAN8SEL	  0x01
73 #define	WB_FANIN_CTRL	0x5c
74 #define	  FANIN_EN_12	  0x40
75 #define	  FANIN_EN_11	  0x20
76 #define	  FANIN_EN_10	  0x10
77 #define	  FANIN_EN_9	  0x08
78 #define	  FANIN_EN_8	  0x04
79 #define	  FANIN_EN_7	  0x02
80 #define	  FANIN_EN_6	  0x01
81 #define	WB_FANIN_SEL	0x5d
82 #define	WB_TD_MD	0x5e	/* TD mode select register */
83 #define	  TD_MD_M(n)	  (0x3 << ((n) * 2))
84 #define	  TD_MD_S(n)	  ((n) * 2)
85 #define	  TD_STOP_M	  0x0
86 #define	  TD_INT_MD	  0x1
87 #define	  TD_EXT_MD	  0x2
88 #define	WB_TR_MD	0x5f
89 #define	  TR2_MD	  0x2
90 #define	  TR1_MD	  0x1
91 
92 #define	WB_TEMP_COUNT		6	/* Total temperature sensors */
93 #define	WB_TD_COUNT		4	/* Temp sensors with "low" part */
94 #define	WB_TR_COUNT		2
95 #define	WB_FAN_COUNT		12
96 #define	WB_FAN_ALWAYS_ON	5	/* First 5 are not controlled */
97 #define	WB_V_COUNT		11
98 
99 static const struct wb_vsens {
100 	const char	*name;
101 	int		reg;
102 	int		scale;	/* Scale in millivolts */
103 	int		add;	/* Scale in millivolts */
104 	int		left_low;	/* left bit in VLOW, if applicable */
105 } voltages[] = {
106 	{ "v_core_a", WB_VCORE_A, 2, 0, 1 },
107 	{ "v_core_b", WB_VCORE_B, 2, 0, 3 },
108 	{ "v_tt", WB_VTT, 2, 0, 5 },
109 	{ "v_sen_1", WB_VSEN1, 16 },
110 	{ "v_sen_2", WB_VSEN2, 16 },
111 	{ "v_sen_3", WB_VSEN3, 16 },
112 	{ "v_sen_4", WB_VSEN4, 8 },
113 	{ "5v", WB_5VDD, 24, 150 },
114 	{ "5v_sb", WB_5VSB, 24, 150 },
115 	{ "v_bat", WB_VBAT, 16 }
116 };
117 
118 struct w83793g_softc {
119 	device_t	sc_dev;
120 
121 };
122 
123 static device_probe_t	w83793g_probe;
124 static device_attach_t	w83793g_attach;
125 static device_detach_t	w83793g_detach;
126 static int w83793g_temp_sysctl(SYSCTL_HANDLER_ARGS);
127 static int w83793g_fan_sysctl(SYSCTL_HANDLER_ARGS);
128 static int w83793g_voltage_sysctl(SYSCTL_HANDLER_ARGS);
129 static int w83793g_case_sysctl(SYSCTL_HANDLER_ARGS);
130 
131 static device_method_t w83793g_methods[] = {
132 	DEVMETHOD(device_probe,		w83793g_probe),
133 	DEVMETHOD(device_attach,	w83793g_attach),
134 	DEVMETHOD(device_detach,	w83793g_detach),
135 
136 	DEVMETHOD_END
137 };
138 
139 static struct ofw_compat_data compat[] = {
140 	{ "winbond,w83793", 1 },
141 	{ NULL, 0 }
142 };
143 
144 DEFINE_CLASS_0(w83793g, w83793g_driver, w83793g_methods,
145     sizeof(struct w83793g_softc));
146 DRIVER_MODULE(w83793g, iicbus, w83793g_driver, NULL, NULL);
147 MODULE_VERSION(w83793g, 1);
148 MODULE_DEPEND(w83793g, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
149 IICBUS_FDT_PNP_INFO(compat);
150 
151 static int
w83793g_readreg(device_t dev,int reg,uint8_t * output)152 w83793g_readreg(device_t dev, int reg, uint8_t *output)
153 {
154 	return (iicdev_readfrom(dev, reg, output, sizeof(*output), IIC_WAIT));
155 }
156 
157 static int
w83793g_writereg(device_t dev,int reg,uint8_t * output)158 w83793g_writereg(device_t dev, int reg, uint8_t *output)
159 {
160 	return (iicdev_writeto(dev, reg, output, sizeof(*output), IIC_WAIT));
161 }
162 
163 static bool
temp_enabled(struct w83793g_softc * sc,int sensor)164 temp_enabled(struct w83793g_softc *sc, int sensor)
165 {
166 	uint8_t reg;
167 	int error;
168 
169 	if (sensor < WB_TD_COUNT) {
170 		error = w83793g_readreg(sc->sc_dev, WB_TD_MD, &reg);
171 		if (error != 0)
172 			return (false);
173 		return ((reg & TD_MD_M(sensor)) != 0);
174 	} else {
175 		error = w83793g_readreg(sc->sc_dev, WB_TR_MD, &reg);
176 		sensor -= WB_TD_COUNT;
177 		if (error != 0)
178 			return (false);
179 		return ((reg & (1 << sensor)) != 0);
180 	}
181 }
182 
183 static bool
fan_enabled(struct w83793g_softc * sc,int fan)184 fan_enabled(struct w83793g_softc *sc, int fan)
185 {
186 	int error;
187 	uint8_t fanin_ctl;
188 
189 	if (fan < WB_FAN_ALWAYS_ON)
190 		return (true);
191 
192 	error = w83793g_readreg(sc->sc_dev, WB_FANIN_CTRL, &fanin_ctl);
193 	if (error != 0)
194 		return (false);
195 
196 	fan -= WB_FAN_ALWAYS_ON;
197 
198 	return ((fanin_ctl & (1 << fan)) != 0);
199 }
200 
201 static int
w83793g_probe(device_t dev)202 w83793g_probe(device_t dev)
203 {
204 	if (ofw_bus_search_compatible(dev, compat)->ocd_data == 0)
205 		return (ENXIO);
206 
207 	device_set_desc(dev, "Winbond W83793 Hardware Monitor");
208 
209 	return (BUS_PROBE_DEFAULT);
210 }
211 
212 static int
w83793g_attach(device_t dev)213 w83793g_attach(device_t dev)
214 {
215 	struct w83793g_softc *sc = device_get_softc(dev);
216 	struct sysctl_oid *root = device_get_sysctl_tree(dev);
217 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
218 	struct sysctl_oid *node;
219 	int i;
220 
221 	sc->sc_dev = dev;
222 	node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "voltages",
223 	    CTLFLAG_RD, NULL, NULL);
224 	for (i = 0; i < nitems(voltages); i++) {
225 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
226 		    voltages[i].name, CTLTYPE_INT | CTLFLAG_RD, sc,
227 		    i, w83793g_voltage_sysctl, "I",
228 		    "voltage (millivolts)");
229 	}
230 	node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "temp",
231 	    CTLFLAG_RD, NULL, NULL);
232 	for (i = 0; i < WB_TEMP_COUNT; i++) {
233 		/* Only supports single-digit sensors. */
234 		char name[sizeof("sensor_") + 1];
235 
236 		if (!temp_enabled(sc, i))
237 			continue;
238 		snprintf(name, sizeof(name), "sensor_%d", i);
239 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, name,
240 		    CTLTYPE_INT | CTLFLAG_RD, sc, WB_TD_BASE + i,
241 		    w83793g_temp_sysctl, "IK2", NULL);
242 	}
243 	node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "fans",
244 	    CTLFLAG_RD, NULL, NULL);
245 	for (i = 0; i < WB_FAN_COUNT; i++) {
246 		/* Supports up to 12 fans */
247 		char name[sizeof("fan_") + 2];
248 
249 		if (!fan_enabled(sc, i))
250 			continue;
251 		snprintf(name, sizeof(name), "fan_%d", i);
252 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, name,
253 		    CTLTYPE_INT | CTLFLAG_RD, sc, WB_FAN_BASE + i,
254 		    w83793g_fan_sysctl, "I", NULL);
255 	}
256 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "chassis_open",
257 	    CTLTYPE_U8 | CTLFLAG_RD, sc, 0, w83793g_case_sysctl, "CU",
258 	    "report if the chassis_open was latched");
259 	return (0);
260 }
261 
262 static int
w83793g_detach(device_t dev)263 w83793g_detach(device_t dev)
264 {
265 	return (ENXIO);
266 }
267 
268 static int
w83793g_temp_sysctl(SYSCTL_HANDLER_ARGS)269 w83793g_temp_sysctl(SYSCTL_HANDLER_ARGS)
270 {
271 	struct w83793g_softc *sc = arg1;
272 	int reg = arg2;
273 	int temp;
274 	int error;
275 	int8_t t_reg;
276 	uint8_t t_low;
277 
278 	error = w83793g_readreg(sc->sc_dev, reg, &t_reg);
279 	if (error != 0)
280 		return (error);
281 
282 	if (reg < WB_TD_BASE + WB_TD_COUNT) {
283 		error = w83793g_readreg(sc->sc_dev, WB_TLOW, &t_low);
284 		if (error != 0)
285 			return (error);
286 	} else
287 		t_low = 0;
288 
289 	temp = (int)t_reg * 100;
290 	temp += (t_low >> (2 * (reg - WB_TD_BASE)) & 0x3) * 25;
291 	temp += 27315;	/* Convert celsius to kelvin */
292 
293 	error = sysctl_handle_int(oidp, &temp, 0, req);
294 
295 	return (error);
296 }
297 
298 static int
w83793g_fan_sysctl(SYSCTL_HANDLER_ARGS)299 w83793g_fan_sysctl(SYSCTL_HANDLER_ARGS)
300 {
301 	struct w83793g_softc *sc = arg1;
302 	int reg = arg2;
303 	int count;
304 	int error;
305 	uint8_t reg_vals[2];	/* Fan count is 2 bytes */
306 
307 	error = iicdev_readfrom(sc->sc_dev, reg, reg_vals, sizeof(reg_vals),
308 	    IIC_WAIT);
309 	if (error != 0)
310 		return (error);
311 
312 	count = ((int)reg_vals[0] << 8) | reg_vals[1];
313 	error = sysctl_handle_int(oidp, &count, 0, req);
314 
315 	return (error);
316 }
317 
318 static int
w83793g_voltage_sysctl(SYSCTL_HANDLER_ARGS)319 w83793g_voltage_sysctl(SYSCTL_HANDLER_ARGS)
320 {
321 	struct w83793g_softc *sc = arg1;
322 	const struct wb_vsens *sensor;
323 	int index = arg2;
324 	int volts;
325 	int error;
326 	uint8_t v_reg;
327 	uint8_t v_low;
328 
329 	sensor = &voltages[index];
330 	error = w83793g_readreg(sc->sc_dev, sensor->reg, &v_reg);
331 	if (error != 0)
332 		return (error);
333 
334 	volts = v_reg;
335 	if (sensor->left_low != 0) {
336 		volts <<= 2;
337 		error = w83793g_readreg(sc->sc_dev, WB_VLOW, &v_low);
338 		if (error != 0)
339 			return (error);
340 		volts |= (v_low >> (sensor->left_low - 1) & 0x3);
341 	}
342 
343 	volts *= sensor->scale;
344 	volts += sensor->add;
345 
346 	error = sysctl_handle_int(oidp, &volts, 0, req);
347 
348 	return (error);
349 }
350 
351 static int
w83793g_case_sysctl(SYSCTL_HANDLER_ARGS)352 w83793g_case_sysctl(SYSCTL_HANDLER_ARGS)
353 {
354 	struct w83793g_softc *sc = arg1;
355 	int error;
356 	uint8_t reg;
357 	bool chassis;
358 
359 	error = w83793g_readreg(sc->sc_dev, INT_STS4, &reg);
360 	if (error != 0)
361 		return (error);
362 
363 	chassis = ((reg & CHASSIS) != 0);
364 
365 	return (sysctl_handle_bool(oidp, &chassis, 0, req));
366 }
367