Line data Source code
1 : /* $OpenBSD: ad741x.c,v 1.14 2008/04/17 19:01:48 deraadt 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 : /* AD741x registers */
27 : #define AD741X_TEMP 0x00
28 : #define AD741X_CONFIG 0x01
29 : #define AD741X_THYST 0x02
30 : #define AD741X_TOTI 0x03
31 : #define AD741X_ADC 0x04
32 : #define AD741X_CONFIG2 0x05
33 :
34 : #define AD741X_CONFMASK 0xe0
35 :
36 : /* Sensors */
37 : #define ADC_TEMP 0
38 : #define ADC_ADC0 1
39 : #define ADC_ADC1 2
40 : #define ADC_ADC2 3
41 : #define ADC_ADC3 4
42 : #define ADC_MAX_SENSORS 5
43 :
44 : struct adc_softc {
45 : struct device sc_dev;
46 : i2c_tag_t sc_tag;
47 : i2c_addr_t sc_addr;
48 : int sc_chip;
49 : u_int8_t sc_config;
50 :
51 : struct ksensor sc_sensor[ADC_MAX_SENSORS];
52 : struct ksensordev sc_sensordev;
53 : };
54 :
55 : int adc_match(struct device *, void *, void *);
56 : void adc_attach(struct device *, struct device *, void *);
57 : void adc_refresh(void *);
58 :
59 : struct cfattach adc_ca = {
60 : sizeof(struct adc_softc), adc_match, adc_attach
61 : };
62 :
63 : struct cfdriver adc_cd = {
64 : NULL, "adc", DV_DULL
65 : };
66 :
67 : int
68 0 : adc_match(struct device *parent, void *match, void *aux)
69 : {
70 0 : struct i2c_attach_args *ia = aux;
71 :
72 0 : if (strcmp(ia->ia_name, "ad7417") == 0 ||
73 0 : strcmp(ia->ia_name, "ad7418") == 0)
74 0 : return (1);
75 0 : return (0);
76 0 : }
77 :
78 : void
79 0 : adc_attach(struct device *parent, struct device *self, void *aux)
80 : {
81 0 : struct adc_softc *sc = (struct adc_softc *)self;
82 0 : struct i2c_attach_args *ia = aux;
83 0 : u_int8_t cmd, data;
84 : int nsens = 0, i;
85 :
86 0 : sc->sc_tag = ia->ia_tag;
87 0 : sc->sc_addr = ia->ia_addr;
88 :
89 0 : printf(": %s", ia->ia_name);
90 :
91 0 : sc->sc_chip = 0;
92 0 : if (strcmp(ia->ia_name, "ad7417") == 0)
93 0 : sc->sc_chip = 7417;
94 0 : if (strcmp(ia->ia_name, "ad7418") == 0)
95 0 : sc->sc_chip = 7418;
96 :
97 0 : if (sc->sc_chip != 0) {
98 0 : cmd = AD741X_CONFIG2;
99 0 : data = 0;
100 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
101 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
102 0 : printf(", config2 reset failed\n");
103 0 : return;
104 : }
105 : }
106 :
107 0 : cmd = AD741X_CONFIG;
108 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
109 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
110 0 : printf(", config reset failed\n");
111 0 : return;
112 : }
113 0 : data &= 0xfe;
114 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
115 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
116 0 : printf(", config reset failed\n");
117 0 : return;
118 : }
119 0 : sc->sc_config = data;
120 :
121 : /* Initialize sensor data. */
122 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
123 : sizeof(sc->sc_sensordev.xname));
124 :
125 0 : sc->sc_sensor[ADC_TEMP].type = SENSOR_TEMP;
126 0 : strlcpy(sc->sc_sensor[ADC_TEMP].desc, "Internal",
127 : sizeof(sc->sc_sensor[ADC_TEMP].desc));
128 : nsens = 1;
129 :
130 0 : if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
131 0 : sc->sc_sensor[ADC_ADC0].type = SENSOR_INTEGER;
132 : nsens++;
133 0 : }
134 0 : if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
135 0 : sc->sc_sensor[ADC_ADC1].type = SENSOR_INTEGER;
136 0 : sc->sc_sensor[ADC_ADC2].type = SENSOR_INTEGER;
137 0 : sc->sc_sensor[ADC_ADC3].type = SENSOR_INTEGER;
138 0 : nsens += 3;
139 0 : }
140 :
141 0 : if (sensor_task_register(sc, adc_refresh, 5) == NULL) {
142 0 : printf(", unable to register update task\n");
143 0 : return;
144 : }
145 :
146 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]);
147 0 : if (sc->sc_chip == 7417 || sc->sc_chip == 7418)
148 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[1]);
149 0 : if (sc->sc_chip == 7417)
150 0 : for (i = 2; i < nsens; i++)
151 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
152 0 : sensordev_install(&sc->sc_sensordev);
153 :
154 0 : printf("\n");
155 0 : }
156 :
157 : void
158 0 : adc_refresh(void *arg)
159 : {
160 0 : struct adc_softc *sc = arg;
161 0 : u_int8_t cmd, reg;
162 0 : u_int16_t data;
163 : int i;
164 :
165 0 : iic_acquire_bus(sc->sc_tag, 0);
166 :
167 0 : reg = (sc->sc_config & AD741X_CONFMASK) | (0 << 5);
168 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
169 0 : sc->sc_addr, &cmd, sizeof cmd, ®, sizeof reg, 0))
170 : goto done;
171 0 : delay(1000);
172 0 : cmd = AD741X_TEMP;
173 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
174 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
175 : goto done;
176 0 : sc->sc_sensor[ADC_TEMP].value = 273150000 +
177 0 : (betoh16(data) >> 6) * 250000;
178 :
179 0 : if (sc->sc_chip == 0)
180 : goto done;
181 :
182 0 : if (sc->sc_chip == 7418) {
183 0 : reg = (reg & AD741X_CONFMASK) | (4 << 5);
184 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
185 0 : sc->sc_addr, &cmd, sizeof cmd, ®, sizeof reg, 0))
186 : goto done;
187 0 : delay(1000);
188 0 : cmd = AD741X_ADC;
189 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
190 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
191 : goto done;
192 0 : sc->sc_sensor[ADC_ADC0].value = betoh16(data) >> 6;
193 0 : goto done;
194 : }
195 :
196 0 : for (i = 0; i < 4; i++) {
197 0 : reg = (reg & AD741X_CONFMASK) | (i << 5);
198 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
199 0 : sc->sc_addr, &cmd, sizeof cmd, ®, sizeof reg, 0))
200 : goto done;
201 0 : delay(1000);
202 0 : cmd = AD741X_ADC;
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 : goto done;
206 0 : sc->sc_sensor[ADC_ADC0 + i].value = betoh16(data) >> 6;
207 : }
208 :
209 : done:
210 0 : iic_release_bus(sc->sc_tag, 0);
211 0 : }
|