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