Home | History | Annotate | Line # | Download | only in i2c
sht3x.c revision 1.2
      1  1.2  christos /*	$NetBSD: sht3x.c,v 1.2 2021/11/12 22:16:27 christos Exp $	*/
      2  1.1      brad 
      3  1.1      brad /*
      4  1.1      brad  * Copyright (c) 2021 Brad Spencer <brad (at) anduin.eldar.org>
      5  1.1      brad  *
      6  1.1      brad  * Permission to use, copy, modify, and distribute this software for any
      7  1.1      brad  * purpose with or without fee is hereby granted, provided that the above
      8  1.1      brad  * copyright notice and this permission notice appear in all copies.
      9  1.1      brad  *
     10  1.1      brad  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  1.1      brad  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  1.1      brad  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  1.1      brad  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  1.1      brad  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  1.1      brad  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16  1.1      brad  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  1.1      brad  */
     18  1.1      brad 
     19  1.1      brad #include <sys/cdefs.h>
     20  1.2  christos __KERNEL_RCSID(0, "$NetBSD: sht3x.c,v 1.2 2021/11/12 22:16:27 christos Exp $");
     21  1.1      brad 
     22  1.1      brad /*
     23  1.1      brad   Driver for the Sensirion SHT30/SHT31/SHT35
     24  1.1      brad */
     25  1.1      brad 
     26  1.1      brad #include <sys/param.h>
     27  1.1      brad #include <sys/systm.h>
     28  1.1      brad #include <sys/kernel.h>
     29  1.1      brad #include <sys/device.h>
     30  1.1      brad #include <sys/module.h>
     31  1.1      brad #include <sys/conf.h>
     32  1.1      brad #include <sys/sysctl.h>
     33  1.1      brad #include <sys/mutex.h>
     34  1.1      brad #include <sys/condvar.h>
     35  1.1      brad #include <sys/kthread.h>
     36  1.1      brad #include <sys/pool.h>
     37  1.1      brad #include <sys/kmem.h>
     38  1.1      brad 
     39  1.1      brad #include <dev/sysmon/sysmonvar.h>
     40  1.1      brad #include <dev/i2c/i2cvar.h>
     41  1.1      brad #include <dev/i2c/sht3xreg.h>
     42  1.1      brad #include <dev/i2c/sht3xvar.h>
     43  1.1      brad 
     44  1.1      brad 
     45  1.1      brad static int	sht3x_take_break(void *, bool);
     46  1.1      brad static int	sht3x_get_status_register(void *, uint16_t *, bool);
     47  1.1      brad static int	sht3x_clear_status_register(void *, bool);
     48  1.1      brad static uint8_t 	sht3x_crc(uint8_t *, size_t);
     49  1.1      brad static int	sht3x_cmdr(struct sht3x_sc *, uint16_t, uint8_t *, size_t);
     50  1.1      brad static int 	sht3x_poke(i2c_tag_t, i2c_addr_t, bool);
     51  1.1      brad static int 	sht3x_match(device_t, cfdata_t, void *);
     52  1.1      brad static void 	sht3x_attach(device_t, device_t, void *);
     53  1.1      brad static int 	sht3x_detach(device_t, int);
     54  1.1      brad static void 	sht3x_refresh(struct sysmon_envsys *, envsys_data_t *);
     55  1.1      brad static int 	sht3x_verify_sysctl(SYSCTLFN_ARGS);
     56  1.1      brad static int 	sht3x_verify_sysctl_heateron(SYSCTLFN_ARGS);
     57  1.1      brad static int 	sht3x_verify_sysctl_modes(SYSCTLFN_ARGS);
     58  1.1      brad static int 	sht3x_verify_sysctl_repeatability(SYSCTLFN_ARGS);
     59  1.1      brad static int 	sht3x_verify_sysctl_rate(SYSCTLFN_ARGS);
     60  1.1      brad static int	sht3x_set_heater(struct sht3x_sc *);
     61  1.1      brad static void     sht3x_thread(void *);
     62  1.1      brad static int	sht3x_init_periodic_measurement(void *, int *);
     63  1.1      brad static void     sht3x_take_periodic_measurement(void *);
     64  1.1      brad static void     sht3x_start_thread(void *);
     65  1.1      brad static void     sht3x_stop_thread(void *);
     66  1.1      brad static int	sht3x_activate(device_t, enum devact);
     67  1.1      brad 
     68  1.1      brad #define SHT3X_DEBUG
     69  1.1      brad #ifdef SHT3X_DEBUG
     70  1.1      brad #define DPRINTF(s, l, x) \
     71  1.1      brad     do { \
     72  1.1      brad 	if (l <= s->sc_sht3xdebug) \
     73  1.1      brad 	    printf x; \
     74  1.1      brad     } while (/*CONSTCOND*/0)
     75  1.1      brad #else
     76  1.1      brad #define DPRINTF(s, l, x)
     77  1.1      brad #endif
     78  1.1      brad 
     79  1.1      brad CFATTACH_DECL_NEW(sht3xtemp, sizeof(struct sht3x_sc),
     80  1.1      brad     sht3x_match, sht3x_attach, sht3x_detach, sht3x_activate);
     81  1.1      brad 
     82  1.1      brad extern struct cfdriver sht3xtemp_cd;
     83  1.1      brad 
     84  1.1      brad static dev_type_open(sht3xopen);
     85  1.1      brad static dev_type_read(sht3xread);
     86  1.1      brad static dev_type_close(sht3xclose);
     87  1.1      brad const struct cdevsw sht3x_cdevsw = {
     88  1.1      brad 	.d_open = sht3xopen,
     89  1.1      brad 	.d_close = sht3xclose,
     90  1.1      brad 	.d_read = sht3xread,
     91  1.1      brad 	.d_write = nowrite,
     92  1.1      brad 	.d_ioctl = noioctl,
     93  1.1      brad 	.d_stop = nostop,
     94  1.1      brad 	.d_tty = notty,
     95  1.1      brad 	.d_poll = nopoll,
     96  1.1      brad 	.d_mmap = nommap,
     97  1.1      brad 	.d_kqfilter = nokqfilter,
     98  1.1      brad 	.d_discard = nodiscard,
     99  1.1      brad 	.d_flag = D_OTHER
    100  1.1      brad };
    101  1.1      brad 
    102  1.1      brad static struct sht3x_sensor sht3x_sensors[] = {
    103  1.1      brad 	{
    104  1.1      brad 		.desc = "humidity",
    105  1.1      brad 		.type = ENVSYS_SRELHUMIDITY,
    106  1.1      brad 	},
    107  1.1      brad 	{
    108  1.1      brad 		.desc = "temperature",
    109  1.1      brad 		.type = ENVSYS_STEMP,
    110  1.1      brad 	}
    111  1.1      brad };
    112  1.1      brad 
    113  1.1      brad /* The typical delays are MOSTLY documented in the datasheet for the chip.
    114  1.1      brad    There is no need to be very accurate with these, just rough estimates
    115  1.1      brad    will work fine.
    116  1.1      brad */
    117  1.1      brad 
    118  1.1      brad static struct sht3x_timing sht3x_timings[] = {
    119  1.1      brad 	{
    120  1.1      brad 		.cmd = SHT3X_SOFT_RESET,
    121  1.1      brad 		.typicaldelay = 3000,
    122  1.1      brad 	},
    123  1.1      brad 	{
    124  1.1      brad 		.cmd = SHT3X_GET_STATUS_REGISTER,
    125  1.1      brad 		.typicaldelay = 100,
    126  1.1      brad 	},
    127  1.1      brad 	{
    128  1.1      brad 		.cmd = SHT3X_BREAK,
    129  1.1      brad 		.typicaldelay = 100,
    130  1.1      brad 	},
    131  1.1      brad 	{
    132  1.1      brad 		.cmd = SHT3X_CLEAR_STATUS_REGISTER,
    133  1.1      brad 		.typicaldelay = 100,
    134  1.1      brad 	},
    135  1.1      brad 	{
    136  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_CS_HIGH,
    137  1.1      brad 		.typicaldelay = 15000,
    138  1.1      brad 	},
    139  1.1      brad 	{
    140  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_CS_MEDIUM,
    141  1.1      brad 		.typicaldelay = 6000,
    142  1.1      brad 	},
    143  1.1      brad 	{
    144  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_CS_LOW,
    145  1.1      brad 		.typicaldelay = 4000,
    146  1.1      brad 	},
    147  1.1      brad 	{
    148  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_HIGH,
    149  1.1      brad 		.typicaldelay = 15000,
    150  1.1      brad 	},
    151  1.1      brad 	{
    152  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_MEDIUM,
    153  1.1      brad 		.typicaldelay = 6000,
    154  1.1      brad 	},
    155  1.1      brad 	{
    156  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_LOW,
    157  1.1      brad 		.typicaldelay = 4000,
    158  1.1      brad 	},
    159  1.1      brad 	{
    160  1.1      brad 		.cmd = SHT3X_WRITE_HIGH_ALERT_SET,
    161  1.1      brad 		.typicaldelay = 5000,
    162  1.1      brad 	},
    163  1.1      brad 	{
    164  1.1      brad 		.cmd = SHT3X_WRITE_HIGH_ALERT_CLEAR,
    165  1.1      brad 		.typicaldelay = 5000,
    166  1.1      brad 	},
    167  1.1      brad 	{
    168  1.1      brad 		.cmd = SHT3X_WRITE_LOW_ALERT_SET,
    169  1.1      brad 		.typicaldelay = 5000,
    170  1.1      brad 	},
    171  1.1      brad 	{
    172  1.1      brad 		.cmd = SHT3X_WRITE_LOW_ALERT_CLEAR,
    173  1.1      brad 		.typicaldelay = 5000,
    174  1.1      brad 	}
    175  1.1      brad };
    176  1.1      brad 
    177  1.1      brad /* In single shot mode, find the command */
    178  1.1      brad 
    179  1.1      brad static struct sht3x_repeatability sht3x_repeatability_ss[] = {
    180  1.1      brad 	{
    181  1.1      brad 		.text = "high",
    182  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_HIGH,
    183  1.1      brad 	},
    184  1.1      brad 	{
    185  1.1      brad 		.text = "medium",
    186  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_MEDIUM,
    187  1.1      brad 	},
    188  1.1      brad 	{
    189  1.1      brad 		.text = "low",
    190  1.1      brad 		.cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_LOW,
    191  1.1      brad 	}
    192  1.1      brad };
    193  1.1      brad 
    194  1.1      brad 
    195  1.1      brad /* For periodic, look at the repeatability and the rate.
    196  1.1      brad  * ART is a bit fake here, as the repeatability is not really
    197  1.1      brad  * used.
    198  1.1      brad  */
    199  1.1      brad 
    200  1.1      brad static struct sht3x_periodic sht3x_periodic_rate[] = {
    201  1.1      brad 	{
    202  1.1      brad 		.repeatability = "high",
    203  1.1      brad 		.rate = "0.5mps",
    204  1.1      brad 		.sdelay = 1000,
    205  1.1      brad 		.cmd = SHT3X_HALF_MPS_HIGH,
    206  1.1      brad 	},
    207  1.1      brad 	{
    208  1.1      brad 		.repeatability = "medium",
    209  1.1      brad 		.rate = "0.5mps",
    210  1.1      brad 		.sdelay = 1000,
    211  1.1      brad 		.cmd = SHT3X_HALF_MPS_MEDIUM,
    212  1.1      brad 	},
    213  1.1      brad 	{
    214  1.1      brad 		.repeatability = "low",
    215  1.1      brad 		.rate = "0.5mps",
    216  1.1      brad 		.sdelay = 1000,
    217  1.1      brad 		.cmd = SHT3X_HALF_MPS_LOW,
    218  1.1      brad 	},
    219  1.1      brad 	{
    220  1.1      brad 		.repeatability = "high",
    221  1.1      brad 		.rate = "1.0mps",
    222  1.1      brad 		.sdelay = 500,
    223  1.1      brad 		.cmd = SHT3X_ONE_MPS_HIGH,
    224  1.1      brad 	},
    225  1.1      brad 	{
    226  1.1      brad 		.repeatability = "medium",
    227  1.1      brad 		.rate = "1.0mps",
    228  1.1      brad 		.sdelay = 500,
    229  1.1      brad 		.cmd = SHT3X_ONE_MPS_MEDIUM,
    230  1.1      brad 	},
    231  1.1      brad 	{
    232  1.1      brad 		.repeatability = "low",
    233  1.1      brad 		.rate = "1.0mps",
    234  1.1      brad 		.sdelay = 500,
    235  1.1      brad 		.cmd = SHT3X_ONE_MPS_LOW,
    236  1.1      brad 	},
    237  1.1      brad 	{
    238  1.1      brad 		.repeatability = "high",
    239  1.1      brad 		.rate = "2.0mps",
    240  1.1      brad 		.sdelay = 250,
    241  1.1      brad 		.cmd = SHT3X_TWO_MPS_HIGH,
    242  1.1      brad 	},
    243  1.1      brad 	{
    244  1.1      brad 		.repeatability = "medium",
    245  1.1      brad 		.rate = "2.0mps",
    246  1.1      brad 		.sdelay = 250,
    247  1.1      brad 		.cmd = SHT3X_TWO_MPS_MEDIUM,
    248  1.1      brad 	},
    249  1.1      brad 	{
    250  1.1      brad 		.repeatability = "low",
    251  1.1      brad 		.rate = "2.0mps",
    252  1.1      brad 		.sdelay = 250,
    253  1.1      brad 		.cmd = SHT3X_TWO_MPS_LOW,
    254  1.1      brad 	},
    255  1.1      brad 	{
    256  1.1      brad 		.repeatability = "high",
    257  1.1      brad 		.rate = "4.0mps",
    258  1.1      brad 		.sdelay = 100,
    259  1.1      brad 		.cmd = SHT3X_FOUR_MPS_HIGH,
    260  1.1      brad 	},
    261  1.1      brad 	{
    262  1.1      brad 		.repeatability = "medium",
    263  1.1      brad 		.rate = "4.0mps",
    264  1.1      brad 		.sdelay = 100,
    265  1.1      brad 		.cmd = SHT3X_FOUR_MPS_MEDIUM,
    266  1.1      brad 	},
    267  1.1      brad 	{
    268  1.1      brad 		.repeatability = "low",
    269  1.1      brad 		.rate = "4.0mps",
    270  1.1      brad 		.sdelay = 100,
    271  1.1      brad 		.cmd = SHT3X_FOUR_MPS_LOW,
    272  1.1      brad 	},
    273  1.1      brad 	{
    274  1.1      brad 		.repeatability = "high",
    275  1.1      brad 		.rate = "10.0mps",
    276  1.1      brad 		.sdelay = 50,
    277  1.1      brad 		.cmd = SHT3X_TEN_MPS_HIGH,
    278  1.1      brad 	},
    279  1.1      brad 	{
    280  1.1      brad 		.repeatability = "medium",
    281  1.1      brad 		.rate = "10.0mps",
    282  1.1      brad 		.sdelay = 50,
    283  1.1      brad 		.cmd = SHT3X_FOUR_MPS_MEDIUM,
    284  1.1      brad 	},
    285  1.1      brad 	{
    286  1.1      brad 		.repeatability = "low",
    287  1.1      brad 		.rate = "10.0mps",
    288  1.1      brad 		.sdelay = 50,
    289  1.1      brad 		.cmd = SHT3X_FOUR_MPS_LOW,
    290  1.1      brad 	},
    291  1.1      brad 	{
    292  1.1      brad 		.repeatability = "high",
    293  1.1      brad 		.rate = "ART",
    294  1.1      brad 		.sdelay = 100,
    295  1.1      brad 		.cmd = SHT3X_ART_ENABLE,
    296  1.1      brad 	},
    297  1.1      brad 	{
    298  1.1      brad 		.repeatability = "medium",
    299  1.1      brad 		.rate = "ART",
    300  1.1      brad 		.sdelay = 100,
    301  1.1      brad 		.cmd = SHT3X_ART_ENABLE,
    302  1.1      brad 	},
    303  1.1      brad 	{
    304  1.1      brad 		.repeatability = "low",
    305  1.1      brad 		.rate = "ART",
    306  1.1      brad 		.sdelay = 100,
    307  1.1      brad 		.cmd = SHT3X_ART_ENABLE,
    308  1.1      brad 	}
    309  1.1      brad };
    310  1.1      brad 
    311  1.1      brad static const char sht3x_rate_names[] =
    312  1.1      brad     "0.5mps, 1.0mps, 2.0mps, 4.0mps, 10.0mps, ART";
    313  1.1      brad 
    314  1.1      brad static const char sht3x_mode_names[] =
    315  1.1      brad     "single-shot, periodic";
    316  1.1      brad 
    317  1.1      brad static const char sht3x_repeatability_names[] =
    318  1.1      brad     "high, medium, low";
    319  1.1      brad 
    320  1.1      brad static int
    321  1.1      brad sht3x_take_break(void *aux, bool have_bus)
    322  1.1      brad {
    323  1.1      brad 	struct sht3x_sc *sc;
    324  1.1      brad 	sc = aux;
    325  1.1      brad 	int error = 0;
    326  1.1      brad 
    327  1.1      brad 	if (! have_bus) {
    328  1.1      brad 		error = iic_acquire_bus(sc->sc_tag, 0);
    329  1.1      brad 		if (error) {
    330  1.2  christos 			DPRINTF(sc, 2, ("%s: Could not acquire iic bus for "
    331  1.2  christos 			    "breaking %d\n", device_xname(sc->sc_dev), error));
    332  1.1      brad 			goto out;
    333  1.1      brad 		}
    334  1.1      brad 	}
    335  1.1      brad 	error = sht3x_cmdr(sc, SHT3X_BREAK, NULL, 0);
    336  1.1      brad 	if (error) {
    337  1.1      brad 		DPRINTF(sc, 2, ("%s: Error breaking: %d\n",
    338  1.1      brad 		    device_xname(sc->sc_dev), error));
    339  1.1      brad 	}
    340  1.2  christos out:
    341  1.1      brad 	if (! have_bus) {
    342  1.1      brad 		iic_release_bus(sc->sc_tag, 0);
    343  1.1      brad 	}
    344  1.1      brad 
    345  1.1      brad 	sc->sc_isperiodic = false;
    346  1.2  christos 	strlcpy(sc->sc_mode, "single-shot", SHT3X_MODE_NAME);
    347  1.1      brad 
    348  1.1      brad 	return error;
    349  1.1      brad }
    350  1.1      brad 
    351  1.1      brad static int
    352  1.1      brad sht3x_get_status_register(void *aux, uint16_t *reg, bool have_bus)
    353  1.1      brad {
    354  1.2  christos 	struct sht3x_sc *sc = aux;
    355  1.1      brad 	uint8_t buf[3];
    356  1.2  christos 	int error;
    357  1.1      brad 
    358  1.1      brad 	if (! have_bus) {
    359  1.1      brad 		error = iic_acquire_bus(sc->sc_tag, 0);
    360  1.1      brad 		if (error) {
    361  1.2  christos 			DPRINTF(sc, 2, ("%s: Could not acquire iic bus for "
    362  1.2  christos 			    "getting status %d\n", device_xname(sc->sc_dev),
    363  1.2  christos 			    error));
    364  1.2  christos 			return error;
    365  1.1      brad 		}
    366  1.1      brad 	}
    367  1.1      brad 	error = sht3x_cmdr(sc, SHT3X_GET_STATUS_REGISTER, buf, 3);
    368  1.1      brad 	if (error) {
    369  1.1      brad 		DPRINTF(sc, 2, ("%s: Error getting status: %d\n",
    370  1.1      brad 		    device_xname(sc->sc_dev), error));
    371  1.2  christos 		goto out;
    372  1.1      brad 	}
    373  1.2  christos 
    374  1.2  christos 	uint8_t c = sht3x_crc(&buf[0], 2);
    375  1.2  christos 	if (c == buf[2]) {
    376  1.2  christos 		*reg = buf[0] << 8 | buf[1];
    377  1.2  christos 	} else {
    378  1.2  christos 		error = EINVAL;
    379  1.2  christos 	}
    380  1.2  christos out:
    381  1.1      brad 	if (! have_bus) {
    382  1.1      brad 		iic_release_bus(sc->sc_tag, 0);
    383  1.1      brad 	}
    384  1.1      brad 
    385  1.1      brad 	return error;
    386  1.1      brad }
    387  1.1      brad 
    388  1.1      brad static int
    389  1.1      brad sht3x_clear_status_register(void *aux, bool have_bus)
    390  1.1      brad {
    391  1.2  christos 	struct sht3x_sc *sc = aux;
    392  1.2  christos 	int error;
    393  1.1      brad 
    394  1.1      brad 	if (! have_bus) {
    395  1.1      brad 		error = iic_acquire_bus(sc->sc_tag, 0);
    396  1.1      brad 		if (error) {
    397  1.2  christos 			DPRINTF(sc, 2, ("%s: Could not acquire iic bus for "
    398  1.2  christos 			    "clearing status %d\n", device_xname(sc->sc_dev),
    399  1.2  christos 			    error));
    400  1.2  christos 			return error;
    401  1.1      brad 		}
    402  1.1      brad 	}
    403  1.1      brad 	error = sht3x_cmdr(sc, SHT3X_CLEAR_STATUS_REGISTER, NULL, 0);
    404  1.1      brad 	if (error) {
    405  1.1      brad 		DPRINTF(sc, 2, ("%s: Error clear status register: %d\n",
    406  1.1      brad 		    device_xname(sc->sc_dev), error));
    407  1.1      brad 	}
    408  1.1      brad 	if (! have_bus) {
    409  1.1      brad 		iic_release_bus(sc->sc_tag, 0);
    410  1.1      brad 	}
    411  1.1      brad 
    412  1.1      brad 	return error;
    413  1.1      brad }
    414  1.1      brad 
    415  1.1      brad void
    416  1.1      brad sht3x_thread(void *aux)
    417  1.1      brad {
    418  1.1      brad 	struct sht3x_sc *sc = aux;
    419  1.1      brad 	int error, rv;
    420  1.1      brad 	int sdelay = 100;
    421  1.1      brad 
    422  1.1      brad 	mutex_enter(&sc->sc_threadmutex);
    423  1.1      brad 
    424  1.1      brad 	while (!sc->sc_stopping && !sc->sc_dying) {
    425  1.1      brad 		if (sc->sc_initperiodic) {
    426  1.2  christos 			error = sht3x_init_periodic_measurement(sc, &sdelay);
    427  1.1      brad 			if (error) {
    428  1.2  christos 				DPRINTF(sc, 2, ("%s: Error initing periodic "
    429  1.2  christos 				    "measurement in thread: %d\n",
    430  1.2  christos 				    device_xname(sc->sc_dev), error));
    431  1.1      brad 			}
    432  1.1      brad 			sc->sc_initperiodic = false;
    433  1.1      brad 		}
    434  1.1      brad 		rv = cv_timedwait(&sc->sc_condvar, &sc->sc_threadmutex,
    435  1.1      brad 		    mstohz(sdelay));
    436  1.2  christos 		if (rv == EWOULDBLOCK && !sc->sc_stopping &&
    437  1.2  christos 		    !sc->sc_initperiodic && !sc->sc_dying) {
    438  1.1      brad 			sht3x_take_periodic_measurement(sc);
    439  1.1      brad 		}
    440  1.1      brad 	}
    441  1.1      brad 	mutex_exit(&sc->sc_threadmutex);
    442  1.1      brad 	kthread_exit(0);
    443  1.1      brad }
    444  1.1      brad 
    445  1.1      brad int
    446  1.1      brad sht3x_init_periodic_measurement(void *aux, int *sdelay)
    447  1.1      brad {
    448  1.2  christos 	struct sht3x_sc *sc = aux;
    449  1.2  christos 	size_t i;
    450  1.2  christos 	int error;
    451  1.2  christos 	uint16_t r;
    452  1.1      brad 
    453  1.1      brad 	for (i = 0; i < __arraycount(sht3x_periodic_rate); i++) {
    454  1.2  christos 		if (strncmp(sc->sc_repeatability,
    455  1.2  christos 		    sht3x_periodic_rate[i].repeatability, SHT3X_REP_NAME) == 0 &&
    456  1.2  christos 		    strncmp(sc->sc_periodic_rate, sht3x_periodic_rate[i].rate,
    457  1.2  christos 		    SHT3X_RATE_NAME) == 0)
    458  1.2  christos 		{
    459  1.1      brad 			r = sht3x_periodic_rate[i].cmd;
    460  1.1      brad 			*sdelay = sht3x_periodic_rate[i].sdelay;
    461  1.1      brad 			break;
    462  1.1      brad 		}
    463  1.1      brad 	}
    464  1.1      brad 
    465  1.1      brad 	if (i == __arraycount(sht3x_periodic_rate)) {
    466  1.1      brad 		*sdelay = 100;
    467  1.2  christos 		return ENODEV;
    468  1.1      brad 	}
    469  1.1      brad 
    470  1.1      brad 	DPRINTF(sc, 2, ("%s: Would init with: %x\n",
    471  1.1      brad 	    device_xname(sc->sc_dev), r));
    472  1.1      brad 
    473  1.2  christos 	mutex_enter(&sc->sc_mutex);
    474  1.2  christos 
    475  1.2  christos 	error = iic_acquire_bus(sc->sc_tag, 0);
    476  1.2  christos 	if (error) {
    477  1.2  christos 		DPRINTF(sc, 2, ("%s: Could not acquire iic bus for initing: "
    478  1.2  christos 		    " %d\n", device_xname(sc->sc_dev), error));
    479  1.2  christos 		goto out;
    480  1.2  christos 	}
    481  1.1      brad 
    482  1.2  christos 	error = sht3x_take_break(sc, true);
    483  1.2  christos 	if (error) {
    484  1.2  christos 	    DPRINTF(sc, 2, ("%s: Could not acquire iic bus for initing: "
    485  1.2  christos 		" %d\n", device_xname(sc->sc_dev), error));
    486  1.2  christos 	    goto out;
    487  1.2  christos 	}
    488  1.1      brad 
    489  1.2  christos 	error = sht3x_cmdr(sc, r, NULL, 0);
    490  1.2  christos 	if (error) {
    491  1.2  christos 		DPRINTF(sc, 2,
    492  1.2  christos 		    ("%s: Error sending periodic measurement command: %d\n",
    493  1.2  christos 		    device_xname(sc->sc_dev), error));
    494  1.2  christos 		goto out;
    495  1.1      brad 	}
    496  1.1      brad 
    497  1.2  christos 	sc->sc_isperiodic = true;
    498  1.2  christos 	strlcpy(sc->sc_mode, "periodic", SHT3X_MODE_NAME);
    499  1.2  christos 
    500  1.2  christos out:
    501  1.2  christos 	iic_release_bus(sc->sc_tag, 0);
    502  1.2  christos 	mutex_exit(&sc->sc_mutex);
    503  1.1      brad 	return error;
    504  1.1      brad }
    505  1.1      brad 
    506  1.1      brad static void
    507  1.1      brad sht3x_take_periodic_measurement(void *aux)
    508  1.1      brad {
    509  1.2  christos 	struct sht3x_sc *sc = aux;
    510  1.2  christos 	int error;
    511  1.1      brad 	struct sht3x_read_q *pp;
    512  1.2  christos 	uint8_t rawbuf[MAX(sizeof(sc->sc_pbuffer), sizeof(pp->measurement))];
    513  1.2  christos 	uint16_t status_reg;
    514  1.1      brad 
    515  1.1      brad 	mutex_enter(&sc->sc_mutex);
    516  1.1      brad 	error = iic_acquire_bus(sc->sc_tag, 0);
    517  1.1      brad 	if (error) {
    518  1.1      brad 		DPRINTF(sc, 2, ("%s: Could not acquire iic bus for getting "
    519  1.1      brad 		    "periodic data: %d\n", device_xname(sc->sc_dev), error));
    520  1.2  christos 		goto out;
    521  1.2  christos 	}
    522  1.2  christos 
    523  1.2  christos 	error = sht3x_get_status_register(sc, &status_reg, true);
    524  1.2  christos 	if (error) {
    525  1.2  christos 		DPRINTF(sc, 2,
    526  1.2  christos 		    ("%s: Error getting status register periodic: %d\n",
    527  1.2  christos 		    device_xname(sc->sc_dev), error));
    528  1.2  christos 		goto err;
    529  1.2  christos 	}
    530  1.2  christos 
    531  1.2  christos 	if (status_reg & SHT3X_RESET_DETECTED) {
    532  1.2  christos 		aprint_error_dev(sc->sc_dev, "Reset detected in periodic mode. "
    533  1.2  christos 		    "Heater may have been reset.\n");
    534  1.2  christos 		delay(3000);
    535  1.2  christos 		sht3x_take_break(sc, true);
    536  1.2  christos 		sht3x_clear_status_register(sc, true);
    537  1.2  christos 		sc->sc_heateron = status_reg & SHT3X_HEATER_STATUS;
    538  1.2  christos 		sc->sc_initperiodic = true;
    539  1.1      brad 	} else {
    540  1.2  christos 		int data_error = sht3x_cmdr(sc, SHT3X_PERIODIC_FETCH_DATA,
    541  1.2  christos 		    rawbuf, sizeof(rawbuf));
    542  1.2  christos 		/*
    543  1.2  christos 		 * EIO is actually expected if the poll interval is faster
    544  1.2  christos 		 * than the rate that the sensor is set to.  Unfortunally,
    545  1.2  christos 		 * this will also mess with the ability to detect an actual
    546  1.2  christos 		 * problem with the sensor in periodic mode, so we do the best
    547  1.2  christos 		 * we can here.
    548  1.2  christos 		 */
    549  1.2  christos 		if (data_error) {
    550  1.2  christos 			if (data_error != EIO) {
    551  1.2  christos 				DPRINTF(sc, 2, ("%s: Error sending periodic "
    552  1.2  christos 				    "fetch command: %d\n",
    553  1.2  christos 				    device_xname(sc->sc_dev), data_error));
    554  1.1      brad 			}
    555  1.2  christos 			goto err;
    556  1.1      brad 		}
    557  1.2  christos 	}
    558  1.2  christos 
    559  1.2  christos 	iic_release_bus(sc->sc_tag, 0);
    560  1.2  christos 	/*
    561  1.2  christos 	 * If there was no errors from anything then the data should be
    562  1.2  christos 	 * valid.
    563  1.2  christos 	 */
    564  1.2  christos 	DPRINTF(sc, 2, ("%s: Raw periodic: %x%x - %x -- %x%x - %x\n",
    565  1.2  christos 	    device_xname(sc->sc_dev), rawbuf[0], rawbuf[1], rawbuf[2],
    566  1.2  christos 	    rawbuf[3], rawbuf[4], rawbuf[5]));
    567  1.2  christos 	memcpy(sc->sc_pbuffer, rawbuf, sizeof(sc->sc_pbuffer));
    568  1.1      brad 
    569  1.2  christos 	if (sc->sc_opened) {
    570  1.2  christos 		mutex_enter(&sc->sc_read_mutex);
    571  1.2  christos 		pp = pool_cache_get(sc->sc_readpool, PR_NOWAIT);
    572  1.2  christos 		if (pp == NULL) {
    573  1.2  christos 			aprint_error_dev(sc->sc_dev,
    574  1.2  christos 			    "Could not allocate memory for pool read\n");
    575  1.1      brad 		} else {
    576  1.2  christos 			memcpy(pp->measurement, rawbuf, sizeof(pp->measurement));
    577  1.2  christos 			DPRINTF(sc, 4, ("%s: Queue insert\n",
    578  1.2  christos 			    device_xname(sc->sc_dev)));
    579  1.2  christos 			SIMPLEQ_INSERT_HEAD(&sc->sc_read_queue, pp, read_q);
    580  1.1      brad 		}
    581  1.2  christos 		cv_signal(&sc->sc_condreadready);
    582  1.2  christos 		mutex_exit(&sc->sc_read_mutex);
    583  1.1      brad 	}
    584  1.2  christos out:
    585  1.2  christos 	mutex_exit(&sc->sc_mutex);
    586  1.2  christos 	return;
    587  1.2  christos err:
    588  1.2  christos 	/*
    589  1.2  christos 	 * We are only going to worry about errors when it was not related
    590  1.2  christos 	 * to actually getting data.  That is a likely indicator of a problem
    591  1.2  christos 	 * with the sensor.
    592  1.2  christos 	 */
    593  1.2  christos 	DPRINTF(sc, 2, ("%s: Raw periodic with error: %x%x - %x -- "
    594  1.2  christos 	    "%x%x - %x -- %d\n", device_xname(sc->sc_dev), rawbuf[0], rawbuf[1],
    595  1.2  christos 	    rawbuf[2], rawbuf[3], rawbuf[4], rawbuf[5], error));
    596  1.2  christos 	iic_release_bus(sc->sc_tag, 0);
    597  1.2  christos 	memcpy(sc->sc_pbuffer, "dedbef", sizeof(sc->sc_pbuffer));
    598  1.1      brad 	mutex_exit(&sc->sc_mutex);
    599  1.1      brad }
    600  1.1      brad 
    601  1.1      brad static void
    602  1.1      brad sht3x_stop_thread(void *aux)
    603  1.1      brad {
    604  1.1      brad 	struct sht3x_sc *sc;
    605  1.1      brad 	sc = aux;
    606  1.1      brad 
    607  1.1      brad 	if (!sc->sc_isperiodic) {
    608  1.1      brad 		return;
    609  1.1      brad 	}
    610  1.1      brad 
    611  1.1      brad 	mutex_enter(&sc->sc_threadmutex);
    612  1.1      brad 	sc->sc_stopping = true;
    613  1.1      brad 	cv_signal(&sc->sc_condvar);
    614  1.1      brad 	mutex_exit(&sc->sc_threadmutex);
    615  1.1      brad 
    616  1.1      brad 	/* wait for the thread to exit */
    617  1.1      brad 	kthread_join(sc->sc_thread);
    618  1.1      brad 
    619  1.1      brad 	mutex_enter(&sc->sc_mutex);
    620  1.1      brad 	sht3x_take_break(sc,false);
    621  1.1      brad 	mutex_exit(&sc->sc_mutex);
    622  1.1      brad }
    623  1.1      brad 
    624  1.1      brad static void
    625  1.1      brad sht3x_start_thread(void *aux)
    626  1.1      brad {
    627  1.1      brad 	struct sht3x_sc *sc;
    628  1.1      brad 	sc = aux;
    629  1.1      brad 	int error;
    630  1.1      brad 
    631  1.1      brad 	error = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL,
    632  1.1      brad 	    sht3x_thread, sc, &sc->sc_thread, "%s", device_xname(sc->sc_dev));
    633  1.1      brad 	if (error) {
    634  1.1      brad 		DPRINTF(sc, 2, ("%s: Unable to create measurement thread: %d\n",
    635  1.1      brad 		    device_xname(sc->sc_dev), error));
    636  1.1      brad 	}
    637  1.1      brad }
    638  1.1      brad 
    639  1.1      brad int
    640  1.1      brad sht3x_verify_sysctl(SYSCTLFN_ARGS)
    641  1.1      brad {
    642  1.1      brad 	int error, t;
    643  1.1      brad 	struct sysctlnode node;
    644  1.1      brad 
    645  1.1      brad 	node = *rnode;
    646  1.1      brad 	t = *(int *)rnode->sysctl_data;
    647  1.1      brad 	node.sysctl_data = &t;
    648  1.1      brad 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    649  1.1      brad 	if (error || newp == NULL)
    650  1.1      brad 		return error;
    651  1.1      brad 
    652  1.1      brad 	if (t < 0)
    653  1.1      brad 		return EINVAL;
    654  1.1      brad 
    655  1.1      brad 	*(int *)rnode->sysctl_data = t;
    656  1.1      brad 
    657  1.1      brad 	return 0;
    658  1.1      brad }
    659  1.1      brad 
    660  1.1      brad int
    661  1.1      brad sht3x_verify_sysctl_heateron(SYSCTLFN_ARGS)
    662  1.1      brad {
    663  1.1      brad 	int 		error;
    664  1.1      brad 	bool 		t;
    665  1.1      brad 	struct sht3x_sc *sc;
    666  1.1      brad 	struct sysctlnode node;
    667  1.1      brad 
    668  1.1      brad 	node = *rnode;
    669  1.1      brad 	sc = node.sysctl_data;
    670  1.1      brad 	t = sc->sc_heateron;
    671  1.1      brad 	node.sysctl_data = &t;
    672  1.1      brad 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    673  1.1      brad 	if (error || newp == NULL)
    674  1.1      brad 		return error;
    675  1.1      brad 
    676  1.1      brad 	sc->sc_heateron = t;
    677  1.1      brad 	error = sht3x_set_heater(sc);
    678  1.1      brad 
    679  1.1      brad 	return error;
    680  1.1      brad }
    681  1.1      brad 
    682  1.1      brad static int
    683  1.1      brad sht3x_set_heater(struct sht3x_sc *sc)
    684  1.1      brad {
    685  1.1      brad 	int error = 0;
    686  1.1      brad 	uint16_t cmd;
    687  1.1      brad 
    688  1.1      brad 	mutex_enter(&sc->sc_mutex);
    689  1.1      brad 	error = iic_acquire_bus(sc->sc_tag, 0);
    690  1.1      brad 	if (error) {
    691  1.1      brad 		DPRINTF(sc, 2, ("%s:%s: Failed to acquire bus: %d\n",
    692  1.1      brad 		    device_xname(sc->sc_dev), __func__, error));
    693  1.2  christos 		goto out;
    694  1.1      brad 	}
    695  1.1      brad 
    696  1.1      brad 	if (sc->sc_heateron) {
    697  1.1      brad 		cmd = SHT3X_HEATER_ENABLE;
    698  1.1      brad 	} else {
    699  1.1      brad 		cmd = SHT3X_HEATER_DISABLE;
    700  1.1      brad 	}
    701  1.1      brad 
    702  1.1      brad 	error = sht3x_cmdr(sc, cmd, NULL, 0);
    703  1.1      brad 
    704  1.1      brad 	iic_release_bus(sc->sc_tag,0);
    705  1.2  christos out:
    706  1.1      brad 	mutex_exit(&sc->sc_mutex);
    707  1.1      brad 
    708  1.1      brad 	return error;
    709  1.1      brad }
    710  1.1      brad 
    711  1.1      brad int
    712  1.1      brad sht3x_verify_sysctl_modes(SYSCTLFN_ARGS)
    713  1.1      brad {
    714  1.1      brad 	char buf[SHT3X_MODE_NAME];
    715  1.1      brad 	struct sht3x_sc *sc;
    716  1.1      brad 	struct sysctlnode node;
    717  1.1      brad 	bool is_ss = false;
    718  1.1      brad 	bool is_periodic = false;
    719  1.2  christos 	int error;
    720  1.1      brad 
    721  1.1      brad 	node = *rnode;
    722  1.1      brad 	sc = node.sysctl_data;
    723  1.1      brad 	(void) memcpy(buf, sc->sc_mode, SHT3X_MODE_NAME);
    724  1.1      brad 	node.sysctl_data = buf;
    725  1.1      brad 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    726  1.1      brad 	if (error || newp == NULL)
    727  1.1      brad 		return error;
    728  1.1      brad 
    729  1.1      brad 	if (sc->sc_opened) {
    730  1.1      brad 		return EINVAL;
    731  1.1      brad 	}
    732  1.1      brad 
    733  1.2  christos 	is_ss = strncmp(node.sysctl_data, "single-shot", SHT3X_MODE_NAME) == 0;
    734  1.2  christos 	is_periodic = strncmp(node.sysctl_data, "periodic", SHT3X_MODE_NAME)
    735  1.2  christos 	    == 0;
    736  1.1      brad 
    737  1.2  christos 	if (!is_ss && !is_periodic) {
    738  1.2  christos 		return EINVAL;
    739  1.2  christos 	}
    740  1.2  christos 
    741  1.2  christos 	(void) memcpy(sc->sc_mode, node.sysctl_data, SHT3X_MODE_NAME);
    742  1.2  christos 	if (is_ss) {
    743  1.2  christos 		sht3x_stop_thread(sc);
    744  1.2  christos 		sc->sc_stopping = false;
    745  1.2  christos 		sc->sc_initperiodic = false;
    746  1.2  christos 		sc->sc_isperiodic = false;
    747  1.1      brad 	}
    748  1.1      brad 
    749  1.2  christos 	if (is_periodic) {
    750  1.2  christos 		sc->sc_stopping = false;
    751  1.2  christos 		sc->sc_initperiodic = true;
    752  1.2  christos 		sc->sc_isperiodic = true;
    753  1.2  christos 		sht3x_start_thread(sc);
    754  1.1      brad 	}
    755  1.1      brad 
    756  1.2  christos 	return 0;
    757  1.1      brad }
    758  1.1      brad 
    759  1.1      brad int
    760  1.1      brad sht3x_verify_sysctl_repeatability(SYSCTLFN_ARGS)
    761  1.1      brad {
    762  1.1      brad 	char buf[SHT3X_REP_NAME];
    763  1.1      brad 	struct sht3x_sc *sc;
    764  1.1      brad 	struct sysctlnode node;
    765  1.2  christos 	int error;
    766  1.1      brad 	size_t i;
    767  1.1      brad 
    768  1.1      brad 	node = *rnode;
    769  1.1      brad 	sc = node.sysctl_data;
    770  1.1      brad 	(void) memcpy(buf, sc->sc_repeatability, SHT3X_REP_NAME);
    771  1.1      brad 	node.sysctl_data = buf;
    772  1.1      brad 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    773  1.1      brad 	if (error || newp == NULL)
    774  1.1      brad 		return error;
    775  1.1      brad 
    776  1.1      brad 	for (i = 0; i < __arraycount(sht3x_repeatability_ss); i++) {
    777  1.1      brad 		if (strncmp(node.sysctl_data, sht3x_repeatability_ss[i].text,
    778  1.1      brad 		    SHT3X_REP_NAME) == 0) {
    779  1.1      brad 			break;
    780  1.1      brad 		}
    781  1.1      brad 	}
    782  1.1      brad 
    783  1.1      brad 	if (i == __arraycount(sht3x_repeatability_ss))
    784  1.1      brad 		return EINVAL;
    785  1.1      brad 	(void) memcpy(sc->sc_repeatability, node.sysctl_data, SHT3X_REP_NAME);
    786  1.1      brad 
    787  1.1      brad 	if (sc->sc_isperiodic) {
    788  1.1      brad 		sc->sc_initperiodic = true;
    789  1.1      brad 	}
    790  1.1      brad 
    791  1.1      brad 	return error;
    792  1.1      brad }
    793  1.1      brad 
    794  1.1      brad int
    795  1.1      brad sht3x_verify_sysctl_rate(SYSCTLFN_ARGS)
    796  1.1      brad {
    797  1.1      brad 	char buf[SHT3X_RATE_NAME];
    798  1.1      brad 	struct sht3x_sc *sc;
    799  1.1      brad 	struct sysctlnode node;
    800  1.2  christos 	int error;
    801  1.1      brad 	size_t i;
    802  1.1      brad 
    803  1.1      brad 	node = *rnode;
    804  1.1      brad 	sc = node.sysctl_data;
    805  1.1      brad 	(void) memcpy(buf, sc->sc_periodic_rate, SHT3X_RATE_NAME);
    806  1.1      brad 	node.sysctl_data = buf;
    807  1.1      brad 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    808  1.1      brad 	if (error || newp == NULL)
    809  1.1      brad 		return error;
    810  1.1      brad 
    811  1.1      brad 	for (i = 0; i < __arraycount(sht3x_periodic_rate); i++) {
    812  1.1      brad 		if (strncmp(node.sysctl_data, sht3x_periodic_rate[i].rate,
    813  1.1      brad 		    SHT3X_RATE_NAME) == 0) {
    814  1.1      brad 			break;
    815  1.1      brad 		}
    816  1.1      brad 	}
    817  1.1      brad 
    818  1.1      brad 	if (i == __arraycount(sht3x_periodic_rate))
    819  1.1      brad 		return EINVAL;
    820  1.2  christos 
    821  1.1      brad 	(void) memcpy(sc->sc_periodic_rate, node.sysctl_data, SHT3X_RATE_NAME);
    822  1.1      brad 
    823  1.1      brad 	if (sc->sc_isperiodic) {
    824  1.1      brad 		sc->sc_initperiodic = true;
    825  1.1      brad 	}
    826  1.1      brad 
    827  1.1      brad 	return error;
    828  1.1      brad }
    829  1.1      brad 
    830  1.1      brad static int
    831  1.1      brad sht3x_cmddelay(uint16_t cmd)
    832  1.1      brad {
    833  1.2  christos 	size_t i;
    834  1.1      brad 
    835  1.2  christos 	for (i = 0; i < __arraycount(sht3x_timings); i++) {
    836  1.1      brad 		if (cmd == sht3x_timings[i].cmd) {
    837  1.1      brad 			break;
    838  1.1      brad 		}
    839  1.1      brad 	}
    840  1.1      brad 
    841  1.2  christos 	if (i == __arraycount(sht3x_timings)) {
    842  1.2  christos 		return -1;
    843  1.1      brad 	}
    844  1.2  christos 	return sht3x_timings[i].typicaldelay;
    845  1.1      brad }
    846  1.1      brad 
    847  1.1      brad static int
    848  1.1      brad sht3x_cmd(i2c_tag_t tag, i2c_addr_t addr, uint16_t *cmd,
    849  1.1      brad     uint8_t clen, uint8_t *buf, size_t blen, int readattempts)
    850  1.1      brad {
    851  1.1      brad 	int error;
    852  1.1      brad 	int cmddelay;
    853  1.1      brad 	uint8_t cmd8[2];
    854  1.1      brad 
    855  1.1      brad 	/* All commands are two bytes and must be in a proper order */
    856  1.1      brad 	KASSERT(clen == 2);
    857  1.1      brad 
    858  1.1      brad 	cmd8[0] = cmd[0] >> 8;
    859  1.1      brad 	cmd8[1] = cmd[0] & 0x00ff;
    860  1.1      brad 
    861  1.2  christos 	error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd8[0], clen,
    862  1.2  christos 	    NULL, 0, 0);
    863  1.2  christos 	if (error)
    864  1.2  christos 		return error;
    865  1.2  christos 
    866  1.2  christos 	cmddelay = sht3x_cmddelay(cmd[0]);
    867  1.2  christos 	if (cmddelay != -1) {
    868  1.2  christos 		delay(cmddelay);
    869  1.2  christos 	}
    870  1.1      brad 
    871  1.2  christos 	/* Not all commands return anything  */
    872  1.2  christos 	if (blen == 0) {
    873  1.2  christos 		return 0;
    874  1.2  christos 	}
    875  1.1      brad 
    876  1.2  christos 	for (int aint = 0; aint < readattempts; aint++) {
    877  1.2  christos 		error = iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0, buf,
    878  1.2  christos 		    blen, 0);
    879  1.2  christos 		if (error == 0)
    880  1.2  christos 			break;
    881  1.2  christos 		delay(1000);
    882  1.1      brad 	}
    883  1.1      brad 
    884  1.1      brad 	return error;
    885  1.1      brad }
    886  1.1      brad 
    887  1.1      brad static int
    888  1.1      brad sht3x_cmdr(struct sht3x_sc *sc, uint16_t cmd, uint8_t *buf, size_t blen)
    889  1.1      brad {
    890  1.2  christos 	return sht3x_cmd(sc->sc_tag, sc->sc_addr, &cmd, 2, buf, blen,
    891  1.2  christos 	    sc->sc_readattempts);
    892  1.1      brad }
    893  1.1      brad 
    894  1.1      brad static	uint8_t
    895  1.2  christos sht3x_crc(uint8_t *data, size_t size)
    896  1.1      brad {
    897  1.1      brad 	uint8_t crc = 0xFF;
    898  1.1      brad 
    899  1.1      brad 	for (size_t i = 0; i < size; i++) {
    900  1.1      brad 		crc ^= data[i];
    901  1.1      brad 		for (size_t j = 8; j > 0; j--) {
    902  1.1      brad 			if (crc & 0x80)
    903  1.1      brad 				crc = (crc << 1) ^ 0x31;
    904  1.1      brad 			else
    905  1.1      brad 				crc <<= 1;
    906  1.1      brad 		}
    907  1.1      brad 	}
    908  1.1      brad 	return crc;
    909  1.1      brad }
    910  1.1      brad 
    911  1.1      brad static int
    912  1.1      brad sht3x_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
    913  1.1      brad {
    914  1.1      brad 	uint16_t reg = SHT3X_GET_STATUS_REGISTER;
    915  1.1      brad 	uint8_t buf[3];
    916  1.1      brad 	int error;
    917  1.1      brad 
    918  1.1      brad 	error = sht3x_cmd(tag, addr, &reg, 2, buf, 3, 10);
    919  1.1      brad 	if (matchdebug) {
    920  1.1      brad 		printf("poke X 1: %d\n", error);
    921  1.1      brad 	}
    922  1.1      brad 	return error;
    923  1.1      brad }
    924  1.1      brad 
    925  1.1      brad static int
    926  1.1      brad sht3x_sysctl_init(struct sht3x_sc *sc)
    927  1.1      brad {
    928  1.1      brad 	int error;
    929  1.1      brad 	const struct sysctlnode *cnode;
    930  1.1      brad 	int sysctlroot_num;
    931  1.1      brad 
    932  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    933  1.1      brad 	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
    934  1.1      brad 	    SYSCTL_DESCR("sht3x controls"), NULL, 0, NULL, 0, CTL_HW,
    935  1.1      brad 	    CTL_CREATE, CTL_EOL)) != 0)
    936  1.1      brad 		return error;
    937  1.1      brad 
    938  1.1      brad 	sysctlroot_num = cnode->sysctl_num;
    939  1.1      brad 
    940  1.1      brad #ifdef SHT3X_DEBUG
    941  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    942  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
    943  1.1      brad 	    SYSCTL_DESCR("Debug level"), sht3x_verify_sysctl, 0,
    944  1.1      brad 	    &sc->sc_sht3xdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
    945  1.1      brad 	    CTL_EOL)) != 0)
    946  1.1      brad 		return error;
    947  1.1      brad 
    948  1.1      brad #endif
    949  1.1      brad 
    950  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    951  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
    952  1.1      brad 	    SYSCTL_DESCR("The number of times to attempt to read the values"),
    953  1.1      brad 	    sht3x_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
    954  1.1      brad 	    sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    955  1.1      brad 		return error;
    956  1.1      brad 
    957  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    958  1.1      brad 	    CTLFLAG_READONLY, CTLTYPE_STRING, "modes",
    959  1.1      brad 	    SYSCTL_DESCR("Valid modes"), 0, 0,
    960  1.1      brad 	    __UNCONST(sht3x_mode_names),
    961  1.1      brad 	    sizeof(sht3x_mode_names) + 1,
    962  1.1      brad 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    963  1.1      brad 		return error;
    964  1.1      brad 
    965  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    966  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_STRING, "mode",
    967  1.1      brad 	    SYSCTL_DESCR("Mode for measurement collection"),
    968  1.1      brad 	    sht3x_verify_sysctl_modes, 0, (void *) sc,
    969  1.1      brad 	    SHT3X_MODE_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    970  1.1      brad 		return error;
    971  1.1      brad 
    972  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    973  1.1      brad 	    CTLFLAG_READONLY, CTLTYPE_STRING, "repeatabilities",
    974  1.1      brad 	    SYSCTL_DESCR("Valid repeatability values"), 0, 0,
    975  1.1      brad 	    __UNCONST(sht3x_repeatability_names),
    976  1.1      brad 	    sizeof(sht3x_repeatability_names) + 1,
    977  1.1      brad 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    978  1.1      brad 		return error;
    979  1.1      brad 
    980  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    981  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_STRING, "repeatability",
    982  1.1      brad 	    SYSCTL_DESCR("Repeatability of RH and Temp"),
    983  1.1      brad 	    sht3x_verify_sysctl_repeatability, 0, (void *) sc,
    984  1.1      brad 	    SHT3X_REP_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    985  1.1      brad 		return error;
    986  1.1      brad 
    987  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    988  1.1      brad 	    CTLFLAG_READONLY, CTLTYPE_STRING, "rates",
    989  1.1      brad 	    SYSCTL_DESCR("Valid peridoic rates"), 0, 0,
    990  1.1      brad 	    __UNCONST(sht3x_rate_names),
    991  1.1      brad 	    sizeof(sht3x_rate_names) + 1,
    992  1.1      brad 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    993  1.1      brad 		return error;
    994  1.1      brad 
    995  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
    996  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_STRING, "rate",
    997  1.1      brad 	    SYSCTL_DESCR("Rate for periodic measurements"),
    998  1.1      brad 	    sht3x_verify_sysctl_rate, 0, (void *) sc,
    999  1.1      brad 	    SHT3X_RATE_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1000  1.1      brad 		return error;
   1001  1.1      brad 
   1002  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
   1003  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
   1004  1.1      brad 	    SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
   1005  1.1      brad 	    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1006  1.1      brad 		return error;
   1007  1.1      brad 
   1008  1.1      brad 	if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
   1009  1.1      brad 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
   1010  1.1      brad 	    SYSCTL_DESCR("Heater on"), sht3x_verify_sysctl_heateron, 0,
   1011  1.1      brad 	    (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
   1012  1.1      brad 		return error;
   1013  1.1      brad 
   1014  1.1      brad 	return 0;
   1015  1.1      brad }
   1016  1.1      brad 
   1017  1.1      brad static int
   1018  1.1      brad sht3x_match(device_t parent, cfdata_t match, void *aux)
   1019  1.1      brad {
   1020  1.1      brad 	struct i2c_attach_args *ia = aux;
   1021  1.1      brad 	int error, match_result;
   1022  1.1      brad 	const bool matchdebug = false;
   1023  1.1      brad 
   1024  1.1      brad 	if (iic_use_direct_match(ia, match, NULL, &match_result))
   1025  1.1      brad 		return match_result;
   1026  1.1      brad 
   1027  1.1      brad 	if (matchdebug) {
   1028  1.1      brad 		printf("Looking at ia_addr: %x\n",ia->ia_addr);
   1029  1.1      brad 	}
   1030  1.1      brad 
   1031  1.1      brad 	/* indirect config - check for configured address */
   1032  1.2  christos 	if (ia->ia_addr != SHT3X_TYPICAL_ADDR_1 &&
   1033  1.2  christos 	    ia->ia_addr != SHT3X_TYPICAL_ADDR_2)
   1034  1.2  christos 		return 0;
   1035  1.1      brad 
   1036  1.2  christos 	/*
   1037  1.2  christos 	 * Check to see if something is really at this i2c address.
   1038  1.2  christos 	 * This will keep phantom devices from appearing
   1039  1.2  christos 	 */
   1040  1.2  christos 	if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
   1041  1.2  christos 		if (matchdebug)
   1042  1.2  christos 			printf("in match acquire bus failed\n");
   1043  1.1      brad 		return 0;
   1044  1.1      brad 	}
   1045  1.2  christos 
   1046  1.2  christos 	error = sht3x_poke(ia->ia_tag, ia->ia_addr, matchdebug);
   1047  1.2  christos 	iic_release_bus(ia->ia_tag, 0);
   1048  1.2  christos 
   1049  1.2  christos 	return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
   1050  1.1      brad }
   1051  1.1      brad 
   1052  1.1      brad static void
   1053  1.1      brad sht3x_attach(device_t parent, device_t self, void *aux)
   1054  1.1      brad {
   1055  1.1      brad 	struct sht3x_sc *sc;
   1056  1.1      brad 	struct i2c_attach_args *ia;
   1057  1.1      brad 	int error, i;
   1058  1.1      brad 	int ecount = 0;
   1059  1.1      brad 	uint8_t buf[6];
   1060  1.1      brad 	uint32_t serialnumber;
   1061  1.1      brad 	uint8_t sncrcpt1, sncrcpt2;
   1062  1.1      brad 
   1063  1.1      brad 	ia = aux;
   1064  1.1      brad 	sc = device_private(self);
   1065  1.1      brad 
   1066  1.1      brad 	sc->sc_dev = self;
   1067  1.1      brad 	sc->sc_tag = ia->ia_tag;
   1068  1.1      brad 	sc->sc_addr = ia->ia_addr;
   1069  1.1      brad 	sc->sc_sht3xdebug = 0;
   1070  1.2  christos 	strlcpy(sc->sc_mode, "single-shot", SHT3X_MODE_NAME);
   1071  1.1      brad 	sc->sc_isperiodic = false;
   1072  1.2  christos 	strlcpy(sc->sc_repeatability, "high", SHT3X_REP_NAME);
   1073  1.2  christos 	strlcpy(sc->sc_periodic_rate, "1.0mps", SHT3X_RATE_NAME);
   1074  1.1      brad 	sc->sc_readattempts = 10;
   1075  1.1      brad 	sc->sc_ignorecrc = false;
   1076  1.1      brad 	sc->sc_heateron = false;
   1077  1.1      brad 	sc->sc_sme = NULL;
   1078  1.1      brad 	sc->sc_stopping = false;
   1079  1.1      brad 	sc->sc_initperiodic = false;
   1080  1.1      brad 	sc->sc_opened = false;
   1081  1.1      brad 	sc->sc_dying = false;
   1082  1.1      brad 	sc->sc_readpoolname = NULL;
   1083  1.1      brad 
   1084  1.1      brad 	aprint_normal("\n");
   1085  1.1      brad 
   1086  1.1      brad 	mutex_init(&sc->sc_dying_mutex, MUTEX_DEFAULT, IPL_NONE);
   1087  1.1      brad 	mutex_init(&sc->sc_read_mutex, MUTEX_DEFAULT, IPL_NONE);
   1088  1.1      brad 	mutex_init(&sc->sc_threadmutex, MUTEX_DEFAULT, IPL_NONE);
   1089  1.1      brad 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
   1090  1.1      brad 	cv_init(&sc->sc_condvar, "sht3xcv");
   1091  1.1      brad 	cv_init(&sc->sc_condreadready, "sht3xread");
   1092  1.1      brad 	cv_init(&sc->sc_cond_dying, "sht3xdie");
   1093  1.1      brad 	sc->sc_numsensors = __arraycount(sht3x_sensors);
   1094  1.1      brad 
   1095  1.1      brad 	if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
   1096  1.1      brad 		aprint_error_dev(self,
   1097  1.1      brad 		    "Unable to create sysmon structure\n");
   1098  1.1      brad 		sc->sc_sme = NULL;
   1099  1.1      brad 		return;
   1100  1.1      brad 	}
   1101  1.1      brad 	if ((error = sht3x_sysctl_init(sc)) != 0) {
   1102  1.1      brad 		aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
   1103  1.1      brad 		goto out;
   1104  1.1      brad 	}
   1105  1.1      brad 
   1106  1.1      brad 	sc->sc_readpoolname = kmem_asprintf("sht3xrp%d",device_unit(self));
   1107  1.2  christos 	sc->sc_readpool = pool_cache_init(sizeof(struct sht3x_read_q), 0, 0, 0,
   1108  1.2  christos 	    sc->sc_readpoolname, NULL, IPL_VM, NULL, NULL, NULL);
   1109  1.1      brad 	pool_cache_sethiwat(sc->sc_readpool,100);
   1110  1.1      brad 
   1111  1.1      brad 	SIMPLEQ_INIT(&sc->sc_read_queue);
   1112  1.1      brad 
   1113  1.1      brad 	error = iic_acquire_bus(sc->sc_tag, 0);
   1114  1.1      brad 	if (error) {
   1115  1.1      brad 		aprint_error_dev(self, "Could not acquire iic bus: %d\n",
   1116  1.1      brad 		    error);
   1117  1.1      brad 		goto out;
   1118  1.1      brad 	}
   1119  1.1      brad 
   1120  1.1      brad 	error = sht3x_cmdr(sc, SHT3X_SOFT_RESET, NULL, 0);
   1121  1.1      brad 	if (error != 0)
   1122  1.1      brad 		aprint_error_dev(self, "Reset failed: %d\n", error);
   1123  1.1      brad 
   1124  1.1      brad 	error = sht3x_clear_status_register(sc, true);
   1125  1.1      brad 	if (error) {
   1126  1.1      brad 		aprint_error_dev(self, "Failed to clear status register: %d\n",
   1127  1.1      brad 		    error);
   1128  1.1      brad 		ecount++;
   1129  1.1      brad 	}
   1130  1.1      brad 
   1131  1.1      brad 	uint16_t status_reg;
   1132  1.1      brad 	error = sht3x_get_status_register(sc, &status_reg, true);
   1133  1.1      brad 	if (error) {
   1134  1.1      brad 		aprint_error_dev(self, "Failed to read status register: %d\n",
   1135  1.1      brad 		    error);
   1136  1.1      brad 		ecount++;
   1137  1.1      brad 	}
   1138  1.1      brad 
   1139  1.1      brad 	DPRINTF(sc, 2, ("%s: read status register values: %04x\n",
   1140  1.1      brad 	    device_xname(sc->sc_dev), status_reg));
   1141  1.1      brad 
   1142  1.1      brad 	error = sht3x_cmdr(sc, SHT3X_READ_SERIAL_NUMBER, buf, 6);
   1143  1.1      brad 	if (error) {
   1144  1.1      brad 		aprint_error_dev(self, "Failed to read serial number: %d\n",
   1145  1.1      brad 		    error);
   1146  1.1      brad 		ecount++;
   1147  1.1      brad 	}
   1148  1.1      brad 
   1149  1.1      brad 	sncrcpt1 = sht3x_crc(&buf[0],2);
   1150  1.1      brad 	sncrcpt2 = sht3x_crc(&buf[3],2);
   1151  1.1      brad 	serialnumber = (buf[0] << 24) | (buf[1] << 16) | (buf[3] << 8) | buf[4];
   1152  1.1      brad 
   1153  1.2  christos 	DPRINTF(sc, 2, ("%s: read serial number values: %02x%02x - %02x - "
   1154  1.2  christos 	    "%02x%02x - %02x -- %02x %02x\n", device_xname(sc->sc_dev), buf[0],
   1155  1.2  christos 	    buf[1], buf[2], buf[3], buf[4], buf[5], sncrcpt1, sncrcpt2));
   1156  1.1      brad 
   1157  1.1      brad 	iic_release_bus(sc->sc_tag, 0);
   1158  1.1      brad 	if (error != 0) {
   1159  1.1      brad 		aprint_error_dev(self, "Unable to setup device\n");
   1160  1.1      brad 		goto out;
   1161  1.1      brad 	}
   1162  1.1      brad 
   1163  1.1      brad 	for (i = 0; i < sc->sc_numsensors; i++) {
   1164  1.1      brad 		strlcpy(sc->sc_sensors[i].desc, sht3x_sensors[i].desc,
   1165  1.1      brad 		    sizeof(sc->sc_sensors[i].desc));
   1166  1.1      brad 
   1167  1.1      brad 		sc->sc_sensors[i].units = sht3x_sensors[i].type;
   1168  1.1      brad 		sc->sc_sensors[i].state = ENVSYS_SINVALID;
   1169  1.1      brad 
   1170  1.1      brad 		DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
   1171  1.1      brad 		    sc->sc_sensors[i].desc));
   1172  1.1      brad 
   1173  1.1      brad 		error = sysmon_envsys_sensor_attach(sc->sc_sme,
   1174  1.1      brad 		    &sc->sc_sensors[i]);
   1175  1.1      brad 		if (error) {
   1176  1.1      brad 			aprint_error_dev(self,
   1177  1.1      brad 			    "Unable to attach sensor %d: %d\n", i, error);
   1178  1.1      brad 			goto out;
   1179  1.1      brad 		}
   1180  1.1      brad 	}
   1181  1.1      brad 
   1182  1.1      brad 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
   1183  1.1      brad 	sc->sc_sme->sme_cookie = sc;
   1184  1.1      brad 	sc->sc_sme->sme_refresh = sht3x_refresh;
   1185  1.1      brad 
   1186  1.1      brad 	DPRINTF(sc, 2, ("sht3x_attach: registering with envsys\n"));
   1187  1.1      brad 
   1188  1.1      brad 	if (sysmon_envsys_register(sc->sc_sme)) {
   1189  1.2  christos 		aprint_error_dev(self, "unable to register with sysmon\n");
   1190  1.1      brad 		sysmon_envsys_destroy(sc->sc_sme);
   1191  1.1      brad 		sc->sc_sme = NULL;
   1192  1.1      brad 		return;
   1193  1.1      brad 	}
   1194  1.1      brad 
   1195  1.2  christos 	/*
   1196  1.2  christos 	 * There is no documented way to ask the chip what version it is. This
   1197  1.2  christos 	 * is likely fine as the only apparent difference is in how precise the
   1198  1.2  christos 	 * measurements will be. The actual conversation with the chip is
   1199  1.2  christos 	 * identical no matter which one you are talking to.
   1200  1.2  christos 	 */
   1201  1.1      brad 
   1202  1.1      brad 	aprint_normal_dev(self, "Sensirion SHT30/SHT31/SHT35, "
   1203  1.2  christos 	    "Serial number: %x%s", serialnumber,
   1204  1.1      brad 	    (sncrcpt1 == buf[2] && sncrcpt2 == buf[5]) ? "\n" : " (bad crc)\n");
   1205  1.1      brad 	return;
   1206  1.1      brad out:
   1207  1.1      brad 	sysmon_envsys_destroy(sc->sc_sme);
   1208  1.1      brad 	sc->sc_sme = NULL;
   1209  1.1      brad }
   1210  1.1      brad 
   1211  1.1      brad static uint16_t
   1212  1.2  christos sht3x_compute_measure_command_ss(const char *repeatability)
   1213  1.1      brad {
   1214  1.1      brad 	int i;
   1215  1.1      brad 	uint16_t r;
   1216  1.1      brad 
   1217  1.1      brad 	for (i = 0; i < __arraycount(sht3x_repeatability_ss); i++) {
   1218  1.1      brad 		if (strncmp(repeatability, sht3x_repeatability_ss[i].text,
   1219  1.1      brad 		    SHT3X_REP_NAME) == 0) {
   1220  1.1      brad 			r = sht3x_repeatability_ss[i].cmd;
   1221  1.1      brad 			break;
   1222  1.1      brad 		}
   1223  1.1      brad 	}
   1224  1.1      brad 
   1225  1.1      brad 	if (i == __arraycount(sht3x_repeatability_ss))
   1226  1.2  christos 		panic("Single-shot could not find command for "
   1227  1.2  christos 		    "repeatability: %s\n", repeatability);
   1228  1.1      brad 
   1229  1.1      brad 	return r;
   1230  1.1      brad }
   1231  1.1      brad 
   1232  1.1      brad /*
   1233  1.2  christos  * The documented conversion calculations for the raw values are as follows:
   1234  1.2  christos  *
   1235  1.2  christos  * %RH = (-6 + 125 * rawvalue / 65535)
   1236  1.2  christos  *
   1237  1.2  christos  * T in Celsius = (-45 + 175 * rawvalue / 65535)
   1238  1.2  christos  *
   1239  1.2  christos  * It follows then:
   1240  1.2  christos  *
   1241  1.2  christos  * T in Kelvin = (228.15 + 175 * rawvalue / 65535)
   1242  1.2  christos  *
   1243  1.2  christos  * given the relationship between Celsius and Kelvin
   1244  1.2  christos  *
   1245  1.2  christos  * What follows reorders the calculation a bit and scales it up to avoid
   1246  1.2  christos  * the use of any floating point.  All that would really have to happen
   1247  1.2  christos  * is a scale up to 10^6 for the sysenv framework, which wants
   1248  1.2  christos  * temperature in micro-kelvin and percent relative humidity scaled up
   1249  1.2  christos  * 10^6, but since this conversion uses 64 bits due to intermediate
   1250  1.2  christos  * values that are bigger than 32 bits the conversion first scales up to
   1251  1.2  christos  * 10^9 and the scales back down by 10^3 at the end.  This preserves some
   1252  1.2  christos  * precision in the conversion that would otherwise be lost.
   1253  1.2  christos  */
   1254  1.1      brad 
   1255  1.1      brad static uint64_t
   1256  1.1      brad sht3x_compute_temp_from_raw(uint8_t msb, uint8_t lsb) {
   1257  1.1      brad 	uint64_t svalue;
   1258  1.1      brad 	int64_t v1;
   1259  1.1      brad 	uint64_t v2;
   1260  1.1      brad 	uint64_t d1 = 65535;
   1261  1.1      brad 	uint64_t mul1;
   1262  1.1      brad 	uint64_t mul2;
   1263  1.1      brad 	uint64_t div1 = 10000;
   1264  1.1      brad 	uint64_t q;
   1265  1.1      brad 
   1266  1.1      brad 	svalue = msb << 8 | lsb;
   1267  1.1      brad 
   1268  1.1      brad 	v1 = 22815; /* this is scaled up already from 228.15 */
   1269  1.1      brad 	v2 = 175;
   1270  1.1      brad 	mul1 = 10000000000;
   1271  1.1      brad 	mul2 = 100000000;
   1272  1.1      brad 
   1273  1.1      brad 	svalue = svalue * mul1;
   1274  1.1      brad 	v1 = v1 * mul2;
   1275  1.1      brad 	/* Perform the conversion */
   1276  1.1      brad 	q = ((v2 * (svalue / d1)) + v1) / div1;
   1277  1.1      brad 
   1278  1.1      brad 	return q;
   1279  1.1      brad }
   1280  1.1      brad 
   1281  1.1      brad static uint64_t
   1282  1.1      brad sht3x_compute_rh_from_raw(uint8_t msb, uint8_t lsb) {
   1283  1.1      brad 	uint64_t svalue;
   1284  1.1      brad 	int64_t v1;
   1285  1.1      brad 	uint64_t v2;
   1286  1.1      brad 	uint64_t d1 = 65535;
   1287  1.1      brad 	uint64_t mul1;
   1288  1.1      brad 	uint64_t mul2;
   1289  1.1      brad 	uint64_t div1 = 10000;
   1290  1.1      brad 	uint64_t q;
   1291  1.1      brad 
   1292  1.1      brad 	svalue = msb << 8 | lsb;
   1293  1.1      brad 
   1294  1.1      brad 	v1 = 0;
   1295  1.1      brad 	v2 = 100;
   1296  1.1      brad 	mul1 = 10000000000;
   1297  1.1      brad 	mul2 = 10000000000;
   1298  1.1      brad 
   1299  1.1      brad 	svalue = svalue * mul1;
   1300  1.1      brad 	v1 = v1 * mul2;
   1301  1.1      brad 	/* Perform the conversion */
   1302  1.1      brad 	q = ((v2 * (svalue / d1)) + v1) / div1;
   1303  1.1      brad 
   1304  1.1      brad 	return q;
   1305  1.1      brad }
   1306  1.1      brad 
   1307  1.2  christos static int
   1308  1.2  christos sht3x_parse_data(struct sht3x_sc *sc, envsys_data_t *edata, uint8_t *rawdata)
   1309  1.1      brad {
   1310  1.1      brad 	uint64_t current_value;
   1311  1.1      brad 	uint8_t *svalptr;
   1312  1.1      brad 
   1313  1.2  christos 	DPRINTF(sc, 2, ("%s: Raw data: %02x%02x %02x - %02x%02x %02x\n",
   1314  1.2  christos 	    device_xname(sc->sc_dev), rawdata[0], rawdata[1], rawdata[2],
   1315  1.2  christos 	    rawdata[3], rawdata[4], rawdata[5]));
   1316  1.1      brad 
   1317  1.1      brad 	switch (edata->sensor) {
   1318  1.1      brad 	case SHT3X_TEMP_SENSOR:
   1319  1.2  christos 		current_value = sht3x_compute_temp_from_raw(rawdata[0],
   1320  1.2  christos 		    rawdata[1]);
   1321  1.2  christos 		svalptr = &rawdata[0];
   1322  1.1      brad 		break;
   1323  1.1      brad 	case SHT3X_HUMIDITY_SENSOR:
   1324  1.2  christos 		current_value = sht3x_compute_rh_from_raw(rawdata[3],
   1325  1.2  christos 		    rawdata[4]);
   1326  1.2  christos 		svalptr = &rawdata[3];
   1327  1.1      brad 		break;
   1328  1.1      brad 	default:
   1329  1.2  christos 		DPRINTF(sc, 2, ("%s: bad sensor type %d\n",
   1330  1.2  christos 		    device_xname(sc->sc_dev), edata->sensor));
   1331  1.2  christos 		return EINTR;
   1332  1.2  christos 	}
   1333  1.2  christos 	uint8_t testcrc;
   1334  1.2  christos 	/* Fake out the CRC check if being asked to ignore CRC */
   1335  1.2  christos 	if (sc->sc_ignorecrc) {
   1336  1.2  christos 		testcrc = *(svalptr + 2);
   1337  1.2  christos 	} else {
   1338  1.2  christos 		testcrc = sht3x_crc(svalptr, 2);
   1339  1.1      brad 	}
   1340  1.1      brad 
   1341  1.2  christos 	if (*(svalptr + 2) != testcrc) {
   1342  1.2  christos 	    DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d != %d\n",
   1343  1.2  christos 	    device_xname(sc->sc_dev), (*svalptr + 2), testcrc));
   1344  1.2  christos 	    return EINVAL;
   1345  1.1      brad 	}
   1346  1.2  christos 	edata->value_cur = (uint32_t) current_value;
   1347  1.2  christos 	edata->state = ENVSYS_SVALID;
   1348  1.2  christos 	return 0;
   1349  1.1      brad }
   1350  1.1      brad 
   1351  1.2  christos static int
   1352  1.2  christos sht3x_refresh_periodic(struct sysmon_envsys *sme, envsys_data_t *edata)
   1353  1.1      brad {
   1354  1.2  christos 	struct sht3x_sc *sc = sme->sme_cookie;
   1355  1.2  christos 	uint8_t rawdata[sizeof(sc->sc_pbuffer)];
   1356  1.1      brad 
   1357  1.2  christos 	memcpy(rawdata, sc->sc_pbuffer, sizeof(rawdata));
   1358  1.1      brad 
   1359  1.2  christos 	return sht3x_parse_data(sc, edata, rawdata);
   1360  1.1      brad 
   1361  1.1      brad }
   1362  1.1      brad 
   1363  1.2  christos static int
   1364  1.2  christos sht3x_refresh_oneshot(struct sysmon_envsys *sme, envsys_data_t *edata)
   1365  1.1      brad {
   1366  1.1      brad 	struct sht3x_sc *sc = sme->sme_cookie;
   1367  1.2  christos 	uint16_t measurement_command_ss;
   1368  1.2  christos 	uint8_t rawdata[sizeof(sc->sc_pbuffer)];
   1369  1.1      brad 	int error;
   1370  1.1      brad 
   1371  1.1      brad 	error = iic_acquire_bus(sc->sc_tag, 0);
   1372  1.1      brad 	if (error) {
   1373  1.1      brad 		DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
   1374  1.1      brad 		    device_xname(sc->sc_dev), error));
   1375  1.2  christos 		return error;
   1376  1.1      brad 	}
   1377  1.1      brad 
   1378  1.2  christos 	measurement_command_ss = sht3x_compute_measure_command_ss(
   1379  1.2  christos 	    sc->sc_repeatability);
   1380  1.2  christos 	DPRINTF(sc, 2, ("%s: Measurement command: %04x\n",
   1381  1.2  christos 	    device_xname(sc->sc_dev), measurement_command_ss));
   1382  1.2  christos 	error = sht3x_cmdr(sc, measurement_command_ss, rawdata, sizeof(rawdata));
   1383  1.2  christos 	if (error == 0) {
   1384  1.2  christos 		DPRINTF(sc, 2, ("%s: Failed to get new status in refresh for "
   1385  1.2  christos 		    "single-shot %d\n", device_xname(sc->sc_dev), error));
   1386  1.2  christos 		if ((error = sht3x_parse_data(sc, edata, rawdata)) == 0)
   1387  1.2  christos 			return 0;
   1388  1.1      brad 	}
   1389  1.1      brad 
   1390  1.2  christos 	uint16_t sbuf;
   1391  1.2  christos 	int status_error = sht3x_get_status_register(sc, &sbuf, true);
   1392  1.1      brad 
   1393  1.2  christos 	if (!status_error) {
   1394  1.2  christos 		DPRINTF(sc, 2, ("%s: read status register single-shot: %04x\n",
   1395  1.2  christos 		    device_xname(sc->sc_dev), sbuf));
   1396  1.1      brad 
   1397  1.2  christos 		if (sbuf & SHT3X_RESET_DETECTED) {
   1398  1.2  christos 			aprint_error_dev(sc->sc_dev,
   1399  1.2  christos 			    "Reset detected in single shot mode. "
   1400  1.2  christos 			    "Heater may have been reset\n");
   1401  1.2  christos 			sht3x_clear_status_register(sc, true);
   1402  1.2  christos 		}
   1403  1.1      brad 
   1404  1.2  christos 		sc->sc_heateron = sbuf & SHT3X_HEATER_STATUS;
   1405  1.1      brad 	}
   1406  1.1      brad 
   1407  1.2  christos 	iic_release_bus(sc->sc_tag, 0);
   1408  1.2  christos 	return 0;
   1409  1.2  christos }
   1410  1.1      brad 
   1411  1.2  christos static void
   1412  1.2  christos sht3x_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
   1413  1.2  christos {
   1414  1.2  christos 	struct sht3x_sc *sc = sme->sme_cookie;
   1415  1.1      brad 
   1416  1.2  christos 	edata->state = ENVSYS_SINVALID;
   1417  1.1      brad 
   1418  1.2  christos 	mutex_enter(&sc->sc_mutex);
   1419  1.1      brad 
   1420  1.2  christos 	if (sc->sc_isperiodic) {
   1421  1.2  christos 		sht3x_refresh_periodic(sme, edata);
   1422  1.2  christos 	} else {
   1423  1.2  christos 		sht3x_refresh_oneshot(sme, edata);
   1424  1.1      brad 	}
   1425  1.1      brad 
   1426  1.1      brad 	mutex_exit(&sc->sc_mutex);
   1427  1.1      brad }
   1428  1.1      brad 
   1429  1.1      brad static int
   1430  1.1      brad sht3xopen(dev_t dev, int flags, int fmt, struct lwp *l)
   1431  1.1      brad {
   1432  1.1      brad 	struct sht3x_sc *sc;
   1433  1.1      brad 
   1434  1.1      brad 	sc = device_lookup_private(&sht3xtemp_cd, minor(dev));
   1435  1.1      brad 	if (!sc)
   1436  1.2  christos 		return ENXIO;
   1437  1.1      brad 
   1438  1.1      brad 	if (sc->sc_opened)
   1439  1.2  christos 		return EBUSY;
   1440  1.1      brad 
   1441  1.1      brad 	mutex_enter(&sc->sc_mutex);
   1442  1.1      brad 	sc->sc_opened = true;
   1443  1.1      brad 
   1444  1.1      brad 	sc->sc_wassingleshot = false;
   1445  1.1      brad 	if (!sc->sc_isperiodic) {
   1446  1.1      brad 		sc->sc_stopping = false;
   1447  1.1      brad 		sc->sc_initperiodic = true;
   1448  1.1      brad 		sc->sc_isperiodic = true;
   1449  1.1      brad 		sc->sc_wassingleshot = true;
   1450  1.1      brad 		sht3x_start_thread(sc);
   1451  1.1      brad 	}
   1452  1.1      brad 	mutex_exit(&sc->sc_mutex);
   1453  1.1      brad 
   1454  1.2  christos 	return 0;
   1455  1.1      brad }
   1456  1.1      brad 
   1457  1.1      brad static int
   1458  1.1      brad sht3xread(dev_t dev, struct uio *uio, int flags)
   1459  1.1      brad {
   1460  1.1      brad 	struct sht3x_sc *sc;
   1461  1.1      brad 	struct sht3x_read_q *pp;
   1462  1.1      brad 	int error,any;
   1463  1.1      brad 
   1464  1.1      brad 	sc = device_lookup_private(&sht3xtemp_cd, minor(dev));
   1465  1.1      brad 	if (!sc)
   1466  1.2  christos 		return ENXIO;
   1467  1.1      brad 
   1468  1.1      brad 	while (uio->uio_resid) {
   1469  1.1      brad 		any = 0;
   1470  1.1      brad 		error = 0;
   1471  1.1      brad 		mutex_enter(&sc->sc_read_mutex);
   1472  1.1      brad 
   1473  1.1      brad 		while (any == 0) {
   1474  1.1      brad 			pp = SIMPLEQ_FIRST(&sc->sc_read_queue);
   1475  1.1      brad 			if (pp != NULL) {
   1476  1.1      brad 				SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
   1477  1.1      brad 				any = 1;
   1478  1.1      brad 				break;
   1479  1.1      brad 			}
   1480  1.2  christos 			error = cv_wait_sig(&sc->sc_condreadready,
   1481  1.2  christos 			    &sc->sc_read_mutex);
   1482  1.2  christos 			if (sc->sc_dying)
   1483  1.2  christos 				error = EIO;
   1484  1.2  christos 			if (error == 0)
   1485  1.2  christos 				continue;
   1486  1.2  christos 			break;
   1487  1.1      brad 		}
   1488  1.1      brad 
   1489  1.1      brad 		if (any == 1 && error == 0) {
   1490  1.2  christos 			uint8_t *p = pp->measurement;
   1491  1.1      brad 			mutex_exit(&sc->sc_read_mutex);
   1492  1.1      brad 			pool_cache_put(sc->sc_readpool,pp);
   1493  1.1      brad 
   1494  1.2  christos 			DPRINTF(sc,2, ("%s: sending %02x%02x %02x -- %02x%02x "
   1495  1.2  christos 			    "%02x -- %x\n", device_xname(sc->sc_dev), p[0],
   1496  1.2  christos 			    p[1], p[2], p[3], p[4], p[5],
   1497  1.2  christos 			    mutex_owned(&sc->sc_read_mutex)));
   1498  1.2  christos 			if ((error = uiomove(pp->measurement,
   1499  1.2  christos 			    sizeof(pp->measurement), uio)) != 0) {
   1500  1.2  christos 				DPRINTF(sc,2, ("%s: send error %d\n",
   1501  1.2  christos 				    device_xname(sc->sc_dev), error));
   1502  1.1      brad 				break;
   1503  1.1      brad 			}
   1504  1.1      brad 		} else {
   1505  1.1      brad 			mutex_exit(&sc->sc_read_mutex);
   1506  1.1      brad 			if (error) {
   1507  1.1      brad 				break;
   1508  1.1      brad 			}
   1509  1.1      brad 		}
   1510  1.1      brad 	}
   1511  1.1      brad 
   1512  1.1      brad 	DPRINTF(sc,2, ("%s: loop done: %d\n",device_xname(sc->sc_dev),error));
   1513  1.1      brad 	if (sc->sc_dying) {
   1514  1.1      brad 		DPRINTF(sc, 2, ("%s: Telling all we are almost dead\n",
   1515  1.1      brad 		    device_xname(sc->sc_dev)));
   1516  1.1      brad 		mutex_enter(&sc->sc_dying_mutex);
   1517  1.1      brad 		cv_signal(&sc->sc_cond_dying);
   1518  1.1      brad 		mutex_exit(&sc->sc_dying_mutex);
   1519  1.1      brad 	}
   1520  1.1      brad 	return error;
   1521  1.1      brad }
   1522  1.1      brad 
   1523  1.1      brad static int
   1524  1.1      brad sht3xclose(dev_t dev, int flags, int fmt, struct lwp *l)
   1525  1.1      brad {
   1526  1.1      brad 	struct sht3x_sc *sc;
   1527  1.1      brad 	struct sht3x_read_q *pp;
   1528  1.1      brad 
   1529  1.1      brad 	sc = device_lookup_private(&sht3xtemp_cd, minor(dev));
   1530  1.1      brad 
   1531  1.1      brad 	if (sc->sc_wassingleshot) {
   1532  1.1      brad 		sht3x_stop_thread(sc);
   1533  1.1      brad 		sc->sc_stopping = false;
   1534  1.1      brad 		sc->sc_initperiodic = false;
   1535  1.1      brad 		sc->sc_isperiodic = false;
   1536  1.1      brad 	}
   1537  1.1      brad 
   1538  1.1      brad 	mutex_enter(&sc->sc_mutex);
   1539  1.1      brad 	/* Drain any read pools */
   1540  1.1      brad 	while ((pp = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) {
   1541  1.1      brad 		SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
   1542  1.1      brad 		pool_cache_put(sc->sc_readpool,pp);
   1543  1.1      brad 	}
   1544  1.1      brad 
   1545  1.1      brad 	/* Say that the device is now free */
   1546  1.1      brad 	sc->sc_opened = false;
   1547  1.1      brad 	mutex_exit(&sc->sc_mutex);
   1548  1.1      brad 
   1549  1.1      brad 	return(0);
   1550  1.1      brad }
   1551  1.1      brad 
   1552  1.1      brad static int
   1553  1.1      brad sht3x_detach(device_t self, int flags)
   1554  1.1      brad {
   1555  1.1      brad 	struct sht3x_sc *sc;
   1556  1.1      brad 	struct sht3x_read_q *pp;
   1557  1.1      brad 
   1558  1.1      brad 	sc = device_private(self);
   1559  1.1      brad 
   1560  1.1      brad 	if (sc->sc_isperiodic) {
   1561  1.1      brad 		sht3x_stop_thread(sc);
   1562  1.1      brad 	}
   1563  1.1      brad 
   1564  1.1      brad 	mutex_enter(&sc->sc_mutex);
   1565  1.1      brad 
   1566  1.1      brad 	sc->sc_dying = true;
   1567  1.1      brad 
   1568  1.1      brad 	/* If this is true we are still open, destroy the condvar */
   1569  1.1      brad 	if (sc->sc_opened) {
   1570  1.1      brad 		mutex_enter(&sc->sc_dying_mutex);
   1571  1.1      brad 		mutex_enter(&sc->sc_read_mutex);
   1572  1.1      brad 		cv_signal(&sc->sc_condreadready);
   1573  1.1      brad 		mutex_exit(&sc->sc_read_mutex);
   1574  1.1      brad 		DPRINTF(sc, 2, ("%s: Will wait for anything to exit\n",
   1575  1.1      brad 		    device_xname(sc->sc_dev)));
   1576  1.2  christos 		cv_timedwait_sig(&sc->sc_cond_dying,
   1577  1.2  christos 		    &sc->sc_dying_mutex, mstohz(5000));
   1578  1.1      brad 		mutex_exit(&sc->sc_dying_mutex);
   1579  1.1      brad 		cv_destroy(&sc->sc_condreadready);
   1580  1.1      brad 		cv_destroy(&sc->sc_cond_dying);
   1581  1.1      brad 	}
   1582  1.1      brad 
   1583  1.1      brad 	/* Drain any read pools */
   1584  1.1      brad 	while ((pp = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) {
   1585  1.1      brad 		SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
   1586  1.1      brad 		pool_cache_put(sc->sc_readpool,pp);
   1587  1.1      brad 	}
   1588  1.1      brad 
   1589  1.1      brad 	/* Destroy the pool cache now that nothing is using it */
   1590  1.1      brad 	pool_cache_destroy(sc->sc_readpool);
   1591  1.1      brad 
   1592  1.1      brad 	/* Remove the sensors */
   1593  1.1      brad 	if (sc->sc_sme != NULL) {
   1594  1.1      brad 		sysmon_envsys_unregister(sc->sc_sme);
   1595  1.1      brad 		sc->sc_sme = NULL;
   1596  1.1      brad 	}
   1597  1.1      brad 	mutex_exit(&sc->sc_mutex);
   1598  1.1      brad 
   1599  1.1      brad 	/* Remove the sysctl tree */
   1600  1.1      brad 	sysctl_teardown(&sc->sc_sht3xlog);
   1601  1.1      brad 
   1602  1.1      brad 	/* Remove the mutex */
   1603  1.1      brad 	mutex_destroy(&sc->sc_mutex);
   1604  1.1      brad 	mutex_destroy(&sc->sc_threadmutex);
   1605  1.1      brad 	mutex_destroy(&sc->sc_read_mutex);
   1606  1.1      brad 	mutex_destroy(&sc->sc_dying_mutex);
   1607  1.1      brad 
   1608  1.1      brad 	/* Free the poolname string */
   1609  1.1      brad         if (sc->sc_readpoolname != NULL) {
   1610  1.1      brad                 kmem_free(sc->sc_readpoolname,strlen(sc->sc_readpoolname) + 1);
   1611  1.1      brad         }
   1612  1.1      brad 
   1613  1.1      brad 	return 0;
   1614  1.1      brad }
   1615  1.1      brad 
   1616  1.1      brad int
   1617  1.1      brad sht3x_activate(device_t self, enum devact act)
   1618  1.1      brad {
   1619  1.1      brad 	struct sht3x_sc *sc = device_private(self);
   1620  1.1      brad 
   1621  1.1      brad 	switch (act) {
   1622  1.1      brad 	case DVACT_DEACTIVATE:
   1623  1.1      brad 		sc->sc_dying = true;
   1624  1.1      brad 		return 0;
   1625  1.1      brad 	default:
   1626  1.1      brad 		return EOPNOTSUPP;
   1627  1.1      brad 	}
   1628  1.1      brad }
   1629  1.1      brad 
   1630  1.1      brad MODULE(MODULE_CLASS_DRIVER, sht3xtemp, "i2cexec,sysmon_envsys");
   1631  1.1      brad 
   1632  1.1      brad #ifdef _MODULE
   1633  1.1      brad #include "ioconf.c"
   1634  1.1      brad #endif
   1635  1.1      brad 
   1636  1.1      brad static int
   1637  1.1      brad sht3xtemp_modcmd(modcmd_t cmd, void *opaque)
   1638  1.1      brad {
   1639  1.1      brad 	int error;
   1640  1.1      brad #ifdef _MODULE
   1641  1.1      brad 	int bmaj = -1, cmaj = -1;
   1642  1.1      brad #endif
   1643  1.1      brad 
   1644  1.1      brad 	switch (cmd) {
   1645  1.1      brad 	case MODULE_CMD_INIT:
   1646  1.1      brad #ifdef _MODULE
   1647  1.1      brad 		error = config_init_component(cfdriver_ioconf_sht3xtemp,
   1648  1.1      brad 		    cfattach_ioconf_sht3xtemp, cfdata_ioconf_sht3xtemp);
   1649  1.1      brad 		if (error)
   1650  1.1      brad 			aprint_error("%s: unable to init component\n",
   1651  1.1      brad 			    sht3xtemp_cd.cd_name);
   1652  1.1      brad 
   1653  1.1      brad 		error = devsw_attach("sht3xtemp", NULL, &bmaj,
   1654  1.1      brad 		    &sht3x_cdevsw, &cmaj);
   1655  1.1      brad 		if (error) {
   1656  1.1      brad 			aprint_error("%s: unable to attach devsw\n",
   1657  1.1      brad 			    sht3xtemp_cd.cd_name);
   1658  1.1      brad 			config_fini_component(cfdriver_ioconf_sht3xtemp,
   1659  1.1      brad 			    cfattach_ioconf_sht3xtemp, cfdata_ioconf_sht3xtemp);
   1660  1.1      brad 		}
   1661  1.1      brad 		return error;
   1662  1.1      brad #else
   1663  1.1      brad 		return 0;
   1664  1.1      brad #endif
   1665  1.1      brad 	case MODULE_CMD_FINI:
   1666  1.1      brad #ifdef _MODULE
   1667  1.1      brad 		devsw_detach(NULL, &sht3x_cdevsw);
   1668  1.1      brad 		return config_fini_component(cfdriver_ioconf_sht3xtemp,
   1669  1.1      brad 		      cfattach_ioconf_sht3xtemp, cfdata_ioconf_sht3xtemp);
   1670  1.1      brad #else
   1671  1.1      brad 		return 0;
   1672  1.1      brad #endif
   1673  1.1      brad 	default:
   1674  1.1      brad 		return ENOTTY;
   1675  1.1      brad 	}
   1676  1.1      brad }
   1677