code:
/*	$OpenBSD: rs5c372.c,v 1.5 2009/10/05 18:59:36 deraadt Exp $	*/
/*	$NetBSD: rs5c372.c,v 1.5 2006/03/29 06:41:24 thorpej Exp $	*/

/*
 * Copyright (c) 2005 Kimihiro Nonaka
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/fcntl.h>
#include <sys/uio.h>
#include <sys/conf.h>
#include <sys/event.h>

#include <dev/clock_subr.h>

#include <dev/i2c/i2cvar.h>

/*
 * RS5C372[AB] Real-Time Clock
 */

#define	RICOHRTC_ADDR		0x32	/* Fixed I2C Slave Address */

#define RICOHRTC_SECONDS	0
#define RICOHRTC_MINUTES	1
#define RICOHRTC_HOURS		2
#define RICOHRTC_DAY		3
#define RICOHRTC_DATE		4
#define RICOHRTC_MONTH		5
#define RICOHRTC_YEAR		6
#define RICOHRTC_CLOCK_CORRECT	7
#define RICOHRTC_ALARMA_MIN	8
#define RICOHRTC_ALARMA_HOUR	9
#define RICOHRTC_ALARMA_DATE	10
#define RICOHRTC_ALARMB_MIN	11
#define RICOHRTC_ALARMB_HOUR	12
#define RICOHRTC_ALARMB_DATE	13
#define RICOHRTC_CONTROL1	14
#define RICOHRTC_CONTROL2	15
#define	RICOHRTC_NREGS		16
#define	RICOHRTC_NRTC_REGS	7

/*
 * Bit definitions.
 */
#define	RICOHRTC_SECONDS_MASK	0x7f
#define	RICOHRTC_MINUTES_MASK	0x7f
#define	RICOHRTC_HOURS_12HRS_PM	(1u << 5)	/* If 12 hr mode, set = PM */
#define	RICOHRTC_HOURS_12MASK	0x1f
#define	RICOHRTC_HOURS_24MASK	0x3f
#define	RICOHRTC_DAY_MASK	0x07
#define	RICOHRTC_DATE_MASK	0x3f
#define	RICOHRTC_MONTH_MASK	0x1f
#define	RICOHRTC_CONTROL2_24HRS	(1u << 5)
#define	RICOHRTC_CONTROL2_XSTP	(1u << 4)	/* read */
#define	RICOHRTC_CONTROL2_ADJ	(1u << 4)	/* write */
#define	RICOHRTC_CONTROL2_NCLEN	(1u << 3)
#define	RICOHRTC_CONTROL2_CTFG	(1u << 2)
#define	RICOHRTC_CONTROL2_AAFG	(1u << 1)
#define	RICOHRTC_CONTROL2_BAFG	(1u << 0)

struct ricohrtc_softc {
	struct device sc_dev;
	i2c_tag_t sc_tag;
	int sc_address;
	struct todr_chip_handle sc_todr;
};

int ricohrtc_match(struct device *, void *, void *);
void ricohrtc_attach(struct device *, struct device *, void *);

struct cfattach ricohrtc_ca = {
	sizeof(struct ricohrtc_softc), ricohrtc_match, ricohrtc_attach
};

struct cfdriver ricohrtc_cd = {
	NULL, "ricohrtc", DV_DULL
};

void ricohrtc_reg_write(struct ricohrtc_softc *, int, uint8_t);
int ricohrtc_clock_read(struct ricohrtc_softc *, struct clock_ymdhms *);
int ricohrtc_clock_write(struct ricohrtc_softc *, struct clock_ymdhms *);
int ricohrtc_gettime(struct todr_chip_handle *, struct timeval *);
int ricohrtc_settime(struct todr_chip_handle *, struct timeval *);
int ricohrtc_getcal(struct todr_chip_handle *, int *);
int ricohrtc_setcal(struct todr_chip_handle *, int);

int
ricohrtc_match(struct device *parent, void *v, void *arg)
{
	struct i2c_attach_args *ia = arg;
#ifdef PARANOID_CHECKS
	u_int8_t data, cmd;
#endif

	if (ia->ia_addr != RICOHRTC_ADDR)
		return (0);

#ifdef PARANOID_CHECKS
	/* Verify that the 'reserved bits in a few registers read 0 */
	if (iic_acquire_bus(ia->ia_tag, I2C_F_POLL)) {
		printf("ricohrtc acquire fail\n");
		return (0);
	}

	cmd = RICOHRTC_SECONDS;
	if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr,
	    &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) {
		iic_release_bus(ia->ia_tag, I2C_F_POLL);
		printf("ricohrtc read %d fail\n", cmd);
		return (0);
	}
	if ((data & ~RICOHRTC_SECONDS_MASK) != 0) {
		iic_release_bus(ia->ia_tag, I2C_F_POLL);
		printf("ricohrtc second %d\n",data);
		return (0);
	}

	cmd = RICOHRTC_MINUTES;
	if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr,
	    &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) {
		iic_release_bus(ia->ia_tag, I2C_F_POLL);
		printf("ricohrtc read %d fail\n", cmd);
		return (0);
	}

	if ((data & ~RICOHRTC_MINUTES_MASK) != 0) {
		iic_release_bus(ia->ia_tag, I2C_F_POLL);
		printf("ricohrtc minute %d\n",data);
		return (0);
	}

	cmd = RICOHRTC_HOURS;
	if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr,
	    &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) {
		iic_release_bus(ia->ia_tag, I2C_F_POLL);
		printf("ricohrtc read %d fail\n", cmd);
		return (0);
	}
	if ((data & ~RICOHRTC_HOURS_24MASK) != 0) {
		iic_release_bus(ia->ia_tag, I2C_F_POLL);
		printf("ricohrtc hour %d\n",data);
		return (0);
	}
	iic_release_bus(ia->ia_tag, I2C_F_POLL);

#endif
	return (1);
}

void
ricohrtc_attach(struct device *parent, struct device *self, void *arg)
{
	struct ricohrtc_softc *sc = (struct ricohrtc_softc *)self;
	struct i2c_attach_args *ia = arg;

	printf(": RICOH RS5C372[AB] Real-time Clock\n");

	sc->sc_tag = ia->ia_tag;
	sc->sc_address = ia->ia_addr;
	sc->sc_todr.cookie = sc;
	sc->sc_todr.todr_gettime = ricohrtc_gettime;
	sc->sc_todr.todr_settime = ricohrtc_settime;
	sc->sc_todr.todr_getcal = ricohrtc_getcal;
	sc->sc_todr.todr_setcal = ricohrtc_setcal;
	sc->sc_todr.todr_setwen = NULL;

#if 0
	todr_attach(&sc->sc_todr);
#else
	/* XXX */
	{
	extern todr_chip_handle_t todr_handle;
	todr_handle = &sc->sc_todr;
	}
#endif

	/* Initialize RTC */
	ricohrtc_reg_write(sc, RICOHRTC_CONTROL2, RICOHRTC_CONTROL2_24HRS);
	ricohrtc_reg_write(sc, RICOHRTC_CONTROL1, 0);
}

int
ricohrtc_gettime(struct todr_chip_handle *ch, struct timeval *tv)
{
	struct ricohrtc_softc *sc = ch->cookie;
	struct clock_ymdhms dt;

	memset(&dt, 0, sizeof(dt));
	if (ricohrtc_clock_read(sc, &dt) == 0)
		return (-1);

	tv->tv_sec = clock_ymdhms_to_secs(&dt);
	tv->tv_usec = 0;
	return (0);
}

int
ricohrtc_settime(struct todr_chip_handle *ch, struct timeval *tv)
{
	struct ricohrtc_softc *sc = ch->cookie;
	struct clock_ymdhms dt;

	clock_secs_to_ymdhms(tv->tv_sec, &dt);

	if (ricohrtc_clock_write(sc, &dt) == 0)
		return (-1);
	return (0);
}

int
ricohrtc_setcal(struct todr_chip_handle *ch, int cal)
{

	return (EOPNOTSUPP);
}

int
ricohrtc_getcal(struct todr_chip_handle *ch, int *cal)
{

	return (EOPNOTSUPP);
}

void
ricohrtc_reg_write(struct ricohrtc_softc *sc, int reg, uint8_t val)
{
	uint8_t cmd;

	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
	reg &= 0xf;
	cmd = (reg << 4);
	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address,
	    &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL)) {
		iic_release_bus(sc->sc_tag, I2C_F_POLL);
		printf("%s: ricohrtc_reg_write: failed to write reg%d\n",
		    sc->sc_dev.dv_xname, reg);
		return;
	}
	iic_release_bus(sc->sc_tag, I2C_F_POLL);
}

int
ricohrtc_clock_read(struct ricohrtc_softc *sc, struct clock_ymdhms *dt)
{
	uint8_t bcd[RICOHRTC_NRTC_REGS];
	uint8_t cmd;

	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
	cmd = (RICOHRTC_SECONDS << 4);
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address,
	    &cmd, sizeof cmd, bcd, RICOHRTC_NRTC_REGS, I2C_F_POLL)) {
		iic_release_bus(sc->sc_tag, I2C_F_POLL);
		printf("%s: ricohrtc_clock_read: failed to read rtc\n",
		    sc->sc_dev.dv_xname);
		return (0);
	}
	iic_release_bus(sc->sc_tag, I2C_F_POLL);

	/*
	 * Convert the RICOHRTC's register values into something useable
	 */
	dt->dt_sec = FROMBCD(bcd[RICOHRTC_SECONDS] & RICOHRTC_SECONDS_MASK);
	dt->dt_min = FROMBCD(bcd[RICOHRTC_MINUTES] & RICOHRTC_MINUTES_MASK);
	dt->dt_hour = FROMBCD(bcd[RICOHRTC_HOURS] & RICOHRTC_HOURS_24MASK);
	dt->dt_day = FROMBCD(bcd[RICOHRTC_DATE] & RICOHRTC_DATE_MASK);
	dt->dt_mon = FROMBCD(bcd[RICOHRTC_MONTH] & RICOHRTC_MONTH_MASK);
	dt->dt_year = FROMBCD(bcd[RICOHRTC_YEAR]) + POSIX_BASE_YEAR;
	return (1);
}

