xref: /openbsd-src/sys/dev/i2c/adm1024.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /*	$OpenBSD: adm1024.c,v 1.15 2022/04/06 18:59:28 naddy Exp $	*/
2ce60c93dSderaadt 
3ce60c93dSderaadt /*
4ce60c93dSderaadt  * Copyright (c) 2005 Theo de Raadt
5ce60c93dSderaadt  *
6ce60c93dSderaadt  * Permission to use, copy, modify, and distribute this software for any
7ce60c93dSderaadt  * purpose with or without fee is hereby granted, provided that the above
8ce60c93dSderaadt  * copyright notice and this permission notice appear in all copies.
9ce60c93dSderaadt  *
10ce60c93dSderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ce60c93dSderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ce60c93dSderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ce60c93dSderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ce60c93dSderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ce60c93dSderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ce60c93dSderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ce60c93dSderaadt  */
18ce60c93dSderaadt 
19ce60c93dSderaadt #include <sys/param.h>
20ce60c93dSderaadt #include <sys/systm.h>
21ce60c93dSderaadt #include <sys/device.h>
22ce60c93dSderaadt #include <sys/sensors.h>
23ce60c93dSderaadt 
24ce60c93dSderaadt #include <dev/i2c/i2cvar.h>
25ce60c93dSderaadt 
26ce60c93dSderaadt /* ADM 1024 registers */
274c619377Sderaadt #define ADM1024_V2_5		0x20
28ce60c93dSderaadt #define ADM1024_Vccp		0x21
29ce60c93dSderaadt #define ADM1024_Vcc		0x22
30ce60c93dSderaadt #define ADM1024_V5		0x23
31ce60c93dSderaadt #define ADM1024_V12		0x24
32ce60c93dSderaadt #define ADM1024_Vccp2		0x25
33ce60c93dSderaadt #define ADM1024_EXT_TEMP	0x26
34ce60c93dSderaadt #define ADM1024_INT_TEMP	0x27
35ce60c93dSderaadt #define ADM1024_FAN1		0x28
3613ed3fa2Sderaadt #define ADM1024_FAN2		0x29
37ce60c93dSderaadt #define ADM1024_STATUS2		0x42
3857bb1d2cSderaadt #define ADM1024_FANC		0x47
39ce60c93dSderaadt #define  ADM1024_STATUS2_EXT	0x40
40ce60c93dSderaadt #define ADM1024_COMPANY		0x3e	/* contains 0x41 */
41ce60c93dSderaadt #define ADM1024_STEPPING	0x3f	/* contains 0x2? */
426f8acdcfSderaadt #define ADM1024_CONFIG1		0x40
436f8acdcfSderaadt #define  ADM1024_CONFIG1_START	0x01
44916c07c4Sderaadt #define  ADM1024_CONFIG1_INTCLR	0x08
45ce60c93dSderaadt 
46ce60c93dSderaadt /* Sensors */
47ce60c93dSderaadt #define ADMLC_INT		0
48ce60c93dSderaadt #define ADMLC_EXT		1
494c619377Sderaadt #define ADMLC_V2_5		2
50ce60c93dSderaadt #define ADMLC_Vccp		3
51ce60c93dSderaadt #define ADMLC_Vcc		4
52ce60c93dSderaadt #define ADMLC_V5		5
53ce60c93dSderaadt #define ADMLC_V12		6
54ce60c93dSderaadt #define ADMLC_Vccp2		7
55ce60c93dSderaadt #define ADMLC_FAN1		8
56ce60c93dSderaadt #define ADMLC_FAN2		9
57ce60c93dSderaadt #define ADMLC_NUM_SENSORS	10
58ce60c93dSderaadt 
59ce60c93dSderaadt struct admlc_softc {
60ce60c93dSderaadt 	struct device	sc_dev;
61ce60c93dSderaadt 	i2c_tag_t	sc_tag;
62ce60c93dSderaadt 	i2c_addr_t	sc_addr;
63ce60c93dSderaadt 
64275cbf62Sderaadt 	struct ksensor	sc_sensor[ADMLC_NUM_SENSORS];
65275cbf62Sderaadt 	struct ksensordev sc_sensordev;
6657bb1d2cSderaadt 	int		sc_fan1mul;
6757bb1d2cSderaadt 	int		sc_fan2mul;
68ce60c93dSderaadt };
69ce60c93dSderaadt 
70ce60c93dSderaadt int	admlc_match(struct device *, void *, void *);
71ce60c93dSderaadt void	admlc_attach(struct device *, struct device *, void *);
72ce60c93dSderaadt void	admlc_refresh(void *);
73ce60c93dSderaadt 
74*471aeecfSnaddy const struct cfattach admlc_ca = {
75ce60c93dSderaadt 	sizeof(struct admlc_softc), admlc_match, admlc_attach
76ce60c93dSderaadt };
77ce60c93dSderaadt 
78ce60c93dSderaadt struct cfdriver admlc_cd = {
79ce60c93dSderaadt 	NULL, "admlc", DV_DULL
80ce60c93dSderaadt };
81ce60c93dSderaadt 
82ce60c93dSderaadt int
admlc_match(struct device * parent,void * match,void * aux)83ce60c93dSderaadt admlc_match(struct device *parent, void *match, void *aux)
84ce60c93dSderaadt {
85ce60c93dSderaadt 	struct i2c_attach_args *ia = aux;
86ce60c93dSderaadt 
87ce60c93dSderaadt 	if (strcmp(ia->ia_name, "adm1024") == 0)
88ce60c93dSderaadt 		return (1);
89ce60c93dSderaadt 	return (0);
90ce60c93dSderaadt }
91ce60c93dSderaadt 
92ce60c93dSderaadt void
admlc_attach(struct device * parent,struct device * self,void * aux)93ce60c93dSderaadt admlc_attach(struct device *parent, struct device *self, void *aux)
94ce60c93dSderaadt {
95ce60c93dSderaadt 	struct admlc_softc *sc = (struct admlc_softc *)self;
96ce60c93dSderaadt 	struct i2c_attach_args *ia = aux;
97916c07c4Sderaadt 	u_int8_t cmd, data, data2;
98ce60c93dSderaadt 	int i;
99ce60c93dSderaadt 
100ce60c93dSderaadt 	sc->sc_tag = ia->ia_tag;
101ce60c93dSderaadt 	sc->sc_addr = ia->ia_addr;
102ce60c93dSderaadt 
103ce60c93dSderaadt 	iic_acquire_bus(sc->sc_tag, 0);
1046f8acdcfSderaadt 	cmd = ADM1024_CONFIG1;
105ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
106b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
107ce60c93dSderaadt 		iic_release_bus(sc->sc_tag, 0);
108ce60c93dSderaadt 		printf(": cannot get control register\n");
109ce60c93dSderaadt 		return;
110ce60c93dSderaadt 	}
111916c07c4Sderaadt 	data2 = data | ADM1024_CONFIG1_START;
112916c07c4Sderaadt 	data2 = data2 & ~ADM1024_CONFIG1_INTCLR;
113916c07c4Sderaadt 	if (data != data2) {
114ce60c93dSderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
115b8631cf2Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
116ce60c93dSderaadt 			iic_release_bus(sc->sc_tag, 0);
117ce60c93dSderaadt 			printf(": cannot set control register\n");
118ce60c93dSderaadt 			return;
119ce60c93dSderaadt 		}
120ce60c93dSderaadt 	}
12157bb1d2cSderaadt 
12257bb1d2cSderaadt 	cmd = ADM1024_FANC;
12357bb1d2cSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
12457bb1d2cSderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
12557bb1d2cSderaadt 		printf(", unable to read fan setting\n");
12657bb1d2cSderaadt 		return;
12757bb1d2cSderaadt 	}
1288bd65a67Sderaadt 	sc->sc_fan1mul = (1 << (data >> 4) & 0x3);
1298bd65a67Sderaadt 	sc->sc_fan2mul = (1 << (data >> 6) & 0x3);
13057bb1d2cSderaadt 
131ce60c93dSderaadt 	iic_release_bus(sc->sc_tag, 0);
132ce60c93dSderaadt 
133ce60c93dSderaadt 	/* Initialize sensor data. */
13427515a6bSderaadt 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
13527515a6bSderaadt 	    sizeof(sc->sc_sensordev.xname));
136ce60c93dSderaadt 
137ce60c93dSderaadt 	sc->sc_sensor[ADMLC_INT].type = SENSOR_TEMP;
13827515a6bSderaadt 	strlcpy(sc->sc_sensor[ADMLC_INT].desc, "Internal",
139ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_INT].desc));
140ce60c93dSderaadt 
141ce60c93dSderaadt 	sc->sc_sensor[ADMLC_EXT].type = SENSOR_TEMP;
14227515a6bSderaadt 	strlcpy(sc->sc_sensor[ADMLC_EXT].desc, "External",
143ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_EXT].desc));
144ce60c93dSderaadt 
1454c619377Sderaadt 	sc->sc_sensor[ADMLC_V2_5].type = SENSOR_VOLTS_DC;
1464c619377Sderaadt 	strlcpy(sc->sc_sensor[ADMLC_V2_5].desc, "2.5 V",
1474c619377Sderaadt 	    sizeof(sc->sc_sensor[ADMLC_V2_5].desc));
148ce60c93dSderaadt 
149ce60c93dSderaadt 	sc->sc_sensor[ADMLC_Vccp].type = SENSOR_VOLTS_DC;
150ce60c93dSderaadt 	strlcpy(sc->sc_sensor[ADMLC_Vccp].desc, "Vccp",
151ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_Vccp].desc));
152ce60c93dSderaadt 
153ce60c93dSderaadt 	sc->sc_sensor[ADMLC_Vcc].type = SENSOR_VOLTS_DC;
154ce60c93dSderaadt 	strlcpy(sc->sc_sensor[ADMLC_Vcc].desc, "Vcc",
155ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_Vcc].desc));
156ce60c93dSderaadt 
157ce60c93dSderaadt 	sc->sc_sensor[ADMLC_V5].type = SENSOR_VOLTS_DC;
158ce60c93dSderaadt 	strlcpy(sc->sc_sensor[ADMLC_V5].desc, "5 V",
159ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_V5].desc));
160ce60c93dSderaadt 
161ce60c93dSderaadt 	sc->sc_sensor[ADMLC_V12].type = SENSOR_VOLTS_DC;
162ce60c93dSderaadt 	strlcpy(sc->sc_sensor[ADMLC_V12].desc, "12 V",
163ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_V12].desc));
164ce60c93dSderaadt 
165ce60c93dSderaadt 	sc->sc_sensor[ADMLC_Vccp2].type = SENSOR_VOLTS_DC;
166ce60c93dSderaadt 	strlcpy(sc->sc_sensor[ADMLC_Vccp2].desc, "Vccp2",
167ce60c93dSderaadt 	    sizeof(sc->sc_sensor[ADMLC_Vccp2].desc));
168ce60c93dSderaadt 
169ce60c93dSderaadt 	sc->sc_sensor[ADMLC_FAN1].type = SENSOR_FANRPM;
170ce60c93dSderaadt 
171ce60c93dSderaadt 	sc->sc_sensor[ADMLC_FAN2].type = SENSOR_FANRPM;
172ce60c93dSderaadt 
173ce60c93dSderaadt 
174abd9fc28Sdlg 	if (sensor_task_register(sc, admlc_refresh, 5) == NULL) {
175ce60c93dSderaadt 		printf(", unable to register update task\n");
176ce60c93dSderaadt 		return;
177ce60c93dSderaadt 	}
178ce60c93dSderaadt 
179ce60c93dSderaadt 	for (i = 0; i < ADMLC_NUM_SENSORS; i++)
18027515a6bSderaadt 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
18127515a6bSderaadt 	sensordev_install(&sc->sc_sensordev);
182ce60c93dSderaadt 
183ce60c93dSderaadt 	printf("\n");
184ce60c93dSderaadt }
185ce60c93dSderaadt 
1868bd65a67Sderaadt static void
fanval(struct ksensor * sens,int mul,u_int8_t data)187275cbf62Sderaadt fanval(struct ksensor *sens, int mul, u_int8_t data)
1888bd65a67Sderaadt {
1898bd65a67Sderaadt 	int tmp = data * mul;
1908bd65a67Sderaadt 
1918bd65a67Sderaadt 	if (tmp == 0)
1928bd65a67Sderaadt 		sens->flags |= SENSOR_FINVALID;
1938bd65a67Sderaadt 	else
1948bd65a67Sderaadt 		sens->value = 1350000 / tmp;
1958bd65a67Sderaadt }
1968bd65a67Sderaadt 
197ce60c93dSderaadt void
admlc_refresh(void * arg)198ce60c93dSderaadt admlc_refresh(void *arg)
199ce60c93dSderaadt {
200ce60c93dSderaadt 	struct admlc_softc *sc = arg;
201ce60c93dSderaadt 	u_int8_t cmd, data;
202ce60c93dSderaadt 	int8_t sdata;
203ce60c93dSderaadt 
204ce60c93dSderaadt 	iic_acquire_bus(sc->sc_tag, 0);
205ce60c93dSderaadt 
206ce60c93dSderaadt 	cmd = ADM1024_INT_TEMP;
207ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
208b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
209ce60c93dSderaadt 		sc->sc_sensor[ADMLC_INT].value = 273150000 + 1000000 * sdata;
210ce60c93dSderaadt 
211ce60c93dSderaadt 	cmd = ADM1024_EXT_TEMP;
212ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
213b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
214ce60c93dSderaadt 		sc->sc_sensor[ADMLC_EXT].value = 273150000 + 1000000 * sdata;
215ce60c93dSderaadt 
216ce60c93dSderaadt 	cmd = ADM1024_STATUS2;
217ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
218b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
219ce60c93dSderaadt 		if (data & ADM1024_STATUS2_EXT)
220ce60c93dSderaadt 			sc->sc_sensor[ADMLC_EXT].flags |= SENSOR_FINVALID;
221ce60c93dSderaadt 		else
222ce60c93dSderaadt 			sc->sc_sensor[ADMLC_EXT].flags &= ~SENSOR_FINVALID;
223ce60c93dSderaadt 	}
224ce60c93dSderaadt 
2254c619377Sderaadt 	cmd = ADM1024_V2_5;
226ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
227b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
2284c619377Sderaadt 		sc->sc_sensor[ADMLC_V2_5].value = 2500000 * data / 192;
229ce60c93dSderaadt 
230ce60c93dSderaadt 	cmd = ADM1024_Vccp;
231ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
232b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
233ce60c93dSderaadt 		sc->sc_sensor[ADMLC_Vcc].value = 2249000 * data / 192;
234ce60c93dSderaadt 
235ce60c93dSderaadt 	cmd = ADM1024_Vcc;
236ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
237b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
238ce60c93dSderaadt 		sc->sc_sensor[ADMLC_Vcc].value = 3300000 * data / 192;
239ce60c93dSderaadt 
240ce60c93dSderaadt 	cmd = ADM1024_V5;
241ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
242b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
243ce60c93dSderaadt 		sc->sc_sensor[ADMLC_V5].value = 5000000 * data / 192;
244ce60c93dSderaadt 
245ce60c93dSderaadt 	cmd = ADM1024_V12;
246ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
247b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
248ce60c93dSderaadt 		sc->sc_sensor[ADMLC_V12].value = 12000000 * data / 192;
249ce60c93dSderaadt 
250ce60c93dSderaadt 	cmd = ADM1024_Vccp2;
251ce60c93dSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
252b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
253ce60c93dSderaadt 		sc->sc_sensor[ADMLC_Vccp2].value = 2700000 * data / 192;
254ce60c93dSderaadt 
25557bb1d2cSderaadt 	cmd = ADM1024_FAN1;
25657bb1d2cSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
257b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
2588bd65a67Sderaadt 		fanval(&sc->sc_sensor[ADMLC_FAN1], sc->sc_fan1mul, data);
25957bb1d2cSderaadt 
26057bb1d2cSderaadt 	cmd = ADM1024_FAN2;
26157bb1d2cSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
262b8631cf2Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
2638bd65a67Sderaadt 		fanval(&sc->sc_sensor[ADMLC_FAN2], sc->sc_fan2mul, data);
264ce60c93dSderaadt 	iic_release_bus(sc->sc_tag, 0);
265ce60c93dSderaadt }
266