Line data Source code
1 : /* $OpenBSD: adm1025.c,v 1.25 2007/06/24 05:34:35 dlg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2005 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 : /* ADM 1025 registers */
27 : #define ADM1025_V2_5 0x20
28 : #define ADM1025_Vccp 0x21
29 : #define ADM1025_V3_3 0x22
30 : #define ADM1025_V5 0x23
31 : #define ADM1025_V12 0x24
32 : #define ADM1025_Vcc 0x25
33 : #define ADM1025_EXT_TEMP 0x26
34 : #define ADM1025_INT_TEMP 0x27
35 : #define ADM1025_STATUS2 0x42
36 : #define ADM1025_STATUS2_EXT 0x40
37 : #define ADM1025_COMPANY 0x3e /* contains 0x41 */
38 : #define ADM1025_STEPPING 0x3f /* contains 0x2? */
39 : #define ADM1025_CONFIG 0x40
40 : #define ADM1025_CONFIG_START 0x01
41 : #define SMSC47M192_V1_5 0x50
42 : #define SMSC47M192_V1_8 0x51
43 : #define SMSC47M192_TEMP2 0x52
44 :
45 : /* Sensors */
46 : #define ADMTM_INT 0
47 : #define ADMTM_EXT 1
48 : #define ADMTM_V2_5 2
49 : #define ADMTM_Vccp 3
50 : #define ADMTM_V3_3 4
51 : #define ADMTM_V5 5
52 : #define ADMTM_V12 6
53 : #define ADMTM_Vcc 7
54 : #define ADMTM_NUM_SENSORS 8
55 : #define SMSC_V1_5 8
56 : #define SMSC_V1_8 9
57 : #define SMSC_TEMP2 10
58 : #define SMSC_NUM_SENSORS 3
59 : struct admtm_softc {
60 : struct device sc_dev;
61 : i2c_tag_t sc_tag;
62 : i2c_addr_t sc_addr;
63 :
64 : struct ksensor sc_sensor[ADMTM_NUM_SENSORS + SMSC_NUM_SENSORS];
65 : struct ksensordev sc_sensordev;
66 : int sc_nsensors;
67 : int sc_model;
68 : };
69 :
70 : int admtm_match(struct device *, void *, void *);
71 : void admtm_attach(struct device *, struct device *, void *);
72 : void admtm_refresh(void *);
73 :
74 : struct cfattach admtm_ca = {
75 : sizeof(struct admtm_softc), admtm_match, admtm_attach
76 : };
77 :
78 : struct cfdriver admtm_cd = {
79 : NULL, "admtm", DV_DULL
80 : };
81 :
82 : int
83 0 : admtm_match(struct device *parent, void *match, void *aux)
84 : {
85 0 : struct i2c_attach_args *ia = aux;
86 :
87 0 : if (strcmp(ia->ia_name, "adm1025") == 0 ||
88 0 : strcmp(ia->ia_name, "47m192") == 0 ||
89 0 : strcmp(ia->ia_name, "ne1619") == 0)
90 0 : return (1);
91 0 : return (0);
92 0 : }
93 :
94 : void
95 0 : admtm_attach(struct device *parent, struct device *self, void *aux)
96 : {
97 0 : struct admtm_softc *sc = (struct admtm_softc *)self;
98 0 : struct i2c_attach_args *ia = aux;
99 0 : u_int8_t cmd, data, data2;
100 : int i;
101 :
102 0 : sc->sc_tag = ia->ia_tag;
103 0 : sc->sc_addr = ia->ia_addr;
104 :
105 0 : printf(": %s", ia->ia_name);
106 :
107 0 : sc->sc_nsensors = ADMTM_NUM_SENSORS;
108 0 : sc->sc_model = 1025;
109 0 : if (strcmp(ia->ia_name, "47m192") == 0) {
110 0 : sc->sc_nsensors += SMSC_NUM_SENSORS;
111 0 : sc->sc_model = 192;
112 0 : }
113 :
114 0 : iic_acquire_bus(sc->sc_tag, 0);
115 0 : cmd = ADM1025_CONFIG;
116 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
117 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
118 0 : iic_release_bus(sc->sc_tag, 0);
119 0 : printf(", cannot get control register\n");
120 0 : return;
121 : }
122 :
123 0 : data2 = data | ADM1025_CONFIG_START;
124 0 : if (data != data2) {
125 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
126 0 : sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
127 0 : iic_release_bus(sc->sc_tag, 0);
128 0 : printf(", cannot set control register\n");
129 0 : return;
130 : }
131 : }
132 0 : iic_release_bus(sc->sc_tag, 0);
133 :
134 : /* Initialize sensor data. */
135 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
136 : sizeof(sc->sc_sensordev.xname));
137 :
138 0 : sc->sc_sensor[ADMTM_INT].type = SENSOR_TEMP;
139 0 : strlcpy(sc->sc_sensor[ADMTM_INT].desc, "Internal",
140 : sizeof(sc->sc_sensor[ADMTM_INT].desc));
141 :
142 0 : sc->sc_sensor[ADMTM_EXT].type = SENSOR_TEMP;
143 0 : strlcpy(sc->sc_sensor[ADMTM_EXT].desc, "External",
144 : sizeof(sc->sc_sensor[ADMTM_EXT].desc));
145 :
146 0 : sc->sc_sensor[ADMTM_V2_5].type = SENSOR_VOLTS_DC;
147 0 : strlcpy(sc->sc_sensor[ADMTM_V2_5].desc, "2.5 V",
148 : sizeof(sc->sc_sensor[ADMTM_V2_5].desc));
149 :
150 0 : sc->sc_sensor[ADMTM_Vccp].type = SENSOR_VOLTS_DC;
151 0 : strlcpy(sc->sc_sensor[ADMTM_Vccp].desc, "Vccp",
152 : sizeof(sc->sc_sensor[ADMTM_Vccp].desc));
153 :
154 0 : sc->sc_sensor[ADMTM_V3_3].type = SENSOR_VOLTS_DC;
155 0 : strlcpy(sc->sc_sensor[ADMTM_V3_3].desc, "3.3 V",
156 : sizeof(sc->sc_sensor[ADMTM_V3_3].desc));
157 :
158 0 : sc->sc_sensor[ADMTM_V5].type = SENSOR_VOLTS_DC;
159 0 : strlcpy(sc->sc_sensor[ADMTM_V5].desc, "5 V",
160 : sizeof(sc->sc_sensor[ADMTM_V5].desc));
161 :
162 0 : sc->sc_sensor[ADMTM_V12].type = SENSOR_VOLTS_DC;
163 0 : strlcpy(sc->sc_sensor[ADMTM_V12].desc, "12 V",
164 : sizeof(sc->sc_sensor[ADMTM_V12].desc));
165 :
166 0 : sc->sc_sensor[ADMTM_Vcc].type = SENSOR_VOLTS_DC;
167 0 : strlcpy(sc->sc_sensor[ADMTM_Vcc].desc, "Vcc",
168 : sizeof(sc->sc_sensor[ADMTM_Vcc].desc));
169 :
170 0 : sc->sc_sensor[SMSC_V1_5].type = SENSOR_VOLTS_DC;
171 0 : strlcpy(sc->sc_sensor[SMSC_V1_5].desc, "1.5 V",
172 : sizeof(sc->sc_sensor[SMSC_V1_5].desc));
173 :
174 0 : sc->sc_sensor[SMSC_V1_8].type = SENSOR_VOLTS_DC;
175 0 : strlcpy(sc->sc_sensor[SMSC_V1_8].desc, "1.8 V",
176 : sizeof(sc->sc_sensor[SMSC_V1_8].desc));
177 :
178 0 : sc->sc_sensor[SMSC_TEMP2].type = SENSOR_TEMP;
179 0 : strlcpy(sc->sc_sensor[SMSC_TEMP2].desc, "External",
180 : sizeof(sc->sc_sensor[SMSC_TEMP2].desc));
181 :
182 0 : if (sensor_task_register(sc, admtm_refresh, 5) == NULL) {
183 0 : printf(", unable to register update task\n");
184 0 : return;
185 : }
186 :
187 0 : for (i = 0; i < sc->sc_nsensors; i++)
188 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
189 0 : sensordev_install(&sc->sc_sensordev);
190 :
191 0 : printf("\n");
192 0 : }
193 :
194 : void
195 0 : admtm_refresh(void *arg)
196 : {
197 0 : struct admtm_softc *sc = arg;
198 0 : u_int8_t cmd, data;
199 0 : int8_t sdata;
200 :
201 0 : iic_acquire_bus(sc->sc_tag, 0);
202 :
203 0 : cmd = ADM1025_INT_TEMP;
204 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
205 0 : sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
206 0 : sc->sc_sensor[ADMTM_INT].value = 273150000 + 1000000 * sdata;
207 :
208 0 : cmd = ADM1025_EXT_TEMP;
209 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
210 0 : sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
211 0 : sc->sc_sensor[ADMTM_EXT].value = 273150000 + 1000000 * sdata;
212 :
213 0 : cmd = ADM1025_STATUS2;
214 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
215 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
216 0 : if (data & ADM1025_STATUS2_EXT)
217 0 : sc->sc_sensor[ADMTM_EXT].flags |= SENSOR_FINVALID;
218 : else
219 0 : sc->sc_sensor[ADMTM_EXT].flags &= ~SENSOR_FINVALID;
220 : }
221 :
222 0 : cmd = ADM1025_V2_5;
223 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
224 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
225 0 : sc->sc_sensor[ADMTM_V2_5].value = 2500000 * data / 192;
226 :
227 0 : cmd = ADM1025_Vccp;
228 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
229 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
230 0 : sc->sc_sensor[ADMTM_Vcc].value = 2249000 * data / 192;
231 :
232 0 : cmd = ADM1025_V3_3;
233 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
234 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
235 0 : sc->sc_sensor[ADMTM_V3_3].value = 3300000 * data / 192;
236 :
237 0 : cmd = ADM1025_V5;
238 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
239 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
240 0 : sc->sc_sensor[ADMTM_V5].value = 5000000 * data / 192;
241 :
242 0 : cmd = ADM1025_V12;
243 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
244 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
245 0 : sc->sc_sensor[ADMTM_V12].value = 12000000 * data / 192;
246 :
247 0 : cmd = ADM1025_Vcc;
248 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
249 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
250 0 : sc->sc_sensor[ADMTM_Vcc].value = 3300000 * data / 192;
251 :
252 0 : if (sc->sc_model == 192) {
253 0 : cmd = SMSC47M192_V1_5;
254 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
255 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
256 0 : sc->sc_sensor[SMSC_V1_5].value = 1500000 * data / 192;
257 :
258 0 : cmd = SMSC47M192_V1_8;
259 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
260 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
261 0 : sc->sc_sensor[SMSC_V1_8].value = 1800000 * data / 192;
262 :
263 0 : cmd = SMSC47M192_TEMP2;
264 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
265 0 : sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata,
266 0 : 0) == 0)
267 0 : sc->sc_sensor[SMSC_TEMP2].value = 273150000 + 1000000 * sdata;
268 :
269 : }
270 :
271 0 : iic_release_bus(sc->sc_tag, 0);
272 0 : }
|