int
ricohrtc_clock_write(struct ricohrtc_softc *sc, struct clock_ymdhms *dt)
{
	uint8_t bcd[RICOHRTC_NRTC_REGS];
	uint8_t cmd;

	/*
	 * Convert our time representation into something the RICOHRTC
	 * can understand.
	 */
	bcd[RICOHRTC_SECONDS] = TOBCD(dt->dt_sec);
	bcd[RICOHRTC_MINUTES] = TOBCD(dt->dt_min);
	bcd[RICOHRTC_HOURS] = TOBCD(dt->dt_hour);
	bcd[RICOHRTC_DATE] = TOBCD(dt->dt_day);
	bcd[RICOHRTC_DAY] = TOBCD(dt->dt_wday);
	bcd[RICOHRTC_MONTH] = TOBCD(dt->dt_mon);
	bcd[RICOHRTC_YEAR] = TOBCD(dt->dt_year - POSIX_BASE_YEAR);

	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
	cmd = (RICOHRTC_SECONDS << 4);
	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address,
	    &cmd, sizeof cmd, bcd, RICOHRTC_NRTC_REGS, I2C_F_POLL)) {
		iic_release_bus(sc->sc_tag, I2C_F_POLL);
		printf("%s: ricohrtc_clock_write: failed to write rtc\n",
		    sc->sc_dev.dv_xname);
		return (0);
	}
	iic_release_bus(sc->sc_tag, I2C_F_POLL);
	return (1);
}


code:
/*	$OpenBSD: sdtemp.c,v 1.15 2014/11/14 07:03:22 jsg Exp $	*/

/*
 * Copyright (c) 2008 Theo de Raadt
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>

#include <dev/i2c/i2cvar.h>

/* JEDEC JC-42.4 registers */
#define JC_TEMP			0x05

/* Sensors */
#define JCTEMP_TEMP		0
#define JCTEMP_NUM_SENSORS	1

struct sdtemp_softc {
	struct device	sc_dev;
	i2c_tag_t	sc_tag;
	i2c_addr_t	sc_addr;

	struct ksensor	sc_sensor[JCTEMP_NUM_SENSORS];
	struct ksensordev sc_sensordev;
};

int	sdtemp_match(struct device *, void *, void *);
void	sdtemp_attach(struct device *, struct device *, void *);
void	sdtemp_refresh(void *);

struct cfattach sdtemp_ca = {
	sizeof(struct sdtemp_softc), sdtemp_match, sdtemp_attach
};

struct cfdriver sdtemp_cd = {
	NULL, "sdtemp", DV_DULL
};

int
sdtemp_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "se97") == 0 ||
	    strcmp(ia->ia_name, "se98") == 0 ||
	    strcmp(ia->ia_name, "max6604") == 0 ||
	    strcmp(ia->ia_name, "mcp9804") == 0 ||
	    strcmp(ia->ia_name, "mcp9805") == 0 ||
	    strcmp(ia->ia_name, "mcp98242") == 0 ||
	    strcmp(ia->ia_name, "mcp98243") == 0 ||
	    strcmp(ia->ia_name, "mcp98244") == 0 ||
	    strcmp(ia->ia_name, "adt7408") == 0 ||
	    strcmp(ia->ia_name, "stts424e02") == 0 ||
	    strcmp(ia->ia_name, "stts424") == 0 ||
	    strcmp(ia->ia_name, "stts2002") == 0 ||
	    strcmp(ia->ia_name, "stts2004") == 0 ||
	    strcmp(ia->ia_name, "stts3000") == 0 ||
	    strcmp(ia->ia_name, "ts3000b3") == 0 ||
	    strcmp(ia->ia_name, "ts3000gb0") == 0 ||
	    strcmp(ia->ia_name, "ts3000gb2") == 0 ||
	    strcmp(ia->ia_name, "ts3001gb2") == 0 ||
	    strcmp(ia->ia_name, "tse2004gb2") == 0 ||
	    strcmp(ia->ia_name, "at30ts00") == 0 ||
	    strcmp(ia->ia_name, "at30tse004") == 0 ||
	    strcmp(ia->ia_name, "cat34ts02") == 0 ||
	    strcmp(ia->ia_name, "cat34ts02c") == 0 ||
	    strcmp(ia->ia_name, "cat34ts04") == 0 ||
	    strcmp(ia->ia_name, "gt30ts00") == 0 ||
	    strcmp(ia->ia_name, "gt34ts02") == 0)
		return (1);
	return (0);
}

void
sdtemp_attach(struct device *parent, struct device *self, void *aux)
{
	struct sdtemp_softc *sc = (struct sdtemp_softc *)self;
	struct i2c_attach_args *ia = aux;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;

	printf(": %s", ia->ia_name);

	/* Initialize sensor data. */
	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));

	sc->sc_sensor[JCTEMP_TEMP].type = SENSOR_TEMP;

	if (sensor_task_register(sc, sdtemp_refresh, 5) == NULL) {
		printf(", unable to register update task\n");
		return;
	}

	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]);
	sensordev_install(&sc->sc_sensordev);

	printf("\n");
}

void
sdtemp_refresh(void *arg)
{
	struct sdtemp_softc *sc = arg;
	u_int8_t cmd;
	int16_t data, sdata;

	iic_acquire_bus(sc->sc_tag, 0);

	cmd = JC_TEMP;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
	    &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
		sdata = betoh16(data) & 0x1fff;
		if (sdata & 0x1000)
			sdata -= 0x2000;
		sc->sc_sensor[JCTEMP_TEMP].value =
		    273150000 + 62500 * sdata;
		sc->sc_sensor[JCTEMP_TEMP].flags &= ~SENSOR_FINVALID;
#if 0
		printf("sdtemp %04x %04x %d\n", data & 0xffff,
		    (u_int)sdata & 0xffff,
		    sc->sc_sensor[JCTEMP_TEMP].value);
#endif
	}

	iic_release_bus(sc->sc_tag, 0);
}

license: unknown


code:
/*	$OpenBSD: spdmem_i2c.c,v 1.1 2010/03/22 21:20:58 miod Exp $	*/
/* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */

/*
 * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Copyright (c) 2007 Nicolas Joly
 * Copyright (c) 2007 Paul Goyette
 * Copyright (c) 2007 Tobias Nygren
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Serial Presence Detect (SPD) memory identification
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <dev/spdmemvar.h>
#include <dev/i2c/i2cvar.h>

struct spdmem_iic_softc {
	struct spdmem_softc	sc_base;
	i2c_tag_t		sc_tag;
	i2c_addr_t		sc_addr;
};

int	spdmem_iic_match(struct device *, void *, void *);
void	spdmem_iic_attach(struct device *, struct device *, void *);
uint8_t	spdmem_iic_read(struct spdmem_softc *, uint8_t);

struct cfattach spdmem_iic_ca = {
	sizeof(struct spdmem_iic_softc), spdmem_iic_match, spdmem_iic_attach
};

int
spdmem_iic_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;
	struct spdmem_iic_softc sc;

	/* clever attachments like openfirmware informed macppc */
	if (strcmp(ia->ia_name, "spd") == 0)
		return (1);

	/* dumb, need sanity checks */
	if (strcmp(ia->ia_name, "eeprom") != 0)
		return (0);

	sc.sc_tag = ia->ia_tag;
	sc.sc_addr = ia->ia_addr;
	sc.sc_base.sc_read = spdmem_iic_read;

	return spdmem_probe(&sc.sc_base);
}

void
spdmem_iic_attach(struct device *parent, struct device *self, void *aux)
{
	struct spdmem_iic_softc *sc = (struct spdmem_iic_softc *)self;
	struct i2c_attach_args *ia = aux;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;
	sc->sc_base.sc_read = spdmem_iic_read;

	printf(":");

	spdmem_attach_common(&sc->sc_base);
}

uint8_t
spdmem_iic_read(struct spdmem_softc *v, uint8_t reg)
{
	struct spdmem_iic_softc *sc = (struct spdmem_iic_softc *)v;
	uint8_t val = 0xff;

	iic_acquire_bus(sc->sc_tag,0);
	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
	    &reg, sizeof reg, &val, sizeof val, 0);
	iic_release_bus(sc->sc_tag, 0);

	return val;
}


code:
/*	$OpenBSD: thmc50.c,v 1.4 2007/10/17 17:14:54 deraadt Exp $	*/

/*
 * Copyright (c) 2007 Theo de Raadt
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>

#include <dev/i2c/i2cvar.h>

/* THMC50 registers */
#define THMC50_TEMP0		0x27
#define THMC50_TEMP1		0x26
#define THMC50_TEMP2		0x20

/* Sensors */
#define THMC_TEMP0		0
#define THMC_TEMP1		1
#define THMC_TEMP2		2
#define THMC_NUM_SENSORS	3

struct thmc_softc {
	struct device	sc_dev;
	i2c_tag_t	sc_tag;
	i2c_addr_t	sc_addr;

