xref: /openbsd/sys/dev/i2c/adt7460.c (revision 73471bf0)
1 /*	$OpenBSD: adt7460.c,v 1.21 2007/12/12 16:56:59 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 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 /* ADT7460 registers */
27 #define ADT7460_2_5V		0x20
28 #define ADT7460_VCCP		0x21
29 #define ADT7460_VCC		0x22
30 #define ADT7460_V5		0x23
31 #define ADT7460_V12		0x24
32 #define ADT7460_VTR		0x99
33 #define ADT7460_VBAT		0x9a
34 #define ADT7460_REM1_TEMP	0x25
35 #define ADT7460_LOCAL_TEMP	0x26
36 #define ADT7460_REM2_TEMP	0x27
37 #define ADT7460_TACH1L		0x28
38 #define ADT7460_TACH1H		0x29
39 #define ADT7460_TACH2L		0x2a
40 #define ADT7460_TACH2H		0x2b
41 #define ADT7460_TACH3L		0x2c
42 #define ADT7460_TACH3H		0x2d
43 #define ADT7460_TACH4L		0x2e
44 #define ADT7460_TACH4H		0x2f
45 #define ADT7460_TACH5L		0xa9
46 #define ADT7460_TACH5H		0xaa
47 #define ADT7460_TACH6L		0xab
48 #define ADT7460_TACH6H		0xac
49 #define ADT7460_REVISION	0x3f
50 #define ADT7460_CONFIG		0x40
51 #define ADT7460_CONFIG_Vcc	0x80
52 
53 /* Sensors */
54 #define ADT_2_5V		0
55 #define ADT_VCCP		1
56 #define ADT_VCC			2
57 #define ADT_V5			3
58 #define ADT_V12			4
59 #define ADT_VTR			5
60 #define ADT_VBAT		6
61 #define ADT_REM1_TEMP		7
62 #define ADT_LOCAL_TEMP		8
63 #define ADT_REM2_TEMP		9
64 #define ADT_TACH1		10
65 #define ADT_TACH2		11
66 #define ADT_TACH3		12
67 #define ADT_TACH4		13
68 #define ADT_TACH5		14
69 #define ADT_TACH6		15
70 #define ADT_NUM_SENSORS		16
71 
72 struct adt_chip {
73 	const char	*name;
74 	short		ratio[7];
75 	int		type;
76 	short		vcc;
77 } adt_chips[] = {
78 	/* register	0x20  0x21  0x22  0x23  0x24  0xa8  0xaa	type	*/
79 	/* 		2.5v  vccp   vcc    5v   12v   vtr  vbat		*/
80 
81 	{ "adt7460",	{ 2500,    0, 3300,    0,     0,    0,    0 },	7460,	5000 },
82 	{ "adt7467",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	7467,	5000 },
83 	{ "adt7475",	{    0, 2250, 3300,    0,     0,    0,    0 },	7475,	   0 },
84 	{ "adt7476",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	7476,	   0 },
85 	{ "adm1027",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	1027,	5000 },
86 	{ "lm85",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	7467,	   0 },
87 	{ "emc6d100",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	6100,	   0 },
88 	{ "emc6w201",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	6201,	   0 },
89 	{ "lm96000",	{ 2500, 2250, 3300, 5000, 12000,    0,    0 },	96000,	   0 },
90 	{ "sch5017",	{ 5000, 2250, 3300, 5000, 12000,    0,    0 },	5017,	   0 },
91 	{ "sch5027",	{ 5000, 2250, 3300, 5000, 12000, 3300, 3300 },	5027,	   0 }
92 };
93 
94 struct {
95 	char		sensor;
96 	u_int8_t	cmd;
97 	u_short		index;
98 } worklist[] = {
99 	{ ADT_2_5V, ADT7460_2_5V, 32768 + 0 },
100 	{ ADT_VCCP, ADT7460_VCCP, 32768 + 1 },
101 	{ ADT_VCC, ADT7460_VCC, 32768 + 2 },
102 	{ ADT_V5, ADT7460_V5, 32768 + 3 },
103 	{ ADT_V12, ADT7460_V12, 32768 + 4 },
104 	{ ADT_VTR, ADT7460_VTR, 32768 + 5 },
105 	{ ADT_VBAT, ADT7460_VBAT, 32768 + 6 },
106 	{ ADT_REM1_TEMP, ADT7460_REM1_TEMP },
107 	{ ADT_LOCAL_TEMP, ADT7460_LOCAL_TEMP },
108 	{ ADT_REM2_TEMP, ADT7460_REM2_TEMP },
109 	{ ADT_TACH1, ADT7460_TACH1L },
110 	{ ADT_TACH2, ADT7460_TACH2L },
111 	{ ADT_TACH3, ADT7460_TACH3L },
112 	{ ADT_TACH4, ADT7460_TACH4L },
113 	{ ADT_TACH5, ADT7460_TACH5L },
114 	{ ADT_TACH6, ADT7460_TACH6L },
115 };
116 
117 struct adt_softc {
118 	struct device sc_dev;
119 	i2c_tag_t sc_tag;
120 	i2c_addr_t sc_addr;
121 	u_int8_t sc_conf;
122 	struct adt_chip *chip;
123 
124 	struct ksensor sc_sensor[ADT_NUM_SENSORS];
125 	struct ksensordev sc_sensordev;
126 };
127 
128 int	adt_match(struct device *, void *, void *);
129 void	adt_attach(struct device *, struct device *, void *);
130 
131 void	adt_refresh(void *);
132 
133 struct cfattach adt_ca = {
134 	sizeof(struct adt_softc), adt_match, adt_attach
135 };
136 
137 struct cfdriver adt_cd = {
138 	NULL, "adt", DV_DULL
139 };
140 
141 int
142 adt_match(struct device *parent, void *match, void *aux)
143 {
144 	struct i2c_attach_args *ia = aux;
145 	int i;
146 
147 	for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++)
148 		if (strcmp(ia->ia_name, adt_chips[i].name) == 0)
149 			return (1);
150 	return (0);
151 }
152 
153 void
154 adt_attach(struct device *parent, struct device *self, void *aux)
155 {
156 	struct adt_softc *sc = (struct adt_softc *)self;
157 	struct i2c_attach_args *ia = aux;
158 	u_int8_t cmd, rev, data;
159 	int i;
160 
161 	sc->sc_tag = ia->ia_tag;
162 	sc->sc_addr = ia->ia_addr;
163 
164 	iic_acquire_bus(sc->sc_tag, 0);
165 
166 	for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) {
167 		if (strcmp(ia->ia_name, adt_chips[i].name) == 0) {
168 			sc->chip = &adt_chips[i];
169 			break;
170 		}
171 	}
172 
173 	cmd = ADT7460_REVISION;
174 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
175 	    sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) {
176 		iic_release_bus(sc->sc_tag, 0);
177 		printf(": cannot read REV register\n");
178 		return;
179 	}
180 
181 	cmd = ADT7460_CONFIG;
182 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
183 	    sc->sc_addr, &cmd, sizeof cmd, &sc->sc_conf, sizeof sc->sc_conf, 0)) {
184 		iic_release_bus(sc->sc_tag, 0);
185 		printf(": cannot read config register\n");
186 		return;
187 	}
188 
189 	if (sc->chip->type == 7460) {
190 		data = 1;
191 		cmd = ADT7460_CONFIG;
192 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
193 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
194 			iic_release_bus(sc->sc_tag, 0);
195 			printf(": cannot set control register\n");
196 			return;
197 		}
198 	}
199 
200 	iic_release_bus(sc->sc_tag, 0);
201 
202 	printf(": %s rev 0x%02x", ia->ia_name, rev);
203 
204 	/* Initialize sensor data. */
205 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
206 	    sizeof(sc->sc_sensordev.xname));
207 
208 	sc->sc_sensor[ADT_2_5V].type = SENSOR_VOLTS_DC;
209 	strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+2.5Vin",
210 	    sizeof(sc->sc_sensor[ADT_2_5V].desc));
211 
212 	if (sc->chip->type == 5017)
213 		strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+5VTR",
214 		    sizeof(sc->sc_sensor[ADT_2_5V].desc));
215 	if (sc->chip->type == 5027)
216 		strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+5V",
217 		    sizeof(sc->sc_sensor[ADT_2_5V].desc));
218 
219 	sc->sc_sensor[ADT_VCCP].type = SENSOR_VOLTS_DC;
220 	strlcpy(sc->sc_sensor[ADT_VCCP].desc, "Vccp",
221 	    sizeof(sc->sc_sensor[ADT_VCCP].desc));
222 
223 	sc->sc_sensor[ADT_VCC].type = SENSOR_VOLTS_DC;
224 	strlcpy(sc->sc_sensor[ADT_VCC].desc, "Vcc",
225 	    sizeof(sc->sc_sensor[ADT_VCC].desc));
226 
227 	sc->sc_sensor[ADT_V5].type = SENSOR_VOLTS_DC;
228 	strlcpy(sc->sc_sensor[ADT_V5].desc, "+5V",
229 	    sizeof(sc->sc_sensor[ADT_V5].desc));
230 
231 	sc->sc_sensor[ADT_V12].type = SENSOR_VOLTS_DC;
232 	strlcpy(sc->sc_sensor[ADT_V12].desc, "+12V",
233 	    sizeof(sc->sc_sensor[ADT_V12].desc));
234 
235 	sc->sc_sensor[ADT_VTR].type = SENSOR_VOLTS_DC;
236 	strlcpy(sc->sc_sensor[ADT_VTR].desc, "+Vtr",
237 	    sizeof(sc->sc_sensor[ADT_VTR].desc));
238 
239 	sc->sc_sensor[ADT_VBAT].type = SENSOR_VOLTS_DC;
240 	strlcpy(sc->sc_sensor[ADT_VBAT].desc, "+Vbat",
241 	    sizeof(sc->sc_sensor[ADT_VBAT].desc));
242 
243 	sc->sc_sensor[ADT_REM1_TEMP].type = SENSOR_TEMP;
244 	strlcpy(sc->sc_sensor[ADT_REM1_TEMP].desc, "Remote",
245 	    sizeof(sc->sc_sensor[ADT_REM1_TEMP].desc));
246 
247 	sc->sc_sensor[ADT_LOCAL_TEMP].type = SENSOR_TEMP;
248 	strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP].desc, "Internal",
249 	    sizeof(sc->sc_sensor[ADT_LOCAL_TEMP].desc));
250 
251 	sc->sc_sensor[ADT_REM2_TEMP].type = SENSOR_TEMP;
252 	strlcpy(sc->sc_sensor[ADT_REM2_TEMP].desc, "Remote",
253 	    sizeof(sc->sc_sensor[ADT_REM2_TEMP].desc));
254 
255 	sc->sc_sensor[ADT_TACH1].type = SENSOR_FANRPM;
256 	sc->sc_sensor[ADT_TACH2].type = SENSOR_FANRPM;
257 	sc->sc_sensor[ADT_TACH3].type = SENSOR_FANRPM;
258 	sc->sc_sensor[ADT_TACH4].type = SENSOR_FANRPM;
259 	sc->sc_sensor[ADT_TACH5].type = SENSOR_FANRPM;
260 	sc->sc_sensor[ADT_TACH6].type = SENSOR_FANRPM;
261 
262 	if (sensor_task_register(sc, adt_refresh, 5) == NULL) {
263 		printf(", unable to register update task\n");
264 		return;
265 	}
266 
267 	for (i = 0; i < ADT_NUM_SENSORS; i++) {
268 		if (worklist[i].index >= 32768 &&
269 		    sc->chip->ratio[worklist[i].index - 32768] == 0)
270 			continue;
271 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
272 	}
273 	sensordev_install(&sc->sc_sensordev);
274 
275 
276 	printf("\n");
277 }
278 
279 void
280 adt_refresh(void *arg)
281 {
282 	struct adt_softc *sc = arg;
283 	u_int8_t cmd, data, data2;
284 	u_int16_t fan;
285 	int i, ratio;
286 
287 	iic_acquire_bus(sc->sc_tag, 0);
288 
289 	for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) {
290 
291 		if (worklist[i].index >= 32768) {
292 			ratio = sc->chip->ratio[worklist[i].index - 32768];
293 			if (ratio == 0)	/* do not read a dead register */
294 				continue;
295 		}
296 		cmd = worklist[i].cmd;
297 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
298 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
299 			sc->sc_sensor[i].flags |= SENSOR_FINVALID;
300 			continue;
301 		}
302 
303 		sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
304 		switch (worklist[i].sensor) {
305 		case ADT_VCC:
306 			if (sc->chip->vcc && (sc->sc_conf & ADT7460_CONFIG_Vcc))
307 				ratio = sc->chip->vcc;
308 			/* FALLTHROUGH */
309 		case ADT_2_5V:
310 		case ADT_VCCP:
311 		case ADT_V5:
312 		case ADT_V12:
313 		case ADT_VTR:
314 		case ADT_VBAT:
315 			sc->sc_sensor[i].value = ratio * 1000 * (u_int)data / 192;
316 			break;
317 		case ADT_LOCAL_TEMP:
318 		case ADT_REM1_TEMP:
319 		case ADT_REM2_TEMP:
320 			if (data == 0x80)
321 				sc->sc_sensor[i].flags |= SENSOR_FINVALID;
322 			else
323 				sc->sc_sensor[i].value =
324 				    (int8_t)data * 1000000 + 273150000;
325 			break;
326 		case ADT_TACH1:
327 		case ADT_TACH2:
328 		case ADT_TACH3:
329 		case ADT_TACH4:
330 			cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */
331 			if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
332 			    sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
333 				sc->sc_sensor[i].flags |= SENSOR_FINVALID;
334 				continue;
335 			}
336 
337 			fan = data + (data2 << 8);
338 			if (fan == 0 || fan == 0xffff)
339 				sc->sc_sensor[i].flags |= SENSOR_FINVALID;
340 			else
341 				sc->sc_sensor[i].value = (90000 * 60) / fan;
342 			break;
343 		case ADT_TACH5:
344 		case ADT_TACH6:
345 			if (sc->chip->type != 5027) {
346 				sc->sc_sensor[i].flags |= SENSOR_FINVALID;
347 				break;	/* only 5027 has these fans? */
348 			}
349 			cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */
350 			if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
351 			    sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
352 				sc->sc_sensor[i].flags |= SENSOR_FINVALID;
353 				continue;
354 			}
355 
356 			fan = data + (data2 << 8);
357 			if (fan == 0 || fan == 0xffff)
358 				sc->sc_sensor[i].flags |= SENSOR_FINVALID;
359 			else
360 				sc->sc_sensor[i].value = fan * 60;
361 			break;
362 		default:
363 			sc->sc_sensor[i].flags |= SENSOR_FINVALID;
364 			break;
365 		}
366 	}
367 
368 	iic_release_bus(sc->sc_tag, 0);
369 }
370