xref: /openbsd/sys/dev/i2c/ad741x.c (revision 471aeecf)
1 /*	$OpenBSD: ad741x.c,v 1.15 2022/04/06 18:59:28 naddy 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 const 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
adc_match(struct device * parent,void * match,void * aux)68 adc_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 
78 void
adc_attach(struct device * parent,struct device * self,void * aux)79 adc_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 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
123 	    sizeof(sc->sc_sensordev.xname));
124 
125 	sc->sc_sensor[ADC_TEMP].type = SENSOR_TEMP;
126 	strlcpy(sc->sc_sensor[ADC_TEMP].desc, "Internal",
127 	    sizeof(sc->sc_sensor[ADC_TEMP].desc));
128 	nsens = 1;
129 
130 	if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
131 		sc->sc_sensor[ADC_ADC0].type = SENSOR_INTEGER;
132 		nsens++;
133 	}
134 	if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
135 		sc->sc_sensor[ADC_ADC1].type = SENSOR_INTEGER;
136 		sc->sc_sensor[ADC_ADC2].type = SENSOR_INTEGER;
137 		sc->sc_sensor[ADC_ADC3].type = SENSOR_INTEGER;
138 		nsens += 3;
139 	}
140 
141 	if (sensor_task_register(sc, adc_refresh, 5) == NULL) {
142 		printf(", unable to register update task\n");
143 		return;
144 	}
145 
146 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]);
147 	if (sc->sc_chip == 7417 || sc->sc_chip == 7418)
148 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[1]);
149 	if (sc->sc_chip == 7417)
150 		for (i = 2; i < nsens; i++)
151 			sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
152 	sensordev_install(&sc->sc_sensordev);
153 
154 	printf("\n");
155 }
156 
157 void
adc_refresh(void * arg)158 adc_refresh(void *arg)
159 {
160 	struct adc_softc *sc = arg;
161 	u_int8_t cmd, reg;
162 	u_int16_t data;
163 	int i;
164 
165 	iic_acquire_bus(sc->sc_tag, 0);
166 
167 	reg = (sc->sc_config & AD741X_CONFMASK) | (0 << 5);
168 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
169 	    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
170 		goto done;
171 	delay(1000);
172 	cmd = AD741X_TEMP;
173 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
174 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
175 		goto done;
176 	sc->sc_sensor[ADC_TEMP].value = 273150000 +
177 	    (betoh16(data) >> 6) * 250000;
178 
179 	if (sc->sc_chip == 0)
180 		goto done;
181 
182 	if (sc->sc_chip == 7418) {
183 		reg = (reg & AD741X_CONFMASK) | (4 << 5);
184 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
185 		    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
186 			goto done;
187 		delay(1000);
188 		cmd = AD741X_ADC;
189 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
190 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
191 			goto done;
192 		sc->sc_sensor[ADC_ADC0].value = betoh16(data) >> 6;
193 		goto done;
194 	}
195 
196 	for (i = 0; i < 4; i++) {
197 		reg = (reg & AD741X_CONFMASK) | (i << 5);
198 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
199 		    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
200 			goto done;
201 		delay(1000);
202 		cmd = AD741X_ADC;
203 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
204 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
205 			goto done;
206 		sc->sc_sensor[ADC_ADC0 + i].value = betoh16(data) >> 6;
207 	}
208 
209 done:
210 	iic_release_bus(sc->sc_tag, 0);
211 }
212