Home | History | Annotate | Line # | Download | only in i2c
hytp14.c revision 1.2.6.3
      1 /*-
      2  * Copyright (c) 2014,2016 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.6.3 2017/12/03 11:37:02 jdolecek 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 #include <sys/sysctl.h>
     48 #include <sys/mutex.h>
     49 #include <sys/condvar.h>
     50 #include <sys/kthread.h>
     51 
     52 #include <dev/sysmon/sysmonvar.h>
     53 #include <dev/i2c/i2cvar.h>
     54 #include <dev/i2c/hytp14reg.h>
     55 #include <dev/i2c/hytp14var.h>
     56 
     57 static int hytp14_match(device_t, cfdata_t, void *);
     58 static void hytp14_attach(device_t, device_t, void *);
     59 static int hytp14_detach(device_t, int);
     60 static void hytp14_measurement_request(void *);
     61 static int hytp14_refresh_sensor(struct hytp14_sc *sc);
     62 static void hytp14_refresh(struct sysmon_envsys *, envsys_data_t *);
     63 static void hytp14_refresh_humidity(struct hytp14_sc *, envsys_data_t *);
     64 static void hytp14_refresh_temp(struct hytp14_sc *, envsys_data_t *);
     65 static void hytp14_thread(void *);
     66 static int sysctl_hytp14_interval(SYSCTLFN_ARGS);
     67 
     68 /* #define HYT_DEBUG 3 */
     69 
     70 #ifdef HYT_DEBUG
     71 volatile int hythygtemp_debug = HYT_DEBUG;
     72 
     73 #define DPRINTF(_L_, _X_) do {			\
     74 	  if ((_L_) <= hythygtemp_debug) {	\
     75 	    printf _X_;				\
     76 	  }                                     \
     77         } while (0)
     78 #else
     79 #define DPRINTF(_L_, _X_)
     80 #endif
     81 
     82 CFATTACH_DECL_NEW(hythygtemp, sizeof(struct hytp14_sc),
     83     hytp14_match, hytp14_attach, hytp14_detach, NULL);
     84 
     85 static struct hytp14_sensor hytp14_sensors[] = {
     86 	{
     87 		.desc = "humidity",
     88 		.type = ENVSYS_SRELHUMIDITY,
     89 		.refresh = hytp14_refresh_humidity
     90 	},
     91 	{
     92 		.desc = "temperature",
     93 		.type = ENVSYS_STEMP,
     94 		.refresh = hytp14_refresh_temp
     95 	}
     96 };
     97 
     98 static int
     99 hytp14_match(device_t parent, cfdata_t match, void *aux)
    100 {
    101 	struct i2c_attach_args *ia;
    102 
    103 	ia = aux;
    104 
    105 	if (ia->ia_name) {
    106 		/* direct config - check name */
    107 		if (strcmp(ia->ia_name, "hythygtemp") == 0)
    108 			return 1;
    109 	} else {
    110 		/* indirect config - check for configured address */
    111 		if ((ia->ia_addr > 0) && (ia->ia_addr <= 0x7F))
    112 			return 1;
    113 	}
    114 	return 0;
    115 }
    116 
    117 static void
    118 hytp14_attach(device_t parent, device_t self, void *aux)
    119 {
    120 	const struct sysctlnode *rnode, *node;
    121 	struct hytp14_sc *sc;
    122 	struct i2c_attach_args *ia;
    123 	int i, rv;
    124 
    125 	ia = aux;
    126 	sc = device_private(self);
    127 
    128 	sc->sc_dev = self;
    129 	sc->sc_tag = ia->ia_tag;
    130 	sc->sc_addr = ia->ia_addr;
    131 
    132 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
    133 	cv_init(&sc->sc_condvar, "hytcv");
    134 
    135 	sc->sc_state = HYTP14_THR_INIT;
    136 
    137 	sc->sc_valid = ENVSYS_SINVALID;
    138 	sc->sc_numsensors = __arraycount(hytp14_sensors);
    139 
    140 	if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
    141 		aprint_error_dev(sc->sc_dev,
    142 		    "unable to create sysmon structure\n");
    143 		return;
    144 	}
    145 
    146 	for (i = 0; i < sc->sc_numsensors; i++) {
    147 		strlcpy(sc->sc_sensors[i].desc,
    148 			hytp14_sensors[i].desc,
    149 			sizeof sc->sc_sensors[i].desc);
    150 
    151 		sc->sc_sensors[i].units = hytp14_sensors[i].type;
    152 		sc->sc_sensors[i].state = ENVSYS_SINVALID;
    153 
    154 		DPRINTF(2, ("hytp14_attach: registering sensor %d (%s)\n", i,
    155 		    sc->sc_sensors[i].desc));
    156 
    157 		if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i])) {
    158 			aprint_error_dev(sc->sc_dev,
    159 			    "unable to attach sensor\n");
    160 			sysmon_envsys_destroy(sc->sc_sme);
    161 			return;
    162 		}
    163 	}
    164 
    165 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
    166 	sc->sc_sme->sme_cookie = sc;
    167 	sc->sc_sme->sme_refresh = hytp14_refresh;
    168 
    169 	DPRINTF(2, ("hytp14_attach: registering with envsys\n"));
    170 
    171 	if (sysmon_envsys_register(sc->sc_sme)) {
    172 		aprint_error_dev(sc->sc_dev,
    173 		    "unable to register with sysmon\n");
    174 		sysmon_envsys_destroy(sc->sc_sme);
    175 		return;
    176 	}
    177 
    178 	/* create a sysctl node for setting the measurement interval */
    179 	rnode = node = NULL;
    180 	sysctl_createv(NULL, 0, NULL, &rnode,
    181 	    CTLFLAG_READWRITE,
    182 	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
    183 	    NULL, 0, NULL, 0,
    184 	    CTL_HW, CTL_CREATE, CTL_EOL);
    185 
    186 	if (rnode != NULL)
    187 		sysctl_createv(NULL, 0, NULL, &node,
    188 		    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
    189 		    CTLTYPE_INT, "interval",
    190 		    SYSCTL_DESCR("Sensor sampling interval in seconds"),
    191 		    sysctl_hytp14_interval, 0, (void *)sc, 0,
    192 		    CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL);
    193 
    194 
    195 	/* set up the default measurement interval for worker thread */
    196 	sc->sc_mrinterval = HYTP14_MR_INTERVAL;
    197 
    198 	/* create worker kthread */
    199 	rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL,
    200 			    hytp14_thread, sc, &sc->sc_thread,
    201 			    "%s", device_xname(sc->sc_dev));
    202 	if (rv)
    203 	  aprint_error_dev(self, "unable to create intr thread\n");
    204 
    205 	aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n");
    206 }
    207 
    208 static int
    209 hytp14_detach(device_t self, int flags)
    210 {
    211 	struct hytp14_sc *sc;
    212 
    213 	sc = device_private(self);
    214 
    215 	if (sc->sc_sme != NULL) {
    216 		sysmon_envsys_unregister(sc->sc_sme);
    217 		sc->sc_sme = NULL;
    218 	}
    219 
    220 	/* stop measurement thread */
    221 	mutex_enter(&sc->sc_mutex);
    222 	sc->sc_state = HYTP14_THR_STOP;
    223 	cv_signal(&sc->sc_condvar);
    224 	mutex_exit(&sc->sc_mutex);
    225 
    226 	/* await thread completion */
    227 	kthread_join(sc->sc_thread);
    228 
    229 	/* cleanup */
    230 	cv_destroy(&sc->sc_condvar);
    231 	mutex_destroy(&sc->sc_mutex);
    232 
    233 	return 0;
    234 }
    235 
    236 static void
    237 hytp14_thread(void *aux)
    238 {
    239 	struct hytp14_sc *sc = aux;
    240 	int rv;
    241 
    242 	mutex_enter(&sc->sc_mutex);
    243 
    244 	DPRINTF(2, ("%s(%s): thread start - state=%d\n",
    245 		    __func__, device_xname(sc->sc_dev),
    246 		    sc->sc_state));
    247 
    248 	while (sc->sc_state != HYTP14_THR_STOP) {
    249 		sc->sc_state = HYTP14_THR_RUN;
    250 
    251 		DPRINTF(2, ("%s(%s): waiting %d seconds\n",
    252 			    __func__, device_xname(sc->sc_dev),
    253 				sc->sc_mrinterval));
    254 
    255 		rv = cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz * sc->sc_mrinterval);
    256 
    257 		if (rv == EWOULDBLOCK) {
    258 			/* timeout - run measurement */
    259 			DPRINTF(2, ("%s(%s): timeout -> measurement\n",
    260 				    __func__, device_xname(sc->sc_dev)));
    261 
    262 			hytp14_measurement_request(sc);
    263 		} else {
    264 			DPRINTF(2, ("%s(%s): condvar signalled - state=%d\n",
    265 				    __func__, device_xname(sc->sc_dev),
    266 				    sc->sc_state));
    267 		}
    268 	}
    269 
    270 	mutex_exit(&sc->sc_mutex);
    271 
    272 	DPRINTF(2, ("%s(%s): thread exit\n",
    273 		    __func__, device_xname(sc->sc_dev)));
    274 
    275 	kthread_exit(0);
    276 }
    277 
    278 static void
    279 hytp14_measurement_request(void *aux)
    280 {
    281 	uint8_t buf[I2C_EXEC_MAX_BUFLEN];
    282 	struct hytp14_sc *sc;
    283 	int error;
    284 
    285 	sc = aux;
    286 	DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev)));
    287 
    288 	error = iic_acquire_bus(sc->sc_tag, 0);
    289 	if (error == 0) {
    290 
    291 		/* send DF command - read last data from sensor */
    292 		error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
    293 		    sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0);
    294 		if (error != 0) {
    295 			DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n",
    296 			    device_xname(sc->sc_dev), __func__,
    297 			    sc->sc_addr, error));
    298 			sc->sc_valid = ENVSYS_SINVALID;
    299 		} else {
    300 			DPRINTF(3, ("%s(%s): DF success : "
    301 			    "0x%02x%02x%02x%02x\n",
    302 			    __func__, device_xname(sc->sc_dev),
    303 			    sc->sc_data[0], sc->sc_data[1],
    304 			    sc->sc_data[2], sc->sc_data[3]));
    305 
    306 			/* remember last data, when valid */
    307 			if (!(sc->sc_data[0] &
    308 			    (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) {
    309 				memcpy(sc->sc_last, sc->sc_data,
    310 				    sizeof(sc->sc_last));
    311 				sc->sc_valid = ENVSYS_SVALID;
    312 			}
    313 		}
    314 
    315 		/* send MR command to request a new measurement */
    316 		error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
    317 		    sc->sc_addr, NULL, 0, buf, sizeof(buf), 0);
    318 
    319                 if (error == 0) {
    320 			DPRINTF(3, ("%s(%s): MR sent\n",
    321 			    __func__, device_xname(sc->sc_dev)));
    322 		} else {
    323 			DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n",
    324 			    device_xname(sc->sc_dev), __func__,
    325 			    sc->sc_addr, error));
    326 		}
    327 
    328 		iic_release_bus(sc->sc_tag, 0);
    329 		DPRINTF(3, ("%s(%s): bus released\n",
    330 		    __func__, device_xname(sc->sc_dev)));
    331 	} else {
    332 		DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n",
    333 		    device_xname(sc->sc_dev), __func__, error));
    334 	}
    335 }
    336 
    337 static int
    338 hytp14_refresh_sensor(struct hytp14_sc *sc)
    339 {
    340 	int error;
    341 
    342 	DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev)));
    343 
    344 	error = iic_acquire_bus(sc->sc_tag, 0);
    345 	if (error == 0) {
    346 
    347 		/* send DF command - read last data from sensor */
    348 		error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
    349 		    sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0);
    350 		if (error != 0) {
    351 			DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n",
    352 			    device_xname(sc->sc_dev), __func__,
    353 			    sc->sc_addr, error));
    354 			sc->sc_valid = ENVSYS_SINVALID;
    355 		} else {
    356 			DPRINTF(3, ("%s(%s): DF success : "
    357 			    "0x%02x%02x%02x%02x\n",
    358 			    __func__, device_xname(sc->sc_dev),
    359 			    sc->sc_data[0], sc->sc_data[1],
    360 			    sc->sc_data[2], sc->sc_data[3]));
    361 
    362 			/*
    363 			 * Use old data from sc_last[] when new data
    364 			 * is not yet valid (i.e. DF command came too
    365 			 * quickly after the last command).
    366 			 */
    367 			if (!(sc->sc_data[0] &
    368 			    (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) {
    369 				memcpy(sc->sc_last, sc->sc_data,
    370 				    sizeof(sc->sc_last));
    371 				sc->sc_valid = ENVSYS_SVALID;
    372 			} else
    373 				memcpy(sc->sc_data, sc->sc_last,
    374 				    sizeof(sc->sc_data));
    375 		}
    376 
    377 		iic_release_bus(sc->sc_tag, 0);
    378 		DPRINTF(3, ("%s(%s): bus released\n",
    379 		    __func__, device_xname(sc->sc_dev)));
    380 	} else {
    381 		DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n",
    382 		    device_xname(sc->sc_dev), __func__, error));
    383 	}
    384 
    385 	return sc->sc_valid;
    386 }
    387 
    388 
    389 static void
    390 hytp14_refresh_humidity(struct hytp14_sc *sc, envsys_data_t *edata)
    391 {
    392 	uint16_t hyg;
    393 	int status;
    394 
    395 	status = hytp14_refresh_sensor(sc);
    396 
    397 	if (status == ENVSYS_SVALID) {
    398 		hyg = (sc->sc_data[0] << 8) | sc->sc_data[1];
    399 
    400 		edata->value_cur = (1000000000 / HYTP14_HYG_SCALE) * (int32_t)HYTP14_HYG_RAWVAL(hyg);
    401 		edata->value_cur /= 10;
    402 	}
    403 
    404 	edata->state = status;
    405 }
    406 
    407 static void
    408 hytp14_refresh_temp(struct hytp14_sc *sc, envsys_data_t *edata)
    409 {
    410 	uint16_t temp;
    411 	int status;
    412 
    413 	status = hytp14_refresh_sensor(sc);
    414 
    415 	if (status == ENVSYS_SVALID) {
    416 		temp = HYTP14_TEMP_RAWVAL((sc->sc_data[2] << 8) | sc->sc_data[3]);
    417 
    418 		edata->value_cur = (HYTP14_TEMP_FACTOR * 1000000) / HYTP14_TEMP_SCALE;
    419 		edata->value_cur *= (int32_t)temp;
    420 		edata->value_cur += HYTP14_TEMP_OFFSET * 1000000 + 273150000;
    421 	}
    422 
    423 	edata->state = status;
    424 }
    425 
    426 static void
    427 hytp14_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    428 {
    429 	struct hytp14_sc *sc;
    430 
    431 	sc = sme->sme_cookie;
    432 	hytp14_sensors[edata->sensor].refresh(sc, edata);
    433 }
    434 
    435 static int
    436 sysctl_hytp14_interval(SYSCTLFN_ARGS)
    437 {
    438 	struct sysctlnode node;
    439 	struct hytp14_sc *sc;
    440 	int32_t t;
    441 	int error;
    442 
    443 	node = *rnode;
    444 	sc = node.sysctl_data;
    445 
    446 	t = sc->sc_mrinterval;
    447 	node.sysctl_data = &t;
    448 
    449 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    450 	if (error || newp == NULL)
    451 		return error;
    452 	if (t <= 0)
    453 		return EINVAL;
    454 
    455 	sc->sc_mrinterval = t;
    456 	return 0;
    457 }
    458 
    459 MODULE(MODULE_CLASS_DRIVER, hythygtemp, "i2cexec,sysmon_envsys");
    460 
    461 #ifdef _MODULE
    462 #include "ioconf.c"
    463 #endif
    464 
    465 static int
    466 hythygtemp_modcmd(modcmd_t cmd, void *opaque)
    467 {
    468 	int error;
    469 
    470 	error = 0;
    471 
    472 	switch (cmd) {
    473 	case MODULE_CMD_INIT:
    474 #ifdef _MODULE
    475 		error = config_init_component(cfdriver_ioconf_hythygtemp,
    476 		    cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp);
    477 #endif
    478 		return error;
    479 
    480 	case MODULE_CMD_FINI:
    481 #ifdef _MODULE
    482 		error = config_fini_component(cfdriver_ioconf_hythygtemp,
    483 		    cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp);
    484 #endif
    485 		return error;
    486 
    487 	default:
    488 		return ENOTTY;
    489 	}
    490 }
    491