1 /* $NetBSD: lm75.c,v 1.19 2008/04/06 20:25:59 cegger Exp $ */
4 * Copyright (c) 2003 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.19 2008/04/06 20:25:59 cegger Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/kernel.h>
46 #include <dev/sysmon/sysmonvar.h>
48 #include <dev/i2c/i2cvar.h>
49 #include <dev/i2c/lm75reg.h>
55 struct sysmon_envsys
*sc_sme
;
56 envsys_data_t sc_sensor
;
58 uint32_t (*sc_lmtemp_decode
)(const uint8_t *);
61 static int lmtemp_match(device_t
, cfdata_t
, void *);
62 static void lmtemp_attach(device_t
, device_t
, void *);
64 CFATTACH_DECL_NEW(lmtemp
, sizeof(struct lmtemp_softc
),
65 lmtemp_match
, lmtemp_attach
, NULL
, NULL
);
67 static void lmtemp_refresh(struct sysmon_envsys
*, envsys_data_t
*);
69 static int lmtemp_config_write(struct lmtemp_softc
*, uint8_t);
70 static uint32_t lmtemp_decode_lm75(const uint8_t *);
71 static uint32_t lmtemp_decode_ds75(const uint8_t *);
72 static uint32_t lmtemp_decode_lm77(const uint8_t *);
81 const char *lmtemp_name
;
84 uint32_t (*lmtemp_decode
)(const uint8_t *);
86 { lmtemp_lm75
, "LM75",
87 LM75_ADDRMASK
, LM75_ADDR
, lmtemp_decode_lm75
},
88 { lmtemp_ds75
, "DS75",
89 LM75_ADDRMASK
, LM75_ADDR
, lmtemp_decode_ds75
},
90 { lmtemp_lm77
, "LM77",
91 LM77_ADDRMASK
, LM77_ADDR
, lmtemp_decode_lm77
},
98 lmtemp_match(device_t parent
, cfdata_t cf
, void *aux
)
100 struct i2c_attach_args
*ia
= aux
;
103 for (i
= 0; lmtemptbl
[i
].lmtemp_type
!= -1 ; i
++)
104 if (lmtemptbl
[i
].lmtemp_type
== cf
->cf_flags
)
106 if (lmtemptbl
[i
].lmtemp_type
== -1)
109 if ((ia
->ia_addr
& lmtemptbl
[i
].lmtemp_addrmask
) ==
110 lmtemptbl
[i
].lmtemp_addr
)
117 lmtemp_attach(device_t parent
, device_t self
, void *aux
)
119 struct lmtemp_softc
*sc
= device_private(self
);
120 struct i2c_attach_args
*ia
= aux
;
123 for (i
= 0; lmtemptbl
[i
].lmtemp_type
!= -1 ; i
++)
124 if (lmtemptbl
[i
].lmtemp_type
==
125 device_cfdata(self
)->cf_flags
)
128 sc
->sc_tag
= ia
->ia_tag
;
129 sc
->sc_address
= ia
->ia_addr
;
131 aprint_naive(": Temperature Sensor\n");
132 aprint_normal(": %s Temperature Sensor\n", lmtemptbl
[i
].lmtemp_name
);
134 /* Set the configuration of the LM75 to defaults. */
135 iic_acquire_bus(sc
->sc_tag
, I2C_F_POLL
);
136 if (lmtemp_config_write(sc
, 0) != 0) {
137 aprint_error_dev(self
, "unable to write config register\n");
138 iic_release_bus(sc
->sc_tag
, I2C_F_POLL
);
141 iic_release_bus(sc
->sc_tag
, I2C_F_POLL
);
143 sc
->sc_sme
= sysmon_envsys_create();
144 /* Initialize sensor data. */
145 sc
->sc_sensor
.units
= ENVSYS_STEMP
;
146 (void)strlcpy(sc
->sc_sensor
.desc
, device_xname(self
),
147 sizeof(sc
->sc_sensor
.desc
));
148 if (sysmon_envsys_sensor_attach(sc
->sc_sme
, &sc
->sc_sensor
)) {
149 sysmon_envsys_destroy(sc
->sc_sme
);
153 sc
->sc_lmtemp_decode
= lmtemptbl
[i
].lmtemp_decode
;
155 /* Hook into system monitor. */
156 sc
->sc_sme
->sme_name
= device_xname(self
);
157 sc
->sc_sme
->sme_cookie
= sc
;
158 sc
->sc_sme
->sme_refresh
= lmtemp_refresh
;
160 if (sysmon_envsys_register(sc
->sc_sme
)) {
161 aprint_error_dev(self
, "unable to register with sysmon\n");
162 sysmon_envsys_destroy(sc
->sc_sme
);
167 lmtemp_config_write(struct lmtemp_softc
*sc
, uint8_t val
)
171 cmdbuf
[0] = LM75_REG_CONFIG
;
174 return iic_exec(sc
->sc_tag
, I2C_OP_WRITE_WITH_STOP
,
175 sc
->sc_address
, cmdbuf
, 1, &cmdbuf
[1], 1, I2C_F_POLL
);
179 lmtemp_temp_read(struct lmtemp_softc
*sc
, uint8_t which
, uint32_t *valp
)
183 uint8_t buf
[LM75_TEMP_LEN
];
187 error
= iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
188 sc
->sc_address
, cmdbuf
, 1, buf
, LM75_TEMP_LEN
, 0);
192 *valp
= sc
->sc_lmtemp_decode(buf
);
197 lmtemp_refresh_sensor_data(struct lmtemp_softc
*sc
)
202 error
= lmtemp_temp_read(sc
, LM75_REG_TEMP
, &val
);
205 aprint_error_dev(&sc
->sc_dev
, "unable to read temperature, error = %d\n",
208 sc
->sc_sensor
.state
= ENVSYS_SINVALID
;
212 sc
->sc_sensor
.value_cur
= val
;
213 sc
->sc_sensor
.state
= ENVSYS_SVALID
;
217 lmtemp_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
219 struct lmtemp_softc
*sc
= sme
->sme_cookie
;
221 iic_acquire_bus(sc
->sc_tag
, 0); /* also locks our instance */
222 lmtemp_refresh_sensor_data(sc
);
223 iic_release_bus(sc
->sc_tag
, 0); /* also unlocks our instance */
227 lmtemp_decode_lm75(const uint8_t *buf
)
233 * LM75 temps are the most-significant 9 bits of a 16-bit reg.
234 * sign-extend the MSB and add in the 0.5 from the LSB
236 temp
= (int8_t) buf
[0];
237 temp
= (temp
<< 1) + ((buf
[1] >> 7) & 0x1);
239 /* Temp is given in 1/2 deg. C, we convert to uK. */
240 val
= temp
* 500000 + 273150000;
246 lmtemp_decode_ds75(const uint8_t *buf
)
251 * Sign-extend the MSB byte, and add in the fractions of a
252 * degree contained in the LSB (precision 1/16th DegC).
254 temp
= (int8_t)buf
[0];
255 temp
= (temp
<< 4) | ((buf
[1] >> 4) & 0xf);
258 * Conversion to uK is simple.
260 return (temp
* 62500 + 273150000);
264 lmtemp_decode_lm77(const uint8_t *buf
)
270 * Describe each bits of temperature registers on LM77.
272 * D11 - D3 : Bit8(MSB) - Bit0
274 temp
= (int8_t)buf
[0];
275 temp
= (temp
<< 5) | ((buf
[1] >> 3) & 0x1f);
277 /* Temp is given in 1/2 deg. C, we convert to uK. */
278 val
= temp
* 500000 + 273150000;