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