Home | History | Annotate | Line # | Download | only in i2c
si70xx.c revision 1.12
      1  1.12      brad /*	$NetBSD: si70xx.c,v 1.12 2025/01/23 19:13:19 brad Exp $	*/
      2   1.1  christos 
      3   1.1  christos /*
      4   1.1  christos  * Copyright (c) 2017 Brad Spencer <brad (at) anduin.eldar.org>
      5   1.1  christos  *
      6   1.1  christos  * Permission to use, copy, modify, and distribute this software for any
      7   1.1  christos  * purpose with or without fee is hereby granted, provided that the above
      8   1.1  christos  * copyright notice and this permission notice appear in all copies.
      9   1.1  christos  *
     10   1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11   1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12   1.1  christos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13   1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14   1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15   1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16   1.1  christos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17   1.1  christos  */
     18   1.1  christos 
     19   1.1  christos #include <sys/cdefs.h>
     20  1.12      brad __KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.12 2025/01/23 19:13:19 brad Exp $");
     21   1.1  christos 
     22   1.1  christos /*
     23   1.9      brad   Driver for the Silicon Labs SI7013/SI7020/SI7021, HTU21D and SHT21
     24   1.1  christos */
     25   1.1  christos 
     26   1.1  christos #include <sys/param.h>
     27   1.1  christos #include <sys/systm.h>
     28   1.1  christos #include <sys/kernel.h>
     29   1.1  christos #include <sys/device.h>
     30   1.1  christos #include <sys/module.h>
     31   1.1  christos #include <sys/sysctl.h>
     32   1.1  christos #include <sys/mutex.h>
     33   1.1  christos 
     34   1.1  christos #include <dev/sysmon/sysmonvar.h>
     35   1.1  christos #include <dev/i2c/i2cvar.h>
     36   1.1  christos #include <dev/i2c/si70xxreg.h>
     37   1.1  christos #include <dev/i2c/si70xxvar.h>
     38   1.1  christos 
     39   1.1  christos 
     40   1.1  christos static uint8_t 	si70xx_crc(uint8_t *, size_t);
     41   1.1  christos static int 	si70xx_poke(i2c_tag_t, i2c_addr_t, bool);
     42   1.1  christos static int 	si70xx_match(device_t, cfdata_t, void *);
     43   1.1  christos static void 	si70xx_attach(device_t, device_t, void *);
     44   1.1  christos static int 	si70xx_detach(device_t, int);
     45   1.1  christos static void 	si70xx_refresh(struct sysmon_envsys *, envsys_data_t *);
     46   1.1  christos static int 	si70xx_update_status(struct si70xx_sc *);
     47   1.1  christos static int 	si70xx_set_heateron(struct si70xx_sc *);
     48   1.1  christos static int 	si70xx_set_resolution(struct si70xx_sc *, size_t);
     49   1.1  christos static int 	si70xx_set_heatervalue(struct si70xx_sc *, size_t);
     50   1.1  christos static int 	si70xx_verify_sysctl(SYSCTLFN_ARGS);
     51   1.1  christos static int 	si70xx_verify_sysctl_resolution(SYSCTLFN_ARGS);
     52   1.1  christos static int 	si70xx_verify_sysctl_heateron(SYSCTLFN_ARGS);
     53   1.1  christos static int 	si70xx_verify_sysctl_heatervalue(SYSCTLFN_ARGS);
     54   1.1  christos 
     55   1.1  christos #define SI70XX_DEBUG
     56   1.1  christos #ifdef SI70XX_DEBUG
     57   1.1  christos #define DPRINTF(s, l, x) \
     58   1.1  christos     do { \
     59   1.1  christos 	if (l <= s->sc_si70xxdebug) \
     60   1.1  christos 	    printf x; \
     61   1.1  christos     } while (/*CONSTCOND*/0)
     62   1.1  christos #else
     63   1.1  christos #define DPRINTF(s, l, x)
     64   1.1  christos #endif
     65   1.1  christos 
     66   1.1  christos CFATTACH_DECL_NEW(si70xxtemp, sizeof(struct si70xx_sc),
     67   1.1  christos     si70xx_match, si70xx_attach, si70xx_detach, NULL);
     68   1.1  christos 
     69   1.1  christos static struct si70xx_sensor si70xx_sensors[] = {
     70   1.1  christos 	{
     71   1.1  christos 		.desc = "humidity",
     72   1.1  christos 		.type = ENVSYS_SRELHUMIDITY,
     73   1.1  christos 	},
     74   1.1  christos 	{
     75   1.1  christos 		.desc = "temperature",
     76   1.1  christos 		.type = ENVSYS_STEMP,
     77   1.1  christos 	}
     78   1.1  christos };
     79   1.1  christos 
     80   1.1  christos static struct si70xx_resolution si70xx_resolutions[] = {
     81   1.1  christos 	{
     82   1.1  christos 		.text = "12bit/14bit",
     83   1.1  christos 		.num = 0x00,
     84   1.1  christos 	},
     85   1.1  christos 	{
     86   1.1  christos 		.text = "8bit/12bit",
     87   1.1  christos 		.num = 0x01,
     88   1.1  christos 	},
     89   1.1  christos 	{
     90   1.1  christos 		.text = "10bit/13bit",
     91   1.1  christos 		.num = 0x80,
     92   1.1  christos 	},
     93   1.1  christos 	{
     94   1.1  christos 		.text = "11bit/11bit",
     95   1.1  christos 		.num = 0x81,
     96   1.1  christos 	}
     97   1.1  christos };
     98   1.1  christos 
     99   1.1  christos static const char si70xx_resolution_names[] =
    100   1.1  christos     "12bit/14bit, 8bit/12bit, 10bit/13bit, 11bit/11bit";
    101   1.1  christos 
    102   1.1  christos static const int si70xx_heatervalues[] = {
    103   1.1  christos     0xdeadbeef, 0x00, 0x01, 0x02, 0x04, 0x08, 0x0f
    104   1.1  christos };
    105   1.1  christos 
    106   1.1  christos int
    107   1.1  christos si70xx_verify_sysctl(SYSCTLFN_ARGS)
    108   1.1  christos {
    109   1.1  christos 	int error, t;
    110   1.1  christos 	struct sysctlnode node;
    111   1.1  christos 
    112   1.1  christos 	node = *rnode;
    113   1.1  christos 	t = *(int *)rnode->sysctl_data;
    114   1.1  christos 	node.sysctl_data = &t;
    115   1.1  christos 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    116   1.1  christos 	if (error || newp == NULL)
    117   1.1  christos 		return error;
    118   1.1  christos 
    119   1.1  christos 	if (t < 0)
    120   1.1  christos 		return EINVAL;
    121   1.1  christos 
    122   1.1  christos 	*(int *)rnode->sysctl_data = t;
    123   1.1  christos 
    124   1.1  christos 	return 0;
    125   1.1  christos }
    126   1.1  christos 
    127   1.1  christos int
    128   1.1  christos si70xx_verify_sysctl_resolution(SYSCTLFN_ARGS)
    129   1.1  christos {
    130   1.1  christos 	char buf[SI70XX_RES_NAME];
    131   1.1  christos 	struct si70xx_sc *sc;
    132   1.1  christos 	struct sysctlnode node;
    133   1.1  christos 	int error = 0;
    134   1.1  christos 	size_t i;
    135   1.1  christos 
    136   1.1  christos 	node = *rnode;
    137   1.1  christos 	sc = node.sysctl_data;
    138   1.1  christos 	(void) memcpy(buf, sc->sc_resolution, SI70XX_RES_NAME);
    139   1.1  christos 	node.sysctl_data = buf;
    140   1.1  christos 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    141   1.1  christos 	if (error || newp == NULL)
    142   1.1  christos 		return error;
    143   1.1  christos 
    144   1.1  christos 	for (i = 0; i < __arraycount(si70xx_resolutions); i++) {
    145   1.1  christos 		if (memcmp(node.sysctl_data, si70xx_resolutions[i].text,
    146   1.1  christos 		    SI70XX_RES_NAME) == 0)
    147   1.1  christos 			break;
    148   1.1  christos 	}
    149   1.1  christos 
    150   1.1  christos 	if (i == __arraycount(si70xx_resolutions))
    151   1.1  christos 		return EINVAL;
    152   1.1  christos 	(void) memcpy(sc->sc_resolution, node.sysctl_data, SI70XX_RES_NAME);
    153   1.1  christos 
    154   1.1  christos 	error = si70xx_set_resolution(sc, i);
    155   1.1  christos 
    156   1.1  christos 	return error;
    157   1.1  christos }
    158   1.1  christos 
    159   1.1  christos int
    160   1.1  christos si70xx_verify_sysctl_heateron(SYSCTLFN_ARGS)
    161   1.1  christos {
    162   1.1  christos 	int 		error;
    163   1.1  christos 	bool 		t;
    164   1.1  christos 	struct si70xx_sc *sc;
    165   1.1  christos 	struct sysctlnode node;
    166   1.1  christos 
    167   1.1  christos 	node = *rnode;
    168   1.1  christos 	sc = node.sysctl_data;
    169   1.1  christos 	t = sc->sc_heateron;
    170   1.1  christos 	node.sysctl_data = &t;
    171   1.1  christos 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    172   1.1  christos 	if (error || newp == NULL)
    173   1.1  christos 		return error;
    174   1.1  christos 
    175   1.1  christos 	sc->sc_heateron = t;
    176   1.1  christos 	error = si70xx_set_heateron(sc);
    177   1.1  christos 
    178   1.1  christos 	return error;
    179   1.1  christos }
    180   1.1  christos 
    181   1.1  christos int
    182   1.1  christos si70xx_verify_sysctl_heatervalue(SYSCTLFN_ARGS)
    183   1.1  christos {
    184   1.1  christos 	int 		error = 0, t;
    185   1.1  christos 	struct si70xx_sc *sc;
    186   1.1  christos 	struct sysctlnode node;
    187   1.1  christos 
    188   1.1  christos 	node = *rnode;
    189   1.1  christos 	sc = node.sysctl_data;
    190   1.1  christos 	t = sc->sc_heaterval;
    191   1.1  christos 	node.sysctl_data = &t;
    192   1.1  christos 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    193   1.1  christos 	if (error || newp == NULL)
    194   1.1  christos 		return (error);
    195   1.1  christos 
    196   1.1  christos 	if (t < 1 || t >= __arraycount(si70xx_heatervalues))
    197   1.1  christos 		return (EINVAL);
    198   1.1  christos 
    199   1.1  christos 	sc->sc_heaterval = t;
    200   1.1  christos 	error = si70xx_set_heatervalue(sc, t);
    201   1.1  christos 
    202   1.1  christos 	return error;
    203   1.1  christos }
    204   1.1  christos 
    205   1.3  christos static uint8_t
    206   1.3  christos si70xx_dir(uint8_t cmd, size_t len)
    207   1.1  christos {
    208   1.3  christos 	switch (cmd) {
    209   1.1  christos 	case SI70XX_READ_USER_REG_1:
    210   1.1  christos 	case SI70XX_READ_HEATER_REG:
    211   1.1  christos 	case SI70XX_READ_ID_PT1A:
    212   1.1  christos 	case SI70XX_READ_ID_PT1B:
    213   1.1  christos 	case SI70XX_READ_ID_PT2A:
    214   1.1  christos 	case SI70XX_READ_ID_PT2B:
    215   1.1  christos 	case SI70XX_READ_FW_VERA:
    216   1.1  christos 	case SI70XX_READ_FW_VERB:
    217  1.12      brad 	case SI70XX_MEASURE_RH_HOLD:
    218  1.12      brad 	case SI70XX_MEASURE_TEMP_HOLD:
    219   1.3  christos 		return I2C_OP_READ_WITH_STOP;
    220   1.1  christos 	case SI70XX_WRITE_USER_REG_1:
    221   1.1  christos 	case SI70XX_WRITE_HEATER_REG:
    222   1.1  christos 	case SI70XX_RESET:
    223   1.3  christos 		return I2C_OP_WRITE_WITH_STOP;
    224   1.1  christos 	case SI70XX_MEASURE_RH_NOHOLD:
    225   1.1  christos 	case SI70XX_MEASURE_TEMP_NOHOLD:
    226  1.12      brad 		return len == 0 ? I2C_OP_WRITE : I2C_OP_READ_WITH_STOP;
    227   1.1  christos 	default:
    228   1.3  christos 		panic("%s: bad command %#x\n", __func__, cmd);
    229   1.3  christos 		return 0;
    230   1.1  christos 	}
    231   1.3  christos }
    232   1.3  christos 
    233   1.3  christos static int
    234   1.3  christos si70xx_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd,
    235   1.3  christos     uint8_t clen, uint8_t *buf, size_t blen)
    236   1.3  christos {
    237   1.3  christos 	uint8_t dir;
    238   1.3  christos 	if (clen == 0)
    239   1.3  christos 		dir = blen == 0 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP;
    240   1.3  christos 	else
    241   1.3  christos 		dir = si70xx_dir(cmd[0], blen);
    242   1.3  christos 
    243   1.3  christos 	if (dir == I2C_OP_READ || dir == I2C_OP_READ_WITH_STOP)
    244   1.3  christos 		memset(buf, 0, blen);
    245   1.1  christos 
    246   1.1  christos 	return iic_exec(tag, dir, addr, cmd, clen, buf, blen, 0);
    247   1.1  christos }
    248   1.1  christos 
    249   1.1  christos static int
    250   1.1  christos si70xx_cmd0(struct si70xx_sc *sc, uint8_t *buf, size_t blen)
    251   1.1  christos {
    252   1.1  christos 	return si70xx_cmd(sc->sc_tag, sc->sc_addr, NULL, 0, buf, blen);
    253   1.1  christos }
    254   1.1  christos 
    255   1.1  christos static int
    256   1.1  christos si70xx_cmd1(struct si70xx_sc *sc, uint8_t cmd, uint8_t *buf, size_t blen)
    257   1.1  christos {
    258   1.1  christos 	return si70xx_cmd(sc->sc_tag, sc->sc_addr, &cmd, 1, buf, blen);
    259   1.1  christos }
    260   1.1  christos 
    261   1.1  christos static int
    262   1.1  christos si70xx_cmd2(struct si70xx_sc *sc, uint8_t cmd1, uint8_t cmd2, uint8_t *buf,
    263   1.1  christos     size_t blen)
    264   1.1  christos {
    265   1.1  christos 	uint8_t cmd[] = { cmd1, cmd2 };
    266   1.1  christos 	return si70xx_cmd(sc->sc_tag, sc->sc_addr, cmd, __arraycount(cmd),
    267   1.1  christos 	    buf, blen);
    268   1.1  christos }
    269   1.1  christos 
    270   1.1  christos static int
    271   1.1  christos si70xx_set_heateron(struct si70xx_sc * sc)
    272   1.1  christos {
    273   1.1  christos 	int error;
    274   1.1  christos 	uint8_t userregister;
    275   1.1  christos 
    276   1.1  christos 	error = iic_acquire_bus(sc->sc_tag, 0);
    277   1.1  christos 	if (error) {
    278   1.1  christos 		DPRINTF(sc, 2, ("%s:%s: Failed to acquire bus: %d\n",
    279   1.1  christos 		    device_xname(sc->sc_dev), __func__, error));
    280   1.1  christos 		return error;
    281   1.1  christos 	}
    282   1.1  christos 
    283   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
    284   1.1  christos 	if (error) {
    285   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
    286   1.1  christos 		    device_xname(sc->sc_dev), error));
    287   1.1  christos 		goto out;
    288   1.1  christos 	}
    289   1.1  christos 
    290   1.1  christos 	DPRINTF(sc, 2, ("%s:%s: reg 1 values before: %#x\n",
    291   1.1  christos 	    device_xname(sc->sc_dev), __func__, userregister));
    292   1.1  christos 	if (sc->sc_heateron) {
    293   1.1  christos 		userregister |= SI70XX_HTRE_MASK;
    294   1.1  christos 	} else {
    295   1.1  christos 		userregister &= ~SI70XX_HTRE_MASK;
    296   1.1  christos 	}
    297   1.1  christos 	DPRINTF(sc, 2, ("%s:%s: user reg 1 values after: %#x\n",
    298   1.1  christos 	    device_xname(sc->sc_dev), __func__, userregister));
    299   1.1  christos 
    300   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_WRITE_USER_REG_1, &userregister, 1);
    301   1.1  christos 	if (error) {
    302   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to write user register 1: %d\n",
    303   1.1  christos 		    device_xname(sc->sc_dev), error));
    304   1.1  christos 	}
    305   1.1  christos out:
    306   1.1  christos 	iic_release_bus(sc->sc_tag, 0);
    307   1.1  christos 	return error;
    308   1.1  christos }
    309   1.1  christos 
    310   1.1  christos static int
    311   1.1  christos si70xx_set_resolution(struct si70xx_sc * sc, size_t index)
    312   1.1  christos {
    313   1.1  christos 	int error;
    314   1.1  christos 	uint8_t userregister;
    315   1.1  christos 
    316   1.1  christos 	error = iic_acquire_bus(sc->sc_tag, 0);
    317   1.1  christos 	if (error) {
    318   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to acquire bus: %d\n",
    319   1.1  christos 		    device_xname(sc->sc_dev), error));
    320   1.1  christos 		return error;
    321   1.1  christos 	}
    322   1.1  christos 
    323   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
    324   1.1  christos 	if (error) {
    325   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
    326   1.1  christos 		    device_xname(sc->sc_dev), error));
    327   1.1  christos 		goto out;
    328   1.1  christos 	}
    329   1.1  christos 
    330   1.1  christos 	DPRINTF(sc, 2, ("%s:%s: reg 1 values before: %#x\n",
    331   1.1  christos 	    device_xname(sc->sc_dev), __func__, userregister));
    332   1.1  christos 	userregister &= (~SI70XX_RESOLUTION_MASK);
    333   1.1  christos 	userregister |= si70xx_resolutions[index].num;
    334   1.1  christos 	DPRINTF(sc, 2, ("%s:%s: reg 1 values after: %#x\n",
    335   1.1  christos 	    device_xname(sc->sc_dev), __func__, userregister));
    336   1.1  christos 
    337   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_WRITE_USER_REG_1, &userregister, 1);
    338   1.1  christos 	if (error) {
    339   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to write user register 1: %d\n",
    340   1.1  christos 		    device_xname(sc->sc_dev), error));
    341   1.1  christos 	}
    342   1.1  christos out:
    343   1.1  christos 	iic_release_bus(sc->sc_tag, 0);
    344   1.1  christos 	return error;
    345   1.1  christos }
    346   1.1  christos 
    347   1.1  christos static int
    348   1.1  christos si70xx_set_heatervalue(struct si70xx_sc * sc, size_t index)
    349   1.1  christos {
    350   1.1  christos 	int error;
    351   1.1  christos 	uint8_t heaterregister;
    352   1.1  christos 
    353   1.1  christos 	error = iic_acquire_bus(sc->sc_tag, 0);
    354   1.1  christos 	if (error) {
    355   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to acquire bus: %d\n",
    356   1.1  christos 		    device_xname(sc->sc_dev), error));
    357   1.1  christos 		return error;
    358   1.1  christos 	}
    359   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
    360   1.1  christos 	if (error) {
    361   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to read heater register: %d\n",
    362   1.1  christos 		    device_xname(sc->sc_dev), error));
    363   1.1  christos 		goto out;
    364   1.1  christos 	}
    365   1.1  christos 
    366   1.1  christos 	DPRINTF(sc, 2, ("%s:%s: heater values before: %#x\n",
    367   1.1  christos 	    device_xname(sc->sc_dev), __func__, heaterregister));
    368   1.1  christos 	heaterregister &= ~SI70XX_HEATER_MASK;
    369   1.1  christos 	heaterregister |= si70xx_heatervalues[index];
    370   1.1  christos 	DPRINTF(sc, 2, ("%s:%s: heater values after: %#x\n",
    371   1.1  christos 	    device_xname(sc->sc_dev), __func__, heaterregister));
    372   1.1  christos 
    373   1.3  christos 	error = si70xx_cmd1(sc, SI70XX_WRITE_HEATER_REG, &heaterregister, 1);
    374   1.1  christos 	if (error) {
    375   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to write heater register: %d\n",
    376   1.1  christos 		    device_xname(sc->sc_dev), error));
    377   1.1  christos 	}
    378   1.1  christos out:
    379   1.1  christos 	iic_release_bus(sc->sc_tag, 0);
    380   1.1  christos 	return error;
    381   1.1  christos }
    382   1.1  christos 
    383   1.1  christos static int
    384   1.1  christos si70xx_update_heater(struct si70xx_sc *sc)
    385   1.1  christos {
    386   1.1  christos 	size_t i;
    387   1.1  christos 	int error;
    388   1.1  christos 	uint8_t heaterregister;
    389   1.1  christos 
    390   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
    391   1.1  christos 	if (error) {
    392   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to read heater register: %d\n",
    393   1.1  christos 		    device_xname(sc->sc_dev), error));
    394   1.1  christos 		return error;
    395   1.1  christos 	}
    396   1.1  christos 
    397   1.1  christos 	DPRINTF(sc, 2, ("%s: read heater reg values: %02x\n",
    398   1.1  christos 	    device_xname(sc->sc_dev), heaterregister));
    399   1.1  christos 
    400   1.1  christos 	uint8_t heat = heaterregister & SI70XX_HEATER_MASK;
    401   1.1  christos 	for (i = 0; i < __arraycount(si70xx_heatervalues); i++) {
    402   1.1  christos 		if (si70xx_heatervalues[i] == heat)
    403   1.1  christos 			break;
    404   1.1  christos 	}
    405   1.1  christos 	sc->sc_heaterval = i != __arraycount(si70xx_heatervalues) ? i : 0;
    406   1.1  christos 	return 0;
    407   1.1  christos }
    408   1.1  christos 
    409   1.1  christos static int
    410   1.1  christos si70xx_update_user(struct si70xx_sc *sc)
    411   1.1  christos {
    412   1.1  christos 	size_t i;
    413   1.1  christos 	int error;
    414   1.1  christos 	uint8_t userregister;
    415   1.1  christos 
    416   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
    417   1.1  christos 	if (error) {
    418   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
    419   1.1  christos 		    device_xname(sc->sc_dev), error));
    420   1.1  christos 		return error;
    421   1.1  christos 	}
    422   1.1  christos 	DPRINTF(sc, 2, ("%s: read user reg 1 values: %#x\n",
    423   1.1  christos 	    device_xname(sc->sc_dev), userregister));
    424   1.1  christos 
    425   1.1  christos 	uint8_t res = userregister & SI70XX_RESOLUTION_MASK;
    426   1.1  christos 	for (i = 0; i < __arraycount(si70xx_resolutions); i++) {
    427   1.1  christos 		if (si70xx_resolutions[i].num == res)
    428   1.1  christos 			break;
    429   1.1  christos 	}
    430   1.1  christos 
    431   1.1  christos 	if (i != __arraycount(si70xx_resolutions)) {
    432   1.1  christos 		memcpy(sc->sc_resolution, si70xx_resolutions[i].text,
    433   1.1  christos 		    SI70XX_RES_NAME);
    434   1.1  christos 	} else {
    435   1.1  christos 		snprintf(sc->sc_resolution, SI70XX_RES_NAME, "%02x", res);
    436   1.1  christos 	}
    437   1.1  christos 
    438   1.1  christos 	sc->sc_vddok = (userregister & SI70XX_VDDS_MASK) == 0;
    439   1.1  christos 	sc->sc_heaterval = userregister & SI70XX_HTRE_MASK;
    440   1.1  christos 	return 0;
    441   1.1  christos }
    442   1.1  christos 
    443   1.1  christos static int
    444   1.1  christos si70xx_update_status(struct si70xx_sc *sc)
    445   1.1  christos {
    446   1.1  christos 	int error1 = si70xx_update_user(sc);
    447   1.9      brad 	int error2 = 0;
    448   1.9      brad 	if (! sc->sc_noheater) {
    449   1.9      brad 		error2 = si70xx_update_heater(sc);
    450   1.9      brad 	}
    451   1.1  christos 	return error1 ? error1 : error2;
    452   1.1  christos }
    453   1.1  christos 
    454   1.1  christos static	uint8_t
    455   1.1  christos si70xx_crc(uint8_t * data, size_t size)
    456   1.1  christos {
    457   1.1  christos 	uint8_t crc = 0;
    458   1.1  christos 
    459   1.1  christos 	for (size_t i = 0; i < size; i++) {
    460   1.1  christos 		crc ^= data[i];
    461   1.1  christos 		for (size_t j = 8; j > 0; j--) {
    462   1.1  christos 			if (crc & 0x80)
    463   1.1  christos 				crc = (crc << 1) ^ 0x131;
    464   1.1  christos 			else
    465   1.1  christos 				crc <<= 1;
    466   1.1  christos 		}
    467   1.1  christos 	}
    468   1.1  christos 	return crc;
    469   1.1  christos }
    470   1.1  christos 
    471   1.1  christos static int
    472   1.1  christos si70xx_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
    473   1.1  christos {
    474   1.1  christos 	uint8_t reg = SI70XX_READ_USER_REG_1;
    475   1.1  christos 	uint8_t buf;
    476   1.1  christos 	int error;
    477   1.1  christos 
    478   1.1  christos 	error = si70xx_cmd(tag, addr, &reg, 1, &buf, 1);
    479   1.1  christos 	if (matchdebug) {
    480   1.1  christos 		printf("poke X 1: %d\n", error);
    481   1.1  christos 	}
    482   1.1  christos 	return error;
    483   1.1  christos }
    484   1.1  christos 
    485   1.1  christos static int
    486   1.1  christos si70xx_sysctl_init(struct si70xx_sc *sc)
    487   1.1  christos {
    488   1.1  christos 	int error;
    489   1.1  christos 	const struct sysctlnode *cnode;
    490   1.1  christos 	int sysctlroot_num;
    491   1.1  christos 
    492   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    493   1.1  christos 	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
    494   1.1  christos 	    SYSCTL_DESCR("si70xx controls"), NULL, 0, NULL, 0, CTL_HW,
    495   1.1  christos 	    CTL_CREATE, CTL_EOL)) != 0)
    496   1.1  christos 		return error;
    497   1.1  christos 
    498   1.1  christos 	sysctlroot_num = cnode->sysctl_num;
    499   1.1  christos 
    500   1.1  christos #ifdef SI70XX_DEBUG
    501   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    502   1.1  christos 	    CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
    503   1.1  christos 	    SYSCTL_DESCR("Debug level"), si70xx_verify_sysctl, 0,
    504   1.1  christos 	    &sc->sc_si70xxdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
    505   1.1  christos 	    CTL_EOL)) != 0)
    506   1.1  christos 		return error;
    507   1.1  christos 
    508   1.1  christos #endif
    509   1.1  christos 
    510   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    511  1.12      brad 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "clockstretch",
    512  1.12      brad 	    SYSCTL_DESCR("Use clock stretch commands for measurements"), NULL, 0,
    513   1.1  christos 	    &sc->sc_clockstretch, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
    514   1.1  christos 	    CTL_EOL)) != 0)
    515   1.1  christos 		return error;
    516   1.1  christos 
    517   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    518   1.1  christos 	    CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
    519   1.1  christos 	    SYSCTL_DESCR("The number of times to attempt to read the values"),
    520   1.1  christos 	    si70xx_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
    521   1.1  christos 	    sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    522   1.1  christos 		return error;
    523   1.1  christos 
    524   1.1  christos 
    525   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    526   1.1  christos 	    CTLFLAG_READONLY, CTLTYPE_STRING, "resolutions",
    527   1.1  christos 	    SYSCTL_DESCR("Valid resolutions"), 0, 0,
    528   1.1  christos 	    __UNCONST(si70xx_resolution_names),
    529   1.1  christos 	    sizeof(si70xx_resolution_names) + 1,
    530   1.1  christos 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    531   1.1  christos 		return error;
    532   1.1  christos 
    533   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    534   1.1  christos 	    CTLFLAG_READWRITE, CTLTYPE_STRING, "resolution",
    535   1.1  christos 	    SYSCTL_DESCR("Resolution of RH and Temp"),
    536   1.1  christos 	    si70xx_verify_sysctl_resolution, 0, (void *) sc,
    537   1.1  christos 	    SI70XX_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    538   1.1  christos 		return error;
    539   1.1  christos 
    540   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    541   1.1  christos 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
    542   1.1  christos 	    SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
    543   1.1  christos 	    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    544   1.1  christos 		return error;
    545   1.1  christos 
    546   1.1  christos 	if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    547   1.1  christos 	    CTLFLAG_READONLY, CTLTYPE_BOOL, "vddok",
    548   1.1  christos 	    SYSCTL_DESCR("Vdd at least 1.9v"), NULL, 0, &sc->sc_vddok, 0,
    549   1.1  christos 	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    550   1.1  christos 		return error;
    551   1.1  christos 
    552   1.9      brad 	if (! sc->sc_noheater) {
    553   1.9      brad 		if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    554   1.9      brad 		    CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
    555   1.9      brad 		    SYSCTL_DESCR("Heater on"), si70xx_verify_sysctl_heateron, 0,
    556   1.9      brad 		    (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    557   1.9      brad 			return error;
    558   1.9      brad 
    559   1.9      brad 		if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
    560   1.9      brad 		    CTLFLAG_READWRITE, CTLTYPE_INT, "heaterstrength",
    561   1.9      brad 		    SYSCTL_DESCR("Heater strength 1 to 6"),
    562   1.9      brad 		    si70xx_verify_sysctl_heatervalue, 0, (void *)sc, 0, CTL_HW,
    563   1.9      brad 		    sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
    564   1.9      brad 			return error;
    565   1.9      brad 	}
    566   1.1  christos 
    567   1.9      brad 	return 0;
    568   1.1  christos }
    569   1.1  christos 
    570   1.1  christos static int
    571   1.1  christos si70xx_match(device_t parent, cfdata_t match, void *aux)
    572   1.1  christos {
    573   1.4   thorpej 	struct i2c_attach_args *ia = aux;
    574   1.4   thorpej 	int error, match_result;
    575   1.1  christos 	const bool matchdebug = false;
    576   1.1  christos 
    577   1.4   thorpej 	if (iic_use_direct_match(ia, match, NULL, &match_result))
    578   1.4   thorpej 		return match_result;
    579   1.1  christos 
    580   1.4   thorpej 	/* indirect config - check for configured address */
    581   1.4   thorpej 	if (ia->ia_addr != SI70XX_TYPICAL_ADDR)
    582   1.4   thorpej 		return 0;
    583   1.1  christos 
    584   1.1  christos 	/*
    585   1.1  christos 	 * Check to see if something is really at this i2c address. This will
    586   1.1  christos 	 * keep phantom devices from appearing
    587   1.1  christos 	 */
    588   1.1  christos 	if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
    589   1.1  christos 		if (matchdebug)
    590   1.1  christos 			printf("in match acquire bus failed\n");
    591   1.1  christos 		return 0;
    592   1.1  christos 	}
    593   1.1  christos 
    594   1.1  christos 	error = si70xx_poke(ia->ia_tag, ia->ia_addr, matchdebug);
    595   1.1  christos 	iic_release_bus(ia->ia_tag, 0);
    596   1.1  christos 
    597   1.4   thorpej 	return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
    598   1.1  christos }
    599   1.1  christos 
    600   1.1  christos static void
    601   1.1  christos si70xx_attach(device_t parent, device_t self, void *aux)
    602   1.1  christos {
    603   1.1  christos 	struct si70xx_sc *sc;
    604   1.1  christos 	struct i2c_attach_args *ia;
    605   1.1  christos 	int error, i;
    606   1.1  christos 	int ecount = 0;
    607   1.1  christos 	uint8_t buf[8];
    608   1.1  christos 	uint8_t testcrcpt1[4];
    609   1.1  christos 	uint8_t testcrcpt2[4];
    610   1.1  christos 	uint8_t crc1 = 0, crc2 = 0;
    611  1.10      brad 	bool validcrcpt1, validcrcpt2;
    612   1.1  christos 	uint8_t readcrc1 = 0, readcrc2 = 0;
    613   1.9      brad 	uint8_t fwversion = 0, model, heaterregister;
    614   1.1  christos 
    615   1.1  christos 	ia = aux;
    616   1.1  christos 	sc = device_private(self);
    617   1.1  christos 
    618   1.1  christos 	sc->sc_dev = self;
    619   1.1  christos 	sc->sc_tag = ia->ia_tag;
    620   1.1  christos 	sc->sc_addr = ia->ia_addr;
    621   1.1  christos 	sc->sc_si70xxdebug = 0;
    622  1.12      brad 	sc->sc_clockstretch = false;
    623  1.10      brad 	sc->sc_readattempts = 40;
    624   1.1  christos 	sc->sc_ignorecrc = false;
    625   1.1  christos 	sc->sc_sme = NULL;
    626   1.9      brad 	sc->sc_noheater = false;
    627   1.9      brad 	sc->sc_nofw = false;
    628   1.1  christos 
    629   1.1  christos 	aprint_normal("\n");
    630   1.1  christos 
    631   1.1  christos 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
    632   1.1  christos 	sc->sc_numsensors = __arraycount(si70xx_sensors);
    633   1.1  christos 
    634   1.1  christos 	if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
    635   1.1  christos 		aprint_error_dev(self,
    636   1.1  christos 		    "Unable to create sysmon structure\n");
    637   1.1  christos 		sc->sc_sme = NULL;
    638   1.1  christos 		return;
    639   1.1  christos 	}
    640   1.1  christos 
    641   1.1  christos 	error = iic_acquire_bus(sc->sc_tag, 0);
    642   1.1  christos 	if (error) {
    643   1.1  christos 		aprint_error_dev(self, "Could not acquire iic bus: %d\n",
    644   1.1  christos 		    error);
    645   1.1  christos 		goto out;
    646   1.1  christos 	}
    647   1.1  christos 	error = si70xx_cmd1(sc, SI70XX_RESET, NULL, 0);
    648   1.1  christos 	if (error != 0)
    649   1.1  christos 		aprint_error_dev(self, "Reset failed: %d\n", error);
    650   1.1  christos 
    651   1.1  christos 	delay(15000);	/* 15 ms max */
    652   1.1  christos 
    653   1.1  christos 	error = si70xx_cmd2(sc, SI70XX_READ_ID_PT1A, SI70XX_READ_ID_PT1B,
    654   1.1  christos 	    buf, 8);
    655   1.1  christos 	if (error) {
    656   1.1  christos 		aprint_error_dev(self, "Failed to read first part of ID: %d\n",
    657   1.1  christos 		    error);
    658   1.1  christos 		ecount++;
    659   1.1  christos 	}
    660   1.1  christos 	testcrcpt1[0] = buf[0];
    661   1.1  christos 	testcrcpt1[1] = buf[2];
    662   1.1  christos 	testcrcpt1[2] = buf[4];
    663   1.1  christos 	testcrcpt1[3] = buf[6];
    664   1.1  christos 	readcrc1 = buf[7];
    665   1.1  christos 	crc1 = si70xx_crc(testcrcpt1, 4);
    666  1.10      brad 	/* A "real" SI70xx has the CRC cover the entire first part of the
    667  1.10      brad 	 * serial number.  An HTU21D has the CRC broken out into each
    668  1.10      brad 	 * part of the serial number.
    669  1.10      brad 	 */
    670  1.10      brad 	validcrcpt1 = (readcrc1 == crc1);
    671  1.10      brad 	if (! validcrcpt1) {
    672  1.10      brad 		validcrcpt1 = (si70xx_crc(&testcrcpt1[0],1) == buf[1] &&
    673  1.10      brad 		    si70xx_crc(&testcrcpt1[1],1) == buf[3] &&
    674  1.10      brad 		    si70xx_crc(&testcrcpt1[2],1) == buf[5] &&
    675  1.10      brad 		    si70xx_crc(&testcrcpt1[3],1) == buf[7]);
    676  1.10      brad 		DPRINTF(sc, 2, ("%s: Part 1 SN CRC was not valid for real type, "
    677  1.10      brad 		    "check clone: %d\n", device_xname(sc->sc_dev), validcrcpt1));
    678  1.10      brad 	}
    679   1.1  christos 
    680   1.1  christos 	DPRINTF(sc, 2, ("%s: read 1 values: %02x%02x%02x%02x%02x%02x%02x%02x "
    681  1.10      brad 	    "- %02x -- %d\n", device_xname(sc->sc_dev), buf[0], buf[1],
    682   1.1  christos 	    buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
    683  1.10      brad 	    crc1, validcrcpt1));
    684   1.1  christos 
    685   1.1  christos 	error = si70xx_cmd2(sc, SI70XX_READ_ID_PT2A, SI70XX_READ_ID_PT2B,
    686  1.12      brad 	    buf, 6);
    687   1.1  christos 	if (error != 0) {
    688   1.1  christos 		aprint_error_dev(self, "Failed to read second part of ID: %d\n",
    689   1.1  christos 		    error);
    690   1.1  christos 		ecount++;
    691   1.1  christos 	}
    692   1.1  christos 	model = testcrcpt2[0] = buf[0];
    693   1.1  christos 	testcrcpt2[1] = buf[1];
    694   1.1  christos 	testcrcpt2[2] = buf[3];
    695   1.1  christos 	testcrcpt2[3] = buf[4];
    696   1.1  christos 	readcrc2 = buf[5];
    697   1.1  christos 	crc2 = si70xx_crc(testcrcpt2, 4);
    698  1.10      brad 	/* It is even stranger for this part of the serial number.  A "real"
    699  1.10      brad 	 * SI70XX will have a single CRC for the entire second part, but
    700  1.10      brad 	 * an HTU21D has a CRC for each word in this case.
    701  1.10      brad 	 *
    702  1.10      brad 	 * The datasheet actually agrees with the HTU21D case, and not the "real"
    703  1.10      brad 	 * chip.
    704  1.10      brad 	 */
    705  1.10      brad 	validcrcpt2 = (readcrc2 == crc2);
    706  1.10      brad 	if (! validcrcpt2) {
    707  1.10      brad 		validcrcpt2 = (si70xx_crc(&testcrcpt2[0],2) == buf[2] &&
    708  1.10      brad 		    si70xx_crc(&testcrcpt2[2],2) == buf[5]);
    709  1.10      brad 		DPRINTF(sc, 2, ("%s: Part 2 SN CRC was not valid for real type, "
    710  1.10      brad 		    "check clone: %d\n", device_xname(sc->sc_dev), validcrcpt2));
    711  1.10      brad 	}
    712   1.1  christos 
    713  1.10      brad 	DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x -- %d\n",
    714   1.1  christos 	    device_xname(sc->sc_dev), buf[0], buf[1], buf[2],
    715  1.10      brad 	    buf[3], buf[4], buf[5], crc2, validcrcpt2));
    716   1.1  christos 
    717   1.1  christos 	error = si70xx_cmd2(sc, SI70XX_READ_FW_VERA, SI70XX_READ_FW_VERB,
    718  1.12      brad 	    buf, 1);
    719   1.1  christos 
    720   1.1  christos 	if (error) {
    721  1.10      brad 		aprint_error_dev(self, "Failed to read firmware version: Error %d\n",
    722   1.1  christos 		    error);
    723   1.9      brad 		sc->sc_nofw = true;
    724   1.9      brad 	}
    725   1.9      brad 	if (! sc->sc_nofw) {
    726   1.9      brad 		fwversion = buf[0];
    727   1.9      brad 		DPRINTF(sc, 2, ("%s: read fw values: %#x\n", device_xname(sc->sc_dev),
    728   1.9      brad 		    fwversion));
    729   1.9      brad 	}
    730   1.9      brad 
    731   1.9      brad 	error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
    732   1.9      brad 
    733   1.9      brad 	if (error) {
    734  1.10      brad 		aprint_error_dev(self, "Failed to read heater register: Error %d\n",
    735   1.9      brad 		    error);
    736   1.9      brad 		sc->sc_noheater = true;
    737   1.1  christos 	}
    738   1.1  christos 
    739   1.1  christos 	error = si70xx_update_status(sc);
    740   1.9      brad 
    741   1.1  christos 	iic_release_bus(sc->sc_tag, 0);
    742   1.9      brad 
    743   1.9      brad 	if ((error = si70xx_sysctl_init(sc)) != 0) {
    744   1.9      brad 		aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
    745   1.9      brad 		goto out;
    746   1.9      brad 	}
    747   1.9      brad 
    748   1.1  christos 	if (error != 0) {
    749   1.1  christos 		aprint_error_dev(self, "Failed to update status: %x\n", error);
    750   1.1  christos 		aprint_error_dev(self, "Unable to setup device\n");
    751   1.1  christos 		goto out;
    752   1.1  christos 	}
    753   1.1  christos 
    754   1.1  christos 	for (i = 0; i < sc->sc_numsensors; i++) {
    755   1.1  christos 		strlcpy(sc->sc_sensors[i].desc, si70xx_sensors[i].desc,
    756   1.1  christos 		    sizeof(sc->sc_sensors[i].desc));
    757   1.1  christos 
    758   1.1  christos 		sc->sc_sensors[i].units = si70xx_sensors[i].type;
    759   1.1  christos 		sc->sc_sensors[i].state = ENVSYS_SINVALID;
    760   1.1  christos 
    761   1.1  christos 		DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
    762   1.1  christos 		    sc->sc_sensors[i].desc));
    763   1.1  christos 
    764   1.1  christos 		error = sysmon_envsys_sensor_attach(sc->sc_sme,
    765   1.1  christos 		    &sc->sc_sensors[i]);
    766   1.1  christos 		if (error) {
    767   1.1  christos 			aprint_error_dev(self,
    768   1.1  christos 			    "Unable to attach sensor %d: %d\n", i, error);
    769   1.6       jdc 			sc->sc_sme = NULL;
    770   1.1  christos 			goto out;
    771   1.1  christos 		}
    772   1.1  christos 	}
    773   1.1  christos 
    774   1.1  christos 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
    775   1.1  christos 	sc->sc_sme->sme_cookie = sc;
    776   1.1  christos 	sc->sc_sme->sme_refresh = si70xx_refresh;
    777   1.1  christos 
    778   1.1  christos 	DPRINTF(sc, 2, ("si70xx_attach: registering with envsys\n"));
    779   1.1  christos 
    780   1.1  christos 	if (sysmon_envsys_register(sc->sc_sme)) {
    781   1.1  christos 		aprint_error_dev(self,
    782   1.1  christos 			"unable to register with sysmon\n");
    783   1.1  christos 		sysmon_envsys_destroy(sc->sc_sme);
    784   1.1  christos 		sc->sc_sme = NULL;
    785   1.1  christos 		return;
    786   1.1  christos 	}
    787   1.1  christos 
    788   1.1  christos 	char modelstr[64];
    789   1.1  christos 	switch (model) {
    790   1.1  christos 	case 0:
    791   1.1  christos 	case 0xff:
    792   1.1  christos 		snprintf(modelstr, sizeof(modelstr), "Engineering Sample");
    793   1.5       mrg 		break;
    794   1.1  christos 	case 13:
    795   1.1  christos 	case 20:
    796   1.1  christos 	case 21:
    797   1.1  christos 		snprintf(modelstr, sizeof(modelstr), "SI70%d", model);
    798   1.1  christos 		break;
    799   1.1  christos 	default:
    800   1.9      brad 		snprintf(modelstr, sizeof(modelstr), "Unknown model %d (maybe an HTU21D)", model);
    801   1.1  christos 		break;
    802   1.1  christos 	}
    803   1.1  christos 
    804   1.1  christos 	const char *fwversionstr;
    805   1.1  christos 	switch (fwversion) {
    806   1.1  christos 	case 0xff:
    807   1.1  christos 		fwversionstr = "1.0";
    808   1.1  christos 		break;
    809   1.1  christos 	case 0x20:
    810   1.1  christos 		fwversionstr = "2.0";
    811   1.1  christos 		break;
    812   1.1  christos 	default:
    813   1.1  christos 		fwversionstr = "unknown";
    814   1.1  christos 		break;
    815   1.1  christos 	}
    816   1.1  christos 
    817   1.1  christos 	aprint_normal_dev(self, "Silicon Labs Model: %s, "
    818   1.1  christos 	    "Firmware version: %s, "
    819   1.1  christos 	    "Serial number: %02x%02x%02x%02x%02x%02x%02x%02x%s",
    820   1.1  christos 	    modelstr, fwversionstr, testcrcpt1[0], testcrcpt1[1],
    821   1.1  christos 	    testcrcpt1[2], testcrcpt1[3], testcrcpt2[0], testcrcpt2[1],
    822   1.1  christos 	    testcrcpt2[2], testcrcpt2[3],
    823  1.10      brad 	    (validcrcpt1 && validcrcpt2) ? "\n" : " (bad crc)\n");
    824   1.1  christos 	return;
    825   1.1  christos out:
    826   1.1  christos 	sysmon_envsys_destroy(sc->sc_sme);
    827   1.1  christos 	sc->sc_sme = NULL;
    828   1.1  christos }
    829   1.1  christos 
    830   1.1  christos static int
    831   1.1  christos si70xx_exec(struct si70xx_sc *sc, uint8_t cmd, envsys_data_t *edata)
    832   1.1  christos {
    833   1.1  christos 	int error;
    834   1.1  christos 	int xdelay;
    835   1.1  christos 	const char *name;
    836   1.1  christos 	int64_t mul, offs;
    837   1.1  christos 	uint8_t buf[3];
    838   1.1  christos 
    839   1.1  christos 	switch (cmd) {
    840   1.1  christos 	case SI70XX_MEASURE_RH_NOHOLD:
    841  1.12      brad 	case SI70XX_MEASURE_RH_HOLD:
    842   1.1  christos 		/*
    843   1.1  christos 		 * The published conversion for RH is: %RH =
    844   1.1  christos 		 * ((125 * RHCODE) / 65536) - 6
    845   1.1  christos 		 *
    846   1.1  christos 		 * The sysmon infrastructure for RH wants %RH *
    847   1.1  christos 		 * 10^6 The result will fit in 32 bits, but
    848   1.1  christos 		 * the intermediate values will not.
    849   1.1  christos 		 */
    850   1.1  christos 		mul = 125000000;
    851   1.1  christos 		offs = -6000000;
    852   1.1  christos 		/*
    853   1.1  christos 		 * Conversion times for %RH in ms
    854   1.1  christos 		 *
    855   1.1  christos 		 *        	Typical Max
    856   1.1  christos 		 * 12-bit	10.0	12.0
    857   1.1  christos 		 * 11-bit	 5.8	 7.0
    858   1.1  christos 		 * 10-bit	 3.7	 4.5
    859   1.1  christos 		 *  8-bit	 2.6	 3.1
    860   1.1  christos 		 *
    861   1.1  christos 		 * A call to read %RH will also read temperature.  The
    862   1.1  christos 		 * conversion time will be the amount of time above
    863   1.1  christos 		 * plus the amount of time for temperature below
    864   1.1  christos 		 */
    865   1.1  christos 		xdelay = 10500;
    866   1.1  christos 		name = "RH";
    867   1.1  christos 		break;
    868   1.1  christos 	case SI70XX_MEASURE_TEMP_NOHOLD:
    869  1.12      brad 	case SI70XX_MEASURE_TEMP_HOLD:
    870   1.1  christos 		/*
    871   1.1  christos 		 * The published conversion for temp is:
    872   1.1  christos 		 * degree C = ((175.72 * TEMPCODE) / 65536) -
    873   1.1  christos 		 * 46.85
    874   1.1  christos 		 *
    875   1.1  christos 		 * The sysmon infrastructure for temp wants
    876   1.1  christos 		 * microkelvin.  This is simple, as degree C
    877   1.1  christos 		 * converts directly with K with simple
    878   1.1  christos 		 * addition. The result will fit in 32 bits,
    879   1.1  christos 		 * but the intermediate values will not.
    880   1.1  christos 		 */
    881   1.1  christos 		mul = 175720000;
    882   1.1  christos 		offs = 226300000;
    883   1.1  christos 		/*
    884   1.1  christos 		 * Conversion times for temperature in ms
    885   1.1  christos 	 	 *
    886   1.1  christos 		 *		Typical	Max
    887   1.1  christos 		 * 14-bit	7.0	10.8
    888   1.1  christos 		 * 13-bit	4.0	 6.2
    889   1.1  christos 		 * 12-bit	2.4	 3.8
    890   1.1  christos 		 * 11-bit	1.5	 2.4
    891   1.1  christos 		 */
    892   1.1  christos 		xdelay = 4750;
    893   1.1  christos 		name = "TEMP";
    894   1.1  christos 		break;
    895   1.1  christos 	default:
    896   1.1  christos 		return EINVAL;
    897   1.1  christos 	}
    898   1.1  christos 
    899  1.12      brad 	if (sc->sc_clockstretch) {
    900  1.12      brad 		error = si70xx_cmd1(sc, cmd, buf, sizeof(buf));
    901  1.12      brad 		if (error) {
    902  1.12      brad 			DPRINTF(sc, 2, ("%s: Failed to read HOLD %s %d %d\n",
    903  1.12      brad 			    device_xname(sc->sc_dev), name, 1, error));
    904  1.12      brad 			return error;
    905  1.12      brad 		}
    906  1.12      brad 	} else {
    907  1.12      brad 		error = si70xx_cmd1(sc, cmd, NULL, 0);
    908  1.12      brad 		if (error) {
    909  1.12      brad 			DPRINTF(sc, 2, ("%s: Failed to read NO HOLD %s %d %d\n",
    910  1.12      brad 			    device_xname(sc->sc_dev), name, 1, error));
    911  1.12      brad 			return error;
    912  1.12      brad 		}
    913   1.1  christos 
    914  1.12      brad 		/*
    915  1.12      brad 		 * It will probably be at least this long... we would
    916  1.12      brad 		 * not have to do this sort of thing if clock
    917  1.12      brad 		 * stretching worked.  Even this is a problem for the
    918  1.12      brad 		 * RPI without a patch to remove a [apparently] not
    919  1.12      brad 		 * needed KASSERT()
    920  1.12      brad 		 */
    921  1.12      brad 		delay(xdelay);
    922   1.1  christos 
    923  1.12      brad 		for (int aint = 0; aint < sc->sc_readattempts; aint++) {
    924  1.12      brad 			error = si70xx_cmd0(sc, buf, sizeof(buf));
    925  1.12      brad 			if (error == 0)
    926  1.12      brad 				break;
    927  1.12      brad 			DPRINTF(sc, 2, ("%s: Failed to read NO HOLD RH"
    928  1.12      brad 			    " %d %d\n", device_xname(sc->sc_dev), 2, error));
    929  1.12      brad 			delay(1000);
    930  1.12      brad 		}
    931   1.1  christos 	}
    932   1.1  christos 
    933   1.1  christos 	DPRINTF(sc, 2, ("%s: %s values: %02x%02x%02x - %02x\n",
    934   1.1  christos 	    device_xname(sc->sc_dev), name, buf[0], buf[1], buf[2],
    935   1.1  christos 	    si70xx_crc(buf, 2)));
    936   1.1  christos 
    937   1.1  christos 	uint8_t crc;
    938   1.1  christos 	if (sc->sc_ignorecrc) {
    939   1.1  christos 		crc = buf[2];
    940   1.1  christos 	} else {
    941   1.1  christos 		crc = si70xx_crc(buf, 2);
    942   1.1  christos 	}
    943   1.1  christos 
    944   1.1  christos 	if (crc != buf[2]) {
    945   1.1  christos 		DPRINTF(sc, 2, ("%s: Bad CRC for %s: %#x and %#x\n",
    946   1.1  christos 		    device_xname(sc->sc_dev), name, crc, buf[2]));
    947   1.1  christos 		return EINVAL;
    948   1.1  christos 	}
    949   1.1  christos 
    950   1.1  christos 	uint16_t val16 = (buf[0] << 8) | buf[1];
    951   1.1  christos 	uint64_t val64 = ((mul * val16) >> 16) + offs;
    952   1.1  christos 	DPRINTF(sc, 2, ("%s: %s calculated values: %x %#jx\n",
    953   1.1  christos 	    device_xname(sc->sc_dev), name, val16, (uintmax_t)val64));
    954   1.1  christos 	edata->value_cur = (uint32_t) val64;
    955   1.1  christos 	edata->state = ENVSYS_SVALID;
    956   1.1  christos 	return 0;
    957   1.1  christos }
    958   1.1  christos 
    959   1.1  christos static void
    960   1.1  christos si70xx_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
    961   1.1  christos {
    962   1.1  christos 	struct si70xx_sc *sc;
    963   1.1  christos 	int 		error;
    964   1.1  christos 
    965   1.1  christos 	sc = sme->sme_cookie;
    966   1.1  christos 	edata->state = ENVSYS_SINVALID;
    967   1.1  christos 
    968   1.1  christos 	mutex_enter(&sc->sc_mutex);
    969   1.1  christos 	error = iic_acquire_bus(sc->sc_tag, 0);
    970   1.1  christos 	if (error) {
    971   1.1  christos 		DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
    972   1.1  christos 		    device_xname(sc->sc_dev), error));
    973   1.1  christos 		goto out;
    974   1.1  christos 	}
    975   1.1  christos 	error = si70xx_update_status(sc);
    976   1.1  christos 	if (error) {
    977   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to update status in refresh %d\n",
    978   1.1  christos 		    device_xname(sc->sc_dev), error));
    979   1.1  christos 		goto out1;
    980   1.1  christos 	}
    981   1.1  christos 	switch (edata->sensor) {
    982   1.1  christos 	case SI70XX_HUMIDITY_SENSOR:
    983  1.12      brad 		if (sc->sc_clockstretch)
    984  1.12      brad 			error = si70xx_exec(sc, SI70XX_MEASURE_RH_HOLD, edata);
    985  1.12      brad 		else
    986  1.12      brad 			error = si70xx_exec(sc, SI70XX_MEASURE_RH_NOHOLD, edata);
    987   1.1  christos 		break;
    988   1.1  christos 
    989   1.1  christos 	case SI70XX_TEMP_SENSOR:
    990  1.12      brad 		if (sc->sc_clockstretch)
    991  1.12      brad 			error = si70xx_exec(sc, SI70XX_MEASURE_TEMP_HOLD, edata);
    992  1.12      brad 		else
    993  1.12      brad 			error = si70xx_exec(sc, SI70XX_MEASURE_TEMP_NOHOLD, edata);
    994   1.1  christos 		break;
    995   1.1  christos 	default:
    996   1.1  christos 		error = EINVAL;
    997   1.1  christos 		break;
    998   1.1  christos 	}
    999   1.1  christos 
   1000   1.1  christos 	if (error) {
   1001   1.1  christos 		DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
   1002   1.1  christos 		    device_xname(sc->sc_dev), error));
   1003   1.1  christos 	}
   1004   1.1  christos out1:
   1005   1.1  christos 	iic_release_bus(sc->sc_tag, 0);
   1006   1.1  christos out:
   1007   1.1  christos 	mutex_exit(&sc->sc_mutex);
   1008   1.1  christos }
   1009   1.1  christos 
   1010   1.1  christos static int
   1011   1.1  christos si70xx_detach(device_t self, int flags)
   1012   1.1  christos {
   1013   1.1  christos 	struct si70xx_sc *sc;
   1014   1.1  christos 
   1015   1.1  christos 	sc = device_private(self);
   1016   1.1  christos 
   1017   1.1  christos 	mutex_enter(&sc->sc_mutex);
   1018   1.1  christos 
   1019   1.1  christos 	/* Remove the sensors */
   1020   1.7   mlelstv 	if (sc->sc_sme != NULL)
   1021   1.1  christos 		sysmon_envsys_unregister(sc->sc_sme);
   1022   1.1  christos 	mutex_exit(&sc->sc_mutex);
   1023   1.1  christos 
   1024   1.1  christos 	/* Remove the sysctl tree */
   1025   1.1  christos 	sysctl_teardown(&sc->sc_si70xxlog);
   1026   1.1  christos 
   1027   1.1  christos 	/* Remove the mutex */
   1028   1.1  christos 	mutex_destroy(&sc->sc_mutex);
   1029   1.1  christos 
   1030   1.1  christos 	return 0;
   1031   1.1  christos }
   1032   1.1  christos 
   1033  1.11  pgoyette MODULE(MODULE_CLASS_DRIVER, si70xxtemp, "iic,sysmon_envsys");
   1034   1.1  christos 
   1035   1.1  christos #ifdef _MODULE
   1036   1.1  christos #include "ioconf.c"
   1037   1.1  christos #endif
   1038   1.1  christos 
   1039   1.1  christos static int
   1040   1.1  christos si70xxtemp_modcmd(modcmd_t cmd, void *opaque)
   1041   1.1  christos {
   1042   1.1  christos 
   1043   1.1  christos 	switch (cmd) {
   1044   1.1  christos 	case MODULE_CMD_INIT:
   1045   1.1  christos #ifdef _MODULE
   1046   1.1  christos 		return config_init_component(cfdriver_ioconf_si70xxtemp,
   1047   1.1  christos 		    cfattach_ioconf_si70xxtemp, cfdata_ioconf_si70xxtemp);
   1048   1.1  christos #else
   1049   1.1  christos 		return 0;
   1050   1.1  christos #endif
   1051   1.1  christos 	case MODULE_CMD_FINI:
   1052   1.1  christos #ifdef _MODULE
   1053   1.2  christos 		return config_fini_component(cfdriver_ioconf_si70xxtemp,
   1054   1.1  christos 		      cfattach_ioconf_si70xxtemp, cfdata_ioconf_si70xxtemp);
   1055   1.1  christos #else
   1056   1.1  christos 		return 0;
   1057   1.1  christos #endif
   1058   1.1  christos 	default:
   1059   1.1  christos 		return ENOTTY;
   1060   1.1  christos 	}
   1061   1.1  christos }
   1062