xref: /freebsd/sys/dev/iicbus/sensor/w83793g.c (revision cd3cc6e910c0f739925c57e42fae6781d693db02)
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, &reg);
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, &reg);
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, &reg);
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