Line data Source code
1 : /* $OpenBSD: adm1030.c,v 1.9 2008/05/01 23:02:05 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 1030 registers */
27 : #define ADM1030_INT_TEMP 0x0a
28 : #define ADM1030_EXT_TEMP 0x0b
29 : #define ADM1030_FAN 0x08
30 : #define ADM1030_FANC 0x20
31 : #define ADM1024_FANC_VAL(x) (x >> 6)
32 :
33 : /* Sensors */
34 : #define ADMTMP_INT 0
35 : #define ADMTMP_EXT 1
36 : #define ADMTMP_FAN 2
37 : #define ADMTMP_NUM_SENSORS 3
38 :
39 : struct admtmp_softc {
40 : struct device sc_dev;
41 : i2c_tag_t sc_tag;
42 : i2c_addr_t sc_addr;
43 : int sc_fanmul;
44 :
45 : struct ksensor sc_sensor[ADMTMP_NUM_SENSORS];
46 : struct ksensordev sc_sensordev;
47 : };
48 :
49 : int admtmp_match(struct device *, void *, void *);
50 : void admtmp_attach(struct device *, struct device *, void *);
51 : void admtmp_refresh(void *);
52 :
53 : struct cfattach admtmp_ca = {
54 : sizeof(struct admtmp_softc), admtmp_match, admtmp_attach
55 : };
56 :
57 : struct cfdriver admtmp_cd = {
58 : NULL, "admtmp", DV_DULL
59 : };
60 :
61 : int
62 0 : admtmp_match(struct device *parent, void *match, void *aux)
63 : {
64 0 : struct i2c_attach_args *ia = aux;
65 :
66 0 : if (strcmp(ia->ia_name, "adm1030") == 0)
67 0 : return (1);
68 0 : return (0);
69 0 : }
70 :
71 : void
72 0 : admtmp_attach(struct device *parent, struct device *self, void *aux)
73 : {
74 0 : struct admtmp_softc *sc = (struct admtmp_softc *)self;
75 0 : struct i2c_attach_args *ia = aux;
76 0 : u_int8_t cmd, data;
77 : int i;
78 :
79 0 : sc->sc_tag = ia->ia_tag;
80 0 : sc->sc_addr = ia->ia_addr;
81 :
82 0 : cmd = ADM1030_FANC;
83 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
84 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
85 0 : printf(": unable to read fan setting\n");
86 0 : return;
87 : }
88 :
89 0 : sc->sc_fanmul = 11250/8 * (1 << ADM1024_FANC_VAL(data)) * 60;
90 :
91 : /* Initialize sensor data. */
92 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
93 : sizeof(sc->sc_sensordev.xname));
94 :
95 0 : sc->sc_sensor[ADMTMP_INT].type = SENSOR_TEMP;
96 0 : strlcpy(sc->sc_sensor[ADMTMP_INT].desc, "Internal",
97 : sizeof(sc->sc_sensor[ADMTMP_INT].desc));
98 :
99 0 : sc->sc_sensor[ADMTMP_EXT].type = SENSOR_TEMP;
100 0 : strlcpy(sc->sc_sensor[ADMTMP_EXT].desc, "External",
101 : sizeof(sc->sc_sensor[ADMTMP_EXT].desc));
102 :
103 0 : sc->sc_sensor[ADMTMP_FAN].type = SENSOR_FANRPM;
104 :
105 0 : if (sensor_task_register(sc, admtmp_refresh, 5) == NULL) {
106 0 : printf(": unable to register update task\n");
107 0 : return;
108 : }
109 :
110 0 : for (i = 0; i < ADMTMP_NUM_SENSORS; i++)
111 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
112 0 : sensordev_install(&sc->sc_sensordev);
113 :
114 0 : printf("\n");
115 0 : }
116 :
117 : void
118 0 : admtmp_refresh(void *arg)
119 : {
120 0 : struct admtmp_softc *sc = arg;
121 0 : u_int8_t cmd, data;
122 :
123 0 : iic_acquire_bus(sc->sc_tag, 0);
124 :
125 0 : cmd = ADM1030_INT_TEMP;
126 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
127 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
128 0 : sc->sc_sensor[ADMTMP_INT].value = 273150000 + 1000000 * data;
129 :
130 0 : cmd = ADM1030_EXT_TEMP;
131 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
132 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
133 0 : sc->sc_sensor[ADMTMP_EXT].value = 273150000 + 1000000 * data;
134 :
135 0 : cmd = ADM1030_FAN;
136 0 : if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
137 0 : sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
138 0 : if (data == 0)
139 0 : sc->sc_sensor[ADMTMP_FAN].flags |= SENSOR_FINVALID;
140 : else {
141 0 : sc->sc_sensor[ADMTMP_FAN].value =
142 0 : sc->sc_fanmul / (2 * (int)data);
143 0 : sc->sc_sensor[ADMTMP_FAN].flags &= ~SENSOR_FINVALID;
144 : }
145 : }
146 :
147 0 : iic_release_bus(sc->sc_tag, 0);
148 0 : }
|