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, ®, 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, ®, 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, ®, 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