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
53static 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
68struct 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
82int	nvt_match(struct device *, void *, void *);
83void	nvt_attach(struct device *, struct device *, void *);
84void	nvt_refresh(void *);
85
86void	nvt_refresh_volts(struct nvt_softc *);
87void	nvt_refresh_temps(struct nvt_softc *);
88void	nvt_refresh_fans(struct nvt_softc *);
89
90uint8_t	nvt_readreg(struct nvt_softc *, uint8_t);
91void	nvt_writereg(struct nvt_softc *, uint8_t, uint8_t);
92
93
94const struct cfattach nvt_ca = {
95	sizeof(struct nvt_softc), nvt_match, nvt_attach
96};
97
98struct cfdriver nvt_cd = {
99	NULL, "nvt", DV_DULL
100};
101
102
103int
104nvt_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
113void
114nvt_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
170void
171nvt_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
192void
193nvt_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
217void
218nvt_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
253void
254nvt_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
281uint8_t
282nvt_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
292void
293nvt_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