xref: /openbsd/sys/dev/i2c/adt7462.c (revision e5dd7070)
1 /*	$OpenBSD: adt7462.c,v 1.6 2008/04/23 11:11:14 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 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 #define ADT7462_TEMPL		0x88
27 #define ADT7462_TEMPH		0x89
28 #define ADT7462_TEMP1L		0x8a
29 #define ADT7462_TEMP1H		0x8b
30 #define ADT7462_TEMP2L		0x8c
31 #define ADT7462_TEMP2H		0x8d
32 #define ADT7462_TEMP3L		0x8e
33 #define ADT7462_TEMP3H		0x8f
34 #define ADT7262_TACH1L		0x98
35 #define ADT7262_TACH1H		0x99
36 #define ADT7262_TACH2L		0x9a
37 #define ADT7262_TACH2H		0x9b
38 #define ADT7262_TACH3L		0x9c
39 #define ADT7262_TACH3H		0x9d
40 #define ADT7262_TACH4L		0x9e
41 #define ADT7262_TACH4H		0x9f
42 #define ADT7262_TACH5L		0xa2
43 #define ADT7262_TACH5H		0xa3
44 #define ADT7262_TACH6L		0xa4
45 #define ADT7262_TACH6H		0xa5
46 #define ADT7262_TACH7L		0xa6
47 #define ADT7262_TACH7H		0xa7
48 #define ADT7262_TACH8L		0xa8
49 #define ADT7262_TACH8H		0xa9
50 
51 /* Sensors */
52 #define ADTFSM_TEMP0		0
53 #define ADTFSM_TEMP1		1
54 #define ADTFSM_TEMP2		2
55 #define ADTFSM_TEMP3		3
56 #define ADTFSM_TACH1		4
57 #define ADTFSM_TACH2		5
58 #define ADTFSM_TACH3		6
59 #define ADTFSM_TACH4		7
60 #define ADTFSM_TACH5		8
61 #define ADTFSM_TACH6		9
62 #define ADTFSM_TACH7		10
63 #define ADTFSM_TACH8		11
64 #define ADTFSM_NUM_SENSORS	12
65 
66 struct adtfsm_softc {
67 	struct device	sc_dev;
68 	i2c_tag_t	sc_tag;
69 	i2c_addr_t	sc_addr;
70 	int		sc_fanmul;
71 
72 	struct ksensor	sc_sensor[ADTFSM_NUM_SENSORS];
73 	struct ksensordev sc_sensordev;
74 };
75 
76 int	adtfsm_match(struct device *, void *, void *);
77 void	adtfsm_attach(struct device *, struct device *, void *);
78 void	adtfsm_refresh(void *);
79 
80 struct cfattach adtfsm_ca = {
81 	sizeof(struct adtfsm_softc), adtfsm_match, adtfsm_attach
82 };
83 
84 struct cfdriver adtfsm_cd = {
85 	NULL, "adtfsm", DV_DULL
86 };
87 
88 int
89 adtfsm_match(struct device *parent, void *match, void *aux)
90 {
91 	struct i2c_attach_args *ia = aux;
92 
93 	if (strcmp(ia->ia_name, "adt7462") == 0)
94 		return (1);
95 	return (0);
96 }
97 
98 void
99 adtfsm_attach(struct device *parent, struct device *self, void *aux)
100 {
101 	struct adtfsm_softc *sc = (struct adtfsm_softc *)self;
102 	struct i2c_attach_args *ia = aux;
103 	int i;
104 
105 	sc->sc_tag = ia->ia_tag;
106 	sc->sc_addr = ia->ia_addr;
107 
108 	/* Initialize sensor data. */
109 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
110 	    sizeof(sc->sc_sensordev.xname));
111 
112 	for (i = ADTFSM_TEMP0; i <= ADTFSM_TEMP3; i++) {
113 		sc->sc_sensor[i].type = SENSOR_TEMP;
114 		sc->sc_sensor[i].flags |= SENSOR_FINVALID;
115 	}
116 
117 	strlcpy(sc->sc_sensor[0].desc, "Internal",
118 	    sizeof(sc->sc_sensor[0].desc));
119 	for (i = 1; i < 4; i++)
120 		strlcpy(sc->sc_sensor[i].desc, "External",
121 		    sizeof(sc->sc_sensor[i].desc));
122 
123 	for (i = ADTFSM_TACH1; i <= ADTFSM_TACH8; i++) {
124 		sc->sc_sensor[i].type = SENSOR_FANRPM;
125 		sc->sc_sensor[i].flags |= SENSOR_FINVALID;
126 	}
127 
128 	if (sensor_task_register(sc, adtfsm_refresh, 5) == NULL) {
129 		printf(", unable to register update task\n");
130 		return;
131 	}
132 
133 	for (i = 0; i < ADTFSM_NUM_SENSORS; i++)
134 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
135 	sensordev_install(&sc->sc_sensordev);
136 
137 	printf("\n");
138 }
139 
140 void
141 adtfsm_refresh(void *arg)
142 {
143 	struct adtfsm_softc *sc = arg;
144 	u_int8_t cmdh, cmdl, datah = 0x01, datal = 0x02;
145 	struct ksensor *ks;
146 	u_short ut;
147 	short t;
148 	int i;
149 
150 	iic_acquire_bus(sc->sc_tag, 0);
151 
152 	for (i = 0; i <= ADTFSM_TEMP3 - ADTFSM_TEMP0; i++) {
153 		cmdl = ADT7462_TEMPL + i * 2;
154 		cmdh = ADT7462_TEMPH + i * 2;
155 		ks = &sc->sc_sensor[ADTFSM_TEMP0 + i];
156 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
157 		    sc->sc_addr, &cmdl, sizeof cmdl, &datal,
158 		    sizeof datal, 0) == 0 &&
159 		    iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
160 		    sc->sc_addr, &cmdh, sizeof cmdh, &datah,
161 		    sizeof datah, 0) == 0) {
162 			t = (((datah << 8) | datal) >> 6) - (64 << 2);
163 			ks->value = 273150000 + t * 250000;
164 			ks->flags &= ~SENSOR_FINVALID;
165 		} else
166 			ks->flags |= SENSOR_FINVALID;
167 	}
168 
169 	for (i = 0; i <= ADTFSM_TACH8 - ADTFSM_TACH1; i++) {
170 		cmdl = ADT7262_TACH1L + i * 2;
171 		cmdh = ADT7262_TACH1H + i * 2;
172 		ks = &sc->sc_sensor[ADTFSM_TACH1 + i];
173 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
174 		    sc->sc_addr, &cmdl, sizeof cmdl, &datal,
175 		    sizeof datal, 0) == 0 &&
176 		    iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
177 		    sc->sc_addr, &cmdh, sizeof cmdh, &datah,
178 		    sizeof datah, 0) == 0) {
179 			ut = ((datah << 8) | datal);
180 			if (ut == 0x0000 || ut == 0xffff)
181 				ks->flags |= SENSOR_FINVALID;
182 			else {
183 				ks->value = 90000 * 60 / ut;
184 				ks->flags &= ~SENSOR_FINVALID;
185 			}
186 		} else
187 			ks->flags |= SENSOR_FINVALID;
188 	}
189 
190 	iic_release_bus(sc->sc_tag, 0);
191 }
192