This source file includes following definitions.
- wbenv_match
- wbenv_attach
- wbenv_setup_sensors
- wbenv_refresh
- w83l784r_refresh_volt
- w83l785r_refresh_volt
- wbenv_refresh_temp
- w83l784r_refresh_temp
- w83l784r_refresh_fanrpm
- w83l785r_refresh_fanrpm
- wbenv_readreg
- wbenv_writereg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
27 #define W83L784R_VCORE 0x20
28 #define W83L784R_VBAT 0x21
29 #define W83L784R_3_3V 0x22
30 #define W83L784R_VCC 0x23
31 #define W83L784R_TEMP1 0x27
32 #define W83L784R_FAN1 0x28
33 #define W83L784R_FAN2 0x29
34 #define W83L784R_CONFIG 0x40
35 #define W83L784R_FANDIV 0x49
36 #define W83L784R_T23ADDR 0x4b
37 #define W83L784R_CHIPID 0x4e
38
39 #define W83L784R_TEMP23 0x00
40
41
42 #define W83L785R_2_5V 0x21
43 #define W83L785R_1_5V 0x22
44 #define W83L785R_VCC 0x23
45 #define W83L785R_TEMP2 0x26
46 #define W83L785R_FANDIV 0x47
47
48
49 #define WBENV_CHIPID_W83L784R 0x50
50 #define WBENV_CHIPID_W83L785R 0x60
51 #define WBENV_CHIPID_W83L785TS_L 0x70
52
53 #define WBENV_MAX_SENSORS 9
54
55
56
57
58
59
60
61 #define RFACT_NONE 10000
62 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
63
64 struct wbenv_softc;
65
66 struct wbenv_sensor {
67 char *desc;
68 enum sensor_type type;
69 u_int8_t reg;
70 void (*refresh)(struct wbenv_softc *, int);
71 int rfact;
72 };
73
74 struct wbenv_softc {
75 struct device sc_dev;
76
77 i2c_tag_t sc_tag;
78 i2c_addr_t sc_addr[3];
79 u_int8_t sc_chip_id;
80
81 struct ksensor sc_sensors[WBENV_MAX_SENSORS];
82 struct ksensordev sc_sensordev;
83 struct wbenv_sensor *sc_wbenv_sensors;
84 int sc_numsensors;
85 };
86
87 int wbenv_match(struct device *, void *, void *);
88 void wbenv_attach(struct device *, struct device *, void *);
89
90 void wbenv_setup_sensors(struct wbenv_softc *, struct wbenv_sensor *);
91 void wbenv_refresh(void *);
92
93 void w83l784r_refresh_volt(struct wbenv_softc *, int);
94 void w83l785r_refresh_volt(struct wbenv_softc *, int);
95 void wbenv_refresh_temp(struct wbenv_softc *, int);
96 void w83l784r_refresh_temp(struct wbenv_softc *, int);
97 void w83l784r_refresh_fanrpm(struct wbenv_softc *, int);
98 void w83l785r_refresh_fanrpm(struct wbenv_softc *, int);
99
100 u_int8_t wbenv_readreg(struct wbenv_softc *, u_int8_t);
101 void wbenv_writereg(struct wbenv_softc *, u_int8_t, u_int8_t);
102
103 struct cfattach wbenv_ca = {
104 sizeof(struct wbenv_softc), wbenv_match, wbenv_attach
105 };
106
107 struct cfdriver wbenv_cd = {
108 NULL, "wbenv", DV_DULL
109 };
110
111 struct wbenv_sensor w83l784r_sensors[] =
112 {
113 { "VCore", SENSOR_VOLTS_DC, W83L784R_VCORE, w83l784r_refresh_volt, RFACT_NONE },
114 { "VBAT", SENSOR_VOLTS_DC, W83L784R_VBAT, w83l784r_refresh_volt, RFACT(232, 99) },
115 { "+3.3V", SENSOR_VOLTS_DC, W83L784R_3_3V, w83l784r_refresh_volt, RFACT_NONE },
116 { "+5V", SENSOR_VOLTS_DC, W83L784R_VCC, w83l784r_refresh_volt, RFACT(50, 34) },
117 { "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
118 { "", SENSOR_TEMP, 1, w83l784r_refresh_temp },
119 { "", SENSOR_TEMP, 2, w83l784r_refresh_temp },
120 { "", SENSOR_FANRPM, W83L784R_FAN1, w83l784r_refresh_fanrpm },
121 { "", SENSOR_FANRPM, W83L784R_FAN2, w83l784r_refresh_fanrpm },
122
123 { NULL }
124 };
125
126 struct wbenv_sensor w83l785r_sensors[] =
127 {
128 { "VCore", SENSOR_VOLTS_DC, W83L784R_VCORE, w83l785r_refresh_volt, RFACT_NONE },
129 { "+2.5V", SENSOR_VOLTS_DC, W83L785R_2_5V, w83l785r_refresh_volt, RFACT(100, 100) },
130 { "+1.5V", SENSOR_VOLTS_DC, W83L785R_1_5V, w83l785r_refresh_volt, RFACT_NONE },
131 { "+3.3V", SENSOR_VOLTS_DC, W83L785R_VCC, w83l785r_refresh_volt, RFACT(20, 40) },
132 { "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
133 { "", SENSOR_TEMP, W83L785R_TEMP2, wbenv_refresh_temp },
134 { "", SENSOR_FANRPM, W83L784R_FAN1, w83l785r_refresh_fanrpm },
135 { "", SENSOR_FANRPM, W83L784R_FAN2, w83l785r_refresh_fanrpm },
136
137 { NULL }
138 };
139
140 struct wbenv_sensor w83l785ts_l_sensors[] =
141 {
142 { "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
143
144 { NULL }
145 };
146
147 int
148 wbenv_match(struct device *parent, void *match, void *aux)
149 {
150 struct i2c_attach_args *ia = aux;
151
152 if (strcmp(ia->ia_name, "w83l784r") == 0 ||
153 strcmp(ia->ia_name, "w83l785r") == 0 ||
154 strcmp(ia->ia_name, "w83l785ts-l") == 0)
155 return (1);
156 return (0);
157 }
158
159 void
160 wbenv_attach(struct device *parent, struct device *self, void *aux)
161 {
162 struct wbenv_softc *sc = (struct wbenv_softc *)self;
163 struct i2c_attach_args *ia = aux;
164 u_int8_t cmd, data, config;
165 int i;
166
167 sc->sc_tag = ia->ia_tag;
168 sc->sc_addr[0] = ia->ia_addr;
169
170 iic_acquire_bus(sc->sc_tag, 0);
171
172 cmd = W83L784R_CHIPID;
173 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
174 sc->sc_addr[0], &cmd, sizeof cmd, &data, sizeof data, 0)) {
175 iic_release_bus(sc->sc_tag, 0);
176 printf(": cannot read chip ID register\n");
177 return;
178 }
179
180 iic_release_bus(sc->sc_tag, 0);
181
182 sc->sc_chip_id = data;
183
184 switch (sc->sc_chip_id) {
185 case WBENV_CHIPID_W83L784R:
186 printf(": W83L784R\n");
187 wbenv_setup_sensors(sc, w83l784r_sensors);
188 break;
189 case WBENV_CHIPID_W83L785R:
190 printf(": W83L785R\n");
191 wbenv_setup_sensors(sc, w83l785r_sensors);
192 goto start;
193 case WBENV_CHIPID_W83L785TS_L:
194 printf(": W83L785TS-L\n");
195 wbenv_setup_sensors(sc, w83l785ts_l_sensors);
196 goto start;
197 default:
198 printf(": unknown Winbond chip (ID 0x%x)\n", sc->sc_chip_id);
199 return;
200 }
201
202 iic_acquire_bus(sc->sc_tag, 0);
203
204 cmd = W83L784R_T23ADDR;
205 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
206 sc->sc_addr[0], &cmd, sizeof cmd, &data, sizeof data, 0)) {
207 iic_release_bus(sc->sc_tag, 0);
208 printf(": cannot read address register\n");
209 return;
210 }
211
212 iic_release_bus(sc->sc_tag, 0);
213
214 sc->sc_addr[1] = 0x48 + (data & 0x7);
215 sc->sc_addr[2] = 0x48 + ((data >> 4) & 0x7);
216
217
218 iic_ignore_addr(sc->sc_addr[1]);
219 iic_ignore_addr(sc->sc_addr[2]);
220
221 start:
222 if (sensor_task_register(sc, wbenv_refresh, 5) == NULL) {
223 printf("%s: unable to register update task\n",
224 sc->sc_dev.dv_xname);
225 return;
226 }
227
228
229 config = wbenv_readreg(sc, W83L784R_CONFIG);
230 wbenv_writereg(sc, W83L784R_CONFIG, config | 0x01);
231
232
233 for (i = 0; i < sc->sc_numsensors; ++i)
234 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
235 sensordev_install(&sc->sc_sensordev);
236 }
237
238 void
239 wbenv_setup_sensors(struct wbenv_softc *sc, struct wbenv_sensor *sensors)
240 {
241 int i;
242
243 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
244 sizeof(sc->sc_sensordev.xname));
245
246 for (i = 0; sensors[i].desc; i++) {
247 sc->sc_sensors[i].type = sensors[i].type;
248 strlcpy(sc->sc_sensors[i].desc, sensors[i].desc,
249 sizeof(sc->sc_sensors[i].desc));
250 sc->sc_numsensors++;
251 }
252 sc->sc_wbenv_sensors = sensors;
253 }
254
255 void
256 wbenv_refresh(void *arg)
257 {
258 struct wbenv_softc *sc = arg;
259 int i;
260
261 iic_acquire_bus(sc->sc_tag, 0);
262
263 for (i = 0; i < sc->sc_numsensors; i++)
264 sc->sc_wbenv_sensors[i].refresh(sc, i);
265
266 iic_release_bus(sc->sc_tag, 0);
267 }
268
269 void
270 w83l784r_refresh_volt(struct wbenv_softc *sc, int n)
271 {
272 struct ksensor *sensor = &sc->sc_sensors[n];
273 int data, reg = sc->sc_wbenv_sensors[n].reg;
274
275 data = wbenv_readreg(sc, reg);
276 sensor->value = (data << 4);
277 sensor->value *= sc->sc_wbenv_sensors[n].rfact;
278 sensor->value /= 10;
279 }
280
281 void
282 w83l785r_refresh_volt(struct wbenv_softc *sc, int n)
283 {
284 struct ksensor *sensor = &sc->sc_sensors[n];
285 int data, reg = sc->sc_wbenv_sensors[n].reg;
286
287 data = wbenv_readreg(sc, reg);
288 sensor->value = (data << 3);
289 sensor->value *= sc->sc_wbenv_sensors[n].rfact;
290 sensor->value /= 10;
291 }
292
293 void
294 wbenv_refresh_temp(struct wbenv_softc *sc, int n)
295 {
296 struct ksensor *sensor = &sc->sc_sensors[n];
297 int sdata;
298
299 sdata = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
300 if (sdata & 0x80)
301 sdata -= 0x100;
302 sensor->value = sdata * 1000000 + 273150000;
303 }
304
305 void
306 w83l784r_refresh_temp(struct wbenv_softc *sc, int n)
307 {
308 struct ksensor *sensor = &sc->sc_sensors[n];
309 int16_t sdata;
310 u_int8_t cmd = 0;
311
312 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
313 sc->sc_addr[sc->sc_wbenv_sensors[n].reg],
314 &cmd, sizeof cmd, &sdata, sizeof sdata, 0);
315 sensor->value = (sdata >> 7) * 500000 + 273150000;
316 }
317
318 void
319 w83l784r_refresh_fanrpm(struct wbenv_softc *sc, int n)
320 {
321 struct ksensor *sensor = &sc->sc_sensors[n];
322 int data, divisor;
323
324 data = wbenv_readreg(sc, W83L784R_FANDIV);
325 if (sc->sc_wbenv_sensors[n].reg == W83L784R_FAN1)
326 divisor = data & 0x07;
327 else
328 divisor = (data >> 4) & 0x07;
329
330 data = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
331 if (data == 0xff || data == 0x00) {
332 sensor->flags |= SENSOR_FINVALID;
333 sensor->value = 0;
334 } else {
335 sensor->flags &= ~SENSOR_FINVALID;
336 sensor->value = 1350000 / (data << divisor);
337 }
338 }
339
340 void
341 w83l785r_refresh_fanrpm(struct wbenv_softc *sc, int n)
342 {
343 struct ksensor *sensor = &sc->sc_sensors[n];
344 int data, divisor;
345
346 data = wbenv_readreg(sc, W83L785R_FANDIV);
347 if (sc->sc_wbenv_sensors[n].reg == W83L784R_FAN1)
348 divisor = data & 0x07;
349 else
350 divisor = (data >> 4) & 0x07;
351
352 data = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
353 if (data == 0xff || data == 0x00) {
354 sensor->flags |= SENSOR_FINVALID;
355 sensor->value = 0;
356 } else {
357 sensor->flags &= ~SENSOR_FINVALID;
358 sensor->value = 1350000 / (data << divisor);
359 }
360 }
361
362 u_int8_t
363 wbenv_readreg(struct wbenv_softc *sc, u_int8_t reg)
364 {
365 u_int8_t data;
366
367 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
368 sc->sc_addr[0], ®, sizeof reg, &data, sizeof data, 0);
369
370 return data;
371 }
372
373 void
374 wbenv_writereg(struct wbenv_softc *sc, u_int8_t reg, u_int8_t data)
375 {
376 iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
377 sc->sc_addr[0], ®, sizeof reg, &data, sizeof data, 0);
378 }