xref: /openbsd/sys/dev/i2c/w83795g.c (revision 471aeecf)
1*471aeecfSnaddy /*	$OpenBSD: w83795g.c,v 1.2 2022/04/06 18:59:28 naddy Exp $	*/
22db8573fSkettenis 
32db8573fSkettenis /*
42db8573fSkettenis  * Copyright (c) 2011 Mark Kettenis
52db8573fSkettenis  *
62db8573fSkettenis  * Permission to use, copy, modify, and distribute this software for any
72db8573fSkettenis  * purpose with or without fee is hereby granted, provided that the above
82db8573fSkettenis  * copyright notice and this permission notice appear in all copies.
92db8573fSkettenis  *
102db8573fSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112db8573fSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122db8573fSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132db8573fSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142db8573fSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152db8573fSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162db8573fSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172db8573fSkettenis  */
182db8573fSkettenis 
192db8573fSkettenis #include <sys/param.h>
202db8573fSkettenis #include <sys/systm.h>
212db8573fSkettenis #include <sys/device.h>
222db8573fSkettenis #include <sys/sensors.h>
232db8573fSkettenis 
242db8573fSkettenis #include <dev/i2c/i2cvar.h>
252db8573fSkettenis 
262db8573fSkettenis /* Nuvoton W83795G Hardware Monitor */
272db8573fSkettenis 
282db8573fSkettenis #define NVT_BANKSELECT		0x00
292db8573fSkettenis #define NVT_CONFIG		0x01
302db8573fSkettenis #define  NVT_CONFIG_48		0x04
312db8573fSkettenis #define NVT_VOLT_CTRL1		0x02
322db8573fSkettenis #define NVT_VOLT_CTRL2		0x03
332db8573fSkettenis #define NVT_TEMP_CTRL1		0x04
342db8573fSkettenis #define NVT_TEMP_CTRL2		0x05
352db8573fSkettenis #define NVT_FANIN_CTRL1		0x06
362db8573fSkettenis #define NVT_FANIN_CTRL2		0x07
372db8573fSkettenis #define NVT_VSEN1		0x10
382db8573fSkettenis #define NVT_3VDD		0x1c
392db8573fSkettenis #define NVT_3VSB		0x1d
402db8573fSkettenis #define NVT_VBAT		0x1e
412db8573fSkettenis #define NVT_TR5			0x1f
422db8573fSkettenis #define NVT_TR6			0x20
432db8573fSkettenis #define NVT_TD1			0x21
442db8573fSkettenis #define NVT_TD2			0x22
452db8573fSkettenis #define NVT_TD3			0x23
462db8573fSkettenis #define NVT_TD4			0x24
472db8573fSkettenis #define NVT_FANIN1_COUNT	0x2e
482db8573fSkettenis #define NVT_VRLSB		0x3c
492db8573fSkettenis 
502db8573fSkettenis /* Voltage */
512db8573fSkettenis #define NVT_NUM_VOLTS	15
522db8573fSkettenis 
532db8573fSkettenis static const char *nvt_volt_desc[NVT_NUM_VOLTS] = {
542db8573fSkettenis 	"", "", "", "", "", "", "", "", "", "", "",
552db8573fSkettenis 	"VTT", "3VDD", "3VSB", "VBat"
562db8573fSkettenis };
572db8573fSkettenis 
582db8573fSkettenis /* Temperature */
592db8573fSkettenis #define NVT_NUM_TEMPS	6
602db8573fSkettenis #define NVT_NUM_TR	2
612db8573fSkettenis #define NVT_NUM_TD	4
622db8573fSkettenis 
632db8573fSkettenis /* Fan */
642db8573fSkettenis #define NVT_NUM_FANS	14
652db8573fSkettenis 
662db8573fSkettenis #define NVT_NUM_SENSORS (NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS)
672db8573fSkettenis 
682db8573fSkettenis struct nvt_softc {
692db8573fSkettenis 	struct device	sc_dev;
702db8573fSkettenis 	i2c_tag_t	sc_tag;
712db8573fSkettenis 	i2c_addr_t	sc_addr;
722db8573fSkettenis 
732db8573fSkettenis 	uint16_t	sc_vctrl;
742db8573fSkettenis 	uint16_t	sc_tctrl1, sc_tctrl2;
752db8573fSkettenis 	uint16_t	sc_fctrl;
762db8573fSkettenis 
772db8573fSkettenis 	struct ksensor	sc_sensors[NVT_NUM_SENSORS];
782db8573fSkettenis 	struct ksensordev sc_sensordev;
792db8573fSkettenis };
802db8573fSkettenis 
812db8573fSkettenis 
822db8573fSkettenis int	nvt_match(struct device *, void *, void *);
832db8573fSkettenis void	nvt_attach(struct device *, struct device *, void *);
842db8573fSkettenis void	nvt_refresh(void *);
852db8573fSkettenis 
862db8573fSkettenis void	nvt_refresh_volts(struct nvt_softc *);
872db8573fSkettenis void	nvt_refresh_temps(struct nvt_softc *);
882db8573fSkettenis void	nvt_refresh_fans(struct nvt_softc *);
892db8573fSkettenis 
902db8573fSkettenis uint8_t	nvt_readreg(struct nvt_softc *, uint8_t);
912db8573fSkettenis void	nvt_writereg(struct nvt_softc *, uint8_t, uint8_t);
922db8573fSkettenis 
932db8573fSkettenis 
94*471aeecfSnaddy const struct cfattach nvt_ca = {
952db8573fSkettenis 	sizeof(struct nvt_softc), nvt_match, nvt_attach
962db8573fSkettenis };
972db8573fSkettenis 
982db8573fSkettenis struct cfdriver nvt_cd = {
992db8573fSkettenis 	NULL, "nvt", DV_DULL
1002db8573fSkettenis };
1012db8573fSkettenis 
1022db8573fSkettenis 
1032db8573fSkettenis int
nvt_match(struct device * parent,void * match,void * aux)1042db8573fSkettenis nvt_match(struct device *parent, void *match, void *aux)
1052db8573fSkettenis {
1062db8573fSkettenis 	struct i2c_attach_args *ia = aux;
1072db8573fSkettenis 
1082db8573fSkettenis 	if (strcmp(ia->ia_name, "w83795g") == 0)
1092db8573fSkettenis 		return (1);
1102db8573fSkettenis 	return (0);
1112db8573fSkettenis }
1122db8573fSkettenis 
1132db8573fSkettenis void
nvt_attach(struct device * parent,struct device * self,void * aux)1142db8573fSkettenis nvt_attach(struct device *parent, struct device *self, void *aux)
1152db8573fSkettenis {
1162db8573fSkettenis 	struct nvt_softc *sc = (struct nvt_softc *)self;
1172db8573fSkettenis 	struct i2c_attach_args *ia = aux;
1182db8573fSkettenis 	uint8_t cfg, vctrl1, vctrl2;
1192db8573fSkettenis 	uint8_t tctrl1, tctrl2, fctrl1, fctrl2;
1202db8573fSkettenis 	int i, j;
1212db8573fSkettenis 
1222db8573fSkettenis 	sc->sc_tag = ia->ia_tag;
1232db8573fSkettenis 	sc->sc_addr = ia->ia_addr;
1242db8573fSkettenis 
1252db8573fSkettenis 	cfg = nvt_readreg(sc, NVT_CONFIG);
1262db8573fSkettenis 	if (cfg & NVT_CONFIG_48)
1272db8573fSkettenis 		printf(": W83795ADG");
1282db8573fSkettenis 	else
1292db8573fSkettenis 		printf(": W83795G");
1302db8573fSkettenis 
1312db8573fSkettenis 	vctrl1 = nvt_readreg(sc, NVT_VOLT_CTRL1);
1322db8573fSkettenis 	vctrl2 = nvt_readreg(sc, NVT_VOLT_CTRL2);
1332db8573fSkettenis 	tctrl1 = nvt_readreg(sc, NVT_TEMP_CTRL1);
1342db8573fSkettenis 	tctrl2 = nvt_readreg(sc, NVT_TEMP_CTRL2);
1352db8573fSkettenis 	fctrl1 = nvt_readreg(sc, NVT_FANIN_CTRL1);
1362db8573fSkettenis 	fctrl2 = nvt_readreg(sc, NVT_FANIN_CTRL2);
1372db8573fSkettenis 
1382db8573fSkettenis 	sc->sc_vctrl = vctrl2 << 8 | vctrl1;
1392db8573fSkettenis 	sc->sc_tctrl1 = tctrl1;
1402db8573fSkettenis 	sc->sc_tctrl2 = tctrl2;
1412db8573fSkettenis 	sc->sc_fctrl = fctrl2 << 8 | fctrl1;
1422db8573fSkettenis 
1432db8573fSkettenis 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
1442db8573fSkettenis 	    sizeof(sc->sc_sensordev.xname));
1452db8573fSkettenis 
1462db8573fSkettenis 	for (i = 0; i < NVT_NUM_VOLTS; i++) {
1472db8573fSkettenis 		strlcpy(sc->sc_sensors[i].desc, nvt_volt_desc[i],
1482db8573fSkettenis 		    sizeof(sc->sc_sensors[i].desc));
1492db8573fSkettenis 		sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
1502db8573fSkettenis 	}
1512db8573fSkettenis 
1522db8573fSkettenis 	for (j = i + NVT_NUM_TEMPS; i < j; i++)
1532db8573fSkettenis 		sc->sc_sensors[i].type = SENSOR_TEMP;
1542db8573fSkettenis 
1552db8573fSkettenis 	for (j = i + NVT_NUM_FANS; i < j; i++)
1562db8573fSkettenis 		sc->sc_sensors[i].type = SENSOR_FANRPM;
1572db8573fSkettenis 
1582db8573fSkettenis 	for (i = 0; i < NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS; i++)
1592db8573fSkettenis 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
1602db8573fSkettenis 
1612db8573fSkettenis 	if (sensor_task_register(sc, nvt_refresh, 5) == NULL) {
1622db8573fSkettenis 		printf(", unable to register update task\n");
1632db8573fSkettenis 		return;
1642db8573fSkettenis 	}
1652db8573fSkettenis 
1662db8573fSkettenis 	sensordev_install(&sc->sc_sensordev);
1672db8573fSkettenis 	printf("\n");
1682db8573fSkettenis }
1692db8573fSkettenis 
1702db8573fSkettenis void
nvt_refresh(void * arg)1712db8573fSkettenis nvt_refresh(void *arg)
1722db8573fSkettenis {
1732db8573fSkettenis 	struct nvt_softc *sc = arg;
1742db8573fSkettenis 	uint8_t bsr;
1752db8573fSkettenis 
1762db8573fSkettenis 	iic_acquire_bus(sc->sc_tag, 0);
1772db8573fSkettenis 
1782db8573fSkettenis 	bsr = nvt_readreg(sc, NVT_BANKSELECT);
1792db8573fSkettenis 	if ((bsr & 0x07) != 0x00)
1802db8573fSkettenis 		nvt_writereg(sc, NVT_BANKSELECT, bsr & 0xf8);
1812db8573fSkettenis 
1822db8573fSkettenis 	nvt_refresh_volts(sc);
1832db8573fSkettenis 	nvt_refresh_temps(sc);
1842db8573fSkettenis 	nvt_refresh_fans(sc);
1852db8573fSkettenis 
1862db8573fSkettenis 	if ((bsr & 0x07) != 0x00)
1872db8573fSkettenis 		nvt_writereg(sc, NVT_BANKSELECT, bsr);
1882db8573fSkettenis 
1892db8573fSkettenis 	iic_release_bus(sc->sc_tag, 0);
1902db8573fSkettenis }
1912db8573fSkettenis 
1922db8573fSkettenis void
nvt_refresh_volts(struct nvt_softc * sc)1932db8573fSkettenis nvt_refresh_volts(struct nvt_softc *sc)
1942db8573fSkettenis {
1952db8573fSkettenis 	struct ksensor *s = &sc->sc_sensors[0];
1962db8573fSkettenis 	uint8_t	vrlsb, data;
1972db8573fSkettenis 	int i, reg;
1982db8573fSkettenis 
1992db8573fSkettenis 	for (i = 0; i < NVT_NUM_VOLTS; i++) {
2002db8573fSkettenis 		if ((sc->sc_vctrl & (1 << i)) == 0) {
2012db8573fSkettenis 			s[i].flags |= SENSOR_FINVALID;
2022db8573fSkettenis 			s[i].value = 0;
2032db8573fSkettenis 			continue;
2042db8573fSkettenis 		}
2052db8573fSkettenis 
2062db8573fSkettenis 		reg = NVT_VSEN1 + i;
2072db8573fSkettenis 		data = nvt_readreg(sc, reg);
2082db8573fSkettenis 		vrlsb = nvt_readreg(sc, NVT_VRLSB);
2092db8573fSkettenis 		if (reg != NVT_3VDD && reg != NVT_3VSB && reg != NVT_VBAT)
2102db8573fSkettenis 			s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 2000;
2112db8573fSkettenis 		else
2122db8573fSkettenis 			s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 6000;
2132db8573fSkettenis 		s[i].flags &= ~SENSOR_FINVALID;
2142db8573fSkettenis 	}
2152db8573fSkettenis }
2162db8573fSkettenis 
2172db8573fSkettenis void
nvt_refresh_temps(struct nvt_softc * sc)2182db8573fSkettenis nvt_refresh_temps(struct nvt_softc *sc)
2192db8573fSkettenis {
2202db8573fSkettenis 	struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS];
2212db8573fSkettenis 	uint8_t	vrlsb;
2222db8573fSkettenis 	int8_t data;
2232db8573fSkettenis 	int i;
2242db8573fSkettenis 
2252db8573fSkettenis 	for (i = 0; i < NVT_NUM_TEMPS; i++) {
2262db8573fSkettenis 		if (i < NVT_NUM_TR
2272db8573fSkettenis 		    && (sc->sc_tctrl1 & (1 << (2 * i))) == 0) {
2282db8573fSkettenis 			s[i].flags |= SENSOR_FINVALID;
2292db8573fSkettenis 			s[i].value = 0;
2302db8573fSkettenis 			continue;
2312db8573fSkettenis 		}
2322db8573fSkettenis 
2332db8573fSkettenis 		if (i >= NVT_NUM_TR
2342db8573fSkettenis 		    && (sc->sc_tctrl2 & (1 << (2 * (i - NVT_NUM_TR)))) == 0) {
2352db8573fSkettenis 			s[i].flags |= SENSOR_FINVALID;
2362db8573fSkettenis 			s[i].value = 0;
2372db8573fSkettenis 			continue;
2382db8573fSkettenis 		}
2392db8573fSkettenis 
2402db8573fSkettenis 		data = nvt_readreg(sc, NVT_TR5 + i);
2412db8573fSkettenis 		vrlsb = nvt_readreg(sc, NVT_VRLSB);
2422db8573fSkettenis 		if (data == -128 && (vrlsb >> 6) == 0) {
2432db8573fSkettenis 			s[i].flags |= SENSOR_FINVALID;
2442db8573fSkettenis 			s[i].value = 0;
2452db8573fSkettenis 			continue;
2462db8573fSkettenis 		}
2472db8573fSkettenis 		s[i].value = data * 1000000 + (vrlsb >> 6) * 250000;
2482db8573fSkettenis 		s[i].value += 273150000;
2492db8573fSkettenis 		s[i].flags &= ~SENSOR_FINVALID;
2502db8573fSkettenis 	}
2512db8573fSkettenis }
2522db8573fSkettenis 
2532db8573fSkettenis void
nvt_refresh_fans(struct nvt_softc * sc)2542db8573fSkettenis nvt_refresh_fans(struct nvt_softc *sc)
2552db8573fSkettenis {
2562db8573fSkettenis 	struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS + NVT_NUM_TEMPS];
2572db8573fSkettenis 	uint8_t	data, vrlsb;
2582db8573fSkettenis 	uint16_t count;
2592db8573fSkettenis 	int i;
2602db8573fSkettenis 
2612db8573fSkettenis 	for (i = 0; i < NVT_NUM_FANS; i++) {
2622db8573fSkettenis 		if ((sc->sc_fctrl & (1 << i)) == 0) {
2632db8573fSkettenis 			s[i].flags |= SENSOR_FINVALID;
2642db8573fSkettenis 			s[i].value = 0;
2652db8573fSkettenis 			continue;
2662db8573fSkettenis 		}
2672db8573fSkettenis 
2682db8573fSkettenis 		data = nvt_readreg(sc, NVT_FANIN1_COUNT + i);
2692db8573fSkettenis 		vrlsb = nvt_readreg(sc, NVT_VRLSB);
2702db8573fSkettenis 		count = (data << 4) + (vrlsb >> 4);
2712db8573fSkettenis 		if (count == 0) {
2722db8573fSkettenis 			s[i].flags |= SENSOR_FINVALID;
2732db8573fSkettenis 			s[i].value = 0;
2742db8573fSkettenis 			continue;
2752db8573fSkettenis 		}
2762db8573fSkettenis 		s[i].value = 1350000 / (count * 2);
2772db8573fSkettenis 		s[i].flags &= ~SENSOR_FINVALID;
2782db8573fSkettenis 	}
2792db8573fSkettenis }
2802db8573fSkettenis 
2812db8573fSkettenis uint8_t
nvt_readreg(struct nvt_softc * sc,uint8_t reg)2822db8573fSkettenis nvt_readreg(struct nvt_softc *sc, uint8_t reg)
2832db8573fSkettenis {
2842db8573fSkettenis 	uint8_t data;
2852db8573fSkettenis 
2862db8573fSkettenis 	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
2872db8573fSkettenis 	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
2882db8573fSkettenis 
2892db8573fSkettenis 	return data;
2902db8573fSkettenis }
2912db8573fSkettenis 
2922db8573fSkettenis void
nvt_writereg(struct nvt_softc * sc,uint8_t reg,uint8_t data)2932db8573fSkettenis nvt_writereg(struct nvt_softc *sc, uint8_t reg, uint8_t data)
2942db8573fSkettenis {
2952db8573fSkettenis 	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
2962db8573fSkettenis 	    sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
2972db8573fSkettenis }
298