Line data Source code
1 : /* $OpenBSD: adm1021.c,v 1.28 2011/03/10 23:14:30 deraadt Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2005 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 : /* ADM 1021 registers */
27 : #define ADM1021_INT_TEMP 0x00
28 : #define ADM1021_EXT_TEMP 0x01
29 : #define ADM1021_STATUS 0x02
30 : #define ADM1021_STATUS_INVAL 0x7f
31 : #define ADM1021_STATUS_NOEXT 0x40
32 : #define ADM1021_CONFIG_READ 0x03
33 : #define ADM1021_CONFIG_WRITE 0x09
34 : #define ADM1021_CONFIG_RUN 0x40
35 : #define ADM1021_COMPANY 0xfe /* contains 0x41 */
36 : #define ADM1021_STEPPING 0xff /* contains 0x3? */
37 :
38 : /* Sensors */
39 : #define ADMTEMP_EXT 0
40 : #define ADMTEMP_INT 1
41 : #define ADMTEMP_NUM_SENSORS 2
42 :
43 : struct admtemp_softc {
44 : struct device sc_dev;
45 : i2c_tag_t sc_tag;
46 : i2c_addr_t sc_addr;
47 :
48 : struct ksensor sc_sensor[ADMTEMP_NUM_SENSORS];
49 : struct ksensordev sc_sensordev;
50 : int sc_noexternal;
51 : };
52 :
53 : int admtemp_match(struct device *, void *, void *);
54 : void admtemp_attach(struct device *, struct device *, void *);
55 : void admtemp_refresh(void *);
56 :
57 : struct cfattach admtemp_ca = {
58 : sizeof(struct admtemp_softc), admtemp_match, admtemp_attach
59 : };
60 :
61 : struct cfdriver admtemp_cd = {
62 : NULL, "admtemp", DV_DULL
63 : };
64 :
65 : int
66 0 : admtemp_match(struct device *parent, void *match, void *aux)
67 : {
68 0 : struct i2c_attach_args *ia = aux;
69 :
70 0 : if (strcmp(ia->ia_name, "adm1021") == 0 ||
71 0 : strcmp(ia->ia_name, "adm1023") == 0 ||
72 0 : strcmp(ia->ia_name, "adm1032") == 0 ||
73 0 : strcmp(ia->ia_name, "g781") == 0 ||
74 0 : strcmp(ia->ia_name, "g781-1") == 0 ||
75 0 : strcmp(ia->ia_name, "gl523sm") == 0 ||
76 0 : strcmp(ia->ia_name, "max1617") == 0 ||
77 0 : strcmp(ia->ia_name, "sa56004x") == 0 ||
78 0 : strcmp(ia->ia_name, "xeontemp") == 0)
79 0 : return (1);
80 0 : return (0);
81 0 : }
82 :
83 : void
84 0 : admtemp_attach(struct device *parent, struct device *self, void *aux)
85 : {
86 0 : struct admtemp_softc *sc = (struct admtemp_softc *)self;
87 0 : struct i2c_attach_args *ia = aux;
88 0 : u_int8_t cmd, data, stat;
89 : int xeon = 0, i;
90 :
91 0 : sc->sc_tag = ia->ia_tag;
92 0 : sc->sc_addr = ia->ia_addr;
93 :
94 0 : if (strcmp(ia->ia_name, "xeontemp") == 0) {
95 0 : printf(": Xeon");
96 : xeon = 1;
97 0 : } else
98 0 : printf(": %s", ia->ia_name);
99 :
100 0 : iic_acquire_bus(sc->sc_tag, 0);
101 0 : cmd = ADM1021_CONFIG_READ;
102 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
103 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
104 0 : iic_release_bus(sc->sc_tag, 0);
105 0 : printf(", cannot get control register\n");
106 0 : return;
107 : }
108 0 : if (data & ADM1021_CONFIG_RUN) {
109 0 : cmd = ADM1021_STATUS;
110 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
111 0 : sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 0)) {
112 0 : iic_release_bus(sc->sc_tag, 0);
113 0 : printf(", cannot read status register\n");
114 0 : return;
115 : }
116 0 : if ((stat & ADM1021_STATUS_INVAL) == ADM1021_STATUS_INVAL) {
117 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
118 0 : sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 0)) {
119 0 : iic_release_bus(sc->sc_tag, 0);
120 0 : printf(", cannot read status register\n");
121 0 : return;
122 : }
123 : }
124 :
125 : /* means external is dead */
126 0 : if ((stat & ADM1021_STATUS_INVAL) != ADM1021_STATUS_INVAL &&
127 0 : (stat & ADM1021_STATUS_NOEXT))
128 0 : sc->sc_noexternal = 1;
129 :
130 0 : data &= ~ADM1021_CONFIG_RUN;
131 0 : cmd = ADM1021_CONFIG_WRITE;
132 0 : if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
133 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
134 0 : iic_release_bus(sc->sc_tag, 0);
135 0 : printf(", cannot set control register\n");
136 0 : return;
137 : }
138 : }
139 0 : iic_release_bus(sc->sc_tag, 0);
140 :
141 : /* Initialize sensor data. */
142 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
143 : sizeof(sc->sc_sensordev.xname));
144 :
145 0 : sc->sc_sensor[ADMTEMP_EXT].type = SENSOR_TEMP;
146 0 : strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc,
147 0 : xeon ? "Xeon" : "External",
148 : sizeof(sc->sc_sensor[ADMTEMP_EXT].desc));
149 :
150 0 : sc->sc_sensor[ADMTEMP_INT].type = SENSOR_TEMP;
151 0 : strlcpy(sc->sc_sensor[ADMTEMP_INT].desc,
152 0 : xeon ? "Xeon" : "Internal",
153 : sizeof(sc->sc_sensor[ADMTEMP_INT].desc));
154 :
155 0 : if (sensor_task_register(sc, admtemp_refresh, 5) == NULL) {
156 0 : printf(", unable to register update task\n");
157 0 : return;
158 : }
159 :
160 0 : for (i = 0; i < (sc->sc_noexternal ? 1 : ADMTEMP_NUM_SENSORS); i++)
161 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
162 0 : sensordev_install(&sc->sc_sensordev);
163 :
164 0 : printf("\n");
165 0 : }
166 :
167 : void
168 0 : admtemp_refresh(void *arg)
169 : {
170 0 : struct admtemp_softc *sc = arg;
171 0 : u_int8_t cmd;
172 0 : int8_t sdata;
173 :
174 0 : iic_acquire_bus(sc->sc_tag, 0);
175 :
176 0 : if (sc->sc_noexternal == 0) {
177 0 : cmd = ADM1021_EXT_TEMP;
178 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
179 0 : &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
180 0 : if (sdata == 0x7f) {
181 0 : sc->sc_sensor[ADMTEMP_EXT].flags |= SENSOR_FINVALID;
182 0 : } else {
183 0 : sc->sc_sensor[ADMTEMP_EXT].value =
184 0 : 273150000 + 1000000 * sdata;
185 0 : sc->sc_sensor[ADMTEMP_EXT].flags &= ~SENSOR_FINVALID;
186 : }
187 : }
188 : } else
189 0 : sc->sc_sensor[ADMTEMP_EXT].flags |= SENSOR_FINVALID;
190 :
191 :
192 0 : cmd = ADM1021_INT_TEMP;
193 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
194 0 : &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
195 0 : if (sdata == 0x7f) {
196 0 : sc->sc_sensor[ADMTEMP_INT].flags |= SENSOR_FINVALID;
197 0 : } else {
198 0 : sc->sc_sensor[ADMTEMP_INT].value =
199 0 : 273150000 + 1000000 * sdata;
200 0 : sc->sc_sensor[ADMTEMP_INT].flags &= ~SENSOR_FINVALID;
201 : }
202 : }
203 :
204 0 : iic_release_bus(sc->sc_tag, 0);
205 0 : }
|