	struct ksensor	sc_sensor[THMC_NUM_SENSORS];
	struct ksensordev sc_sensordev;
};

int	thmc_match(struct device *, void *, void *);
void	thmc_attach(struct device *, struct device *, void *);
void	thmc_refresh(void *);

struct cfattach thmc_ca = {
	sizeof(struct thmc_softc), thmc_match, thmc_attach
};

struct cfdriver thmc_cd = {
	NULL, "thmc", DV_DULL
};

int
thmc_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "thmc50") == 0 ||
	    strcmp(ia->ia_name, "adm1022") == 0 ||
	    strcmp(ia->ia_name, "adm1028") == 0)
		return (1);
	return (0);
}

void
thmc_attach(struct device *parent, struct device *self, void *aux)
{
	struct thmc_softc *sc = (struct thmc_softc *)self;
	struct i2c_attach_args *ia = aux;
	int numsensors = THMC_NUM_SENSORS;
	int i;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;

	printf(": %s", ia->ia_name);

	/* Initialize sensor data. */
	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));

	sc->sc_sensor[THMC_TEMP0].type = SENSOR_TEMP;
	strlcpy(sc->sc_sensor[THMC_TEMP0].desc, "Internal",
	    sizeof(sc->sc_sensor[THMC_TEMP0].desc));

	sc->sc_sensor[THMC_TEMP1].type = SENSOR_TEMP;
	strlcpy(sc->sc_sensor[THMC_TEMP1].desc, "External",
	    sizeof(sc->sc_sensor[THMC_TEMP1].desc));

	if (strcmp(ia->ia_name, "adm1022") == 0) {
		/* Only the adm1022 has a THMC50_TEMP2 sensor */
		sc->sc_sensor[THMC_TEMP2].type = SENSOR_TEMP;
		strlcpy(sc->sc_sensor[THMC_TEMP2].desc, "External",
		    sizeof(sc->sc_sensor[THMC_TEMP2].desc));
	} else {
		sc->sc_sensor[THMC_TEMP2].type = -1;
		numsensors--;
	}

	if (sensor_task_register(sc, thmc_refresh, 5) == NULL) {
		printf(", unable to register update task\n");
		return;
	}

	for (i = 0; i < numsensors; i++)
		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
	sensordev_install(&sc->sc_sensordev);

	printf("\n");
}

void
thmc_refresh(void *arg)
{
	struct thmc_softc *sc = arg;
	u_int8_t cmd;
	int8_t sdata;

	iic_acquire_bus(sc->sc_tag, 0);

	cmd = THMC50_TEMP0;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
		sc->sc_sensor[THMC_TEMP0].value = 273150000 + 1000000 * sdata;
		sc->sc_sensor[THMC_TEMP0].flags &= ~SENSOR_FINVALID;
	} else
		sc->sc_sensor[THMC_TEMP0].flags |= SENSOR_FINVALID;

	cmd = THMC50_TEMP1;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
		sc->sc_sensor[THMC_TEMP1].value = 273150000 + 1000000 * sdata;
		sc->sc_sensor[THMC_TEMP1].flags &= ~SENSOR_FINVALID;
	} else
		sc->sc_sensor[THMC_TEMP1].flags |= SENSOR_FINVALID;

	if (sc->sc_sensor[THMC_TEMP2].type > 0) {
		cmd = THMC50_TEMP2;
		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
		    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
			sc->sc_sensor[THMC_TEMP2].value = 273150000 + 1000000 * sdata;
			sc->sc_sensor[THMC_TEMP2].flags &= ~SENSOR_FINVALID;
		} else
			sc->sc_sensor[THMC_TEMP2].flags |= SENSOR_FINVALID;
	}

	iic_release_bus(sc->sc_tag, 0);
}


code:
/*	$OpenBSD: tsl2560.c,v 1.7 2008/04/18 01:17:51 deraadt Exp $	*/

/*
 * Copyright (c) 2005 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>

#include <dev/i2c/i2cvar.h>

/* TSL2560/61 registers */
#define TSL2560_REG_CONTROL	0x80
#define  TSL2560_CONTROL_POWER	0x03
#define TSL2560_REG_TIMING	0x81
#define  TSL2560_TIMING_GAIN	0x10 /* high gain (16x) */
#define  TSL2560_TIMING_INTEG0	0x00 /* 13.7ms */
#define  TSL2560_TIMING_INTEG1	0x01 /* 101ms */
#define  TSL2560_TIMING_INTEG2	0x02 /* 402ms */
#define TSL2560_REG_ID		0x8a
#define TSL2560_REG_DATA0	0xac
#define TSL2560_REG_DATA1	0xae

struct tsl_softc {
	struct device sc_dev;
	i2c_tag_t sc_tag;
	i2c_addr_t sc_addr;

	struct ksensor sc_sensor;
	struct ksensordev sc_sensordev;
};

int	tsl_match(struct device *, void *, void *);
void	tsl_attach(struct device *, struct device *, void *);

void	tsl_refresh(void *);
u_int64_t tsl_lux(u_int32_t, u_int32_t);

struct cfattach tsl_ca = {
	sizeof(struct tsl_softc), tsl_match, tsl_attach
};

struct cfdriver tsl_cd = {
	NULL, "tsl", DV_DULL
};

int
tsl_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "tsl2560") == 0)
		return (1);
	return (0);
}

void
tsl_attach(struct device *parent, struct device *self, void *aux)
{
	struct tsl_softc *sc = (struct tsl_softc *)self;
	struct i2c_attach_args *ia = aux;
	u_int8_t cmd, data;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;

	iic_acquire_bus(sc->sc_tag, 0);
	cmd = TSL2560_REG_CONTROL; data = TSL2560_CONTROL_POWER;
	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		printf(": power up failed\n");
		return;
	}
	cmd = TSL2560_REG_TIMING;
	data = TSL2560_TIMING_GAIN | TSL2560_TIMING_INTEG2;
	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		printf(": cannot write timing register\n");
		return;
	}
	cmd = TSL2560_REG_ID;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		printf(": cannot read ID register\n");
		return;
	}
	iic_release_bus(sc->sc_tag, 0);

	switch (data >> 4) {
	case 0:
		printf(": TSL2560 rev %x", data & 0x0f);
		break;
	case 1:
		printf(": TSL2561 rev %x", data & 0x0f);
		break;
	default:
		printf(": unknown part number %x", data >> 4);
		break;
	}

	/* Initialize sensor data. */
	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));
	sc->sc_sensor.type = SENSOR_LUX;

	if (sensor_task_register(sc, tsl_refresh, 5) == NULL) {
		printf(": unable to register update task\n");
		return;
	}

	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
	sensordev_install(&sc->sc_sensordev);

	printf("\n");
}

void
tsl_refresh(void *arg)
{
	struct tsl_softc *sc = arg;
	u_int8_t cmd, data[2];
	u_int16_t chan0, chan1;

	iic_acquire_bus(sc->sc_tag, 0);
	cmd = TSL2560_REG_DATA0;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		sc->sc_sensor.flags |= SENSOR_FINVALID;
		return;
	}
	chan0 = data[1] << 8 | data[0];
	cmd = TSL2560_REG_DATA1;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		sc->sc_sensor.flags |= SENSOR_FINVALID;
		return;
	}
	chan1 = data[1] << 8 | data[0];
	iic_release_bus(sc->sc_tag, 0);

	sc->sc_sensor.value = tsl_lux(chan0, chan1);
	sc->sc_sensor.flags &= ~SENSOR_FINVALID;
}

/* Precision for fixed-point math. */
#define TSL2560_RATIO_SCALE	9
#define TSL2560_LUX_SCALE	14

/*
 * The TSL2560/2561 comes in a ChipScale or TMB-6 package and the
 * calibration is slightly different for each package.  The constants
 * below are for the TMB-6 package.
 */

#define TSL2560_K1T	0x0040	/* 0.125 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B1T	0x01f2	/* 0.0304 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M1T	0x01be	/* 0.0272 * (1 << TSL2560_LUX_SCALE) */

#define TSL2560_K2T	0x0080	/* 0.250 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B2T	0x0214	/* 0.0324 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M2T	0x02d1	/* 0.0440 * (1 << TSL2560_LUX_SCALE) */

#define TSL2560_K3T	0x00c0	/* 0.375 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B3T	0x023f	/* 0.0351 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M3T	0x037b	/* 0.0544 * (1 << TSL2560_LUX_SCALE) */

#define TSL2560_K4T	0x0080	/* 0.50 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B4T	0x0214	/* 0.0381 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M4T	0x02d1	/* 0.0624 * (1 << TSL2560_LUX_SCALE) */

#define TSL2560_K5T	0x0138	/* 0.61 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B5T	0x016f	/* 0.0224 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M5T	0x01fc	/* 0.0310 * (1 << TSL2560_LUX_SCALE) */

#define TSL2560_K6T	0x0100	/* 0.80 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B6T	0x0270	/* 0.0128 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M6T	0x03fe	/* 0.0153 * (1 << TSL2560_LUX_SCALE) */

#define TSL2560_K7T	0x019a	/* 1.3 * (1 << TSL2560_RATIO_SCALE) */
#define TSL2560_B7T	0x0018	/* 0.00146 * (1 << TSL2560_LUX_SCALE) */
#define TSL2560_M7T	0x0012	/* 0.00112 * (1 << TSL2560_LUX_SCALE) */

