1/*	$OpenBSD: adm1031.c,v 1.9 2022/04/06 18:59:28 naddy Exp $	*/
2
3/*
4 * Copyright (c) 2005 Theo de Raadt
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/param.h>
20#include <sys/systm.h>
21#include <sys/device.h>
22#include <sys/sensors.h>
23
24#include <dev/i2c/i2cvar.h>
25
26/* adm 1031 registers */
27#define ADM1031_INT_TEMP	0x0a
28#define ADM1031_EXT_TEMP	0x0b
29#define ADM1031_EXT2_TEMP	0x0c
30#define ADM1031_FAN		0x08
31#define ADM1031_FANC		0x20
32#define ADM1031_FAN2		0x09
33#define ADM1031_FAN2C		0x21
34#define  ADM1024_FANC_VAL(x)	(x >> 6)
35
36/* Sensors */
37#define ADMTT_INT		0
38#define ADMTT_EXT		1
39#define ADMTT_EXT2		2
40#define ADMTT_FAN		3
41#define ADMTT_FAN2		4
42#define ADMTT_NUM_SENSORS	5
43
44struct admtt_softc {
45	struct device	sc_dev;
46	i2c_tag_t	sc_tag;
47	i2c_addr_t	sc_addr;
48	int		sc_fanmul;
49
50	struct ksensor	sc_sensor[ADMTT_NUM_SENSORS];
51	struct ksensordev sc_sensordev;
52};
53
54int	admtt_match(struct device *, void *, void *);
55void	admtt_attach(struct device *, struct device *, void *);
56void	admtt_refresh(void *);
57
58const struct cfattach admtt_ca = {
59	sizeof(struct admtt_softc), admtt_match, admtt_attach
60};
61
62struct cfdriver admtt_cd = {
63	NULL, "admtt", DV_DULL
64};
65
66int
67admtt_match(struct device *parent, void *match, void *aux)
68{
69	struct i2c_attach_args *ia = aux;
70
71	if (strcmp(ia->ia_name, "adm1031") == 0)
72		return (1);
73	return (0);
74}
75
76void
77admtt_attach(struct device *parent, struct device *self, void *aux)
78{
79	struct admtt_softc *sc = (struct admtt_softc *)self;
80	struct i2c_attach_args *ia = aux;
81	u_int8_t cmd, data;
82	int i;
83
84	sc->sc_tag = ia->ia_tag;
85	sc->sc_addr = ia->ia_addr;
86
87	cmd = ADM1031_FANC;
88	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
89	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
90		printf(", unable to read fan setting\n");
91		return;
92	}
93	sc->sc_fanmul = 11250/8 * (1 << ADM1024_FANC_VAL(data)) * 60;
94
95	/* Initialize sensor data. */
96	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
97	    sizeof(sc->sc_sensordev.xname));
98
99	sc->sc_sensor[ADMTT_INT].type = SENSOR_TEMP;
100	strlcpy(sc->sc_sensor[ADMTT_INT].desc, "Internal",
101	    sizeof(sc->sc_sensor[ADMTT_INT].desc));
102
103	sc->sc_sensor[ADMTT_EXT].type = SENSOR_TEMP;
104	strlcpy(sc->sc_sensor[ADMTT_EXT].desc, "External",
105	    sizeof(sc->sc_sensor[ADMTT_EXT].desc));
106
107	sc->sc_sensor[ADMTT_EXT2].type = SENSOR_TEMP;
108	strlcpy(sc->sc_sensor[ADMTT_EXT2].desc, "External",
109	    sizeof(sc->sc_sensor[ADMTT_EXT2].desc));
110
111	sc->sc_sensor[ADMTT_FAN].type = SENSOR_FANRPM;
112
113	sc->sc_sensor[ADMTT_FAN2].type = SENSOR_FANRPM;
114
115	if (sensor_task_register(sc, admtt_refresh, 5) == NULL) {
116		printf(", unable to register update task\n");
117		return;
118	}
119
120	for (i = 0; i < ADMTT_NUM_SENSORS; i++)
121		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
122	sensordev_install(&sc->sc_sensordev);
123
124	printf("\n");
125}
126
127void
128admtt_refresh(void *arg)
129{
130	struct admtt_softc *sc = arg;
131	u_int8_t cmd, data;
132
133	iic_acquire_bus(sc->sc_tag, 0);
134
135	cmd = ADM1031_INT_TEMP;
136	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
137	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
138		sc->sc_sensor[ADMTT_INT].value = 273150000 + 1000000 * data;
139
140	cmd = ADM1031_EXT_TEMP;
141	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
142	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
143		sc->sc_sensor[ADMTT_EXT].value = 273150000 + 1000000 * data;
144
145	cmd = ADM1031_EXT2_TEMP;
146	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
147	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
148		sc->sc_sensor[ADMTT_EXT2].value = 273150000 + 1000000 * data;
149
150	cmd = ADM1031_FAN;
151	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
152	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
153		if (data == 0)
154			sc->sc_sensor[ADMTT_FAN].flags |= SENSOR_FINVALID;
155		else {
156			sc->sc_sensor[ADMTT_FAN].value =
157			    sc->sc_fanmul / (2 * (int)data);
158			sc->sc_sensor[ADMTT_FAN].flags &= ~SENSOR_FINVALID;
159		}
160	}
161
162	cmd = ADM1031_FAN2;
163	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
164	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
165		if (data == 0)
166			sc->sc_sensor[ADMTT_FAN2].flags |= SENSOR_FINVALID;
167		else {
168			sc->sc_sensor[ADMTT_FAN2].value =
169			    sc->sc_fanmul / (2 * (int)data);
170			sc->sc_sensor[ADMTT_FAN2].flags &= ~SENSOR_FINVALID;
171		}
172	}
173
174	iic_release_bus(sc->sc_tag, 0);
175}
176