xref: /openbsd/sys/dev/i2c/ad741x.c (revision 471aeecf)
1*471aeecfSnaddy /*	$OpenBSD: ad741x.c,v 1.15 2022/04/06 18:59:28 naddy Exp $	*/
2afa48fb4Sderaadt 
3afa48fb4Sderaadt /*
4afa48fb4Sderaadt  * Copyright (c) 2005 Theo de Raadt
5afa48fb4Sderaadt  *
6afa48fb4Sderaadt  * Permission to use, copy, modify, and distribute this software for any
7afa48fb4Sderaadt  * purpose with or without fee is hereby granted, provided that the above
8afa48fb4Sderaadt  * copyright notice and this permission notice appear in all copies.
9afa48fb4Sderaadt  *
10afa48fb4Sderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11afa48fb4Sderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12afa48fb4Sderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13afa48fb4Sderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14afa48fb4Sderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15afa48fb4Sderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16afa48fb4Sderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17afa48fb4Sderaadt  */
18afa48fb4Sderaadt 
19afa48fb4Sderaadt #include <sys/param.h>
20afa48fb4Sderaadt #include <sys/systm.h>
21afa48fb4Sderaadt #include <sys/device.h>
22afa48fb4Sderaadt #include <sys/sensors.h>
23afa48fb4Sderaadt 
24afa48fb4Sderaadt #include <dev/i2c/i2cvar.h>
25afa48fb4Sderaadt 
26afa48fb4Sderaadt /* AD741x registers */
27afa48fb4Sderaadt #define AD741X_TEMP	0x00
28afa48fb4Sderaadt #define AD741X_CONFIG	0x01
29afa48fb4Sderaadt #define AD741X_THYST	0x02
30afa48fb4Sderaadt #define AD741X_TOTI	0x03
31afa48fb4Sderaadt #define AD741X_ADC	0x04
32afa48fb4Sderaadt #define AD741X_CONFIG2	0x05
33afa48fb4Sderaadt 
34afa48fb4Sderaadt #define AD741X_CONFMASK	0xe0
35afa48fb4Sderaadt 
36afa48fb4Sderaadt /* Sensors */
37afa48fb4Sderaadt #define ADC_TEMP		0
38afa48fb4Sderaadt #define ADC_ADC0		1
39afa48fb4Sderaadt #define ADC_ADC1		2
40afa48fb4Sderaadt #define ADC_ADC2		3
41afa48fb4Sderaadt #define ADC_ADC3		4
4280cc87b2Sderaadt #define ADC_MAX_SENSORS		5
43afa48fb4Sderaadt 
44afa48fb4Sderaadt struct adc_softc {
45afa48fb4Sderaadt 	struct device	sc_dev;
46afa48fb4Sderaadt 	i2c_tag_t	sc_tag;
47afa48fb4Sderaadt 	i2c_addr_t	sc_addr;
489eb37912Sderaadt 	int		sc_chip;
499eb37912Sderaadt 	u_int8_t	sc_config;
50afa48fb4Sderaadt 
51275cbf62Sderaadt 	struct ksensor sc_sensor[ADC_MAX_SENSORS];
52275cbf62Sderaadt 	struct ksensordev sc_sensordev;
53afa48fb4Sderaadt };
54afa48fb4Sderaadt 
55afa48fb4Sderaadt int	adc_match(struct device *, void *, void *);
56afa48fb4Sderaadt void	adc_attach(struct device *, struct device *, void *);
57afa48fb4Sderaadt void	adc_refresh(void *);
58afa48fb4Sderaadt 
59*471aeecfSnaddy const struct cfattach adc_ca = {
60afa48fb4Sderaadt 	sizeof(struct adc_softc), adc_match, adc_attach
61afa48fb4Sderaadt };
62afa48fb4Sderaadt 
63afa48fb4Sderaadt struct cfdriver adc_cd = {
64afa48fb4Sderaadt 	NULL, "adc", DV_DULL
65afa48fb4Sderaadt };
66afa48fb4Sderaadt 
67afa48fb4Sderaadt int
adc_match(struct device * parent,void * match,void * aux)68afa48fb4Sderaadt adc_match(struct device *parent, void *match, void *aux)
69afa48fb4Sderaadt {
70afa48fb4Sderaadt 	struct i2c_attach_args *ia = aux;
71afa48fb4Sderaadt 
729b06f7aeSderaadt 	if (strcmp(ia->ia_name, "ad7417") == 0 ||
7393e28638Sderaadt 	    strcmp(ia->ia_name, "ad7418") == 0)
74afa48fb4Sderaadt 		return (1);
75afa48fb4Sderaadt 	return (0);
76afa48fb4Sderaadt }
77afa48fb4Sderaadt 
78afa48fb4Sderaadt void
adc_attach(struct device * parent,struct device * self,void * aux)79afa48fb4Sderaadt adc_attach(struct device *parent, struct device *self, void *aux)
80afa48fb4Sderaadt {
81afa48fb4Sderaadt 	struct adc_softc *sc = (struct adc_softc *)self;
82afa48fb4Sderaadt 	struct i2c_attach_args *ia = aux;
83afa48fb4Sderaadt 	u_int8_t cmd, data;
849eb37912Sderaadt 	int nsens = 0, i;
85afa48fb4Sderaadt 
86afa48fb4Sderaadt 	sc->sc_tag = ia->ia_tag;
87afa48fb4Sderaadt 	sc->sc_addr = ia->ia_addr;
88afa48fb4Sderaadt 
899b06f7aeSderaadt 	printf(": %s", ia->ia_name);
909b06f7aeSderaadt 
919eb37912Sderaadt 	sc->sc_chip = 0;
929b06f7aeSderaadt 	if (strcmp(ia->ia_name, "ad7417") == 0)
939eb37912Sderaadt 		sc->sc_chip = 7417;
949b06f7aeSderaadt 	if (strcmp(ia->ia_name, "ad7418") == 0)
959eb37912Sderaadt 		sc->sc_chip = 7418;
9680cc87b2Sderaadt 
979eb37912Sderaadt 	if (sc->sc_chip != 0) {
98afa48fb4Sderaadt 		cmd = AD741X_CONFIG2;
99afa48fb4Sderaadt 		data = 0;
100afa48fb4Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
101afa48fb4Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
102afa48fb4Sderaadt 			printf(", config2 reset failed\n");
103afa48fb4Sderaadt 			return;
104afa48fb4Sderaadt 		}
10580cc87b2Sderaadt 	}
106afa48fb4Sderaadt 
1079eb37912Sderaadt 	cmd = AD741X_CONFIG;
1089eb37912Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
1099eb37912Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
1109eb37912Sderaadt 		printf(", config reset failed\n");
1119eb37912Sderaadt 		return;
1129eb37912Sderaadt 	}
1139eb37912Sderaadt 	data &= 0xfe;
1149eb37912Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
1159eb37912Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
1169eb37912Sderaadt 		printf(", config reset failed\n");
1179eb37912Sderaadt 		return;
1189eb37912Sderaadt 	}
1199eb37912Sderaadt 	sc->sc_config = data;
1209eb37912Sderaadt 
121afa48fb4Sderaadt 	/* Initialize sensor data. */
12227515a6bSderaadt 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
12327515a6bSderaadt 	    sizeof(sc->sc_sensordev.xname));
124afa48fb4Sderaadt 
125afa48fb4Sderaadt 	sc->sc_sensor[ADC_TEMP].type = SENSOR_TEMP;
12627515a6bSderaadt 	strlcpy(sc->sc_sensor[ADC_TEMP].desc, "Internal",
127afa48fb4Sderaadt 	    sizeof(sc->sc_sensor[ADC_TEMP].desc));
1289eb37912Sderaadt 	nsens = 1;
129afa48fb4Sderaadt 
1309eb37912Sderaadt 	if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
131afa48fb4Sderaadt 		sc->sc_sensor[ADC_ADC0].type = SENSOR_INTEGER;
1329eb37912Sderaadt 		nsens++;
1339eb37912Sderaadt 	}
1349eb37912Sderaadt 	if (sc->sc_chip == 7417 || sc->sc_chip == 7418) {
135afa48fb4Sderaadt 		sc->sc_sensor[ADC_ADC1].type = SENSOR_INTEGER;
136afa48fb4Sderaadt 		sc->sc_sensor[ADC_ADC2].type = SENSOR_INTEGER;
137afa48fb4Sderaadt 		sc->sc_sensor[ADC_ADC3].type = SENSOR_INTEGER;
1389eb37912Sderaadt 		nsens += 3;
13980cc87b2Sderaadt 	}
140afa48fb4Sderaadt 
141abd9fc28Sdlg 	if (sensor_task_register(sc, adc_refresh, 5) == NULL) {
142afa48fb4Sderaadt 		printf(", unable to register update task\n");
143afa48fb4Sderaadt 		return;
144afa48fb4Sderaadt 	}
145afa48fb4Sderaadt 
14627515a6bSderaadt 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]);
1479eb37912Sderaadt 	if (sc->sc_chip == 7417 || sc->sc_chip == 7418)
14827515a6bSderaadt 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[1]);
1499eb37912Sderaadt 	if (sc->sc_chip == 7417)
1509eb37912Sderaadt 		for (i = 2; i < nsens; i++)
15127515a6bSderaadt 			sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
15227515a6bSderaadt 	sensordev_install(&sc->sc_sensordev);
153afa48fb4Sderaadt 
154afa48fb4Sderaadt 	printf("\n");
155afa48fb4Sderaadt }
156afa48fb4Sderaadt 
157afa48fb4Sderaadt void
adc_refresh(void * arg)158afa48fb4Sderaadt adc_refresh(void *arg)
159afa48fb4Sderaadt {
160afa48fb4Sderaadt 	struct adc_softc *sc = arg;
16191eacc75Sderaadt 	u_int8_t cmd, reg;
16291eacc75Sderaadt 	u_int16_t data;
163afa48fb4Sderaadt 	int i;
164afa48fb4Sderaadt 
165afa48fb4Sderaadt 	iic_acquire_bus(sc->sc_tag, 0);
166afa48fb4Sderaadt 
1679eb37912Sderaadt 	reg = (sc->sc_config & AD741X_CONFMASK) | (0 << 5);
168afa48fb4Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
169afa48fb4Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
17080cc87b2Sderaadt 		goto done;
1719eb37912Sderaadt 	delay(1000);
172afa48fb4Sderaadt 	cmd = AD741X_TEMP;
173afa48fb4Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
174afa48fb4Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
17580cc87b2Sderaadt 		goto done;
176afa48fb4Sderaadt 	sc->sc_sensor[ADC_TEMP].value = 273150000 +
17791eacc75Sderaadt 	    (betoh16(data) >> 6) * 250000;
178afa48fb4Sderaadt 
1799eb37912Sderaadt 	if (sc->sc_chip == 0)
18080cc87b2Sderaadt 		goto done;
18180cc87b2Sderaadt 
1829eb37912Sderaadt 	if (sc->sc_chip == 7418) {
1839eb37912Sderaadt 		reg = (reg & AD741X_CONFMASK) | (4 << 5);
1849eb37912Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
1859eb37912Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
1869eb37912Sderaadt 			goto done;
1879eb37912Sderaadt 		delay(1000);
1889eb37912Sderaadt 		cmd = AD741X_ADC;
1899eb37912Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
1909eb37912Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
1919eb37912Sderaadt 			goto done;
19291eacc75Sderaadt 		sc->sc_sensor[ADC_ADC0].value = betoh16(data) >> 6;
1939eb37912Sderaadt 		goto done;
1949eb37912Sderaadt 	}
1959eb37912Sderaadt 
196afa48fb4Sderaadt 	for (i = 0; i < 4; i++) {
197afa48fb4Sderaadt 		reg = (reg & AD741X_CONFMASK) | (i << 5);
198afa48fb4Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
199afa48fb4Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &reg, sizeof reg, 0))
20080cc87b2Sderaadt 			goto done;
2019eb37912Sderaadt 		delay(1000);
202afa48fb4Sderaadt 		cmd = AD741X_ADC;
203afa48fb4Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
204afa48fb4Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0))
20580cc87b2Sderaadt 			goto done;
20691eacc75Sderaadt 		sc->sc_sensor[ADC_ADC0 + i].value = betoh16(data) >> 6;
207afa48fb4Sderaadt 	}
208afa48fb4Sderaadt 
20980cc87b2Sderaadt done:
210afa48fb4Sderaadt 	iic_release_bus(sc->sc_tag, 0);
211afa48fb4Sderaadt }
212