u_int64_t
tsl_lux(u_int32_t chan0, u_int32_t chan1)
{
	u_int32_t ratio, ratio1;
	u_int32_t b, m;
	int64_t lux;

	ratio1 = 0;
	if (chan0 != 0)
		ratio1 = (chan1 << (TSL2560_RATIO_SCALE + 1)) / chan0;
	ratio = (ratio1 + 1) >> 1;

	b = 0, m = 0;
	if (ratio <= TSL2560_K1T)
		b = TSL2560_B1T, m = TSL2560_M1T;
	else if (ratio <= TSL2560_K2T)
		b = TSL2560_B2T, m = TSL2560_M2T;
	else if (ratio <= TSL2560_K3T)
		b = TSL2560_B3T, m = TSL2560_M3T;
	else if (ratio <= TSL2560_K4T)
		b = TSL2560_B4T, m = TSL2560_M4T;
	else if (ratio <= TSL2560_K5T)
		b = TSL2560_B5T, m = TSL2560_M5T;
	else if (ratio <= TSL2560_K6T)
		b = TSL2560_B6T, m = TSL2560_M6T;
	else if (ratio <= TSL2560_K7T)
		b = TSL2560_B7T, m = TSL2560_M7T;

	lux = b * chan0 - m * chan1;
	if (lux < 0)
		lux = 0;
	return ((lux * 1000000) >> TSL2560_LUX_SCALE);
}


code:
/*	$OpenBSD: w83793g.c,v 1.5 2009/01/26 15:07:49 kettenis Exp $	*/

/*
 * Copyright (c) 2007 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>

#include <dev/i2c/i2cvar.h>

/* Winbond W83793G Hardware Monitor */

#define WB_BANKSELECT	0x00

/* Voltage */
#define WB_NUM_VOLTS	10

static const char *wb_volt_desc[WB_NUM_VOLTS] = {
	"VCore", "VCore", "VTT",
	"", "", "3.3V", "12V", "5VDD", "5VSB", "VBat"
};

#define WB_VCOREA	0x10
#define WB_VCOREB	0x11
#define WB_VTT		0x12
#define WB_VLOW		0x1b

#define WB_VSENS1	0x14
#define WB_VSENS2	0x15
#define WB_3VSEN	0x16
#define WB_12VSEN	0x17
#define WB_5VDD		0x18
#define WB_5VSB		0x19
#define WB_VBAT		0x1a

/* Temperature */
#define WB_NUM_TEMPS	6

#define WB_TD_COUNT	4
#define WB_TD_START	0x1c
#define WB_TDLOW	0x22

#define WB_TR_COUNT	2
#define WB_TR_START	0x20

/* Fan */
#define WB_NUM_FANS	12
#define WB_FAN_START	0x23

struct wbng_softc {
	struct device	sc_dev;
	i2c_tag_t	sc_tag;
	i2c_addr_t	sc_addr;

	struct ksensor	sc_sensors[WB_NUM_VOLTS + WB_NUM_TEMPS + WB_NUM_FANS];
	struct ksensordev sc_sensordev;
};

int	wbng_match(struct device *, void *, void *);
void	wbng_attach(struct device *, struct device *, void *);
void	wbng_refresh(void *);

void	wbng_refresh_volts(struct wbng_softc *);
void	wbng_refresh_temps(struct wbng_softc *);
void	wbng_refresh_fans(struct wbng_softc *);

uint8_t	wbng_readreg(struct wbng_softc *, uint8_t);
void	wbng_writereg(struct wbng_softc *, uint8_t, uint8_t);

struct cfattach wbng_ca = {
	sizeof(struct wbng_softc), wbng_match, wbng_attach
};

struct cfdriver wbng_cd = {
	NULL, "wbng", DV_DULL
};

int
wbng_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "w83793g") == 0)
		return 1;
	return 0;
}

void
wbng_attach(struct device *parent, struct device *self, void *aux)
{
	struct wbng_softc *sc = (struct wbng_softc *)self;
	struct i2c_attach_args *ia = aux;
	int i, j;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;

	printf(": %s", ia->ia_name);

	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));

	for (i = 0; i < WB_NUM_VOLTS; i++) {
		strlcpy(sc->sc_sensors[i].desc, wb_volt_desc[i],
		    sizeof(sc->sc_sensors[i].desc));
		sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
	}

	for (j = i + WB_NUM_TEMPS; i < j; i++)
		sc->sc_sensors[i].type = SENSOR_TEMP;

	for (j = i + WB_NUM_FANS; i < j; i++)
		sc->sc_sensors[i].type = SENSOR_FANRPM;

	for (i = 0; i < WB_NUM_VOLTS + WB_NUM_TEMPS + WB_NUM_FANS; i++)
		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);

	if (sensor_task_register(sc, wbng_refresh, 5) == NULL) {
		printf(", unable to register update task\n");
		return;
	}

	sensordev_install(&sc->sc_sensordev);
	printf("\n");
}

void
wbng_refresh(void *arg)
{
	struct wbng_softc *sc = arg;
	uint8_t bsr;

	iic_acquire_bus(sc->sc_tag, 0);

	bsr = wbng_readreg(sc, WB_BANKSELECT);
	if ((bsr & 0x07) != 0x0)
		wbng_writereg(sc, WB_BANKSELECT, bsr & 0xf8);

	wbng_refresh_volts(sc);
	wbng_refresh_temps(sc);
	wbng_refresh_fans(sc);

	if ((bsr & 0x07) != 0x0)
		wbng_writereg(sc, WB_BANKSELECT, bsr);

	iic_release_bus(sc->sc_tag, 0);
}

void
wbng_refresh_volts(struct wbng_softc *sc)
{
	struct ksensor *s = &sc->sc_sensors[0];
	uint8_t	vlow, data;

	/* high precision voltage sensors */

	vlow = wbng_readreg(sc, WB_VLOW);

	data = wbng_readreg(sc, WB_VCOREA);
	s[0].value = ((data << 3) | (((vlow & 0x03)) << 1)) * 1000;

	data = wbng_readreg(sc, WB_VCOREB);
	s[1].value = ((data << 3) | (((vlow & 0x0c) >> 2) << 1)) * 1000;

	data = wbng_readreg(sc, WB_VTT);
	s[2].value = ((data << 3) | (((vlow & 0x30) >> 4) << 1)) * 1000;

	/* low precision voltage sensors */

	data = wbng_readreg(sc, WB_VSENS1);
	s[3].value = (data << 4) * 1000;

	data = wbng_readreg(sc, WB_VSENS2);
	s[4].value = (data << 4) * 1000;

	data = wbng_readreg(sc, WB_3VSEN);
	s[5].value = (data << 4) * 1000;

	data = wbng_readreg(sc, WB_12VSEN);
	s[6].value = (data << 4) * 6100;	/*XXX, the factor is a guess */

	data = wbng_readreg(sc, WB_5VDD);
	s[7].value = (data << 4) * 1500 + 150000;

	data = wbng_readreg(sc, WB_5VSB);
	s[8].value = (data << 4) * 1500 + 150000;

	data = wbng_readreg(sc, WB_VBAT);
	s[9].value = (data << 4) * 1000;
}

void
wbng_refresh_temps(struct wbng_softc *sc)
{
	struct ksensor *s = &sc->sc_sensors[WB_NUM_VOLTS];
	int data, i;
	uint8_t	tdlow, low;

	/* high precision temperature sensors */
	tdlow = wbng_readreg(sc, WB_TDLOW);
	for (i = 0; i < WB_TD_COUNT; i++) {
		data = wbng_readreg(sc, WB_TD_START + i);
		/*
		 * XXX: datasheet says nothing about acceptable values,
		 * let's consider only values between -55 degC and +125 degC.
		 */
		if (data > 0x7f && data < 0xc9) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}
		if (data & 0x80)
			data -= 0x100;
		low = (tdlow & (0x03 << (i * 2))) >> (i * 2);
		s[i].value = data * 1000000 + low * 250000 + 273150000;
		s[i].flags &= ~SENSOR_FINVALID;
	}
	s += i;

	/* low precision temperature sensors */
	for (i = 0; i < WB_TR_COUNT; i++) {
		data = wbng_readreg(sc, WB_TR_START + i);
		/*
		 * XXX: datasheet says nothing about acceptable values,
		 * let's consider only values between -55 degC and +125 degC.
		 */
		if (data > 0x7f && data < 0xc9) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}
		if (data & 0x80)
			data -= 0x100;
		s[i].value = data * 1000000 + 273150000;
		s[i].flags &= ~SENSOR_FINVALID;
	}
}

void
wbng_refresh_fans(struct wbng_softc *sc)
{
	struct ksensor *s = &sc->sc_sensors[WB_NUM_VOLTS + WB_NUM_TEMPS];
	int i;

	for (i = 0; i < WB_NUM_FANS; i++) {
		uint8_t h = wbng_readreg(sc, WB_FAN_START + i * 2);
		uint8_t l = wbng_readreg(sc, WB_FAN_START + i * 2 + 1);
		uint16_t b = h << 8 | l;

		if (b >= 0x0fff || b == 0x0f00 || b == 0x0000) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
		} else {
			s[i].flags &= ~SENSOR_FINVALID;
			s[i].value = 1350000 / b;
		}
	}
}

uint8_t
wbng_readreg(struct wbng_softc *sc, uint8_t reg)
{
	uint8_t data;

	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);

	return data;
}

void
wbng_writereg(struct wbng_softc *sc, uint8_t reg, uint8_t data)
{
	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
}


code:
/*	$OpenBSD: w83795g.c,v 1.1 2011/07/03 21:30:20 kettenis Exp $	*/

