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