xref: /openbsd/sys/dev/i2c/w83795g.c (revision 471aeecf)
1 /*	$OpenBSD: w83795g.c,v 1.2 2022/04/06 18:59:28 naddy Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/sensors.h>
23 
24 #include <dev/i2c/i2cvar.h>
25 
26 /* Nuvoton W83795G Hardware Monitor */
27 
28 #define NVT_BANKSELECT		0x00
29 #define NVT_CONFIG		0x01
30 #define  NVT_CONFIG_48		0x04
31 #define NVT_VOLT_CTRL1		0x02
32 #define NVT_VOLT_CTRL2		0x03
33 #define NVT_TEMP_CTRL1		0x04
34 #define NVT_TEMP_CTRL2		0x05
35 #define NVT_FANIN_CTRL1		0x06
36 #define NVT_FANIN_CTRL2		0x07
37 #define NVT_VSEN1		0x10
38 #define NVT_3VDD		0x1c
39 #define NVT_3VSB		0x1d
40 #define NVT_VBAT		0x1e
41 #define NVT_TR5			0x1f
42 #define NVT_TR6			0x20
43 #define NVT_TD1			0x21
44 #define NVT_TD2			0x22
45 #define NVT_TD3			0x23
46 #define NVT_TD4			0x24
47 #define NVT_FANIN1_COUNT	0x2e
48 #define NVT_VRLSB		0x3c
49 
50 /* Voltage */
51 #define NVT_NUM_VOLTS	15
52 
53 static const char *nvt_volt_desc[NVT_NUM_VOLTS] = {
54 	"", "", "", "", "", "", "", "", "", "", "",
55 	"VTT", "3VDD", "3VSB", "VBat"
56 };
57 
58 /* Temperature */
59 #define NVT_NUM_TEMPS	6
60 #define NVT_NUM_TR	2
61 #define NVT_NUM_TD	4
62 
63 /* Fan */
64 #define NVT_NUM_FANS	14
65 
66 #define NVT_NUM_SENSORS (NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS)
67 
68 struct nvt_softc {
69 	struct device	sc_dev;
70 	i2c_tag_t	sc_tag;
71 	i2c_addr_t	sc_addr;
72 
73 	uint16_t	sc_vctrl;
74 	uint16_t	sc_tctrl1, sc_tctrl2;
75 	uint16_t	sc_fctrl;
76 
77 	struct ksensor	sc_sensors[NVT_NUM_SENSORS];
78 	struct ksensordev sc_sensordev;
79 };
80 
81 
82 int	nvt_match(struct device *, void *, void *);
83 void	nvt_attach(struct device *, struct device *, void *);
84 void	nvt_refresh(void *);
85 
86 void	nvt_refresh_volts(struct nvt_softc *);
87 void	nvt_refresh_temps(struct nvt_softc *);
88 void	nvt_refresh_fans(struct nvt_softc *);
89 
90 uint8_t	nvt_readreg(struct nvt_softc *, uint8_t);
91 void	nvt_writereg(struct nvt_softc *, uint8_t, uint8_t);
92 
93 
94 const struct cfattach nvt_ca = {
95 	sizeof(struct nvt_softc), nvt_match, nvt_attach
96 };
97 
98 struct cfdriver nvt_cd = {
99 	NULL, "nvt", DV_DULL
100 };
101 
102 
103 int
nvt_match(struct device * parent,void * match,void * aux)104 nvt_match(struct device *parent, void *match, void *aux)
105 {
106 	struct i2c_attach_args *ia = aux;
107 
108 	if (strcmp(ia->ia_name, "w83795g") == 0)
109 		return (1);
110 	return (0);
111 }
112 
113 void
nvt_attach(struct device * parent,struct device * self,void * aux)114 nvt_attach(struct device *parent, struct device *self, void *aux)
115 {
116 	struct nvt_softc *sc = (struct nvt_softc *)self;
117 	struct i2c_attach_args *ia = aux;
118 	uint8_t cfg, vctrl1, vctrl2;
119 	uint8_t tctrl1, tctrl2, fctrl1, fctrl2;
120 	int i, j;
121 
122 	sc->sc_tag = ia->ia_tag;
123 	sc->sc_addr = ia->ia_addr;
124 
125 	cfg = nvt_readreg(sc, NVT_CONFIG);
126 	if (cfg & NVT_CONFIG_48)
127 		printf(": W83795ADG");
128 	else
129 		printf(": W83795G");
130 
131 	vctrl1 = nvt_readreg(sc, NVT_VOLT_CTRL1);
132 	vctrl2 = nvt_readreg(sc, NVT_VOLT_CTRL2);
133 	tctrl1 = nvt_readreg(sc, NVT_TEMP_CTRL1);
134 	tctrl2 = nvt_readreg(sc, NVT_TEMP_CTRL2);
135 	fctrl1 = nvt_readreg(sc, NVT_FANIN_CTRL1);
136 	fctrl2 = nvt_readreg(sc, NVT_FANIN_CTRL2);
137 
138 	sc->sc_vctrl = vctrl2 << 8 | vctrl1;
139 	sc->sc_tctrl1 = tctrl1;
140 	sc->sc_tctrl2 = tctrl2;
141 	sc->sc_fctrl = fctrl2 << 8 | fctrl1;
142 
143 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
144 	    sizeof(sc->sc_sensordev.xname));
145 
146 	for (i = 0; i < NVT_NUM_VOLTS; i++) {
147 		strlcpy(sc->sc_sensors[i].desc, nvt_volt_desc[i],
148 		    sizeof(sc->sc_sensors[i].desc));
149 		sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
150 	}
151 
152 	for (j = i + NVT_NUM_TEMPS; i < j; i++)
153 		sc->sc_sensors[i].type = SENSOR_TEMP;
154 
155 	for (j = i + NVT_NUM_FANS; i < j; i++)
156 		sc->sc_sensors[i].type = SENSOR_FANRPM;
157 
158 	for (i = 0; i < NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS; i++)
159 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
160 
161 	if (sensor_task_register(sc, nvt_refresh, 5) == NULL) {
162 		printf(", unable to register update task\n");
163 		return;
164 	}
165 
166 	sensordev_install(&sc->sc_sensordev);
167 	printf("\n");
168 }
169 
170 void
nvt_refresh(void * arg)171 nvt_refresh(void *arg)
172 {
173 	struct nvt_softc *sc = arg;
174 	uint8_t bsr;
175 
176 	iic_acquire_bus(sc->sc_tag, 0);
177 
178 	bsr = nvt_readreg(sc, NVT_BANKSELECT);
179 	if ((bsr & 0x07) != 0x00)
180 		nvt_writereg(sc, NVT_BANKSELECT, bsr & 0xf8);
181 
182 	nvt_refresh_volts(sc);
183 	nvt_refresh_temps(sc);
184 	nvt_refresh_fans(sc);
185 
186 	if ((bsr & 0x07) != 0x00)
187 		nvt_writereg(sc, NVT_BANKSELECT, bsr);
188 
189 	iic_release_bus(sc->sc_tag, 0);
190 }
191 
192 void
nvt_refresh_volts(struct nvt_softc * sc)193 nvt_refresh_volts(struct nvt_softc *sc)
194 {
195 	struct ksensor *s = &sc->sc_sensors[0];
196 	uint8_t	vrlsb, data;
197 	int i, reg;
198 
199 	for (i = 0; i < NVT_NUM_VOLTS; i++) {
200 		if ((sc->sc_vctrl & (1 << i)) == 0) {
201 			s[i].flags |= SENSOR_FINVALID;
202 			s[i].value = 0;
203 			continue;
204 		}
205 
206 		reg = NVT_VSEN1 + i;
207 		data = nvt_readreg(sc, reg);
208 		vrlsb = nvt_readreg(sc, NVT_VRLSB);
209 		if (reg != NVT_3VDD && reg != NVT_3VSB && reg != NVT_VBAT)
210 			s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 2000;
211 		else
212 			s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 6000;
213 		s[i].flags &= ~SENSOR_FINVALID;
214 	}
215 }
216 
217 void
nvt_refresh_temps(struct nvt_softc * sc)218 nvt_refresh_temps(struct nvt_softc *sc)
219 {
220 	struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS];
221 	uint8_t	vrlsb;
222 	int8_t data;
223 	int i;
224 
225 	for (i = 0; i < NVT_NUM_TEMPS; i++) {
226 		if (i < NVT_NUM_TR
227 		    && (sc->sc_tctrl1 & (1 << (2 * i))) == 0) {
228 			s[i].flags |= SENSOR_FINVALID;
229 			s[i].value = 0;
230 			continue;
231 		}
232 
233 		if (i >= NVT_NUM_TR
234 		    && (sc->sc_tctrl2 & (1 << (2 * (i - NVT_NUM_TR)))) == 0) {
235 			s[i].flags |= SENSOR_FINVALID;
236 			s[i].value = 0;
237 			continue;
238 		}
239 
240 		data = nvt_readreg(sc, NVT_TR5 + i);
241 		vrlsb = nvt_readreg(sc, NVT_VRLSB);
242 		if (data == -128 && (vrlsb >> 6) == 0) {
243 			s[i].flags |= SENSOR_FINVALID;
244 			s[i].value = 0;
245 			continue;
246 		}
247 		s[i].value = data * 1000000 + (vrlsb >> 6) * 250000;
248 		s[i].value += 273150000;
249 		s[i].flags &= ~SENSOR_FINVALID;
250 	}
251 }
252 
253 void
nvt_refresh_fans(struct nvt_softc * sc)254 nvt_refresh_fans(struct nvt_softc *sc)
255 {
256 	struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS + NVT_NUM_TEMPS];
257 	uint8_t	data, vrlsb;
258 	uint16_t count;
259 	int i;
260 
261 	for (i = 0; i < NVT_NUM_FANS; i++) {
262 		if ((sc->sc_fctrl & (1 << i)) == 0) {
263 			s[i].flags |= SENSOR_FINVALID;
264 			s[i].value = 0;
265 			continue;
266 		}
267 
268 		data = nvt_readreg(sc, NVT_FANIN1_COUNT + i);
269 		vrlsb = nvt_readreg(sc, NVT_VRLSB);
270 		count = (data << 4) + (vrlsb >> 4);
271 		if (count == 0) {
272 			s[i].flags |= SENSOR_FINVALID;
273 			s[i].value = 0;
274 			continue;
275 		}
276 		s[i].value = 1350000 / (count * 2);
277 		s[i].flags &= ~SENSOR_FINVALID;
278 	}
279 }
280 
281 uint8_t
nvt_readreg(struct nvt_softc * sc,uint8_t reg)282 nvt_readreg(struct nvt_softc *sc, uint8_t reg)
283 {
284 	uint8_t data;
285 
286 	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
287 	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
288 
289 	return data;
290 }
291 
292 void
nvt_writereg(struct nvt_softc * sc,uint8_t reg,uint8_t data)293 nvt_writereg(struct nvt_softc *sc, uint8_t reg, uint8_t data)
294 {
295 	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
296 	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
297 }
298