/*
 * Copyright (c) 2011 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>

#include <dev/i2c/i2cvar.h>

/* Nuvoton W83795G Hardware Monitor */

#define NVT_BANKSELECT		0x00
#define NVT_CONFIG		0x01
#define  NVT_CONFIG_48		0x04
#define NVT_VOLT_CTRL1		0x02
#define NVT_VOLT_CTRL2		0x03
#define NVT_TEMP_CTRL1		0x04
#define NVT_TEMP_CTRL2		0x05
#define NVT_FANIN_CTRL1		0x06
#define NVT_FANIN_CTRL2		0x07
#define NVT_VSEN1		0x10
#define NVT_3VDD		0x1c
#define NVT_3VSB		0x1d
#define NVT_VBAT		0x1e
#define NVT_TR5			0x1f
#define NVT_TR6			0x20
#define NVT_TD1			0x21
#define NVT_TD2			0x22
#define NVT_TD3			0x23
#define NVT_TD4			0x24
#define NVT_FANIN1_COUNT	0x2e
#define NVT_VRLSB		0x3c

/* Voltage */
#define NVT_NUM_VOLTS	15

static const char *nvt_volt_desc[NVT_NUM_VOLTS] = {
	"", "", "", "", "", "", "", "", "", "", "",
	"VTT", "3VDD", "3VSB", "VBat"
};

/* Temperature */
#define NVT_NUM_TEMPS	6
#define NVT_NUM_TR	2
#define NVT_NUM_TD	4

/* Fan */
#define NVT_NUM_FANS	14

#define NVT_NUM_SENSORS (NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS)

struct nvt_softc {
	struct device	sc_dev;
	i2c_tag_t	sc_tag;
	i2c_addr_t	sc_addr;

	uint16_t	sc_vctrl;
	uint16_t	sc_tctrl1, sc_tctrl2;
	uint16_t	sc_fctrl;

	struct ksensor	sc_sensors[NVT_NUM_SENSORS];
	struct ksensordev sc_sensordev;
};

int	nvt_match(struct device *, void *, void *);
void	nvt_attach(struct device *, struct device *, void *);
void	nvt_refresh(void *);

void	nvt_refresh_volts(struct nvt_softc *);
void	nvt_refresh_temps(struct nvt_softc *);
void	nvt_refresh_fans(struct nvt_softc *);

uint8_t	nvt_readreg(struct nvt_softc *, uint8_t);
void	nvt_writereg(struct nvt_softc *, uint8_t, uint8_t);

struct cfattach nvt_ca = {
	sizeof(struct nvt_softc), nvt_match, nvt_attach
};

struct cfdriver nvt_cd = {
	NULL, "nvt", DV_DULL
};

int
nvt_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "w83795g") == 0)
		return (1);
	return (0);
}

void
nvt_attach(struct device *parent, struct device *self, void *aux)
{
	struct nvt_softc *sc = (struct nvt_softc *)self;
	struct i2c_attach_args *ia = aux;
	uint8_t cfg, vctrl1, vctrl2;
	uint8_t tctrl1, tctrl2, fctrl1, fctrl2;
	int i, j;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;

	cfg = nvt_readreg(sc, NVT_CONFIG);
	if (cfg & NVT_CONFIG_48)
		printf(": W83795ADG");
	else
		printf(": W83795G");

	vctrl1 = nvt_readreg(sc, NVT_VOLT_CTRL1);
	vctrl2 = nvt_readreg(sc, NVT_VOLT_CTRL2);
	tctrl1 = nvt_readreg(sc, NVT_TEMP_CTRL1);
	tctrl2 = nvt_readreg(sc, NVT_TEMP_CTRL2);
	fctrl1 = nvt_readreg(sc, NVT_FANIN_CTRL1);
	fctrl2 = nvt_readreg(sc, NVT_FANIN_CTRL2);

	sc->sc_vctrl = vctrl2 << 8 | vctrl1;
	sc->sc_tctrl1 = tctrl1;
	sc->sc_tctrl2 = tctrl2;
	sc->sc_fctrl = fctrl2 << 8 | fctrl1;

	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));

	for (i = 0; i < NVT_NUM_VOLTS; i++) {
		strlcpy(sc->sc_sensors[i].desc, nvt_volt_desc[i],
		    sizeof(sc->sc_sensors[i].desc));
		sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
	}

	for (j = i + NVT_NUM_TEMPS; i < j; i++)
		sc->sc_sensors[i].type = SENSOR_TEMP;

	for (j = i + NVT_NUM_FANS; i < j; i++)
		sc->sc_sensors[i].type = SENSOR_FANRPM;

	for (i = 0; i < NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS; i++)
		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);

	if (sensor_task_register(sc, nvt_refresh, 5) == NULL) {
		printf(", unable to register update task\n");
		return;
	}

	sensordev_install(&sc->sc_sensordev);
	printf("\n");
}

void
nvt_refresh(void *arg)
{
	struct nvt_softc *sc = arg;
	uint8_t bsr;

	iic_acquire_bus(sc->sc_tag, 0);

	bsr = nvt_readreg(sc, NVT_BANKSELECT);
	if ((bsr & 0x07) != 0x00)
		nvt_writereg(sc, NVT_BANKSELECT, bsr & 0xf8);

	nvt_refresh_volts(sc);
	nvt_refresh_temps(sc);
	nvt_refresh_fans(sc);

	if ((bsr & 0x07) != 0x00)
		nvt_writereg(sc, NVT_BANKSELECT, bsr);

	iic_release_bus(sc->sc_tag, 0);
}

void
nvt_refresh_volts(struct nvt_softc *sc)
{
	struct ksensor *s = &sc->sc_sensors[0];
	uint8_t	vrlsb, data;
	int i, reg;

	for (i = 0; i < NVT_NUM_VOLTS; i++) {
		if ((sc->sc_vctrl & (1 << i)) == 0) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}

		reg = NVT_VSEN1 + i;
		data = nvt_readreg(sc, reg);
		vrlsb = nvt_readreg(sc, NVT_VRLSB);
		if (reg != NVT_3VDD && reg != NVT_3VSB && reg != NVT_VBAT)
			s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 2000;
		else
			s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 6000;
		s[i].flags &= ~SENSOR_FINVALID;
	}
}

void
nvt_refresh_temps(struct nvt_softc *sc)
{
	struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS];
	uint8_t	vrlsb;
	int8_t data;
	int i;

	for (i = 0; i < NVT_NUM_TEMPS; i++) {
		if (i < NVT_NUM_TR
		    && (sc->sc_tctrl1 & (1 << (2 * i))) == 0) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}

		if (i >= NVT_NUM_TR
		    && (sc->sc_tctrl2 & (1 << (2 * (i - NVT_NUM_TR)))) == 0) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}

		data = nvt_readreg(sc, NVT_TR5 + i);
		vrlsb = nvt_readreg(sc, NVT_VRLSB);
		if (data == -128 && (vrlsb >> 6) == 0) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}
		s[i].value = data * 1000000 + (vrlsb >> 6) * 250000;
		s[i].value += 273150000;
		s[i].flags &= ~SENSOR_FINVALID;
	}
}

void
nvt_refresh_fans(struct nvt_softc *sc)
{
	struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS + NVT_NUM_TEMPS];
	uint8_t	data, vrlsb;
	uint16_t count;
	int i;

	for (i = 0; i < NVT_NUM_FANS; i++) {
		if ((sc->sc_fctrl & (1 << i)) == 0) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}

		data = nvt_readreg(sc, NVT_FANIN1_COUNT + i);
		vrlsb = nvt_readreg(sc, NVT_VRLSB);
		count = (data << 4) + (vrlsb >> 4);
		if (count == 0) {
			s[i].flags |= SENSOR_FINVALID;
			s[i].value = 0;
			continue;
		}
		s[i].value = 1350000 / (count * 2);
		s[i].flags &= ~SENSOR_FINVALID;
	}
}

uint8_t
nvt_readreg(struct nvt_softc *sc, uint8_t reg)
{
	uint8_t data;

	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);

	return data;
}

void
nvt_writereg(struct nvt_softc *sc, uint8_t reg, uint8_t data)
{
	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
}


code:
/*	$OpenBSD: w83l784r.c,v 1.12 2007/06/24 05:34:35 dlg Exp $	*/

/*
 * Copyright (c) 2006 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>

#include <dev/i2c/i2cvar.h>

/* W83L784R registers */
#define W83L784R_VCORE		0x20
#define W83L784R_VBAT		0x21
#define W83L784R_3_3V		0x22
#define W83L784R_VCC		0x23
#define W83L784R_TEMP1		0x27
#define W83L784R_FAN1		0x28
#define W83L784R_FAN2		0x29
#define W83L784R_CONFIG		0x40
#define W83L784R_FANDIV		0x49
#define W83L784R_T23ADDR	0x4b
#define W83L784R_CHIPID		0x4e

#define W83L784R_TEMP23		0x00

/* W83L785R registers */
#define W83L785R_2_5V		0x21
#define W83L785R_1_5V		0x22
#define W83L785R_VCC		0x23
#define W83L785R_TEMP2		0x26
#define W83L785R_FANDIV		0x47

/* Chip IDs */
#define WBENV_CHIPID_W83L784R		0x50
#define WBENV_CHIPID_W83L785R		0x60
#define WBENV_CHIPID_W83L785TS_L	0x70

#define WBENV_MAX_SENSORS  9

/*
 * The W83L784R/W83L785R can measure voltages up to 4.096/2.048 V.
 * To measure higher voltages the input is attenuated with (external)
 * resistors.  So we have to convert the sensor values back to real
 * voltages by applying the appropriate resistor factor.
 */
