xref: /openbsd/sys/dev/i2c/maxim6690.c (revision 471aeecf)
1 /*	$OpenBSD: maxim6690.c,v 1.17 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 /* Maxim MAX6642/90 registers */
27 #define MAX6690_INT_TEMP	0x00
28 #define MAX6690_EXT_TEMP	0x01
29 #define MAX6690_INT_TEMP2	0x11
30 #define MAX6690_EXT_TEMP2	0x10
31 #define MAX6690_STATUS		0x02
32 #define MAX6690_DEVID		0xfe
33 #define MAX6690_REVISION	0xff	/* absent on MAX6642 */
34 
35 #define MAX6642_TEMP_INVALID	0xff	/* sensor disconnected */
36 #define MAX6690_TEMP_INVALID	0x80	/* sensor disconnected */
37 #define MAX6690_TEMP_INVALID2	0x7f	/* open-circuit without pull-up */
38 #define LM90_TEMP_INVALID	0x7f	/* sensor disconnected */
39 
40 #define MAX6642_TEMP2_MASK	0xc0	/* significant bits */
41 #define MAX6690_TEMP2_MASK	0xe0	/* significant bits */
42 #define LM90_TEMP2_MASK		0xe0	/* significant bits */
43 
44 /* Sensors */
45 #define MAXTMP_INT		0
46 #define MAXTMP_EXT		1
47 #define MAXTMP_NUM_SENSORS	2
48 
49 struct maxtmp_softc {
50 	struct device sc_dev;
51 	i2c_tag_t sc_tag;
52 	i2c_addr_t sc_addr;
53 
54 	u_int8_t sc_temp_invalid[2];
55 	u_int8_t sc_temp2_mask;
56 
57 	struct ksensor sc_sensor[MAXTMP_NUM_SENSORS];
58 	struct ksensordev sc_sensordev;
59 };
60 
61 int	maxtmp_match(struct device *, void *, void *);
62 void	maxtmp_attach(struct device *, struct device *, void *);
63 void	maxtmp_refresh(void *);
64 
65 const struct cfattach maxtmp_ca = {
66 	sizeof(struct maxtmp_softc), maxtmp_match, maxtmp_attach
67 };
68 
69 struct cfdriver maxtmp_cd = {
70 	NULL, "maxtmp", DV_DULL
71 };
72 
73 int
maxtmp_match(struct device * parent,void * match,void * aux)74 maxtmp_match(struct device *parent, void *match, void *aux)
75 {
76 	struct i2c_attach_args *ia = aux;
77 
78 	if (strcmp(ia->ia_name, "max6642") == 0 ||
79 	    strcmp(ia->ia_name, "max6690") == 0 ||
80 	    strcmp(ia->ia_name, "max6657") == 0 ||
81 	    strcmp(ia->ia_name, "max6658") == 0 ||
82 	    strcmp(ia->ia_name, "max6659") == 0 ||
83 	    strcmp(ia->ia_name, "lm63") == 0 ||
84 	    strcmp(ia->ia_name, "lm86") == 0 ||
85 	    strcmp(ia->ia_name, "lm89") == 0 ||
86 	    strcmp(ia->ia_name, "lm89-1") == 0 ||
87 	    strcmp(ia->ia_name, "lm90") == 0 ||
88 	    strcmp(ia->ia_name, "lm99") == 0 ||
89 	    strcmp(ia->ia_name, "lm99-1") == 0)
90 		return (1);
91 	return (0);
92 }
93 
94 void
maxtmp_attach(struct device * parent,struct device * self,void * aux)95 maxtmp_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct maxtmp_softc *sc = (struct maxtmp_softc *)self;
98 	struct i2c_attach_args *ia = aux;
99 	int i;
100 
101 	sc->sc_tag = ia->ia_tag;
102 	sc->sc_addr = ia->ia_addr;
103 
104 	if (strcmp(ia->ia_name, "max6642") == 0) {
105 		sc->sc_temp_invalid[0] = MAX6642_TEMP_INVALID;
106 		sc->sc_temp_invalid[1] = MAX6642_TEMP_INVALID;
107 		sc->sc_temp2_mask = MAX6642_TEMP2_MASK;
108 	} else if (strcmp(ia->ia_name, "max6690") == 0 ||
109 	    strcmp(ia->ia_name, "max6657") == 0 ||
110 	    strcmp(ia->ia_name, "max6658") == 0 ||
111 	    strcmp(ia->ia_name, "max6659") == 0) {
112 		sc->sc_temp_invalid[0] = MAX6690_TEMP_INVALID;
113 		sc->sc_temp_invalid[1] = MAX6690_TEMP_INVALID2;
114 		sc->sc_temp2_mask = MAX6690_TEMP2_MASK;
115 	} else {
116 		sc->sc_temp_invalid[0] = LM90_TEMP_INVALID;
117 		sc->sc_temp_invalid[1] = LM90_TEMP_INVALID;
118 		sc->sc_temp2_mask = LM90_TEMP2_MASK;
119 	}
120 	printf(": %s", ia->ia_name);
121 
122 	/* Initialize sensor data. */
123 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
124 	    sizeof(sc->sc_sensordev.xname));
125 
126 	sc->sc_sensor[MAXTMP_INT].type = SENSOR_TEMP;
127 	strlcpy(sc->sc_sensor[MAXTMP_INT].desc, "Internal",
128 	    sizeof(sc->sc_sensor[MAXTMP_INT].desc));
129 
130 	sc->sc_sensor[MAXTMP_EXT].type = SENSOR_TEMP;
131 	strlcpy(sc->sc_sensor[MAXTMP_EXT].desc, "External",
132 	    sizeof(sc->sc_sensor[MAXTMP_EXT].desc));
133 
134 	if (sensor_task_register(sc, maxtmp_refresh, 5) == NULL) {
135 		printf(", unable to register update task\n");
136 		return;
137 	}
138 
139 	for (i = 0; i < MAXTMP_NUM_SENSORS; i++)
140 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
141 	sensordev_install(&sc->sc_sensordev);
142 
143 	printf("\n");
144 }
145 
146 void	maxtmp_readport(struct maxtmp_softc *, u_int8_t, u_int8_t, int);
147 
148 void
maxtmp_readport(struct maxtmp_softc * sc,u_int8_t cmd1,u_int8_t cmd2,int index)149 maxtmp_readport(struct maxtmp_softc *sc, u_int8_t cmd1, u_int8_t cmd2,
150     int index)
151 {
152 	u_int8_t data, data2;
153 
154 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
155 	    sc->sc_addr, &cmd1, sizeof cmd1, &data, sizeof data, 0))
156 		goto invalid;
157 	if (data == sc->sc_temp_invalid[0] || data == sc->sc_temp_invalid[1])
158 		goto invalid;
159 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
160 	    sc->sc_addr, &cmd2, sizeof cmd2, &data2, sizeof data2, 0))
161 		goto invalid;
162 
163 	/* Set any meaningless bits to zero. */
164 	data2 &= sc->sc_temp2_mask;
165 
166 	sc->sc_sensor[index].value = 273150000 +
167 	    1000000 * data + (data2 >> 5) * 1000000 / 8;
168 	return;
169 
170 invalid:
171 	sc->sc_sensor[index].flags |= SENSOR_FINVALID;
172 }
173 
174 void
maxtmp_refresh(void * arg)175 maxtmp_refresh(void *arg)
176 {
177 	struct maxtmp_softc *sc = arg;
178 
179 	iic_acquire_bus(sc->sc_tag, 0);
180 
181 	maxtmp_readport(sc, MAX6690_INT_TEMP, MAX6690_INT_TEMP2, MAXTMP_INT);
182 	maxtmp_readport(sc, MAX6690_EXT_TEMP, MAX6690_EXT_TEMP2, MAXTMP_EXT);
183 
184 	iic_release_bus(sc->sc_tag, 0);
185 }
186