Line data Source code
1 : /* $OpenBSD: lm93.c,v 1.8 2007/10/31 20:46:17 cnst Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2007 Theo de Raadt
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 : /* LM93 registers */
27 : #define LM93_CPU1_TEMP 0x50
28 : #define LM93_CPU2_TEMP 0x51
29 : #define LM93_INT_TEMP 0x52
30 : #define LM93_EXT_TEMP 0x53
31 : #define LM93_IN1_V 0x56
32 : #define LM93_IN2_V 0x57
33 : #define LM93_IN3_V 0x58
34 : #define LM93_IN4_V 0x59
35 : #define LM93_IN5_V 0x5a
36 : #define LM93_IN6_V 0x5b
37 : #define LM93_IN7_V 0x5c
38 : #define LM93_IN8_V 0x5d
39 : #define LM93_IN9_V 0x5e
40 : #define LM93_IN10_V 0x5f
41 : #define LM93_IN11_V 0x60
42 : #define LM93_IN12_V 0x61
43 : #define LM93_IN13_V 0x62
44 : #define LM93_IN14_V 0x63
45 : #define LM93_IN15_V 0x64
46 : #define LM93_IN16_V 0x65
47 : #define LM93_TACH1L 0x6e
48 : #define LM93_TACH1H 0x6f
49 : #define LM93_TACH2L 0x70
50 : #define LM93_TACH2H 0x71
51 : #define LM93_TACH3L 0x72
52 : #define LM93_TACH3H 0x73
53 : #define LM93_TACH4L 0x74
54 : #define LM93_TACH4H 0x75
55 : #define LM93_REVISION 0x3f
56 :
57 : /* Sensors */
58 : #define LMN_CPU1_TEMP 0
59 : #define LMN_CPU2_TEMP 1
60 : #define LMN_INT_TEMP 2
61 : #define LMN_EXT_TEMP 3
62 : #define LMN_IN1_V 4
63 : #define LMN_IN2_V 5
64 : #define LMN_IN3_V 6
65 : #define LMN_IN4_V 7
66 : #define LMN_IN5_V 8
67 : #define LMN_IN6_V 9
68 : #define LMN_IN7_V 10
69 : #define LMN_IN8_V 11
70 : #define LMN_IN9_V 12
71 : #define LMN_IN10_V 13
72 : #define LMN_IN11_V 14
73 : #define LMN_IN12_V 15
74 : #define LMN_IN13_V 16
75 : #define LMN_IN14_V 17
76 : #define LMN_IN15_V 18
77 : #define LMN_IN16_V 19
78 : #define LMN_TACH1 20
79 : #define LMN_TACH2 21
80 : #define LMN_TACH3 22
81 : #define LMN_TACH4 23
82 : #define LMN_NUM_SENSORS 24
83 :
84 : struct {
85 : char sensor;
86 : u_int8_t cmd;
87 : char *name;
88 : u_short mVscale;
89 : u_short tempscale; /* else a fan */
90 : } lmn_worklist[] = {
91 : { LMN_CPU1_TEMP, LM93_CPU1_TEMP, "CPU", 0, 1 },
92 : { LMN_CPU2_TEMP, LM93_CPU2_TEMP, "CPU", 0, 1 },
93 : { LMN_INT_TEMP, LM93_INT_TEMP, "Internal", 0, 1 },
94 : { LMN_EXT_TEMP, LM93_EXT_TEMP, "External", 0, 1 },
95 :
96 : { LMN_IN1_V, LM93_IN1_V, "+12V", 1236*10, 0 },
97 : { LMN_IN2_V, LM93_IN2_V, "+12V", 1236*10, 0 },
98 : { LMN_IN3_V, LM93_IN3_V, "+12V", 1236*10, 0 },
99 : { LMN_IN4_V, LM93_IN4_V, "FSB_Vtt 1.6V", 1600, 0 },
100 : { LMN_IN5_V, LM93_IN5_V, "3GIO 2V ", 2000, 0 },
101 : { LMN_IN6_V, LM93_IN6_V, "ICH_Core 2V", 2000, 0 },
102 : { LMN_IN7_V, LM93_IN7_V, "Vccp 1.6V", 1600, 0 },
103 : { LMN_IN8_V, LM93_IN8_V, "Vccp 1.6V", 1600, 0 },
104 : { LMN_IN9_V, LM93_IN9_V, "+3.3V", 4400, 0 },
105 : { LMN_IN10_V, LM93_IN10_V, "+5V", 6667, 0 },
106 : { LMN_IN11_V, LM93_IN11_V, "SCSI_Core 3.3V", 3333, 0 },
107 : { LMN_IN12_V, LM93_IN12_V, "Mem_Core 2.6V", 2625, 0 },
108 : { LMN_IN13_V, LM93_IN13_V, "Mem_Vtt 1.3V", 1312, 0 },
109 : { LMN_IN14_V, LM93_IN14_V, "Gbit_Core 1.3V", 1312, 0 },
110 : { LMN_IN15_V, LM93_IN15_V, "-12V", -1236*10, 0 },
111 : { LMN_IN16_V, LM93_IN16_V, "+3.3V S/B", 3600, 0 },
112 :
113 : { LMN_TACH1, LM93_TACH1L, "", 0, 0 },
114 : { LMN_TACH2, LM93_TACH2L, "", 0, 0 },
115 : { LMN_TACH3, LM93_TACH3L, "", 0, 0 },
116 : { LMN_TACH4, LM93_TACH4L, "", 0, 0 }
117 : };
118 :
119 : struct lmn_softc {
120 : struct device sc_dev;
121 : i2c_tag_t sc_tag;
122 : i2c_addr_t sc_addr;
123 : u_int8_t sc_conf;
124 :
125 : struct ksensor sc_sensor[LMN_NUM_SENSORS];
126 : struct ksensordev sc_sensordev;
127 : };
128 :
129 : int lmn_match(struct device *, void *, void *);
130 : void lmn_attach(struct device *, struct device *, void *);
131 :
132 : void lmn_refresh(void *);
133 :
134 : struct cfattach lmn_ca = {
135 : sizeof(struct lmn_softc), lmn_match, lmn_attach
136 : };
137 :
138 : struct cfdriver lmn_cd = {
139 : NULL, "lmn", DV_DULL
140 : };
141 :
142 : int
143 0 : lmn_match(struct device *parent, void *match, void *aux)
144 : {
145 0 : struct i2c_attach_args *ia = aux;
146 :
147 0 : if (strcmp(ia->ia_name, "lm93") == 0)
148 0 : return (1);
149 0 : return (0);
150 0 : }
151 :
152 : void
153 0 : lmn_attach(struct device *parent, struct device *self, void *aux)
154 : {
155 0 : struct lmn_softc *sc = (struct lmn_softc *)self;
156 0 : struct i2c_attach_args *ia = aux;
157 : int i;
158 :
159 0 : sc->sc_tag = ia->ia_tag;
160 0 : sc->sc_addr = ia->ia_addr;
161 :
162 0 : printf(": %s", ia->ia_name);
163 :
164 : /* Initialize sensor data. */
165 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
166 : sizeof(sc->sc_sensordev.xname));
167 :
168 0 : if (sensor_task_register(sc, lmn_refresh, 5) == NULL) {
169 0 : printf(", unable to register update task\n");
170 0 : return;
171 : }
172 :
173 0 : for (i = 0; i < LMN_NUM_SENSORS; i++) {
174 0 : if (lmn_worklist[i].tempscale)
175 0 : sc->sc_sensor[i].type = SENSOR_TEMP;
176 0 : else if (lmn_worklist[i].mVscale)
177 0 : sc->sc_sensor[i].type = SENSOR_VOLTS_DC;
178 : else
179 0 : sc->sc_sensor[i].type = SENSOR_FANRPM;
180 0 : strlcpy(sc->sc_sensor[i].desc, lmn_worklist[i].name,
181 : sizeof(sc->sc_sensor[i].desc));
182 :
183 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
184 : }
185 0 : sensordev_install(&sc->sc_sensordev);
186 :
187 0 : printf("\n");
188 0 : }
189 :
190 : void
191 0 : lmn_refresh(void *arg)
192 : {
193 0 : struct lmn_softc *sc = arg;
194 0 : u_int8_t cmd, data, data2;
195 : u_int16_t fan;
196 : int i;
197 :
198 0 : iic_acquire_bus(sc->sc_tag, 0);
199 :
200 0 : for (i = 0; i < sizeof lmn_worklist / sizeof(lmn_worklist[0]); i++) {
201 :
202 0 : cmd = lmn_worklist[i].cmd;
203 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
204 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
205 0 : sc->sc_sensor[i].flags |= SENSOR_FINVALID;
206 0 : continue;
207 : }
208 :
209 0 : sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
210 0 : if (lmn_worklist[i].tempscale) {
211 0 : if (data == 0x80)
212 0 : sc->sc_sensor[i].flags |= SENSOR_FINVALID;
213 : else
214 0 : sc->sc_sensor[i].value =
215 0 : (int8_t)data * 1000000 + 273150000;
216 0 : } else if (lmn_worklist[i].mVscale) {
217 0 : sc->sc_sensor[i].value = lmn_worklist[i].mVscale *
218 0 : 1000 * (u_int)data / 192;
219 0 : } else {
220 0 : cmd = lmn_worklist[i].cmd + 1; /* TACHnH follows TACHnL */
221 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
222 0 : sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
223 0 : sc->sc_sensor[i].flags |= SENSOR_FINVALID;
224 0 : continue;
225 : }
226 :
227 0 : fan = data + (data2 << 8);
228 0 : if (fan == 0 || fan == 0xffff)
229 0 : sc->sc_sensor[i].flags |= SENSOR_FINVALID;
230 : else
231 0 : sc->sc_sensor[i].value = (90000 * 60) / fan;
232 : }
233 : }
234 :
235 0 : iic_release_bus(sc->sc_tag, 0);
236 0 : }
|