#define RFACT_NONE	10000
#define RFACT(x, y)	(RFACT_NONE * ((x) + (y)) / (y))

struct wbenv_softc;

struct wbenv_sensor {
	char *desc;
	enum sensor_type type;
	u_int8_t reg;
	void (*refresh)(struct wbenv_softc *, int);
	int rfact;
};

struct wbenv_softc {
	struct device sc_dev;

	i2c_tag_t sc_tag;
	i2c_addr_t sc_addr[3];
	u_int8_t sc_chip_id;

	struct ksensor sc_sensors[WBENV_MAX_SENSORS];
	struct ksensordev sc_sensordev;
	struct wbenv_sensor *sc_wbenv_sensors;
	int sc_numsensors;
};

int	wbenv_match(struct device *, void *, void *);
void	wbenv_attach(struct device *, struct device *, void *);

void	wbenv_setup_sensors(struct wbenv_softc *, struct wbenv_sensor *);
void	wbenv_refresh(void *);

void	w83l784r_refresh_volt(struct wbenv_softc *, int);
void	w83l785r_refresh_volt(struct wbenv_softc *, int);
void	wbenv_refresh_temp(struct wbenv_softc *, int);
void	w83l784r_refresh_temp(struct wbenv_softc *, int);
void	w83l784r_refresh_fanrpm(struct wbenv_softc *, int);
void	w83l785r_refresh_fanrpm(struct wbenv_softc *, int);

u_int8_t wbenv_readreg(struct wbenv_softc *, u_int8_t);
void	wbenv_writereg(struct wbenv_softc *, u_int8_t, u_int8_t);

struct cfattach wbenv_ca = {
	sizeof(struct wbenv_softc), wbenv_match, wbenv_attach
};

struct cfdriver wbenv_cd = {
	NULL, "wbenv", DV_DULL
};

struct wbenv_sensor w83l784r_sensors[] =
{
	{ "VCore", SENSOR_VOLTS_DC, W83L784R_VCORE, w83l784r_refresh_volt, RFACT_NONE },
	{ "VBAT", SENSOR_VOLTS_DC, W83L784R_VBAT, w83l784r_refresh_volt, RFACT(232, 99) },
	{ "+3.3V", SENSOR_VOLTS_DC, W83L784R_3_3V, w83l784r_refresh_volt, RFACT_NONE },
	{ "+5V", SENSOR_VOLTS_DC, W83L784R_VCC, w83l784r_refresh_volt, RFACT(50, 34) },
	{ "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
	{ "", SENSOR_TEMP, 1, w83l784r_refresh_temp },
	{ "", SENSOR_TEMP, 2, w83l784r_refresh_temp },
	{ "", SENSOR_FANRPM, W83L784R_FAN1, w83l784r_refresh_fanrpm },
	{ "", SENSOR_FANRPM, W83L784R_FAN2, w83l784r_refresh_fanrpm },

	{ NULL }
};

struct wbenv_sensor w83l785r_sensors[] =
{
	{ "VCore", SENSOR_VOLTS_DC, W83L784R_VCORE, w83l785r_refresh_volt, RFACT_NONE },
	{ "+2.5V", SENSOR_VOLTS_DC, W83L785R_2_5V, w83l785r_refresh_volt, RFACT(100, 100) },
	{ "+1.5V", SENSOR_VOLTS_DC, W83L785R_1_5V, w83l785r_refresh_volt, RFACT_NONE },
	{ "+3.3V", SENSOR_VOLTS_DC, W83L785R_VCC, w83l785r_refresh_volt, RFACT(20, 40) },
	{ "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
	{ "", SENSOR_TEMP, W83L785R_TEMP2, wbenv_refresh_temp },
	{ "", SENSOR_FANRPM, W83L784R_FAN1, w83l785r_refresh_fanrpm },
	{ "", SENSOR_FANRPM, W83L784R_FAN2, w83l785r_refresh_fanrpm },

	{ NULL }
};

struct wbenv_sensor w83l785ts_l_sensors[] =
{
	{ "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },

	{ NULL }
};

int
wbenv_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "w83l784r") == 0 ||
	    strcmp(ia->ia_name, "w83l785r") == 0 ||
	    strcmp(ia->ia_name, "w83l785ts-l") == 0)
		return (1);
	return (0);
}

void
wbenv_attach(struct device *parent, struct device *self, void *aux)
{
	struct wbenv_softc *sc = (struct wbenv_softc *)self;
	struct i2c_attach_args *ia = aux;
	u_int8_t cmd, data, config;
	int i;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr[0] = ia->ia_addr;

	iic_acquire_bus(sc->sc_tag, 0);

	cmd = W83L784R_CHIPID;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr[0], &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		printf(": cannot read chip ID register\n");
		return;
	}

	iic_release_bus(sc->sc_tag, 0);

	sc->sc_chip_id = data;

	switch (sc->sc_chip_id) {
	case WBENV_CHIPID_W83L784R:
		printf(": W83L784R\n");
		wbenv_setup_sensors(sc, w83l784r_sensors);
		break;
	case WBENV_CHIPID_W83L785R:
		printf(": W83L785R\n");
		wbenv_setup_sensors(sc, w83l785r_sensors);
		goto start;
	case WBENV_CHIPID_W83L785TS_L:
		printf(": W83L785TS-L\n");
		wbenv_setup_sensors(sc, w83l785ts_l_sensors);
		goto start;
	default:
		printf(": unknown Winbond chip (ID 0x%x)\n", sc->sc_chip_id);
		return;
	}

	iic_acquire_bus(sc->sc_tag, 0);

	cmd = W83L784R_T23ADDR;
	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr[0], &cmd, sizeof cmd, &data, sizeof data, 0)) {
		iic_release_bus(sc->sc_tag, 0);
		printf(": cannot read address register\n");
		return;
	}

	iic_release_bus(sc->sc_tag, 0);

	sc->sc_addr[1] = 0x48 + (data & 0x7);
	sc->sc_addr[2] = 0x48 + ((data >> 4) & 0x7);

	/* Make the bus scan ignore the satellites. */
	iic_ignore_addr(sc->sc_addr[1]);
	iic_ignore_addr(sc->sc_addr[2]);

 start:
	if (sensor_task_register(sc, wbenv_refresh, 5) == NULL) {
		printf("%s: unable to register update task\n",
		    sc->sc_dev.dv_xname);
		return;
	}

	/* Start the monitoring loop */
	config = wbenv_readreg(sc, W83L784R_CONFIG);
	wbenv_writereg(sc, W83L784R_CONFIG, config | 0x01);

	/* Add sensors */
	for (i = 0; i < sc->sc_numsensors; ++i)
		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
	sensordev_install(&sc->sc_sensordev);
}

void
wbenv_setup_sensors(struct wbenv_softc *sc, struct wbenv_sensor *sensors)
{
	int i;

	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));

	for (i = 0; sensors[i].desc; i++) {
		sc->sc_sensors[i].type = sensors[i].type;
		strlcpy(sc->sc_sensors[i].desc, sensors[i].desc,
		    sizeof(sc->sc_sensors[i].desc));
		sc->sc_numsensors++;
	}
	sc->sc_wbenv_sensors = sensors;
}

void
wbenv_refresh(void *arg)
{
	struct wbenv_softc *sc = arg;
	int i;

	iic_acquire_bus(sc->sc_tag, 0);

	for (i = 0; i < sc->sc_numsensors; i++)
		sc->sc_wbenv_sensors[i].refresh(sc, i);

	iic_release_bus(sc->sc_tag, 0);
}

void
w83l784r_refresh_volt(struct wbenv_softc *sc, int n)
{
	struct ksensor *sensor = &sc->sc_sensors[n];
	int data, reg = sc->sc_wbenv_sensors[n].reg;

	data = wbenv_readreg(sc, reg);
	sensor->value = (data << 4); /* 16 mV LSB */
	sensor->value *= sc->sc_wbenv_sensors[n].rfact;
	sensor->value /= 10;
}

void
w83l785r_refresh_volt(struct wbenv_softc *sc, int n)
{
	struct ksensor *sensor = &sc->sc_sensors[n];
	int data, reg = sc->sc_wbenv_sensors[n].reg;

	data = wbenv_readreg(sc, reg);
	sensor->value = (data << 3); /* 8 mV LSB */
	sensor->value *= sc->sc_wbenv_sensors[n].rfact;
	sensor->value /= 10;
}

void
wbenv_refresh_temp(struct wbenv_softc *sc, int n)
{
	struct ksensor *sensor = &sc->sc_sensors[n];
	int sdata;

	sdata = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
	if (sdata & 0x80)
		sdata -= 0x100;
	sensor->value = sdata * 1000000 + 273150000;
}

void
w83l784r_refresh_temp(struct wbenv_softc *sc, int n)
{
	struct ksensor *sensor = &sc->sc_sensors[n];
	int16_t sdata;
	u_int8_t cmd = 0;

	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr[sc->sc_wbenv_sensors[n].reg],
	    &cmd, sizeof cmd, &sdata, sizeof sdata, 0);
	sensor->value = (sdata >> 7) * 500000 + 273150000;
}

void
w83l784r_refresh_fanrpm(struct wbenv_softc *sc, int n)
{
	struct ksensor *sensor = &sc->sc_sensors[n];
	int data, divisor;

	data = wbenv_readreg(sc, W83L784R_FANDIV);
	if (sc->sc_wbenv_sensors[n].reg == W83L784R_FAN1)
		divisor = data & 0x07;
	else
		divisor = (data >> 4) & 0x07;

	data = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
	if (data == 0xff || data == 0x00) {
		sensor->flags |= SENSOR_FINVALID;
		sensor->value = 0;
	} else {
		sensor->flags &= ~SENSOR_FINVALID;
		sensor->value = 1350000 / (data << divisor);
	}
}

