ad741x.c revision 1.7
1/*	$OpenBSD: ad741x.c,v 1.7 2006/01/19 17:08:39 grange 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
44struct 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 sensor sc_sensor[ADC_MAX_SENSORS];
52};
53
54int	adc_match(struct device *, void *, void *);
55void	adc_attach(struct device *, struct device *, void *);
56int	adc_check(struct i2c_attach_args *, u_int8_t *, u_int8_t *);
57void	adc_refresh(void *);
58
59struct cfattach adc_ca = {
60	sizeof(struct adc_softc), adc_match, adc_attach
61};
62
63struct cfdriver adc_cd = {
64	NULL, "adc", DV_DULL
65};
66
67int
68adc_match(struct device *parent, void *match, void *aux)
69{
70	struct i2c_attach_args *ia = aux;
71
72	if (strcmp(ia->ia_name, "ad7417") == 0 ||
73	    strcmp(ia->ia_name, "ad7418") == 0)
74		return (1);
75	return (0);
76}
77
78void
79adc_attach(struct device *parent, struct device *self, void *aux)
80{
81	struct adc_softc *sc = (struct adc_softc *)self;
82	struct i2c_attach_args *ia = aux;
83	u_int8_t cmd, data;
84	int nsens = 0, i;
85
86	sc->sc_tag = ia->ia_tag;
87	sc->sc_addr = ia->ia_addr;
88
89	printf(": %s", ia->ia_name);
90
91	sc->sc_chip = 0;
92	if (strcmp(ia->ia_name, "ad7417") == 0)
93		sc->sc_chip = 7417;
94	if (strcmp(ia->ia_name, "ad7418") == 0)
95		sc->sc_chip = 7418;
96
97	if (sc->sc_chip != 0) {
98		cmd = AD741X_CONFIG2;
99		data = 0;
100		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
101		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
102			printf(", config2 reset failed\n");
103			return;
104		}
105	}
106
107	cmd = AD741X_CONFIG;
108	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
109	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
110		printf(", config reset failed\n");
111		return;
112	}
113	data &= 0xfe;
114	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
115	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
116		printf(", config reset failed\n");
117		return;
118	}
119	sc->sc_config = data;
120
121	/* Initialize sensor data. */
122	for (i = 0; i < ADC_MAX_SENSORS; i++)
123		strlcpy(sc->sc_sensor[i].device, sc->sc_dev.dv_xname,
124		    sizeof(sc->sc_sensor[i].device));
125
126	sc->sc_sensor[ADC_TEMP].type = SENSOR_TEMP;
127	strlcpy(sc->sc_sensor[ADC_TEMP].desc, "Internal",
128	    sizeof(sc->sc_sensor[ADC_TEMP].desc));
129	nsens = 1;
130
131	if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
132		sc->sc_sensor[ADC_ADC0].type = SENSOR_INTEGER;
133		strlcpy(sc->sc_sensor[ADC_ADC0].desc, "adc0",
134		    sizeof(sc->sc_sensor[ADC_ADC0].desc));
135		nsens++;
136	}
137	if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
138		sc->sc_sensor[ADC_ADC1].type = SENSOR_INTEGER;
139		strlcpy(sc->sc_sensor[ADC_ADC1].desc, "adc1",
140		    sizeof(sc->sc_sensor[ADC_ADC1].desc));
141		sc->sc_sensor[ADC_ADC2].type = SENSOR_INTEGER;
142		strlcpy(sc->sc_sensor[ADC_ADC2].desc, "adc2",
143		    sizeof(sc->sc_sensor[ADC_ADC2].desc));
144		sc->sc_sensor[ADC_ADC3].type = SENSOR_INTEGER;
145		strlcpy(sc->sc_sensor[ADC_ADC3].desc, "adc3",
146		    sizeof(sc->sc_sensor[ADC_ADC3].desc));
147		nsens += 3;
148	}
149
150	if (sensor_task_register(sc, adc_refresh, 5)) {
151		printf(", unable to register update task\n");
152		return;
153	}
154
155	sensor_add(&sc->sc_sensor[0]);
156	if (sc->sc_chip == 7417 || sc->sc_chip == 7418)
157		sensor_add(&sc->sc_sensor[1]);
158	if (sc->sc_chip == 7417)
159		for (i = 2; i < nsens; i++)
160			sensor_add(&sc->sc_sensor[i]);
161
162	printf("\n");
163}
164
165void	adc_readport(struct adc_softc *, u_int8_t, u_int8_t, int);
166
167void
168adc_refresh(void *arg)
169{
170	struct adc_softc *sc = arg;
171	u_int8_t cmd, data[2], reg;
172	int i;
173
174	iic_acquire_bus(sc->sc_tag, 0);
175
176	reg = (sc->sc_config & AD741X_CONFMASK) | (0 << 5);
177	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
178	    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
179		goto done;
180	delay(1000);
181	cmd = AD741X_TEMP;
182	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
183	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
184		goto done;
185	sc->sc_sensor[ADC_TEMP].value = 273150000 +
186	    ((data[0] << 8 | data[1]) >> 6) * 250000;
187
188	if (sc->sc_chip == 0)
189		goto done;
190
191	if (sc->sc_chip == 7418) {
192		reg = (reg & AD741X_CONFMASK) | (4 << 5);
193		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
194		    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
195			goto done;
196		delay(1000);
197		cmd = AD741X_ADC;
198		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
199		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
200			goto done;
201		sc->sc_sensor[ADC_ADC0].value =
202		    (data[0] << 8 | data[1]) >> 6;
203		goto done;
204	}
205
206	for (i = 0; i < 4; i++) {
207		reg = (reg & AD741X_CONFMASK) | (i << 5);
208		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
209		    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
210			goto done;
211		delay(1000);
212		cmd = AD741X_ADC;
213		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
214		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
215			goto done;
216		sc->sc_sensor[ADC_ADC0 + i].value =
217		    (data[0] << 8 | data[1]) >> 6;
218	}
219
220done:
221	iic_release_bus(sc->sc_tag, 0);
222}
223