xref: /openbsd-src/sys/dev/i2c/fcu.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /*	$OpenBSD: fcu.c,v 1.8 2022/04/06 18:59:28 naddy Exp $	*/
2eacaf845Sderaadt 
3eacaf845Sderaadt /*
4eacaf845Sderaadt  * Copyright (c) 2005 Mark Kettenis
5eacaf845Sderaadt  *
6eacaf845Sderaadt  * Permission to use, copy, modify, and distribute this software for any
7eacaf845Sderaadt  * purpose with or without fee is hereby granted, provided that the above
8eacaf845Sderaadt  * copyright notice and this permission notice appear in all copies.
9eacaf845Sderaadt  *
10eacaf845Sderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11eacaf845Sderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12eacaf845Sderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13eacaf845Sderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14eacaf845Sderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15eacaf845Sderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16eacaf845Sderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eacaf845Sderaadt  */
18eacaf845Sderaadt 
19eacaf845Sderaadt #include <sys/param.h>
20eacaf845Sderaadt #include <sys/systm.h>
21eacaf845Sderaadt #include <sys/device.h>
22eacaf845Sderaadt #include <sys/sensors.h>
23eacaf845Sderaadt 
24eacaf845Sderaadt #include <dev/i2c/i2cvar.h>
25eacaf845Sderaadt 
26eacaf845Sderaadt /* FCU registers */
27eacaf845Sderaadt #define FCU_FAN_FAIL	0x0b		/* fans states in bits 0<1-6>7 */
28eacaf845Sderaadt #define FCU_FAN_ACTIVE	0x0d
29eacaf845Sderaadt #define FCU_FANREAD(x)	0x11 + (x)*2
30eacaf845Sderaadt #define FCU_FANSET(x)	0x10 + (x)*2
31eacaf845Sderaadt #define FCU_PWM_FAIL	0x2b
32eacaf845Sderaadt #define FCU_PWM_ACTIVE	0x2d
33eacaf845Sderaadt #define FCU_PWMREAD(x)	0x30 + (x)*2
34eacaf845Sderaadt 
35eacaf845Sderaadt /* Sensors */
36eacaf845Sderaadt #define FCU_RPM1		0
37eacaf845Sderaadt #define FCU_RPM2		1
38eacaf845Sderaadt #define FCU_RPM3		2
39eacaf845Sderaadt #define FCU_RPM4		3
40eacaf845Sderaadt #define FCU_RPM5		4
41eacaf845Sderaadt #define FCU_RPM6		5
42eacaf845Sderaadt #define  FCU_FANS		6
43eacaf845Sderaadt #define FCU_PWM1		6
44eacaf845Sderaadt #define FCU_PWM2		7
45eacaf845Sderaadt #define  FCU_PWMS		2
46eacaf845Sderaadt #define FCU_NUM_SENSORS		8
47eacaf845Sderaadt 
48eacaf845Sderaadt struct fcu_softc {
49eacaf845Sderaadt 	struct device sc_dev;
50eacaf845Sderaadt 	i2c_tag_t sc_tag;
51eacaf845Sderaadt 	i2c_addr_t sc_addr;
52eacaf845Sderaadt 
53275cbf62Sderaadt 	struct ksensor sc_sensor[FCU_NUM_SENSORS];
54275cbf62Sderaadt 	struct ksensordev sc_sensordev;
55eacaf845Sderaadt };
56eacaf845Sderaadt 
57eacaf845Sderaadt int	fcu_match(struct device *, void *, void *);
58eacaf845Sderaadt void	fcu_attach(struct device *, struct device *, void *);
59eacaf845Sderaadt 
60eacaf845Sderaadt void	fcu_refresh(void *);
61eacaf845Sderaadt 
62*471aeecfSnaddy const struct cfattach fcu_ca = {
63eacaf845Sderaadt 	sizeof(struct fcu_softc), fcu_match, fcu_attach
64eacaf845Sderaadt };
65eacaf845Sderaadt 
66eacaf845Sderaadt struct cfdriver fcu_cd = {
67eacaf845Sderaadt 	NULL, "fcu", DV_DULL
68eacaf845Sderaadt };
69eacaf845Sderaadt 
70eacaf845Sderaadt int
fcu_match(struct device * parent,void * match,void * aux)71eacaf845Sderaadt fcu_match(struct device *parent, void *match, void *aux)
72eacaf845Sderaadt {
73eacaf845Sderaadt 	struct i2c_attach_args *ia = aux;
74eacaf845Sderaadt 
759b06f7aeSderaadt 	if (strcmp(ia->ia_name, "fcu") == 0)
76eacaf845Sderaadt 		return (1);
77eacaf845Sderaadt 	return (0);
78eacaf845Sderaadt }
79eacaf845Sderaadt 
80eacaf845Sderaadt void
fcu_attach(struct device * parent,struct device * self,void * aux)81eacaf845Sderaadt fcu_attach(struct device *parent, struct device *self, void *aux)
82eacaf845Sderaadt {
83eacaf845Sderaadt 	struct fcu_softc *sc = (struct fcu_softc *)self;
84eacaf845Sderaadt 	struct i2c_attach_args *ia = aux;
85eacaf845Sderaadt 	int i;
86eacaf845Sderaadt 
87eacaf845Sderaadt 	sc->sc_tag = ia->ia_tag;
88eacaf845Sderaadt 	sc->sc_addr = ia->ia_addr;
89eacaf845Sderaadt 
90eacaf845Sderaadt 	/* Initialize sensor data. */
9127515a6bSderaadt 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
9227515a6bSderaadt 	    sizeof(sc->sc_sensordev.xname));
9327515a6bSderaadt 	for (i = 0; i < FCU_FANS; i++)
94eacaf845Sderaadt 		sc->sc_sensor[i].type = SENSOR_FANRPM;
95eacaf845Sderaadt 	for (i = 0; i < FCU_PWMS; i++) {
964017dd19Sderaadt 		sc->sc_sensor[FCU_PWM1 + i].type = SENSOR_PERCENT;
9727515a6bSderaadt 		strlcpy(sc->sc_sensor[FCU_PWM1 + i].desc, "PWM",
9827515a6bSderaadt 		    sizeof(sc->sc_sensor[FCU_PWM1 + i].desc));
99eacaf845Sderaadt 	}
100eacaf845Sderaadt 
101abd9fc28Sdlg 	if (sensor_task_register(sc, fcu_refresh, 5) == NULL) {
102eacaf845Sderaadt 		printf(", unable to register update task\n");
103eacaf845Sderaadt 		return;
104eacaf845Sderaadt 	}
105eacaf845Sderaadt 
106eacaf845Sderaadt 	for (i = 0; i < FCU_NUM_SENSORS; i++)
10727515a6bSderaadt 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
10827515a6bSderaadt 	sensordev_install(&sc->sc_sensordev);
109eacaf845Sderaadt 
110eacaf845Sderaadt 	printf("\n");
111eacaf845Sderaadt }
112eacaf845Sderaadt 
113eacaf845Sderaadt void
fcu_refresh(void * arg)114eacaf845Sderaadt fcu_refresh(void *arg)
115eacaf845Sderaadt {
116eacaf845Sderaadt 	struct fcu_softc *sc = arg;
117eacaf845Sderaadt 	u_int8_t cmd, fail, fan[2], active;
118eacaf845Sderaadt 	int i;
119eacaf845Sderaadt 
120eacaf845Sderaadt 	iic_acquire_bus(sc->sc_tag, 0);
121eacaf845Sderaadt 
122eacaf845Sderaadt 	cmd = FCU_FAN_FAIL;
123eacaf845Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
124eacaf845Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &fail, sizeof fail, 0))
125eacaf845Sderaadt 		goto abort;
126eacaf845Sderaadt 	cmd = FCU_FAN_ACTIVE;
127eacaf845Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
128eacaf845Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &active, sizeof active, 0))
129eacaf845Sderaadt 		goto abort;
130eacaf845Sderaadt 	fail &= active;
131eacaf845Sderaadt 
132eacaf845Sderaadt 	for (i = 0; i < FCU_FANS; i++) {
133eacaf845Sderaadt 		if (fail & (1 << (i + 1)))
134eacaf845Sderaadt 			sc->sc_sensor[i].flags |= SENSOR_FINVALID;
135eacaf845Sderaadt 		else
136eacaf845Sderaadt 			sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
137eacaf845Sderaadt 	}
138eacaf845Sderaadt 
139eacaf845Sderaadt 	cmd = FCU_PWM_FAIL;
140eacaf845Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
141eacaf845Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &fail, sizeof fail, 0))
142eacaf845Sderaadt 		goto abort;
143eacaf845Sderaadt 	cmd = FCU_PWM_ACTIVE;
144eacaf845Sderaadt 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
145eacaf845Sderaadt 	    sc->sc_addr, &cmd, sizeof cmd, &active, sizeof active, 0))
146eacaf845Sderaadt 		goto abort;
147eacaf845Sderaadt 	fail &= active;
148eacaf845Sderaadt 
149eacaf845Sderaadt 	for (i = 0; i < FCU_PWMS; i++) {
150eacaf845Sderaadt 		if (fail & (1 << (i + 1)))
151eacaf845Sderaadt 			sc->sc_sensor[FCU_PWMS + i].flags |= SENSOR_FINVALID;
152eacaf845Sderaadt 		else
153eacaf845Sderaadt 			sc->sc_sensor[FCU_PWMS + i].flags &= ~SENSOR_FINVALID;
154eacaf845Sderaadt 	}
155eacaf845Sderaadt 
156eacaf845Sderaadt 	for (i = 0; i < FCU_FANS; i++) {
157eacaf845Sderaadt 		cmd = FCU_FANREAD(i + 1);
158eacaf845Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
159eacaf845Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &fan, sizeof fan, 0)) {
160eacaf845Sderaadt 			sc->sc_sensor[FCU_RPM1 + i].flags |= SENSOR_FINVALID;
161eacaf845Sderaadt 			continue;
162eacaf845Sderaadt 		}
163eacaf845Sderaadt 		sc->sc_sensor[FCU_RPM1 + i].value = (fan[0] << 5) | (fan[1] >> 3);
164eacaf845Sderaadt 	}
165eacaf845Sderaadt 
166eacaf845Sderaadt 	for (i = 0; i < FCU_PWMS; i++) {
167eacaf845Sderaadt 		cmd = FCU_PWMREAD(i + 1);
168eacaf845Sderaadt 		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
169eacaf845Sderaadt 		    sc->sc_addr, &cmd, sizeof cmd, &fan, sizeof fan, 0)) {
170eacaf845Sderaadt 			sc->sc_sensor[FCU_PWM1 + i].flags |= SENSOR_FINVALID;
171eacaf845Sderaadt 			continue;
172eacaf845Sderaadt 		}
1734017dd19Sderaadt 		sc->sc_sensor[FCU_PWM1 + i].value = (fan[0] * 100 * 1000) / 255;
174eacaf845Sderaadt 	}
175eacaf845Sderaadt 
176eacaf845Sderaadt abort:
177eacaf845Sderaadt 	iic_release_bus(sc->sc_tag, 0);
178eacaf845Sderaadt }
179