void
w83l785r_refresh_fanrpm(struct wbenv_softc *sc, int n)
{
	struct ksensor *sensor = &sc->sc_sensors[n];
	int data, divisor;

	data = wbenv_readreg(sc, W83L785R_FANDIV);
	if (sc->sc_wbenv_sensors[n].reg == W83L784R_FAN1)
		divisor = data & 0x07;
	else
		divisor = (data >> 4) & 0x07;

	data = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
	if (data == 0xff || data == 0x00) {
		sensor->flags |= SENSOR_FINVALID;
		sensor->value = 0;
	} else {
		sensor->flags &= ~SENSOR_FINVALID;
		sensor->value = 1350000 / (data << divisor);
	}
}

u_int8_t
wbenv_readreg(struct wbenv_softc *sc, u_int8_t reg)
{
	u_int8_t data;

	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr[0], &reg, sizeof reg, &data, sizeof data, 0);

	return data;
}

void
wbenv_writereg(struct wbenv_softc *sc, u_int8_t reg, u_int8_t data)
{
	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
	    sc->sc_addr[0], &reg, sizeof reg, &data, sizeof data, 0);
}


code:
/*	$OpenBSD: wm8750reg.h,v 1.2 2005/12/31 04:31:27 deraadt Exp $	*/

/*
 * Copyright (c) 2005 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Wolfson Microelectronics' WM8750 I2C/I2S audio codec:
 * - I2C register definitions.  Used in the Sharp Zaurus SL-C3000.
 */

#define LINVOL_REG 0x00			/* Left Input volume */
#define  LINVOL_LIVU 0x100
#define  LINVOL_LINMUTE 0x80
#define  LINVOL_LIZC 0x40
#define  LINVOL_LINVOL_MASK 0x3F
#define  LINVOL_GET_LINVOL(x) ((x) & 0x3F)
#define  LINVOL_SET_LINVOL(x) (x)

#define RINVOL_REG 0x01			/* Right Input volume */
#define  RINVOL_RIVU 0x100
#define  RINVOL_RINMUTE 0x80
#define  RINVOL_RIZC 0x40
#define  RINVOL_RINVOL_MASK 0x3F
#define  RINVOL_GET_RINVOL(x) ((x) & 0x3F)
#define  RINVOL_SET_RINVOL(x) (x)

#define LOUT1VOL_REG 0x02		/* LOUT1 volume */
#define  LOUT1VOL_LO1VU 0x100
#define  LOUT1VOL_LO1ZC 0x80
#define  LOUT1VOL_LOUT1VOL_MASK 0x7F
#define  LOUT1VOL_GET_LOUT1VOL(x) ((x) & 0x7F)
#define  LOUT1VOL_SET_LOUT1VOL(x) (x)

#define ROUT1VOL_REG 0x03		/* ROUT1 volume */
#define  ROUT1VOL_RO1VU 0x100
#define  ROUT1VOL_RO1ZC 0x80
#define  ROUT1VOL_ROUT1VOL_MASK 0x7F
#define  ROUT1VOL_GET_ROUT1VOL(x) ((x) & 0x7F)
#define  ROUT1VOL_SET_ROUT1VOL(x) (x)

#define ADCDACCTL_REG 0x05		/* ADC & DAC Control */
#define  ADCDACCTL_ADCDIV2 0x100
#define  ADCDACCTL_DACDIV2 0x80
#define  ADCDACCTL_ADCPOL_MASK 0x60
#define  ADCDACCTL_GET_ADCPOL(x) (((x) >> 5) & 0x60)
#define  ADCDACCTL_SET_ADCPOL(x) ((x) << 5)
#define  ADCDACCTL_HPOR 0x10
#define  ADCDACCTL_DACMU 0x8
#define  ADCDACCTL_DEEMPH_MASK 0x6
#define  ADCDACCTL_GET_DEEMPH(x) (((x) >> 1) & 0x6)
#define  ADCDACCTL_SET_DEEMPH(x) ((x) << 1)
#define  ADCDACCTL_ADCHPD 0x1

#define AUDINT_REG 0x07			/* Audio Interface */
#define  AUDINT_BCLKINV 0x80
#define  AUDINT_MS 0x40
#define  AUDINT_LRSWAP 0x20
#define  AUDINT_LRP 0x10
#define  AUDINT_WL_MASK 0xC
#define  AUDINT_GET_WL(x) (((x) >> 2) & 0xC)
#define  AUDINT_SET_WL(x) ((x) << 2)
#define  AUDINT_FORMAT_MASK 0x3
#define  AUDINT_GET_FORMAT(x) ((x) & 0x3)
#define  AUDINT_SET_FORMAT(x) (x)

#define SRATE_REG 0x08			/* Sample rate */
#define  SRATE_BCM_MASK 0x180
#define  SRATE_GET_BCM(x) (((x) >> 7) & 0x180)
#define  SRATE_SET_BCM(x) ((x) << 7)
#define  SRATE_CLKDIV2 0x40
#define  SRATE_SR_MASK 0x3E
#define  SRATE_GET_SR(x) (((x) >> 1) & 0x3E)
#define  SRATE_SET_SR(x) ((x) << 1)
#define  SRATE_USB 0x1

#define LDACVOL_REG 0x0A		/* Left DAC volume */
#define  LDACVOL_LDVU 0x100
#define  LDACVOL_LDACVOL_MASK 0xFF
#define  LDACVOL_GET_LDACVOL(x) ((x) & 0xFF)
#define  LDACVOL_SET_LDACVOL(x) (x)

#define RDACVOL_REG 0x0B		/* Right DAC volume */
#define  RDACVOL_RDVU 0x100
#define  RDACVOL_RDACVOL_MASK 0xFF
#define  RDACVOL_GET_RDACVOL(x) ((x) & 0xFF)
#define  RDACVOL_SET_RDACVOL(x) (x)

#define BASSCTL_REG 0x0C		/* Bass control */
#define  BASSCTL_BB 0x80
#define  BASSCTL_BC 0x40
#define  BASSCTL_BASS_MASK 0xF
#define  BASSCTL_GET_BASS(x) ((x) & 0xF)
#define  BASSCTL_SET_BASS(x) (x)

#define TREBCTL_REG 0x0D		/* Treble control */
#define  TREBCTL_TC 0x40
#define  TREBCTL_TRBL_MASK 0xF
#define  TREBCTL_GET_TRBL(x) ((x) & 0xF)
#define  TREBCTL_SET_TRBL(x) (x)

#define RESET_REG 0x0F			/* Reset */

#define C3DCTL_REG 0x10			/* 3D control */
#define  C3DCTL_MODE3D 0x80
#define  C3DCTL_3DUC 0x40
#define  C3DCTL_3DLC 0x20
#define  C3DCTL_3DDEPTH_MASK 0x1E
#define  C3DCTL_GET_3DDEPTH(x) (((x) >> 1) & 0x1E)
#define  C3DCTL_SET_3DDEPTH(x) ((x) << 1)
#define  C3DCTL_3DEN 0x1

#define ALC1_REG 0x11			/* ALC1 */
#define  ALC1_ALCSEL_MASK 0x180
#define  ALC1_GET_ALCSEL(x) (((x) >> 7) & 0x180)
#define  ALC1_SET_ALCSEL(x) ((x) << 7)
#define  ALC1_MAXGAIN_MASK 0x70
#define  ALC1_GET_MAXGAIN(x) (((x) >> 4) & 0x70)
#define  ALC1_SET_MAXGAIN(x) ((x) << 4)
#define  ALC1_ALCL_MASK 0xF
#define  ALC1_GET_ALCL(x) ((x) & 0xF)
#define  ALC1_SET_ALCL(x) (x)

#define ALC2_REG 0x12			/* ALC2 */
#define  ALC2_ALCZC 0x80
#define  ALC2_HLD_MASK 0xF
#define  ALC2_GET_HLD(x) ((x) & 0xF)
#define  ALC2_SET_HLD(x) (x)

#define ALC3_REG 0x13			/* ALC3 */
#define  ALC3_DCY_MASK 0xF0
#define  ALC3_GET_DCY(x) (((x) >> 4) & 0xF0)
#define  ALC3_SET_DCY(x) ((x) << 4)
#define  ALC3_ATK_MASK 0xF
#define  ALC3_GET_ATK(x) ((x) & 0xF)
#define  ALC3_SET_ATK(x) (x)

#define NOISEGATE_REG 0x14		/* Noise Gate */
#define  NOISEGATE_NGTH_MASK 0xF8
#define  NOISEGATE_GET_NGTH(x) (((x) >> 3) & 0xF8)
#define  NOISEGATE_SET_NGTH(x) ((x) << 3)
#define  NOISEGATE_NGG_MASK 0x6
#define  NOISEGATE_GET_NGG(x) (((x) >> 1) & 0x6)
#define  NOISEGATE_SET_NGG(x) ((x) << 1)
#define  NOISEGATE_NGAT 0x1

#define LADCVOL_REG 0x15		/* Left ADC volume */
#define  LADCVOL_LAVU 0x100
#define  LADCVOL_LADCVOL_MASK 0xFF
#define  LADCVOL_GET_LADCVOL(x) ((x) & 0xFF)
#define  LADCVOL_SET_LADCVOL(x) (x)

