1 /*- 2 * Copyright (c) 2014 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Frank Kardel. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * IST-AG P14 calibrated Hygro-/Temperature sensor module 32 * Devices: HYT-271, HYT-221 and HYT-939 33 * 34 * see: 35 * http://www.ist-ag.com/eh/ist-ag/resource.nsf/imgref/Download_AHHYTM_E2.1.pdf/ 36 * $FILE/AHHYTM_E2.1.pdf 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1.2 2014/06/29 09:52:43 kardel Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 #include <sys/module.h> 47 48 #include <dev/sysmon/sysmonvar.h> 49 50 #include <dev/i2c/i2cvar.h> 51 #include <dev/i2c/hytp14reg.h> 52 #include <dev/i2c/hytp14var.h> 53 54 static int hytp14_match(device_t, cfdata_t, void *); 55 static void hytp14_attach(device_t, device_t, void *); 56 static int hytp14_detach(device_t, int); 57 static int hytp14_refresh_sensor(struct hytp14_sc *sc); 58 static void hytp14_refresh(struct sysmon_envsys *, envsys_data_t *); 59 static void hytp14_refresh_humidity(struct hytp14_sc *, envsys_data_t *); 60 static void hytp14_refresh_temp(struct hytp14_sc *, envsys_data_t *); 61 62 /* #define HYT_DEBUG 3 */ 63 #ifdef HYT_DEBUG 64 volatile int hythygtemp_debug = HYT_DEBUG; 65 66 #define DPRINTF(_L_, _X_) do { \ 67 if ((_L_) <= hythygtemp_debug) { \ 68 printf _X_; \ 69 } \ 70 } while (0) 71 #else 72 #define DPRINTF(_L_, _X_) 73 #endif 74 75 CFATTACH_DECL_NEW(hythygtemp, sizeof(struct hytp14_sc), 76 hytp14_match, hytp14_attach, hytp14_detach, NULL); 77 78 static struct hytp14_sensor hytp14_sensors[] = { 79 { 80 .desc = "humidity", 81 .type = ENVSYS_SRELHUMIDITY, 82 .refresh = hytp14_refresh_humidity 83 }, 84 { 85 .desc = "temperature", 86 .type = ENVSYS_STEMP, 87 .refresh = hytp14_refresh_temp 88 } 89 }; 90 91 static int 92 hytp14_match(device_t parent, cfdata_t match, void *aux) 93 { 94 struct i2c_attach_args *ia = aux; 95 96 if (ia->ia_name) { 97 /* direct config - check name */ 98 if (strcmp(ia->ia_name, "hythygtemp") == 0) 99 return 1; 100 } else { 101 /* indirect config - check for configured address */ 102 if ((ia->ia_addr > 0) && (ia->ia_addr <= 0x7F)) 103 return 1; 104 } 105 return 0; 106 } 107 108 static void 109 hytp14_attach(device_t parent, device_t self, void *aux) 110 { 111 struct hytp14_sc *sc = device_private(self); 112 struct i2c_attach_args *ia = aux; 113 int i; 114 115 sc->sc_dev = self; 116 sc->sc_tag = ia->ia_tag; 117 sc->sc_addr = ia->ia_addr; 118 sc->sc_refresh = 0; 119 sc->sc_valid = ENVSYS_SINVALID; 120 sc->sc_numsensors = __arraycount(hytp14_sensors); 121 122 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 123 aprint_error_dev(sc->sc_dev, 124 "unable to create sysmon structure\n"); 125 return; 126 } 127 128 for (i = 0; i < sc->sc_numsensors; i++) { 129 strlcpy(sc->sc_sensors[i].desc, 130 hytp14_sensors[i].desc, 131 sizeof sc->sc_sensors[i].desc); 132 133 sc->sc_sensors[i].units = hytp14_sensors[i].type; 134 sc->sc_sensors[i].state = ENVSYS_SINVALID; 135 136 DPRINTF(2, ("hytp14_attach: registering sensor %d (%s)\n", i, 137 sc->sc_sensors[i].desc)); 138 139 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i])) { 140 aprint_error_dev(sc->sc_dev, 141 "unable to attach sensor\n"); 142 sysmon_envsys_destroy(sc->sc_sme); 143 return; 144 } 145 } 146 147 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 148 sc->sc_sme->sme_cookie = sc; 149 sc->sc_sme->sme_refresh = hytp14_refresh; 150 151 DPRINTF(2, ("hytp14_attach: registering with envsys\n")); 152 153 if (sysmon_envsys_register(sc->sc_sme)) { 154 aprint_error_dev(sc->sc_dev, 155 "unable to register with sysmon\n"); 156 sysmon_envsys_destroy(sc->sc_sme); 157 return; 158 } 159 160 aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); 161 } 162 163 static int hytp14_detach(device_t self, int flags) 164 { 165 struct hytp14_sc *sc = device_private(self); 166 167 if (sc->sc_sme != NULL) { 168 sysmon_envsys_unregister(sc->sc_sme); 169 sc->sc_sme = NULL; 170 } 171 172 return 0; 173 } 174 175 static int 176 hytp14_refresh_sensor(struct hytp14_sc *sc) 177 { 178 int error = 0; 179 uint8_t buf[I2C_EXEC_MAX_BUFLEN]; 180 181 /* no more than once per second */ 182 if (hardclock_ticks - sc->sc_refresh < hz) 183 return sc->sc_valid; 184 185 DPRINTF(2, ("hytp14_refresh_sensor(%s)\n", device_xname(sc->sc_dev))); 186 187 if ((error = iic_acquire_bus(sc->sc_tag, 0)) == 0) { 188 DPRINTF(3, ("hytp14_refresh_sensor(%s): bus locked\n", device_xname(sc->sc_dev))); 189 190 /* send MR command */ 191 /* avoid quick read/write by providing a result buffer */ 192 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 193 sc->sc_addr, NULL, 0, buf, sizeof buf, 0); 194 if (error == 0) { 195 DPRINTF(3, ("hytp14_refresh_sensor(%s): MR sent\n", 196 device_xname(sc->sc_dev))); 197 198 /* send DF command - read data from sensor */ 199 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 200 sc->sc_addr, NULL, 0, sc->sc_data, 201 sizeof sc->sc_data, 0); 202 if (error != 0) { 203 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 204 device_xname(sc->sc_dev), 205 __func__, sc->sc_addr, error)); 206 } else { 207 DPRINTF(2, ("hytp14_refresh_sensor(%s): DF success : 0x%02x%02x%02x%02x\n", 208 device_xname(sc->sc_dev), 209 sc->sc_data[0], 210 sc->sc_data[1], 211 sc->sc_data[2], 212 sc->sc_data[3])); 213 } 214 } else { 215 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 216 device_xname(sc->sc_dev), __func__, 217 sc->sc_addr, error)); 218 } 219 220 iic_release_bus(sc->sc_tag, 0); 221 DPRINTF(3, ("hytp14_refresh_sensor(%s): bus released\n", device_xname(sc->sc_dev))); 222 } else { 223 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 224 device_xname(sc->sc_dev), __func__, sc->sc_addr, error)); 225 } 226 227 sc->sc_refresh = hardclock_ticks; 228 229 /* skip data if sensor is in command mode */ 230 if (error == 0 && (sc->sc_data[0] & HYTP14_RESP_CMDMODE) == 0) { 231 sc->sc_valid = ENVSYS_SVALID; 232 } else { 233 sc->sc_valid = ENVSYS_SINVALID; 234 } 235 236 return sc->sc_valid; 237 } 238 239 240 static void 241 hytp14_refresh_humidity(struct hytp14_sc *sc, envsys_data_t *edata) 242 { 243 uint16_t hyg; 244 int status; 245 246 status = hytp14_refresh_sensor(sc); 247 248 if (status == ENVSYS_SVALID) { 249 hyg = (sc->sc_data[0] << 8) | sc->sc_data[1]; 250 251 edata->value_cur = (1000000000 / HYTP14_HYG_SCALE) * (int32_t)HYTP14_HYG_RAWVAL(hyg); 252 edata->value_cur /= 10; 253 } 254 255 edata->state = status; 256 } 257 258 static void 259 hytp14_refresh_temp(struct hytp14_sc *sc, envsys_data_t *edata) 260 { 261 uint16_t temp; 262 int status; 263 264 status = hytp14_refresh_sensor(sc); 265 266 if (status == ENVSYS_SVALID) { 267 temp = HYTP14_TEMP_RAWVAL((sc->sc_data[2] << 8) | sc->sc_data[3]); 268 269 edata->value_cur = (HYTP14_TEMP_FACTOR * 1000000) / HYTP14_TEMP_SCALE; 270 edata->value_cur *= (int32_t)temp; 271 edata->value_cur += HYTP14_TEMP_OFFSET * 1000000 + 273150000; 272 } 273 274 edata->state = status; 275 } 276 277 static void 278 hytp14_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 279 { 280 struct hytp14_sc *sc = sme->sme_cookie; 281 282 hytp14_sensors[edata->sensor].refresh(sc, edata); 283 } 284 285 286 MODULE(MODULE_CLASS_DRIVER, hythygtemp, "iic"); 287 288 #ifdef _MODULE 289 #include "ioconf.c" 290 #endif 291 292 static int 293 hythygtemp_modcmd(modcmd_t cmd, void *opaque) 294 { 295 int error = 0; 296 297 switch (cmd) { 298 case MODULE_CMD_INIT: 299 #ifdef _MODULE 300 error = config_init_component(cfdriver_ioconf_hythygtemp, 301 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 302 #endif 303 return error; 304 305 case MODULE_CMD_FINI: 306 #ifdef _MODULE 307 error = config_fini_component(cfdriver_ioconf_hythygtemp, 308 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 309 #endif 310 return error; 311 312 default: 313 return ENOTTY; 314 } 315 } 316