1 /* $NetBSD: owtemp.c,v 1.14 2008/05/05 13:58:58 xtraeme Exp $ */
2 /* $OpenBSD: owtemp.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */
5 * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
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.
21 * 1-Wire temperature family type device driver.
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: owtemp.c,v 1.14 2008/05/05 13:58:58 xtraeme Exp $");
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/kernel.h>
33 #include <dev/sysmon/sysmonvar.h>
35 #include <dev/onewire/onewiredevs.h>
36 #include <dev/onewire/onewirereg.h>
37 #include <dev/onewire/onewirevar.h>
39 #define DS_CMD_CONVERT 0x44
40 #define DS_CMD_READ_SCRATCHPAD 0xbe
46 envsys_data_t sc_sensor
;
47 struct sysmon_envsys
*sc_sme
;
49 uint32_t (*sc_owtemp_decode
)(const uint8_t *);
54 static int owtemp_match(device_t
, cfdata_t
, void *);
55 static void owtemp_attach(device_t
, device_t
, void *);
56 static int owtemp_detach(device_t
, int);
57 static int owtemp_activate(device_t
, enum devact
);
59 static void owtemp_update(void *);
61 CFATTACH_DECL_NEW(owtemp
, sizeof(struct owtemp_softc
),
62 owtemp_match
, owtemp_attach
, owtemp_detach
, owtemp_activate
);
64 extern struct cfdriver owtemp_cd
;
66 static const struct onewire_matchfam owtemp_fams
[] = {
67 { ONEWIRE_FAMILY_DS1920
},
68 { ONEWIRE_FAMILY_DS18B20
},
69 { ONEWIRE_FAMILY_DS1822
},
72 static void owtemp_refresh(struct sysmon_envsys
*, envsys_data_t
*);
74 static uint32_t owtemp_decode_ds18b20(const uint8_t *);
75 static uint32_t owtemp_decode_ds1920(const uint8_t *);
78 owtemp_match(device_t parent
, cfdata_t match
, void *aux
)
80 return (onewire_matchbyfam(aux
, owtemp_fams
,
81 __arraycount(owtemp_fams
)));
85 owtemp_attach(device_t parent
, device_t self
, void *aux
)
87 struct owtemp_softc
*sc
= device_private(self
);
88 struct onewire_attach_args
*oa
= aux
;
92 sc
->sc_onewire
= oa
->oa_onewire
;
93 sc
->sc_rom
= oa
->oa_rom
;
95 switch(ONEWIRE_ROM_FAMILY_TYPE(sc
->sc_rom
)) {
96 case ONEWIRE_FAMILY_DS18B20
:
97 case ONEWIRE_FAMILY_DS1822
:
98 sc
->sc_owtemp_decode
= owtemp_decode_ds18b20
;
100 case ONEWIRE_FAMILY_DS1920
:
101 sc
->sc_owtemp_decode
= owtemp_decode_ds1920
;
105 sc
->sc_sme
= sysmon_envsys_create();
107 /* Initialize sensor */
108 sc
->sc_sensor
.units
= ENVSYS_STEMP
;
109 (void)strlcpy(sc
->sc_sensor
.desc
,
110 device_xname(self
), sizeof(sc
->sc_sensor
.desc
));
111 if (sysmon_envsys_sensor_attach(sc
->sc_sme
, &sc
->sc_sensor
)) {
112 sysmon_envsys_destroy(sc
->sc_sme
);
116 /* Hook into system monitor. */
117 sc
->sc_sme
->sme_name
= device_xname(self
);
118 sc
->sc_sme
->sme_cookie
= sc
;
119 sc
->sc_sme
->sme_refresh
= owtemp_refresh
;
121 if (sysmon_envsys_register(sc
->sc_sme
)) {
122 aprint_error_dev(self
, "unable to register with sysmon\n");
123 sysmon_envsys_destroy(sc
->sc_sme
);
131 owtemp_detach(device_t self
, int flags
)
133 struct owtemp_softc
*sc
= device_private(self
);
135 sysmon_envsys_unregister(sc
->sc_sme
);
141 owtemp_activate(device_t self
, enum devact act
)
143 struct owtemp_softc
*sc
= device_private(self
);
146 case DVACT_DEACTIVATE
:
155 owtemp_update(void *arg
)
157 struct owtemp_softc
*sc
= arg
;
160 onewire_lock(sc
->sc_onewire
);
161 if (onewire_reset(sc
->sc_onewire
) != 0)
163 onewire_matchrom(sc
->sc_onewire
, sc
->sc_rom
);
166 * Start temperature conversion. The conversion takes up to 750ms.
167 * After sending the command, the data line must be held high for
168 * at least 750ms to provide power during the conversion process.
169 * As such, no other activity may take place on the 1-Wire bus for
170 * at least this period.
172 onewire_write_byte(sc
->sc_onewire
, DS_CMD_CONVERT
);
173 tsleep(sc
, PRIBIO
, "owtemp", hz
);
175 if (onewire_reset(sc
->sc_onewire
) != 0)
177 onewire_matchrom(sc
->sc_onewire
, sc
->sc_rom
);
180 * The result of the temperature measurement is placed in the
181 * first two bytes of the scratchpad.
183 onewire_write_byte(sc
->sc_onewire
, DS_CMD_READ_SCRATCHPAD
);
184 onewire_read_block(sc
->sc_onewire
, data
, 9);
186 if (onewire_crc(data
, 8) == data
[8]) {
187 sc
->sc_sensor
.value
= 273150000 +
188 (int)((u_int16_t
)data
[1] << 8 | data
[0]) * 500000;
192 sc
->sc_sensor
.value_cur
= sc
->sc_owtemp_decode(data
);
193 sc
->sc_sensor
.state
= ENVSYS_SVALID
;
196 onewire_unlock(sc
->sc_onewire
);
200 owtemp_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
202 struct owtemp_softc
*sc
= sme
->sme_cookie
;
208 owtemp_decode_ds18b20(const uint8_t *buf
)
213 * Sign-extend the MSB byte, and add in the fractions of a
214 * degree contained in the LSB (precision 1/16th DegC).
216 temp
= (int8_t)buf
[1];
217 temp
= (temp
<< 8) | buf
[0];
220 * Conversion to uK is simple.
222 return (temp
* 62500 + 273150000);
226 owtemp_decode_ds1920(const uint8_t *buf
)
231 * Sign-extend the MSB byte, and add in the fractions of a
232 * degree contained in the LSB (precision 1/2 DegC).
234 temp
= (int8_t)buf
[1];
235 temp
= (temp
<< 8) | buf
[0];
238 return (temp
* 500000 + 273150000);