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 #if 0
158 static int
159 w83793g_writereg(device_t dev, int reg, uint8_t *output)
160 {
161 return (iicdev_writeto(dev, reg, output, sizeof(*output), IIC_WAIT));
162 }
163 #endif
164
165 static bool
temp_enabled(struct w83793g_softc * sc,int sensor)166 temp_enabled(struct w83793g_softc *sc, int sensor)
167 {
168 uint8_t reg;
169 int error;
170
171 if (sensor < WB_TD_COUNT) {
172 error = w83793g_readreg(sc->sc_dev, WB_TD_MD, ®);
173 if (error != 0)
174 return (false);
175 return ((reg & TD_MD_M(sensor)) != 0);
176 } else {
177 error = w83793g_readreg(sc->sc_dev, WB_TR_MD, ®);
178 sensor -= WB_TD_COUNT;
179 if (error != 0)
180 return (false);
181 return ((reg & (1 << sensor)) != 0);
182 }
183 }
184
185 static bool
fan_enabled(struct w83793g_softc * sc,int fan)186 fan_enabled(struct w83793g_softc *sc, int fan)
187 {
188 int error;
189 uint8_t fanin_ctl;
190
191 if (fan < WB_FAN_ALWAYS_ON)
192 return (true);
193
194 error = w83793g_readreg(sc->sc_dev, WB_FANIN_CTRL, &fanin_ctl);
195 if (error != 0)
196 return (false);
197
198 fan -= WB_FAN_ALWAYS_ON;
199
200 return ((fanin_ctl & (1 << fan)) != 0);
201 }
202
203 static int
w83793g_probe(device_t dev)204 w83793g_probe(device_t dev)
205 {
206 if (ofw_bus_search_compatible(dev, compat)->ocd_data == 0)
207 return (ENXIO);
208
209 device_set_desc(dev, "Winbond W83793 Hardware Monitor");
210
211 return (BUS_PROBE_DEFAULT);
212 }
213
214 static int
w83793g_attach(device_t dev)215 w83793g_attach(device_t dev)
216 {
217 struct w83793g_softc *sc = device_get_softc(dev);
218 struct sysctl_oid *root = device_get_sysctl_tree(dev);
219 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
220 struct sysctl_oid *node;
221 int i;
222
223 sc->sc_dev = dev;
224 node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "voltages",
225 CTLFLAG_RD, NULL, NULL);
226 for (i = 0; i < nitems(voltages); i++) {
227 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
228 voltages[i].name, CTLTYPE_INT | CTLFLAG_RD, sc,
229 i, w83793g_voltage_sysctl, "I",
230 "voltage (millivolts)");
231 }
232 node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "temp",
233 CTLFLAG_RD, NULL, NULL);
234 for (i = 0; i < WB_TEMP_COUNT; i++) {
235 /* Only supports single-digit sensors. */
236 char name[sizeof("sensor_") + 1];
237
238 if (!temp_enabled(sc, i))
239 continue;
240 snprintf(name, sizeof(name), "sensor_%d", i);
241 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, name,
242 CTLTYPE_INT | CTLFLAG_RD, sc, WB_TD_BASE + i,
243 w83793g_temp_sysctl, "IK2", NULL);
244 }
245 node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "fans",
246 CTLFLAG_RD, NULL, NULL);
247 for (i = 0; i < WB_FAN_COUNT; i++) {
248 /* Supports up to 12 fans */
249 char name[sizeof("fan_") + 2];
250
251 if (!fan_enabled(sc, i))
252 continue;
253 snprintf(name, sizeof(name), "fan_%d", i);
254 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, name,
255 CTLTYPE_INT | CTLFLAG_RD, sc, WB_FAN_BASE + i,
256 w83793g_fan_sysctl, "I", NULL);
257 }
258 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "chassis_open",
259 CTLTYPE_U8 | CTLFLAG_RD, sc, 0, w83793g_case_sysctl, "CU",
260 "report if the chassis_open was latched");
261 return (0);
262 }
263
264 static int
w83793g_detach(device_t dev)265 w83793g_detach(device_t dev)
266 {
267 return (ENXIO);
268 }
269
270 static int
w83793g_temp_sysctl(SYSCTL_HANDLER_ARGS)271 w83793g_temp_sysctl(SYSCTL_HANDLER_ARGS)
272 {
273 struct w83793g_softc *sc = arg1;
274 int reg = arg2;
275 int temp;
276 int error;
277 int8_t t_reg;
278 uint8_t t_low;
279
280 error = w83793g_readreg(sc->sc_dev, reg, &t_reg);
281 if (error != 0)
282 return (error);
283
284 if (reg < WB_TD_BASE + WB_TD_COUNT) {
285 error = w83793g_readreg(sc->sc_dev, WB_TLOW, &t_low);
286 if (error != 0)
287 return (error);
288 } else
289 t_low = 0;
290
291 temp = (int)t_reg * 100;
292 temp += (t_low >> (2 * (reg - WB_TD_BASE)) & 0x3) * 25;
293 temp += 27315; /* Convert celsius to kelvin */
294
295 error = sysctl_handle_int(oidp, &temp, 0, req);
296
297 return (error);
298 }
299
300 static int
w83793g_fan_sysctl(SYSCTL_HANDLER_ARGS)301 w83793g_fan_sysctl(SYSCTL_HANDLER_ARGS)
302 {
303 struct w83793g_softc *sc = arg1;
304 int reg = arg2;
305 int count;
306 int error;
307 uint8_t reg_vals[2]; /* Fan count is 2 bytes */
308
309 error = iicdev_readfrom(sc->sc_dev, reg, reg_vals, sizeof(reg_vals),
310 IIC_WAIT);
311 if (error != 0)
312 return (error);
313
314 count = ((int)reg_vals[0] << 8) | reg_vals[1];
315 error = sysctl_handle_int(oidp, &count, 0, req);
316
317 return (error);
318 }
319
320 static int
w83793g_voltage_sysctl(SYSCTL_HANDLER_ARGS)321 w83793g_voltage_sysctl(SYSCTL_HANDLER_ARGS)
322 {
323 struct w83793g_softc *sc = arg1;
324 const struct wb_vsens *sensor;
325 int index = arg2;
326 int volts;
327 int error;
328 uint8_t v_reg;
329 uint8_t v_low;
330
331 sensor = &voltages[index];
332 error = w83793g_readreg(sc->sc_dev, sensor->reg, &v_reg);
333 if (error != 0)
334 return (error);
335
336 volts = v_reg;
337 if (sensor->left_low != 0) {
338 volts <<= 2;
339 error = w83793g_readreg(sc->sc_dev, WB_VLOW, &v_low);
340 if (error != 0)
341 return (error);
342 volts |= (v_low >> (sensor->left_low - 1) & 0x3);
343 }
344
345 volts *= sensor->scale;
346 volts += sensor->add;
347
348 error = sysctl_handle_int(oidp, &volts, 0, req);
349
350 return (error);
351 }
352
353 static int
w83793g_case_sysctl(SYSCTL_HANDLER_ARGS)354 w83793g_case_sysctl(SYSCTL_HANDLER_ARGS)
355 {
356 struct w83793g_softc *sc = arg1;
357 int error;
358 uint8_t reg;
359 bool chassis;
360
361 error = w83793g_readreg(sc->sc_dev, INT_STS4, ®);
362 if (error != 0)
363 return (error);
364
365 chassis = ((reg & CHASSIS) != 0);
366
367 return (sysctl_handle_bool(oidp, &chassis, 0, req));
368 }
369