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