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