xref: /dragonfly/sys/dev/powermng/it/it.c (revision 5d302545)
11d03db02SHasso Tepper /*
21d03db02SHasso Tepper  * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org>
31d03db02SHasso Tepper  * All rights reserved.
41d03db02SHasso Tepper  *
51d03db02SHasso Tepper  * Redistribution and use in source and binary forms, with or without
61d03db02SHasso Tepper  * modification, are permitted provided that the following conditions
71d03db02SHasso Tepper  * are met:
81d03db02SHasso Tepper  * 1. Redistributions of source code must retain the above copyright
91d03db02SHasso Tepper  *    notice, this list of conditions and the following disclaimer.
101d03db02SHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
111d03db02SHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
121d03db02SHasso Tepper  *    documentation and/or other materials provided with the distribution.
131d03db02SHasso Tepper  *
141d03db02SHasso Tepper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
151d03db02SHasso Tepper  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
161d03db02SHasso Tepper  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
171d03db02SHasso Tepper  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
181d03db02SHasso Tepper  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
191d03db02SHasso Tepper  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
201d03db02SHasso Tepper  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
211d03db02SHasso Tepper  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
221d03db02SHasso Tepper  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
231d03db02SHasso Tepper  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
241d03db02SHasso Tepper  *
251d03db02SHasso Tepper  * $OpenBSD: it.c,v 1.22 2007/03/22 16:55:31 deraadt Exp $
261d03db02SHasso Tepper  */
271d03db02SHasso Tepper 
281d03db02SHasso Tepper #include <sys/param.h>
291d03db02SHasso Tepper #include <sys/kernel.h>
301d03db02SHasso Tepper #include <sys/bus.h>
311d03db02SHasso Tepper #include <sys/module.h>
321d03db02SHasso Tepper #include <sys/rman.h>
331d03db02SHasso Tepper 
341d03db02SHasso Tepper #include <bus/isa/isavar.h>
351d03db02SHasso Tepper #include <sys/systm.h>
361d03db02SHasso Tepper 
371d03db02SHasso Tepper #include <sys/sensors.h>
381d03db02SHasso Tepper 
391d03db02SHasso Tepper #include "itvar.h"
401d03db02SHasso Tepper 
411d03db02SHasso Tepper #if defined(ITDEBUG)
426ab5c081SSascha Wildner #define DPRINTF(x)		do { kprintf x; } while (0)
431d03db02SHasso Tepper #else
441d03db02SHasso Tepper #define DPRINTF(x)
451d03db02SHasso Tepper #endif
461d03db02SHasso Tepper 
471d03db02SHasso Tepper /*
481d03db02SHasso Tepper  * IT87-compatible chips can typically measure voltages up to 4.096 V.
491d03db02SHasso Tepper  * To measure higher voltages the input is attenuated with (external)
501d03db02SHasso Tepper  * resistors.  Negative voltages are measured using a reference
511d03db02SHasso Tepper  * voltage.  So we have to convert the sensor values back to real
521d03db02SHasso Tepper  * voltages by applying the appropriate resistor factor.
531d03db02SHasso Tepper  */
541d03db02SHasso Tepper #define RFACT_NONE	10000
551d03db02SHasso Tepper #define RFACT(x, y)	(RFACT_NONE * ((x) + (y)) / (y))
561d03db02SHasso Tepper 
57*5d302545SFrançois Tigeot int it_probe(device_t);
58*5d302545SFrançois Tigeot int it_attach(device_t);
59*5d302545SFrançois Tigeot int it_detach(device_t);
601d03db02SHasso Tepper u_int8_t it_readreg(struct it_softc *, int);
611d03db02SHasso Tepper void it_writereg(struct it_softc *, int, int);
621d03db02SHasso Tepper void it_setup_volt(struct it_softc *, int, int);
631d03db02SHasso Tepper void it_setup_temp(struct it_softc *, int, int);
641d03db02SHasso Tepper void it_setup_fan(struct it_softc *, int, int);
651d03db02SHasso Tepper 
661d03db02SHasso Tepper void it_generic_stemp(struct it_softc *, struct ksensor *);
671d03db02SHasso Tepper void it_generic_svolt(struct it_softc *, struct ksensor *);
681d03db02SHasso Tepper void it_generic_fanrpm(struct it_softc *, struct ksensor *);
691d03db02SHasso Tepper 
701d03db02SHasso Tepper void it_refresh_sensor_data(struct it_softc *);
711d03db02SHasso Tepper void it_refresh(void *);
721d03db02SHasso Tepper 
731d03db02SHasso Tepper static device_method_t it_methods[] = {
741d03db02SHasso Tepper 	/* Methods from the device interface */
751d03db02SHasso Tepper 	DEVMETHOD(device_probe,         it_probe),
761d03db02SHasso Tepper 	DEVMETHOD(device_attach,        it_attach),
771d03db02SHasso Tepper 	DEVMETHOD(device_detach,        it_detach),
781d03db02SHasso Tepper 
791d03db02SHasso Tepper 	/* Terminate method list */
80d3c9c58eSSascha Wildner 	DEVMETHOD_END
811d03db02SHasso Tepper };
821d03db02SHasso Tepper 
831d03db02SHasso Tepper static driver_t it_driver = {
841d03db02SHasso Tepper 	"it",
851d03db02SHasso Tepper 	it_methods,
861d03db02SHasso Tepper 	sizeof (struct it_softc)
871d03db02SHasso Tepper };
881d03db02SHasso Tepper 
891d03db02SHasso Tepper static devclass_t it_devclass;
901d03db02SHasso Tepper 
911d03db02SHasso Tepper DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL);
921d03db02SHasso Tepper 
931d03db02SHasso Tepper 
941d03db02SHasso Tepper const int it_vrfact[] = {
951d03db02SHasso Tepper 	RFACT_NONE,
961d03db02SHasso Tepper 	RFACT_NONE,
971d03db02SHasso Tepper 	RFACT_NONE,
981d03db02SHasso Tepper 	RFACT(68, 100),
991d03db02SHasso Tepper 	RFACT(30, 10),
1001d03db02SHasso Tepper 	RFACT(21, 10),
1011d03db02SHasso Tepper 	RFACT(83, 20),
1021d03db02SHasso Tepper 	RFACT(68, 100),
1031d03db02SHasso Tepper 	RFACT_NONE
1041d03db02SHasso Tepper };
1051d03db02SHasso Tepper 
1061d03db02SHasso Tepper int
it_probe(device_t dev)107*5d302545SFrançois Tigeot it_probe(device_t dev)
1081d03db02SHasso Tepper {
1091d03db02SHasso Tepper 	struct resource *iores;
1101d03db02SHasso Tepper 	int iorid = 0;
1111d03db02SHasso Tepper 	bus_space_tag_t iot;
1121d03db02SHasso Tepper 	bus_space_handle_t ioh;
1131d03db02SHasso Tepper 	u_int8_t cr;
1141d03db02SHasso Tepper 
1151d03db02SHasso Tepper 	iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
1161d03db02SHasso Tepper 	    0ul, ~0ul, 8, RF_ACTIVE);
1171d03db02SHasso Tepper 	if (iores == NULL) {
1181d03db02SHasso Tepper 		DPRINTF(("%s: can't map i/o space\n", __func__));
1191d03db02SHasso Tepper 		return 1;
1201d03db02SHasso Tepper 	}
1211d03db02SHasso Tepper 	iot = rman_get_bustag(iores);
1221d03db02SHasso Tepper 	ioh = rman_get_bushandle(iores);
1231d03db02SHasso Tepper 
1241d03db02SHasso Tepper 	/* Check Vendor ID */
1251d03db02SHasso Tepper 	bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID);
1261d03db02SHasso Tepper 	cr = bus_space_read_1(iot, ioh, ITC_DATA);
1271d03db02SHasso Tepper 	bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
1281d03db02SHasso Tepper 	DPRINTF(("it: vendor id 0x%x\n", cr));
1291d03db02SHasso Tepper 	if (cr != IT_ID_IT87)
1301d03db02SHasso Tepper 		return 1;
1311d03db02SHasso Tepper 
1321d03db02SHasso Tepper 	return 0;
1331d03db02SHasso Tepper }
1341d03db02SHasso Tepper 
1351d03db02SHasso Tepper int
it_attach(device_t dev)136*5d302545SFrançois Tigeot it_attach(device_t dev)
1371d03db02SHasso Tepper {
1381d03db02SHasso Tepper 	struct it_softc *sc = device_get_softc(dev);
1391d03db02SHasso Tepper 	int i;
1401d03db02SHasso Tepper 	u_int8_t cr;
1411d03db02SHasso Tepper 
1421d03db02SHasso Tepper 	sc->sc_dev = dev;
1431d03db02SHasso Tepper 	sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
1441d03db02SHasso Tepper 	    0ul, ~0ul, 8, RF_ACTIVE);
1451d03db02SHasso Tepper 	if (sc->sc_iores == NULL) {
1461d03db02SHasso Tepper 		device_printf(dev, "can't map i/o space\n");
1471d03db02SHasso Tepper 		return 1;
1481d03db02SHasso Tepper 	}
1491d03db02SHasso Tepper 	sc->sc_iot = rman_get_bustag(sc->sc_iores);
1501d03db02SHasso Tepper 	sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
1511d03db02SHasso Tepper 
1521d03db02SHasso Tepper 	sc->numsensors = IT_NUM_SENSORS;
1531d03db02SHasso Tepper 
1541d03db02SHasso Tepper 	it_setup_fan(sc, 0, 3);
1551d03db02SHasso Tepper 	it_setup_volt(sc, 3, 9);
1561d03db02SHasso Tepper 	it_setup_temp(sc, 12, 3);
1571d03db02SHasso Tepper 
1581bedd63aSSepherosa Ziehau 	sensor_task_register(sc, it_refresh, 5);
1591d03db02SHasso Tepper 
1601d03db02SHasso Tepper 	/* Activate monitoring */
1611d03db02SHasso Tepper 	cr = it_readreg(sc, ITD_CONFIG);
1621d03db02SHasso Tepper 	cr |= 0x01 | 0x08;
1631d03db02SHasso Tepper 	it_writereg(sc, ITD_CONFIG, cr);
1641d03db02SHasso Tepper 
1651d03db02SHasso Tepper 	/* Initialize sensors */
1661d03db02SHasso Tepper 	strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev),
1671d03db02SHasso Tepper 	    sizeof(sc->sensordev.xname));
1681d03db02SHasso Tepper 	for (i = 0; i < sc->numsensors; ++i)
1691d03db02SHasso Tepper 		sensor_attach(&sc->sensordev, &sc->sensors[i]);
1701d03db02SHasso Tepper 	sensordev_install(&sc->sensordev);
1711d03db02SHasso Tepper 
1721d03db02SHasso Tepper 	return 0;
1731d03db02SHasso Tepper }
1741d03db02SHasso Tepper 
1751d03db02SHasso Tepper int
it_detach(device_t dev)176*5d302545SFrançois Tigeot it_detach(device_t dev)
1771d03db02SHasso Tepper {
1781d03db02SHasso Tepper 	struct it_softc *sc = device_get_softc(dev);
1791d03db02SHasso Tepper 	int error;
1801d03db02SHasso Tepper 
1811d03db02SHasso Tepper 	sensordev_deinstall(&sc->sensordev);
1821d03db02SHasso Tepper 	sensor_task_unregister(sc);
1831d03db02SHasso Tepper 
1841d03db02SHasso Tepper 	error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
1851d03db02SHasso Tepper 	    sc->sc_iores);
1861d03db02SHasso Tepper 	if (error)
1871d03db02SHasso Tepper 		return error;
1881d03db02SHasso Tepper 
1891d03db02SHasso Tepper 	return 0;
1901d03db02SHasso Tepper }
1911d03db02SHasso Tepper 
1921d03db02SHasso Tepper u_int8_t
it_readreg(struct it_softc * sc,int reg)1931d03db02SHasso Tepper it_readreg(struct it_softc *sc, int reg)
1941d03db02SHasso Tepper {
1951d03db02SHasso Tepper 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg);
1961d03db02SHasso Tepper 	return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ITC_DATA));
1971d03db02SHasso Tepper }
1981d03db02SHasso Tepper 
1991d03db02SHasso Tepper void
it_writereg(struct it_softc * sc,int reg,int val)2001d03db02SHasso Tepper it_writereg(struct it_softc *sc, int reg, int val)
2011d03db02SHasso Tepper {
2021d03db02SHasso Tepper 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg);
2031d03db02SHasso Tepper 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_DATA, val);
2041d03db02SHasso Tepper }
2051d03db02SHasso Tepper 
2061d03db02SHasso Tepper void
it_setup_volt(struct it_softc * sc,int start,int n)2071d03db02SHasso Tepper it_setup_volt(struct it_softc *sc, int start, int n)
2081d03db02SHasso Tepper {
2091d03db02SHasso Tepper 	int i;
2101d03db02SHasso Tepper 
2111d03db02SHasso Tepper 	for (i = 0; i < n; ++i) {
2121d03db02SHasso Tepper 		sc->sensors[start + i].type = SENSOR_VOLTS_DC;
2131d03db02SHasso Tepper 	}
2141d03db02SHasso Tepper 
2151d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
2161d03db02SHasso Tepper 	    "VCORE_A");
2171d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
2181d03db02SHasso Tepper 	    "VCORE_B");
2191d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
2201d03db02SHasso Tepper 	    "+3.3V");
2211d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
2221d03db02SHasso Tepper 	    "+5V");
2231d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
2241d03db02SHasso Tepper 	    "+12V");
2251d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
2261d03db02SHasso Tepper 	    "Unused");
2271d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
2281d03db02SHasso Tepper 	    "-12V");
2291d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
2301d03db02SHasso Tepper 	    "+5VSB");
2311d03db02SHasso Tepper 	ksnprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
2321d03db02SHasso Tepper 	    "VBAT");
2331d03db02SHasso Tepper }
2341d03db02SHasso Tepper 
2351d03db02SHasso Tepper void
it_setup_temp(struct it_softc * sc,int start,int n)2361d03db02SHasso Tepper it_setup_temp(struct it_softc *sc, int start, int n)
2371d03db02SHasso Tepper {
2381d03db02SHasso Tepper 	int i;
2391d03db02SHasso Tepper 
2401d03db02SHasso Tepper 	for (i = 0; i < n; ++i)
2411d03db02SHasso Tepper 		sc->sensors[start + i].type = SENSOR_TEMP;
2421d03db02SHasso Tepper }
2431d03db02SHasso Tepper 
2441d03db02SHasso Tepper void
it_setup_fan(struct it_softc * sc,int start,int n)2451d03db02SHasso Tepper it_setup_fan(struct it_softc *sc, int start, int n)
2461d03db02SHasso Tepper {
2471d03db02SHasso Tepper 	int i;
2481d03db02SHasso Tepper 
2491d03db02SHasso Tepper 	for (i = 0; i < n; ++i)
2501d03db02SHasso Tepper 		sc->sensors[start + i].type = SENSOR_FANRPM;
2511d03db02SHasso Tepper }
2521d03db02SHasso Tepper 
2531d03db02SHasso Tepper void
it_generic_stemp(struct it_softc * sc,struct ksensor * sensors)2541d03db02SHasso Tepper it_generic_stemp(struct it_softc *sc, struct ksensor *sensors)
2551d03db02SHasso Tepper {
2561d03db02SHasso Tepper 	int i, sdata;
2571d03db02SHasso Tepper 
2581d03db02SHasso Tepper 	for (i = 0; i < 3; i++) {
2591d03db02SHasso Tepper 		sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i);
2601d03db02SHasso Tepper 		/* Convert temperature to Fahrenheit degres */
2611d03db02SHasso Tepper 		sensors[i].value = sdata * 1000000 + 273150000;
2621d03db02SHasso Tepper 	}
2631d03db02SHasso Tepper }
2641d03db02SHasso Tepper 
2651d03db02SHasso Tepper void
it_generic_svolt(struct it_softc * sc,struct ksensor * sensors)2661d03db02SHasso Tepper it_generic_svolt(struct it_softc *sc, struct ksensor *sensors)
2671d03db02SHasso Tepper {
2681d03db02SHasso Tepper 	int i, sdata;
2691d03db02SHasso Tepper 
2701d03db02SHasso Tepper 	for (i = 0; i < 9; i++) {
2711d03db02SHasso Tepper 		sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i);
2721d03db02SHasso Tepper 		DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
2731d03db02SHasso Tepper 		/* voltage returned as (mV >> 4) */
2741d03db02SHasso Tepper 		sensors[i].value = (sdata << 4);
2751d03db02SHasso Tepper 		/* these two values are negative and formula is different */
2761d03db02SHasso Tepper 		if (i == 5 || i == 6)
2771d03db02SHasso Tepper 			sensors[i].value = ((sdata << 4) - IT_VREF);
2781d03db02SHasso Tepper 		/* rfact is (factor * 10^4) */
2791d03db02SHasso Tepper 		sensors[i].value *= it_vrfact[i];
2801d03db02SHasso Tepper 		/* division by 10 gets us back to uVDC */
2811d03db02SHasso Tepper 		sensors[i].value /= 10;
2821d03db02SHasso Tepper 		if (i == 5 || i == 6)
2831d03db02SHasso Tepper 			sensors[i].value += IT_VREF * 1000;
2841d03db02SHasso Tepper 	}
2851d03db02SHasso Tepper }
2861d03db02SHasso Tepper 
2871d03db02SHasso Tepper void
it_generic_fanrpm(struct it_softc * sc,struct ksensor * sensors)2881d03db02SHasso Tepper it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors)
2891d03db02SHasso Tepper {
2901d03db02SHasso Tepper 	int i, sdata, divisor, odivisor, ndivisor;
2911d03db02SHasso Tepper 
2921d03db02SHasso Tepper 	odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN);
2931d03db02SHasso Tepper 	for (i = 0; i < 3; i++, divisor >>= 3) {
2941d03db02SHasso Tepper 		sensors[i].flags &= ~SENSOR_FINVALID;
2951d03db02SHasso Tepper 		if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) {
2961d03db02SHasso Tepper 			sensors[i].flags |= SENSOR_FINVALID;
2971d03db02SHasso Tepper 			if (i == 2)
2981d03db02SHasso Tepper 				ndivisor ^= 0x40;
2991d03db02SHasso Tepper 			else {
3001d03db02SHasso Tepper 				ndivisor &= ~(7 << (i * 3));
3011d03db02SHasso Tepper 				ndivisor |= ((divisor + 1) & 7) << (i * 3);
3021d03db02SHasso Tepper 			}
3031d03db02SHasso Tepper 		} else if (sdata == 0) {
3041d03db02SHasso Tepper 			sensors[i].value = 0;
3051d03db02SHasso Tepper 		} else {
3061d03db02SHasso Tepper 			if (i == 2)
3071d03db02SHasso Tepper 				divisor = divisor & 1 ? 3 : 1;
3081d03db02SHasso Tepper 			sensors[i].value = 1350000 / (sdata << (divisor & 7));
3091d03db02SHasso Tepper 		}
3101d03db02SHasso Tepper 	}
3111d03db02SHasso Tepper 	if (ndivisor != odivisor)
3121d03db02SHasso Tepper 		it_writereg(sc, ITD_FAN, ndivisor);
3131d03db02SHasso Tepper }
3141d03db02SHasso Tepper 
3151d03db02SHasso Tepper /*
3161d03db02SHasso Tepper  * pre:  last read occurred >= 1.5 seconds ago
3171d03db02SHasso Tepper  * post: sensors[] current data are the latest from the chip
3181d03db02SHasso Tepper  */
3191d03db02SHasso Tepper void
it_refresh_sensor_data(struct it_softc * sc)3201d03db02SHasso Tepper it_refresh_sensor_data(struct it_softc *sc)
3211d03db02SHasso Tepper {
3221d03db02SHasso Tepper 	/* Refresh our stored data for every sensor */
3231d03db02SHasso Tepper 	it_generic_stemp(sc, &sc->sensors[12]);
3241d03db02SHasso Tepper 	it_generic_svolt(sc, &sc->sensors[3]);
3251d03db02SHasso Tepper 	it_generic_fanrpm(sc, &sc->sensors[0]);
3261d03db02SHasso Tepper }
3271d03db02SHasso Tepper 
3281d03db02SHasso Tepper void
it_refresh(void * arg)3291d03db02SHasso Tepper it_refresh(void *arg)
3301d03db02SHasso Tepper {
3311d03db02SHasso Tepper 	struct it_softc *sc = (struct it_softc *)arg;
3321d03db02SHasso Tepper 
3331d03db02SHasso Tepper 	it_refresh_sensor_data(sc);
3341d03db02SHasso Tepper }
335