1 /* $NetBSD: tmp121.c,v 1.1 2006/10/02 07:18:19 gdamore Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 5 * Copyright (c) 2006 Garrett D'Amore. 6 * All rights reserved. 7 * 8 * Portions of this code were written by Garrett D'Amore for the 9 * Champaign-Urbana Community Wireless Network Project. 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgements: 22 * This product includes software developed by the Urbana-Champaign 23 * Independent Media Center. 24 * This product includes software developed by Garrett D'Amore. 25 * 4. Urbana-Champaign Independent Media Center's name and Garrett 26 * D'Amore's name may not be used to endorse or promote products 27 * derived from this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT 30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: tmp121.c,v 1.1 2006/10/02 07:18:19 gdamore Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/device.h> 50 #include <sys/kernel.h> 51 52 #include <dev/sysmon/sysmonvar.h> 53 54 #include <dev/spi/spivar.h> 55 56 struct tmp121temp_softc { 57 struct device sc_dev; 58 59 struct spi_handle *sc_sh; 60 61 struct envsys_tre_data sc_sensor[1]; 62 struct envsys_basic_info sc_info[1]; 63 64 struct sysmon_envsys sc_sysmon; 65 }; 66 67 static int tmp121temp_match(struct device *, struct cfdata *, void *); 68 static void tmp121temp_attach(struct device *, struct device *, void *); 69 70 static int tmp121temp_gtredata(struct sysmon_envsys *, 71 struct envsys_tre_data *); 72 static int tmp121temp_streinfo(struct sysmon_envsys *, 73 struct envsys_basic_info *); 74 75 CFATTACH_DECL(tmp121temp, sizeof(struct tmp121temp_softc), 76 tmp121temp_match, tmp121temp_attach, NULL, NULL); 77 78 79 static const struct envsys_range tmp121temp_ranges[] = { 80 /* this looks suspect to me, manual says ranges are inclusive */ 81 { 0, 1, ENVSYS_STEMP }, 82 { 1, 0, -1 }, 83 }; 84 85 static int 86 tmp121temp_match(struct device *parent, struct cfdata *cf, void *aux) 87 { 88 struct spi_attach_args *sa = aux; 89 90 /* configure for 10MHz */ 91 if (spi_configure(sa->sa_handle, SPI_MODE_0, 1000000)) 92 return 0; 93 94 return 1; 95 } 96 97 static void 98 tmp121temp_attach(struct device *parent, struct device *self, void *aux) 99 { 100 struct tmp121temp_softc *sc = device_private(self); 101 struct spi_attach_args *sa = aux; 102 prop_string_t desc; 103 104 aprint_naive(": Temperature Sensor\n"); 105 aprint_normal(": TI TMP121 Temperature Sensor\n"); 106 107 sc->sc_sh = sa->sa_handle; 108 109 sc->sc_info[0].sensor = 0; 110 sc->sc_info[0].validflags = ENVSYS_FVALID; 111 112 sc->sc_sensor[0].sensor = 0; 113 sc->sc_sensor[0].validflags = ENVSYS_FVALID; 114 sc->sc_sensor[0].warnflags = ENVSYS_WARN_OK; 115 sc->sc_sensor[0].units = sc->sc_info[0].units = ENVSYS_STEMP; 116 117 /* 118 * set up the description, which we allow MD code to override in 119 * a property. 120 */ 121 desc = prop_dictionary_get(device_properties(self), 122 "envsys-description"); 123 if (desc != NULL && 124 prop_object_type(desc) == PROP_TYPE_STRING && 125 prop_string_size(desc) > 0) 126 strcpy(sc->sc_info[0].desc, prop_string_cstring_nocopy(desc)); 127 else 128 strcpy(sc->sc_info[0].desc, device_xname(self)); 129 130 131 sc->sc_sysmon.sme_ranges = tmp121temp_ranges; 132 sc->sc_sysmon.sme_sensor_info = sc->sc_info; 133 sc->sc_sysmon.sme_sensor_data = sc->sc_sensor; 134 sc->sc_sysmon.sme_gtredata = tmp121temp_gtredata; 135 sc->sc_sysmon.sme_streinfo = tmp121temp_streinfo; 136 sc->sc_sysmon.sme_cookie = sc; 137 sc->sc_sysmon.sme_nsensors = 1; 138 sc->sc_sysmon.sme_envsys_version = 1000; 139 140 if (sysmon_envsys_register(&sc->sc_sysmon)) 141 aprint_error("%s: unable to register with sysmon\n", 142 device_xname(self)); 143 144 } 145 146 static void 147 tmp121temp_refresh(struct tmp121temp_softc *sc) 148 { 149 uint16_t reg; 150 int16_t sreg; 151 int val; 152 153 if (spi_recv(sc->sc_sh, 2, (uint8_t *)®) != 0) { 154 sc->sc_sensor[0].validflags &= ~ENVSYS_FCURVALID; 155 return; 156 } 157 158 sreg = (int16_t)be16toh(reg); 159 160 /* 161 * convert to uK: 162 * 163 * TMP121 bits: 164 * D15 : sign bit 165 * D14-D3 : data (D14 is MSB) 166 * D2-D0 : zero 167 * 168 * The data is represented in units of 0.0625 deg C. 169 */ 170 sreg >>= 3; 171 val = sreg * 62500 + 273150000; 172 173 sc->sc_sensor[0].cur.data_us = val; 174 sc->sc_sensor[0].validflags |= ENVSYS_FCURVALID; 175 } 176 177 static int 178 tmp121temp_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred) 179 { 180 struct tmp121temp_softc *sc = sme->sme_cookie; 181 182 /* 183 * XXX: locking? possibly we could copy out bad sensor data. 184 * I'm not going to worry about it right now -- sysmon is probably 185 * single threaded anyway. 186 */ 187 188 tmp121temp_refresh(sc); 189 *tred = sc->sc_sensor[tred->sensor]; 190 191 return (0); 192 } 193 194 static int 195 tmp121temp_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo) 196 { 197 struct tmp121temp_softc *sc = sme->sme_cookie; 198 199 memcpy(sc->sc_info[binfo->sensor].desc, binfo->desc, 200 sizeof(sc->sc_info[binfo->sensor].desc)); 201 sc->sc_info[binfo->sensor].desc[ 202 sizeof(sc->sc_info[binfo->sensor].desc) - 1] = '\0'; 203 204 binfo->validflags = ENVSYS_FVALID; 205 206 return (0); 207 } 208