Line data Source code
1 : /* $OpenBSD: w83795g.c,v 1.1 2011/07/03 21:30:20 kettenis 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 : 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
104 0 : nvt_match(struct device *parent, void *match, void *aux)
105 : {
106 0 : struct i2c_attach_args *ia = aux;
107 :
108 0 : if (strcmp(ia->ia_name, "w83795g") == 0)
109 0 : return (1);
110 0 : return (0);
111 0 : }
112 :
113 : void
114 0 : nvt_attach(struct device *parent, struct device *self, void *aux)
115 : {
116 0 : struct nvt_softc *sc = (struct nvt_softc *)self;
117 0 : 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 0 : sc->sc_tag = ia->ia_tag;
123 0 : sc->sc_addr = ia->ia_addr;
124 :
125 0 : cfg = nvt_readreg(sc, NVT_CONFIG);
126 0 : if (cfg & NVT_CONFIG_48)
127 0 : printf(": W83795ADG");
128 : else
129 0 : printf(": W83795G");
130 :
131 0 : vctrl1 = nvt_readreg(sc, NVT_VOLT_CTRL1);
132 0 : vctrl2 = nvt_readreg(sc, NVT_VOLT_CTRL2);
133 0 : tctrl1 = nvt_readreg(sc, NVT_TEMP_CTRL1);
134 0 : tctrl2 = nvt_readreg(sc, NVT_TEMP_CTRL2);
135 0 : fctrl1 = nvt_readreg(sc, NVT_FANIN_CTRL1);
136 0 : fctrl2 = nvt_readreg(sc, NVT_FANIN_CTRL2);
137 :
138 0 : sc->sc_vctrl = vctrl2 << 8 | vctrl1;
139 0 : sc->sc_tctrl1 = tctrl1;
140 0 : sc->sc_tctrl2 = tctrl2;
141 0 : sc->sc_fctrl = fctrl2 << 8 | fctrl1;
142 :
143 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
144 : sizeof(sc->sc_sensordev.xname));
145 :
146 0 : for (i = 0; i < NVT_NUM_VOLTS; i++) {
147 0 : strlcpy(sc->sc_sensors[i].desc, nvt_volt_desc[i],
148 : sizeof(sc->sc_sensors[i].desc));
149 0 : sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
150 : }
151 :
152 0 : for (j = i + NVT_NUM_TEMPS; i < j; i++)
153 0 : sc->sc_sensors[i].type = SENSOR_TEMP;
154 :
155 0 : for (j = i + NVT_NUM_FANS; i < j; i++)
156 0 : sc->sc_sensors[i].type = SENSOR_FANRPM;
157 :
158 0 : for (i = 0; i < NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS; i++)
159 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
160 :
161 0 : if (sensor_task_register(sc, nvt_refresh, 5) == NULL) {
162 0 : printf(", unable to register update task\n");
163 0 : return;
164 : }
165 :
166 0 : sensordev_install(&sc->sc_sensordev);
167 0 : printf("\n");
168 0 : }
169 :
170 : void
171 0 : nvt_refresh(void *arg)
172 : {
173 0 : struct nvt_softc *sc = arg;
174 : uint8_t bsr;
175 :
176 0 : iic_acquire_bus(sc->sc_tag, 0);
177 :
178 0 : bsr = nvt_readreg(sc, NVT_BANKSELECT);
179 0 : if ((bsr & 0x07) != 0x00)
180 0 : nvt_writereg(sc, NVT_BANKSELECT, bsr & 0xf8);
181 :
182 0 : nvt_refresh_volts(sc);
183 0 : nvt_refresh_temps(sc);
184 0 : nvt_refresh_fans(sc);
185 :
186 0 : if ((bsr & 0x07) != 0x00)
187 0 : nvt_writereg(sc, NVT_BANKSELECT, bsr);
188 :
189 0 : iic_release_bus(sc->sc_tag, 0);
190 0 : }
191 :
192 : void
193 0 : nvt_refresh_volts(struct nvt_softc *sc)
194 : {
195 0 : struct ksensor *s = &sc->sc_sensors[0];
196 : uint8_t vrlsb, data;
197 : int i, reg;
198 :
199 0 : for (i = 0; i < NVT_NUM_VOLTS; i++) {
200 0 : if ((sc->sc_vctrl & (1 << i)) == 0) {
201 0 : s[i].flags |= SENSOR_FINVALID;
202 0 : s[i].value = 0;
203 0 : continue;
204 : }
205 :
206 0 : reg = NVT_VSEN1 + i;
207 0 : data = nvt_readreg(sc, reg);
208 0 : vrlsb = nvt_readreg(sc, NVT_VRLSB);
209 0 : if (reg != NVT_3VDD && reg != NVT_3VSB && reg != NVT_VBAT)
210 0 : s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 2000;
211 : else
212 0 : s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 6000;
213 0 : s[i].flags &= ~SENSOR_FINVALID;
214 0 : }
215 0 : }
216 :
217 : void
218 0 : nvt_refresh_temps(struct nvt_softc *sc)
219 : {
220 0 : struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS];
221 : uint8_t vrlsb;
222 : int8_t data;
223 : int i;
224 :
225 0 : for (i = 0; i < NVT_NUM_TEMPS; i++) {
226 0 : if (i < NVT_NUM_TR
227 0 : && (sc->sc_tctrl1 & (1 << (2 * i))) == 0) {
228 0 : s[i].flags |= SENSOR_FINVALID;
229 0 : s[i].value = 0;
230 0 : continue;
231 : }
232 :
233 0 : if (i >= NVT_NUM_TR
234 0 : && (sc->sc_tctrl2 & (1 << (2 * (i - NVT_NUM_TR)))) == 0) {
235 0 : s[i].flags |= SENSOR_FINVALID;
236 0 : s[i].value = 0;
237 0 : continue;
238 : }
239 :
240 0 : data = nvt_readreg(sc, NVT_TR5 + i);
241 0 : vrlsb = nvt_readreg(sc, NVT_VRLSB);
242 0 : if (data == -128 && (vrlsb >> 6) == 0) {
243 0 : s[i].flags |= SENSOR_FINVALID;
244 0 : s[i].value = 0;
245 0 : continue;
246 : }
247 0 : s[i].value = data * 1000000 + (vrlsb >> 6) * 250000;
248 0 : s[i].value += 273150000;
249 0 : s[i].flags &= ~SENSOR_FINVALID;
250 0 : }
251 0 : }
252 :
253 : void
254 0 : nvt_refresh_fans(struct nvt_softc *sc)
255 : {
256 0 : 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 0 : for (i = 0; i < NVT_NUM_FANS; i++) {
262 0 : if ((sc->sc_fctrl & (1 << i)) == 0) {
263 0 : s[i].flags |= SENSOR_FINVALID;
264 0 : s[i].value = 0;
265 0 : continue;
266 : }
267 :
268 0 : data = nvt_readreg(sc, NVT_FANIN1_COUNT + i);
269 0 : vrlsb = nvt_readreg(sc, NVT_VRLSB);
270 0 : count = (data << 4) + (vrlsb >> 4);
271 0 : if (count == 0) {
272 0 : s[i].flags |= SENSOR_FINVALID;
273 0 : s[i].value = 0;
274 0 : continue;
275 : }
276 0 : s[i].value = 1350000 / (count * 2);
277 0 : s[i].flags &= ~SENSOR_FINVALID;
278 0 : }
279 0 : }
280 :
281 : uint8_t
282 0 : nvt_readreg(struct nvt_softc *sc, uint8_t reg)
283 : {
284 0 : uint8_t data;
285 :
286 0 : iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
287 0 : sc->sc_addr, ®, sizeof reg, &data, sizeof data, 0);
288 :
289 0 : return data;
290 0 : }
291 :
292 : void
293 0 : nvt_writereg(struct nvt_softc *sc, uint8_t reg, uint8_t data)
294 : {
295 0 : iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
296 0 : sc->sc_addr, ®, sizeof reg, &data, sizeof data, 0);
297 0 : }
|