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