#define RADCVOL_REG 0x16		/* Right ADC volume */
#define  RADCVOL_RAVU 0x100
#define  RADCVOL_RADCVOL_MASK 0xFF
#define  RADCVOL_GET_RADCVOL(x) ((x) & 0xFF)
#define  RADCVOL_SET_RADCVOL(x) (x)

#define ADCTL1_REG 0x17			/* Additional control(1) */
#define  ADCTL1_TSDEN 0x100
#define  ADCTL1_VSEL_MASK 0xC0
#define  ADCTL1_GET_VSEL(x) (((x) >> 6) & 0xC0)
#define  ADCTL1_SET_VSEL(x) ((x) << 6)
#define  ADCTL1_DMONOMIX_MASK 0x30
#define  ADCTL1_GET_DMONOMIX(x) (((x) >> 4) & 0x30)
#define  ADCTL1_SET_DMONOMIX(x) ((x) << 4)
#define  ADCTL1_DATSEL_MASK 0xC
#define  ADCTL1_GET_DATSEL(x) (((x) >> 2) & 0xC)
#define  ADCTL1_SET_DATSEL(x) ((x) << 2)
#define  ADCTL1_DACINV 0x2
#define  ADCTL1_TOEN 0x1

#define ADCTL2_REG 0x18			/* Additional control(2) */
#define  ADCTL2_OUTSW3_MASK 0x180
#define  ADCTL2_GET_OUTSW3(x) (((x) >> 7) & 0x180)
#define  ADCTL2_SET_OUTSW3(x) ((x) << 7)
#define  ADCTL2_HPSWEN 0x40
#define  ADCTL2_HPSWPOL 0x20
#define  ADCTL2_ROUT2INV 0x10
#define  ADCTL2_TRI 0x08
#define  ADCTL2_LRCM 0x04
#define  ADCTL2_ADCOSR 0x02
#define  ADCTL2_DACOSR 0x01

#define PWRMGMT1_REG 0x19		/* Pwr Mgmt (1) */
#define  PWRMGMT1_VMIDSEL_MASK 0x180
#define  PWRMGMT1_GET_VMIDSEL(x) (((x) >> 7) & 0x180)
#define  PWRMGMT1_SET_VMIDSEL(x) ((x) << 7)
#define  PWRMGMT1_VREF 0x40
#define  PWRMGMT1_AINL 0x20
#define  PWRMGMT1_AINR 0x10
#define  PWRMGMT1_ADCL 0x8
#define  PWRMGMT1_ADCR 0x4
#define  PWRMGMT1_MICB 0x2
#define  PWRMGMT1_DIGENB 0x1

#define PWRMGMT2_REG 0x1A		/* Pwr Mgmt (2) */
#define  PWRMGMT2_DACL 0x100
#define  PWRMGMT2_DACR 0x80
#define  PWRMGMT2_LOUT1 0x40
#define  PWRMGMT2_ROUT1 0x20
#define  PWRMGMT2_LOUT2 0x10
#define  PWRMGMT2_ROUT2 0x8
#define  PWRMGMT2_MONO 0x4
#define  PWRMGMT2_OUT3 0x2

#define ADCTL3_REG 0x1B			/* Additional Control (3) */
#define  ADCTL3_ADCLRM_MASK 0x180
#define  ADCTL3_GET_ADCLRM(x) (((x) >> 7) & 0x180)
#define  ADCTL3_SET_ADCLRM(x) ((x) << 7)
#define  ADCTL3_VROI 0x40
#define  ADCTL3_HPFLREN 0x20

#define ADCINPMODE_REG 0x1F		/* ADC input mode */
#define  ADCINPMODE_DS 0x100
#define  ADCINPMODE_MONOMIX_MASK 0xC0
#define  ADCINPMODE_GET_MONOMIX(x) (((x) >> 6) & 0xC0)
#define  ADCINPMODE_SET_MONOMIX(x) ((x) << 6)
#define  ADCINPMODE_RDCM 0x20
#define  ADCINPMODE_LDCM 0x10

#define ADCLSPATH_REG 0x20		/* ADCL signal path */
#define  ADCLSPATH_LINSEL_MASK 0xC0
#define  ADCLSPATH_GET_LINSEL(x) (((x) >> 6) & 0xC0)
#define  ADCLSPATH_SET_LINSEL(x) ((x) << 6)
#define  ADCLSPATH_LMICBOOST_MASK 0x30
#define  ADCLSPATH_GET_LMICBOOST(x) (((x) >> 4) & 0x30)
#define  ADCLSPATH_SET_LMICBOOST(x) ((x) << 4)

#define ADCRSPATH_REG 0x21		/* ADCR signal path */
#define  ADCRSPATH_RINSEL_MASK 0xC0
#define  ADCRSPATH_GET_RINSEL(x) (((x) >> 6) & 0xC0)
#define  ADCRSPATH_SET_RINSEL(x) ((x) << 6)
#define  ADCRSPATH_RMICBOOST_MASK 0x30
#define  ADCRSPATH_GET_RMICBOOST(x) (((x) >> 4) & 0x30)
#define  ADCRSPATH_SET_RMICBOOST(x) ((x) << 4)

#define LOUTMIX1_REG 0x22		/* Left out Mix (1) */
#define  LOUTMIX1_LD2LO 0x100
#define  LOUTMIX1_LI2LO 0x80
#define  LOUTMIX1_LI2LOVOL_MASK 0x70
#define  LOUTMIX1_GET_LI2LOVOL(x) (((x) >> 4) & 0x70)
#define  LOUTMIX1_SET_LI2LOVOL(x) ((x) << 4)
#define  LOUTMIX1_LMIXSEL_MASK 0x7
#define  LOUTMIX1_GET_LMIXSEL(x) ((x) & 0x7)
#define  LOUTMIX1_SET_LMIXSEL(x) (x)

#define LOUTMIX2_REG 0x23		/* Left out Mix (2) */
#define  LOUTMIX2_RD2LO 0x100
#define  LOUTMIX2_RI2LO 0x80
#define  LOUTMIX2_RI2LOVOL_MASK 0x70
#define  LOUTMIX2_GET_RI2LOVOL(x) (((x) >> 4) & 0x70)
#define  LOUTMIX2_SET_RI2LOVOL(x) ((x) << 4)

#define ROUTMIX1_REG 0x24		/* Right out Mix (1) */
#define  ROUTMIX1_LD2RO 0x100
#define  ROUTMIX1_LI2RO 0x80
#define  ROUTMIX1_LI2ROVOL_MASK 0x70
#define  ROUTMIX1_GET_LI2ROVOL(x) (((x) >> 4) & 0x70)
#define  ROUTMIX1_SET_LI2ROVOL(x) ((x) << 4)
#define  ROUTMIX1_RMIXSEL_MASK 0x7
#define  ROUTMIX1_GET_RMIXSEL(x) ((x) & 0x7)
#define  ROUTMIX1_SET_RMIXSEL(x) (x)

#define ROUTMIX2_REG 0x25		/* Right out Mix (2) */
#define  ROUTMIX2_RD2RO 0x100
#define  ROUTMIX2_RI2RO 0x80
#define  ROUTMIX2_RI2ROVOL_MASK 0x70
#define  ROUTMIX2_GET_RI2ROVOL(x) (((x) >> 4) & 0x70)
#define  ROUTMIX2_SET_RI2ROVOL(x) ((x) << 4)

#define MOUTMIX1_REG 0x26		/* Mono out Mix (1) */
#define  MOUTMIX1_LD2MO 0x100
#define  MOUTMIX1_LI2MO 0x80
#define  MOUTMIX1_LI2MOVOL_MASK 0x70
#define  MOUTMIX1_GET_LI2MOVOL(x) (((x) >> 4) & 0x70)
#define  MOUTMIX1_SET_LI2MOVOL(x) ((x) << 4)

#define MOUTMIX2_REG 0x27		/* Mono out Mix (2) */
#define  MOUTMIX2_RD2MO 0x100
#define  MOUTMIX2_RI2MO 0x80
#define  MOUTMIX2_RI2MOVOL_MASK 0x70
#define  MOUTMIX2_GET_RI2MOVOL(x) (((x) >> 4) & 0x70)
#define  MOUTMIX2_SET_RI2MOVOL(x) ((x) << 4)

#define LOUT2VOL_REG 0x28		/* LOUT2 volume */
#define  LOUT2VOL_LO2VU 0x100
#define  LOUT2VOL_LO2ZC 0x80
#define  LOUT2VOL_LOUT2VOL_MASK 0x7F
#define  LOUT2VOL_GET_LOUT2VOL(x) ((x) & 0x7F)
#define  LOUT2VOL_SET_LOUT2VOL(x) (x)

#define ROUT2VOL_REG 0x29		/* ROUT2 volume */
#define  ROUT2VOL_RO2VU 0x100
#define  ROUT2VOL_RO2ZC 0x80
#define  ROUT2VOL_ROUT2VOL_MASK 0x7F
#define  ROUT2VOL_GET_ROUT2VOL(x) ((x) & 0x7F)
#define  ROUT2VOL_SET_ROUT2VOL(x) (x)

#define MOUTVOL_REG 0x2A		/* MONOOUT volume */
#define  MOUTVOL_MOZC 0x80
#define  MOUTVOL_MOUTVOL_MASK 0x7F
#define  MOUTVOL_GET_MOUTVOL(x) ((x) & 0x7F)
#define  MOUTVOL_SET_MOUTVOL(x) (x)


code: src/sys/dev/ic

path: sys/dev/ic/CVS/Repository