1 /* $NetBSD: adm1021.c,v 1.2 2009/05/12 14:23:33 cegger Exp $ */
2 /* $OpenBSD: adm1021.c,v 1.27 2007/06/24 05:34:35 dlg Exp $ */
5 * Copyright (c) 2005 Theo de Raadt
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: adm1021.c,v 1.2 2009/05/12 14:23:33 cegger Exp $");
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <dev/sysmon/sysmonvar.h>
28 #include <dev/i2c/i2cvar.h>
31 /* ADM 1021 registers */
32 #define ADM1021_INT_TEMP 0x00
33 #define ADM1021_EXT_TEMP 0x01
34 #define ADM1021_STATUS 0x02
35 #define ADM1021_STATUS_INVAL 0x7f
36 #define ADM1021_STATUS_NOEXT 0x40
37 #define ADM1021_CONFIG_READ 0x03
38 #define ADM1021_CONFIG_WRITE 0x09
39 #define ADM1021_CONFIG_RUN 0x40
40 #define ADM1021_COMPANY 0xfe /* contains 0x41 */
41 #define ADM1021_DIE_REVISION 0xff
46 #define ADMTEMP_NUM_SENSORS 2
48 struct admtemp_softc
{
54 struct sysmon_envsys
*sc_sme
;
55 envsys_data_t sc_sensor
[ADMTEMP_NUM_SENSORS
];
58 int admtemp_match(device_t
, cfdata_t
, void *);
59 void admtemp_attach(device_t
, device_t
, void *);
60 void admtemp_refresh(struct sysmon_envsys
*, envsys_data_t
*);
62 CFATTACH_DECL_NEW(admtemp
, sizeof(struct admtemp_softc
),
63 admtemp_match
, admtemp_attach
, NULL
, NULL
);
67 admtemp_match(device_t parent
, cfdata_t match
, void *aux
)
69 struct i2c_attach_args
*ia
= aux
;
71 if (((ia
->ia_addr
>= 0x18) && (ia
->ia_addr
<= 0x1a)) ||
72 ((ia
->ia_addr
>= 0x29) && (ia
->ia_addr
<= 0x2b)) ||
73 ((ia
->ia_addr
>= 0x4c) && (ia
->ia_addr
<= 0x4e)))
81 admtemp_attach(device_t parent
, device_t self
, void *aux
)
83 struct admtemp_softc
*sc
= device_private(self
);
84 struct i2c_attach_args
*ia
= aux
;
85 u_int8_t cmd
, data
, stat
;
87 sc
->sc_tag
= ia
->ia_tag
;
88 sc
->sc_addr
= ia
->ia_addr
;
90 aprint_normal(": ADM1021 or compatible environmental sensor\n");
92 iic_acquire_bus(sc
->sc_tag
, 0);
93 cmd
= ADM1021_CONFIG_READ
;
94 if (iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
95 sc
->sc_addr
, &cmd
, sizeof cmd
, &data
, sizeof data
, 0)) {
96 iic_release_bus(sc
->sc_tag
, 0);
97 aprint_error_dev(&sc
->sc_dev
, "cannot get control register\n");
100 if (data
& ADM1021_CONFIG_RUN
) {
101 cmd
= ADM1021_STATUS
;
102 if (iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
103 sc
->sc_addr
, &cmd
, sizeof cmd
, &stat
, sizeof stat
, 0)) {
104 iic_release_bus(sc
->sc_tag
, 0);
105 aprint_error_dev(&sc
->sc_dev
,
106 "cannot read status register\n");
109 if ((stat
& ADM1021_STATUS_INVAL
) == ADM1021_STATUS_INVAL
) {
110 if (iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
111 sc
->sc_addr
, &cmd
, sizeof cmd
, &stat
, sizeof stat
,
113 iic_release_bus(sc
->sc_tag
, 0);
114 aprint_error_dev(&sc
->sc_dev
,
115 "cannot read status register\n");
120 /* means external is dead */
121 if ((stat
& ADM1021_STATUS_INVAL
) != ADM1021_STATUS_INVAL
&&
122 (stat
& ADM1021_STATUS_NOEXT
))
123 sc
->sc_noexternal
= 1;
125 data
&= ~ADM1021_CONFIG_RUN
;
126 cmd
= ADM1021_CONFIG_WRITE
;
127 if (iic_exec(sc
->sc_tag
, I2C_OP_WRITE_WITH_STOP
,
128 sc
->sc_addr
, &cmd
, sizeof cmd
, &data
, sizeof data
, 0)) {
129 iic_release_bus(sc
->sc_tag
, 0);
130 aprint_error_dev(&sc
->sc_dev
,
131 "cannot set control register\n");
135 iic_release_bus(sc
->sc_tag
, 0);
137 /* Initialize sensor data. */
138 sc
->sc_sensor
[ADMTEMP_INT
].units
= ENVSYS_STEMP
;
139 sc
->sc_sensor
[ADMTEMP_EXT
].units
= ENVSYS_STEMP
;
140 strlcpy(sc
->sc_sensor
[ADMTEMP_INT
].desc
, "internal",sizeof("internal"));
141 strlcpy(sc
->sc_sensor
[ADMTEMP_EXT
].desc
, "external",sizeof("external"));
142 sc
->sc_sme
= sysmon_envsys_create();
143 if (sysmon_envsys_sensor_attach(
144 sc
->sc_sme
, &sc
->sc_sensor
[ADMTEMP_INT
])) {
145 sysmon_envsys_destroy(sc
->sc_sme
);
146 aprint_error_dev(&sc
->sc_dev
,
147 "unable to attach internal at sysmon\n");
150 if (sc
->sc_noexternal
== 0 &&
151 sysmon_envsys_sensor_attach(
152 sc
->sc_sme
, &sc
->sc_sensor
[ADMTEMP_EXT
])) {
153 sysmon_envsys_destroy(sc
->sc_sme
);
154 aprint_error_dev(&sc
->sc_dev
,
155 "unable to attach external at sysmon\n");
158 sc
->sc_sme
->sme_name
= device_xname(self
);
159 sc
->sc_sme
->sme_cookie
= sc
;
160 sc
->sc_sme
->sme_refresh
= admtemp_refresh
;
161 if (sysmon_envsys_register(sc
->sc_sme
)) {
162 aprint_error_dev(&sc
->sc_dev
,
163 "unable to register with sysmon\n");
164 sysmon_envsys_destroy(sc
->sc_sme
);
171 admtemp_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
173 struct admtemp_softc
*sc
= sme
->sme_cookie
;
177 iic_acquire_bus(sc
->sc_tag
, 0);
179 if (edata
->sensor
== ADMTEMP_INT
)
180 cmd
= ADM1021_INT_TEMP
;
182 cmd
= ADM1021_EXT_TEMP
;
183 if (iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
, sc
->sc_addr
,
184 &cmd
, sizeof cmd
, &sdata
, sizeof sdata
, 0) == 0) {
185 if (sdata
== ADM1021_STATUS_INVAL
) {
186 edata
->state
= ENVSYS_SINVALID
;
188 edata
->value_cur
= 273150000 + 1000000 * sdata
;
189 edata
->state
= ENVSYS_SVALID
;
193 iic_release_bus(sc
->sc_tag
, 0);