xref: /openbsd/sys/dev/i2c/adm1021.c (revision 992a98bb)
1*992a98bbSderaadt /*	$OpenBSD: adm1021.c,v 1.8 2005/12/26 01:04:55 deraadt Exp $	*/
24e3ece99Sderaadt 
34e3ece99Sderaadt /*
44e3ece99Sderaadt  * Copyright (c) 2005 Theo de Raadt
54e3ece99Sderaadt  *
64e3ece99Sderaadt  * Permission to use, copy, modify, and distribute this software for any
74e3ece99Sderaadt  * purpose with or without fee is hereby granted, provided that the above
84e3ece99Sderaadt  * copyright notice and this permission notice appear in all copies.
94e3ece99Sderaadt  *
104e3ece99Sderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114e3ece99Sderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124e3ece99Sderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134e3ece99Sderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144e3ece99Sderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154e3ece99Sderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164e3ece99Sderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174e3ece99Sderaadt  */
184e3ece99Sderaadt 
194e3ece99Sderaadt #include <sys/param.h>
204e3ece99Sderaadt #include <sys/systm.h>
214e3ece99Sderaadt #include <sys/device.h>
224e3ece99Sderaadt #include <sys/sensors.h>
234e3ece99Sderaadt 
244e3ece99Sderaadt #include <dev/i2c/i2cvar.h>
254e3ece99Sderaadt 
264e3ece99Sderaadt /* ADM 1021 registers */
274e3ece99Sderaadt #define ADM1021_INT_TEMP	0x00
284e3ece99Sderaadt #define ADM1021_EXT_TEMP	0x01
294e3ece99Sderaadt #define ADM1021_STATUS		0x02
30dd58f502Sderaadt #define ADM1021_CONFIG_READ	0x03
31dd58f502Sderaadt #define ADM1021_CONFIG_WRITE	0x09
32*992a98bbSderaadt #define  ADM1021_CONFIG_RUN	0x40
334e3ece99Sderaadt #define ADM1021_COMPANY		0xfe	/* contains 0x41 */
344e3ece99Sderaadt #define ADM1021_STEPPING	0xff	/* contains 0x3? */
354e3ece99Sderaadt 
364e3ece99Sderaadt /* Sensors */
374a9fb704Sderaadt #define ADMTEMP_EXT		0
384a9fb704Sderaadt #define ADMTEMP_INT		1
394e3ece99Sderaadt #define ADMTEMP_NUM_SENSORS	2
404e3ece99Sderaadt 
414e3ece99Sderaadt struct admtemp_softc {
424e3ece99Sderaadt 	struct device	sc_dev;
434e3ece99Sderaadt 	i2c_tag_t	sc_tag;
444e3ece99Sderaadt 	i2c_addr_t	sc_addr;
454e3ece99Sderaadt 
464e3ece99Sderaadt 	struct sensor	sc_sensor[ADMTEMP_NUM_SENSORS];
47af73b13aSderaadt 	int		sc_xeon;
484e3ece99Sderaadt };
494e3ece99Sderaadt 
504e3ece99Sderaadt int	admtemp_match(struct device *, void *, void *);
514e3ece99Sderaadt void	admtemp_attach(struct device *, struct device *, void *);
524e3ece99Sderaadt void	admtemp_refresh(void *);
534e3ece99Sderaadt 
544e3ece99Sderaadt struct cfattach admtemp_ca = {
554e3ece99Sderaadt 	sizeof(struct admtemp_softc), admtemp_match, admtemp_attach
564e3ece99Sderaadt };
574e3ece99Sderaadt 
584e3ece99Sderaadt struct cfdriver admtemp_cd = {
594e3ece99Sderaadt 	NULL, "admtemp", DV_DULL
604e3ece99Sderaadt };
614e3ece99Sderaadt 
624e3ece99Sderaadt int
634e3ece99Sderaadt admtemp_match(struct device *parent, void *match, void *aux)
644e3ece99Sderaadt {
654e3ece99Sderaadt 	struct i2c_attach_args *ia = aux;
664e3ece99Sderaadt 
67e109779fSderaadt 	if (strcmp(ia->ia_name, "adm1021") == 0 ||
68e109779fSderaadt 	    strcmp(ia->ia_name, "xeon") == 0) {
694e3ece99Sderaadt 		/*
704e3ece99Sderaadt 		 * should also ensure that
714e3ece99Sderaadt 		 * config & 0x80 == 0x00
724e3ece99Sderaadt 		 * status1 & 0xc0 == 0x00
734e3ece99Sderaadt 		 * status2 & 0xbc == 0x00
744e3ece99Sderaadt 		 * before accepting this to be for real
754e3ece99Sderaadt 		 */
764e3ece99Sderaadt 		return (1);
774e3ece99Sderaadt 	}
78f571b3bfSderaadt 	return (0);
794e3ece99Sderaadt }
804e3ece99Sderaadt 
814e3ece99Sderaadt void
824e3ece99Sderaadt admtemp_attach(struct device *parent, struct device *self, void *aux)
834e3ece99Sderaadt {
844e3ece99Sderaadt 	struct admtemp_softc *sc = (struct admtemp_softc *)self;
854e3ece99Sderaadt 	struct i2c_attach_args *ia = aux;
86*992a98bbSderaadt 	u_int8_t cmd, data;
874e3ece99Sderaadt 	int i;
884e3ece99Sderaadt 
894e3ece99Sderaadt 	sc->sc_tag = ia->ia_tag;
904e3ece99Sderaadt 	sc->sc_addr = ia->ia_addr;
914e3ece99Sderaadt 
92af73b13aSderaadt 	if (ia->ia_name && strcmp(ia->ia_name, "xeon") == 0) {
93c179919eSderaadt 		printf(": Xeon");
94af73b13aSderaadt 		sc->sc_xeon = 1;
95af73b13aSderaadt 	}
96af73b13aSderaadt 
97*992a98bbSderaadt 	iic_acquire_bus(sc->sc_tag, 0);
98*992a98bbSderaadt 	cmd = ADM1021_CONFIG_READ;
99*992a98bbSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
100*992a98bbSderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) {
101*992a98bbSderaadt 		iic_release_bus(sc->sc_tag, 0);
102*992a98bbSderaadt 		printf(": cannot get control register\n");
103*992a98bbSderaadt 		return;
104*992a98bbSderaadt 	}
105*992a98bbSderaadt 	data &= ~ADM1021_CONFIG_RUN;
106*992a98bbSderaadt 	cmd = ADM1021_CONFIG_WRITE;
107*992a98bbSderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
108*992a98bbSderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) {
109*992a98bbSderaadt 		iic_release_bus(sc->sc_tag, 0);
110*992a98bbSderaadt 		printf(": cannot set control register\n");
111*992a98bbSderaadt 		return;
112*992a98bbSderaadt 	}
113*992a98bbSderaadt 	iic_release_bus(sc->sc_tag, 0);
114dd58f502Sderaadt 
1154e3ece99Sderaadt 	/* Initialize sensor data. */
1164e3ece99Sderaadt 	for (i = 0; i < ADMTEMP_NUM_SENSORS; i++)
1174e3ece99Sderaadt 		strlcpy(sc->sc_sensor[i].device, sc->sc_dev.dv_xname,
1184e3ece99Sderaadt 		    sizeof(sc->sc_sensor[i].device));
1194e3ece99Sderaadt 
1204a9fb704Sderaadt 	sc->sc_sensor[ADMTEMP_EXT].type = SENSOR_TEMP;
1214a9fb704Sderaadt 	strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc,
1224a9fb704Sderaadt 	    sc->sc_xeon ? "Xeon" : "External",
1234a9fb704Sderaadt 	    sizeof(sc->sc_sensor[ADMTEMP_EXT].desc));
1244a9fb704Sderaadt 
1254e3ece99Sderaadt 	sc->sc_sensor[ADMTEMP_INT].type = SENSOR_TEMP;
1264e3ece99Sderaadt 	strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, "Internal",
1274e3ece99Sderaadt 	    sizeof(sc->sc_sensor[ADMTEMP_INT].desc));
1284e3ece99Sderaadt 
1294e3ece99Sderaadt 	if (sensor_task_register(sc, admtemp_refresh, 5)) {
1304e3ece99Sderaadt 		printf(", unable to register update task\n");
1314e3ece99Sderaadt 		return;
1324e3ece99Sderaadt 	}
1334e3ece99Sderaadt 
1344a9fb704Sderaadt 	for (i = 0; i < (sc->sc_xeon ? 1 : ADMTEMP_NUM_SENSORS); i++)
1354e3ece99Sderaadt 		SENSOR_ADD(&sc->sc_sensor[i]);
1364e3ece99Sderaadt 
1374e3ece99Sderaadt 	printf("\n");
1384e3ece99Sderaadt }
1394e3ece99Sderaadt 
1404e3ece99Sderaadt void
1414e3ece99Sderaadt admtemp_refresh(void *arg)
1424e3ece99Sderaadt {
1434e3ece99Sderaadt 	struct admtemp_softc *sc = arg;
144dd58f502Sderaadt 	u_int8_t cmd;
145dd58f502Sderaadt 	int8_t sdata;
1464e3ece99Sderaadt 
1474e3ece99Sderaadt 	iic_acquire_bus(sc->sc_tag, 0);
1484e3ece99Sderaadt 
1494a9fb704Sderaadt 	cmd = ADM1021_EXT_TEMP;
1504a9fb704Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
1514a9fb704Sderaadt 	    &cmd, sizeof cmd, &sdata, sizeof sdata, I2C_F_POLL) == 0)
1524a9fb704Sderaadt 		sc->sc_sensor[ADMTEMP_EXT].value =
1534a9fb704Sderaadt 		    273150000 + 1000000 * sdata;
1544a9fb704Sderaadt 
155af73b13aSderaadt 	if (sc->sc_xeon == 0) {
1564e3ece99Sderaadt 		cmd = ADM1021_INT_TEMP;
1574a9fb704Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
1584a9fb704Sderaadt 		    &cmd, sizeof cmd, &sdata,  sizeof sdata, I2C_F_POLL) == 0)
159af73b13aSderaadt 			sc->sc_sensor[ADMTEMP_INT].value =
160af73b13aSderaadt 			    273150000 + 1000000 * sdata;
161af73b13aSderaadt 	}
1624e3ece99Sderaadt 
1634e3ece99Sderaadt 	iic_release_bus(sc->sc_tag, 0);
1644e3ece99Sderaadt }
165