1/*	$OpenBSD: lm87.c,v 1.21 2022/04/06 18:59:28 naddy Exp $	*/
2
3/*
4 * Copyright (c) 2005 Mark Kettenis
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/* LM87 registers */
27#define LM87_2_5V	0x20
28#define LM87_VCCP1	0x21
29#define LM87_VCC	0x22
30#define LM87_5V		0x23
31#define LM87_12V	0x24
32#define LM87_VCCP2	0x25
33#define LM87_EXT_TEMP	0x26
34#define LM87_INT_TEMP	0x27
35#define LM87_FAN1	0x28
36#define LM87_FAN2	0x29
37#define LM87_REVISION	0x3f
38#define LM87_CONFIG1	0x40
39#define  LM87_CONFIG1_START	0x01
40#define  LM87_CONFIG1_INTCLR	0x08
41#define LM87_CHANNEL	0x16
42#define  LM87_CHANNEL_AIN1	0x01
43#define  LM87_CHANNEL_AIN2	0x02
44#define LM87_FANDIV	0x47
45
46/* Sensors */
47#define LMENV_2_5V		0
48#define LMENV_VCCP1		1
49#define LMENV_VCC		2
50#define LMENV_5V		3
51#define LMENV_12V		4
52#define LMENV_VCCP2		5
53#define LMENV_EXT_TEMP		6
54#define LMENV_INT_TEMP		7
55#define LMENV_FAN1		8
56#define LMENV_FAN2		9
57#define LMENV_NUM_SENSORS	10
58
59struct lmenv_softc {
60	struct device sc_dev;
61	i2c_tag_t sc_tag;
62	i2c_addr_t sc_addr;
63
64	struct ksensor sc_sensor[LMENV_NUM_SENSORS];
65	struct ksensordev sc_sensordev;
66	int	sc_fan1_div, sc_fan2_div;
67	int	sc_family;
68};
69
70int	lmenv_match(struct device *, void *, void *);
71void	lmenv_attach(struct device *, struct device *, void *);
72
73void	lmenv_refresh(void *);
74
75const struct cfattach lmenv_ca = {
76	sizeof(struct lmenv_softc), lmenv_match, lmenv_attach
77};
78
79struct cfdriver lmenv_cd = {
80	NULL, "lmenv", DV_DULL
81};
82
83int
84lmenv_match(struct device *parent, void *match, void *aux)
85{
86	struct i2c_attach_args *ia = aux;
87
88	if (strcmp(ia->ia_name, "lm87") == 0 ||
89	    strcmp(ia->ia_name, "lm87cimt") == 0 ||
90	    strcmp(ia->ia_name, "adm9240") == 0 ||
91	    strcmp(ia->ia_name, "lm81") == 0 ||
92	    strcmp(ia->ia_name, "ds1780") == 0)
93		return (1);
94	return (0);
95}
96
97void
98lmenv_attach(struct device *parent, struct device *self, void *aux)
99{
100	struct lmenv_softc *sc = (struct lmenv_softc *)self;
101	struct i2c_attach_args *ia = aux;
102	u_int8_t cmd, data, data2, channel;
103	int i;
104
105	sc->sc_tag = ia->ia_tag;
106	sc->sc_addr = ia->ia_addr;
107
108	sc->sc_family = 87;
109	if (strcmp(ia->ia_name, "lm81") == 0 ||
110	    strcmp(ia->ia_name, "adm9240") == 0 ||
111	    strcmp(ia->ia_name, "ds1780") == 0)
112		sc->sc_family = 81;
113
114	iic_acquire_bus(sc->sc_tag, 0);
115
116	cmd = LM87_REVISION;
117	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
118	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
119		iic_release_bus(sc->sc_tag, 0);
120		printf(": cannot read ID register\n");
121		return;
122	}
123	printf(": %s rev %x", ia->ia_name, data);
124
125	cmd = LM87_FANDIV;
126	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
127	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
128		iic_release_bus(sc->sc_tag, 0);
129		printf(", cannot read Fan Divisor register\n");
130		return;
131	}
132	sc->sc_fan1_div = 1 << ((data >> 4) & 0x03);
133	sc->sc_fan2_div = 1 << ((data >> 6) & 0x03);
134
135	if (sc->sc_family == 87) {
136		cmd = LM87_CHANNEL;
137		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
138		    sc->sc_addr, &cmd, sizeof cmd, &channel,
139		    sizeof channel, 0)) {
140			iic_release_bus(sc->sc_tag, 0);
141			printf(", cannot read Channel register\n");
142			return;
143		}
144	} else
145		channel = 0;
146
147	cmd = LM87_CONFIG1;
148	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
149	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
150		iic_release_bus(sc->sc_tag, 0);
151		printf(", cannot read Configuration Register 1\n");
152		return;
153	}
154
155	/*
156	 * if chip is not running, try to start it.
157	 * if it is stalled doing an interrupt, unstall it
158	 */
159	data2 = (data | LM87_CONFIG1_START);
160	data2 = data2 & ~LM87_CONFIG1_INTCLR;
161
162	if (data != data2) {
163		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
164		    sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
165			iic_release_bus(sc->sc_tag, 0);
166			printf(", cannot write Configuration Register 1\n");
167			return;
168		}
169		printf(", starting scan");
170	}
171	iic_release_bus(sc->sc_tag, 0);
172
173	/* Initialize sensor data. */
174	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
175	    sizeof(sc->sc_sensordev.xname));
176
177	sc->sc_sensor[LMENV_2_5V].type = SENSOR_VOLTS_DC;
178	strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "+2.5Vin",
179	    sizeof(sc->sc_sensor[LMENV_2_5V].desc));
180
181	sc->sc_sensor[LMENV_VCCP1].type = SENSOR_VOLTS_DC;
182	strlcpy(sc->sc_sensor[LMENV_VCCP1].desc, "Vccp",
183	    sizeof(sc->sc_sensor[LMENV_VCCP1].desc));
184
185	sc->sc_sensor[LMENV_VCC].type = SENSOR_VOLTS_DC;
186	strlcpy(sc->sc_sensor[LMENV_VCC].desc, "+Vcc",
187	    sizeof(sc->sc_sensor[LMENV_VCC].desc));
188
189	sc->sc_sensor[LMENV_5V].type = SENSOR_VOLTS_DC;
190	strlcpy(sc->sc_sensor[LMENV_5V].desc, "+5Vin/Vcc",
191	    sizeof(sc->sc_sensor[LMENV_5V].desc));
192
193	sc->sc_sensor[LMENV_12V].type = SENSOR_VOLTS_DC;
194	strlcpy(sc->sc_sensor[LMENV_12V].desc, "+12Vin",
195	    sizeof(sc->sc_sensor[LMENV_12V].desc));
196
197	sc->sc_sensor[LMENV_VCCP2].type = SENSOR_VOLTS_DC;
198	strlcpy(sc->sc_sensor[LMENV_VCCP2].desc, "Vccp",
199	    sizeof(sc->sc_sensor[LMENV_VCCP2].desc));
200
201	sc->sc_sensor[LMENV_EXT_TEMP].type = SENSOR_TEMP;
202	strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External",
203	    sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc));
204	if (sc->sc_family == 81)
205		sc->sc_sensor[LMENV_EXT_TEMP].flags |= SENSOR_FINVALID;
206
207	sc->sc_sensor[LMENV_INT_TEMP].type = SENSOR_TEMP;
208	strlcpy(sc->sc_sensor[LMENV_INT_TEMP].desc, "Internal",
209	    sizeof(sc->sc_sensor[LMENV_INT_TEMP].desc));
210
211	if (channel & LM87_CHANNEL_AIN1) {
212		sc->sc_sensor[LMENV_FAN1].type = SENSOR_VOLTS_DC;
213		strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "AIN1",
214		    sizeof(sc->sc_sensor[LMENV_FAN1].desc));
215	} else {
216		sc->sc_sensor[LMENV_FAN1].type = SENSOR_FANRPM;
217	}
218
219	if (channel & LM87_CHANNEL_AIN2) {
220		sc->sc_sensor[LMENV_FAN2].type = SENSOR_VOLTS_DC;
221		strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "AIN2",
222		    sizeof(sc->sc_sensor[LMENV_FAN2].desc));
223	} else {
224		sc->sc_sensor[LMENV_FAN2].type = SENSOR_FANRPM;
225	}
226
227	if (sensor_task_register(sc, lmenv_refresh, 5) == NULL) {
228		printf(", unable to register update task\n");
229		return;
230	}
231
232	for (i = 0; i < LMENV_NUM_SENSORS; i++)
233		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
234	sensordev_install(&sc->sc_sensordev);
235
236	printf("\n");
237}
238
239void
240lmenv_refresh(void *arg)
241{
242	struct lmenv_softc *sc = arg;
243	u_int8_t cmd, data;
244	u_int tmp;
245	int sensor;
246
247	iic_acquire_bus(sc->sc_tag, 0);
248
249	for (sensor = 0; sensor < LMENV_NUM_SENSORS; sensor++) {
250		cmd = LM87_2_5V + sensor;
251		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
252		    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
253			sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
254			continue;
255		}
256
257		sc->sc_sensor[sensor].flags &= ~SENSOR_FINVALID;
258		switch (sensor) {
259		case LMENV_2_5V:
260			sc->sc_sensor[sensor].value = 2500000 * data / 192;
261			break;
262		case LMENV_5V:
263			sc->sc_sensor[sensor].value = 5000000 * data / 192;
264			break;
265		case LMENV_12V:
266			sc->sc_sensor[sensor].value = 12000000 * data / 192;
267			break;
268		case LMENV_VCCP1:
269		case LMENV_VCCP2:
270			sc->sc_sensor[sensor].value = 2700000 * data / 192;
271			break;
272		case LMENV_VCC:
273			sc->sc_sensor[sensor].value = 3300000 * data / 192;
274			break;
275		case LMENV_EXT_TEMP:
276			if (sc->sc_family == 81) {
277				sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
278				break;		/* missing on LM81 */
279			}
280			/* FALLTHROUGH */
281		case LMENV_INT_TEMP:
282			if (data == 0x80)
283				sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
284			else
285				sc->sc_sensor[sensor].value =
286				    (int8_t)data * 1000000 + 273150000;
287			break;
288		case LMENV_FAN1:
289			if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
290				sc->sc_sensor[sensor].value =
291				    1870000 * data / 192;
292				break;
293			}
294			tmp = data * sc->sc_fan1_div;
295			if (tmp == 0)
296				sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
297			else
298				sc->sc_sensor[sensor].value = 1350000 / tmp;
299			break;
300		case LMENV_FAN2:
301			if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
302				sc->sc_sensor[sensor].value =
303				    1870000 * data / 192;
304				break;
305			}
306			tmp = data * sc->sc_fan2_div;
307			if (tmp == 0)
308				sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
309			else
310				sc->sc_sensor[sensor].value = 1350000 / tmp;
311			break;
312		default:
313			sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
314			break;
315		}
316	}
317
318	iic_release_bus(sc->sc_tag, 0);
319}
320