1 /* $OpenBSD: adt7462.c,v 1.7 2022/04/06 18:59:28 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2008 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 #define ADT7462_TEMPL 0x88
27 #define ADT7462_TEMPH 0x89
28 #define ADT7462_TEMP1L 0x8a
29 #define ADT7462_TEMP1H 0x8b
30 #define ADT7462_TEMP2L 0x8c
31 #define ADT7462_TEMP2H 0x8d
32 #define ADT7462_TEMP3L 0x8e
33 #define ADT7462_TEMP3H 0x8f
34 #define ADT7262_TACH1L 0x98
35 #define ADT7262_TACH1H 0x99
36 #define ADT7262_TACH2L 0x9a
37 #define ADT7262_TACH2H 0x9b
38 #define ADT7262_TACH3L 0x9c
39 #define ADT7262_TACH3H 0x9d
40 #define ADT7262_TACH4L 0x9e
41 #define ADT7262_TACH4H 0x9f
42 #define ADT7262_TACH5L 0xa2
43 #define ADT7262_TACH5H 0xa3
44 #define ADT7262_TACH6L 0xa4
45 #define ADT7262_TACH6H 0xa5
46 #define ADT7262_TACH7L 0xa6
47 #define ADT7262_TACH7H 0xa7
48 #define ADT7262_TACH8L 0xa8
49 #define ADT7262_TACH8H 0xa9
50
51 /* Sensors */
52 #define ADTFSM_TEMP0 0
53 #define ADTFSM_TEMP1 1
54 #define ADTFSM_TEMP2 2
55 #define ADTFSM_TEMP3 3
56 #define ADTFSM_TACH1 4
57 #define ADTFSM_TACH2 5
58 #define ADTFSM_TACH3 6
59 #define ADTFSM_TACH4 7
60 #define ADTFSM_TACH5 8
61 #define ADTFSM_TACH6 9
62 #define ADTFSM_TACH7 10
63 #define ADTFSM_TACH8 11
64 #define ADTFSM_NUM_SENSORS 12
65
66 struct adtfsm_softc {
67 struct device sc_dev;
68 i2c_tag_t sc_tag;
69 i2c_addr_t sc_addr;
70 int sc_fanmul;
71
72 struct ksensor sc_sensor[ADTFSM_NUM_SENSORS];
73 struct ksensordev sc_sensordev;
74 };
75
76 int adtfsm_match(struct device *, void *, void *);
77 void adtfsm_attach(struct device *, struct device *, void *);
78 void adtfsm_refresh(void *);
79
80 const struct cfattach adtfsm_ca = {
81 sizeof(struct adtfsm_softc), adtfsm_match, adtfsm_attach
82 };
83
84 struct cfdriver adtfsm_cd = {
85 NULL, "adtfsm", DV_DULL
86 };
87
88 int
adtfsm_match(struct device * parent,void * match,void * aux)89 adtfsm_match(struct device *parent, void *match, void *aux)
90 {
91 struct i2c_attach_args *ia = aux;
92
93 if (strcmp(ia->ia_name, "adt7462") == 0)
94 return (1);
95 return (0);
96 }
97
98 void
adtfsm_attach(struct device * parent,struct device * self,void * aux)99 adtfsm_attach(struct device *parent, struct device *self, void *aux)
100 {
101 struct adtfsm_softc *sc = (struct adtfsm_softc *)self;
102 struct i2c_attach_args *ia = aux;
103 int i;
104
105 sc->sc_tag = ia->ia_tag;
106 sc->sc_addr = ia->ia_addr;
107
108 /* Initialize sensor data. */
109 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
110 sizeof(sc->sc_sensordev.xname));
111
112 for (i = ADTFSM_TEMP0; i <= ADTFSM_TEMP3; i++) {
113 sc->sc_sensor[i].type = SENSOR_TEMP;
114 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
115 }
116
117 strlcpy(sc->sc_sensor[0].desc, "Internal",
118 sizeof(sc->sc_sensor[0].desc));
119 for (i = 1; i < 4; i++)
120 strlcpy(sc->sc_sensor[i].desc, "External",
121 sizeof(sc->sc_sensor[i].desc));
122
123 for (i = ADTFSM_TACH1; i <= ADTFSM_TACH8; i++) {
124 sc->sc_sensor[i].type = SENSOR_FANRPM;
125 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
126 }
127
128 if (sensor_task_register(sc, adtfsm_refresh, 5) == NULL) {
129 printf(", unable to register update task\n");
130 return;
131 }
132
133 for (i = 0; i < ADTFSM_NUM_SENSORS; i++)
134 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
135 sensordev_install(&sc->sc_sensordev);
136
137 printf("\n");
138 }
139
140 void
adtfsm_refresh(void * arg)141 adtfsm_refresh(void *arg)
142 {
143 struct adtfsm_softc *sc = arg;
144 u_int8_t cmdh, cmdl, datah = 0x01, datal = 0x02;
145 struct ksensor *ks;
146 u_short ut;
147 short t;
148 int i;
149
150 iic_acquire_bus(sc->sc_tag, 0);
151
152 for (i = 0; i <= ADTFSM_TEMP3 - ADTFSM_TEMP0; i++) {
153 cmdl = ADT7462_TEMPL + i * 2;
154 cmdh = ADT7462_TEMPH + i * 2;
155 ks = &sc->sc_sensor[ADTFSM_TEMP0 + i];
156 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
157 sc->sc_addr, &cmdl, sizeof cmdl, &datal,
158 sizeof datal, 0) == 0 &&
159 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
160 sc->sc_addr, &cmdh, sizeof cmdh, &datah,
161 sizeof datah, 0) == 0) {
162 t = (((datah << 8) | datal) >> 6) - (64 << 2);
163 ks->value = 273150000 + t * 250000;
164 ks->flags &= ~SENSOR_FINVALID;
165 } else
166 ks->flags |= SENSOR_FINVALID;
167 }
168
169 for (i = 0; i <= ADTFSM_TACH8 - ADTFSM_TACH1; i++) {
170 cmdl = ADT7262_TACH1L + i * 2;
171 cmdh = ADT7262_TACH1H + i * 2;
172 ks = &sc->sc_sensor[ADTFSM_TACH1 + i];
173 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
174 sc->sc_addr, &cmdl, sizeof cmdl, &datal,
175 sizeof datal, 0) == 0 &&
176 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
177 sc->sc_addr, &cmdh, sizeof cmdh, &datah,
178 sizeof datah, 0) == 0) {
179 ut = ((datah << 8) | datal);
180 if (ut == 0x0000 || ut == 0xffff)
181 ks->flags |= SENSOR_FINVALID;
182 else {
183 ks->value = 90000 * 60 / ut;
184 ks->flags &= ~SENSOR_FINVALID;
185 }
186 } else
187 ks->flags |= SENSOR_FINVALID;
188 }
189
190 iic_release_bus(sc->sc_tag, 0);
191 }
192