1*471aeecfSnaddy /* $OpenBSD: maxim6690.c,v 1.17 2022/04/06 18:59:28 naddy Exp $ */
2a6317888Sderaadt
3a6317888Sderaadt /*
4a6317888Sderaadt * Copyright (c) 2005 Theo de Raadt
5a6317888Sderaadt *
6a6317888Sderaadt * Permission to use, copy, modify, and distribute this software for any
7a6317888Sderaadt * purpose with or without fee is hereby granted, provided that the above
8a6317888Sderaadt * copyright notice and this permission notice appear in all copies.
9a6317888Sderaadt *
10a6317888Sderaadt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a6317888Sderaadt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a6317888Sderaadt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a6317888Sderaadt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a6317888Sderaadt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a6317888Sderaadt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a6317888Sderaadt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a6317888Sderaadt */
18a6317888Sderaadt
19a6317888Sderaadt #include <sys/param.h>
20a6317888Sderaadt #include <sys/systm.h>
21a6317888Sderaadt #include <sys/device.h>
22a6317888Sderaadt #include <sys/sensors.h>
23a6317888Sderaadt
24a6317888Sderaadt #include <dev/i2c/i2cvar.h>
25a6317888Sderaadt
26af76b4b6Skettenis /* Maxim MAX6642/90 registers */
27af76b4b6Skettenis #define MAX6690_INT_TEMP 0x00
28af76b4b6Skettenis #define MAX6690_EXT_TEMP 0x01
293cde71c3Skettenis #define MAX6690_INT_TEMP2 0x11
303cde71c3Skettenis #define MAX6690_EXT_TEMP2 0x10
31af76b4b6Skettenis #define MAX6690_STATUS 0x02
32af76b4b6Skettenis #define MAX6690_DEVID 0xfe
33af76b4b6Skettenis #define MAX6690_REVISION 0xff /* absent on MAX6642 */
34a6317888Sderaadt
35af76b4b6Skettenis #define MAX6642_TEMP_INVALID 0xff /* sensor disconnected */
36af76b4b6Skettenis #define MAX6690_TEMP_INVALID 0x80 /* sensor disconnected */
3764d0e8eeSdjm #define MAX6690_TEMP_INVALID2 0x7f /* open-circuit without pull-up */
38d48aa296Sderaadt #define LM90_TEMP_INVALID 0x7f /* sensor disconnected */
39af76b4b6Skettenis
40af76b4b6Skettenis #define MAX6642_TEMP2_MASK 0xc0 /* significant bits */
41af76b4b6Skettenis #define MAX6690_TEMP2_MASK 0xe0 /* significant bits */
42d48aa296Sderaadt #define LM90_TEMP2_MASK 0xe0 /* significant bits */
43a6317888Sderaadt
44a6317888Sderaadt /* Sensors */
45a6317888Sderaadt #define MAXTMP_INT 0
46a6317888Sderaadt #define MAXTMP_EXT 1
47a6317888Sderaadt #define MAXTMP_NUM_SENSORS 2
48a6317888Sderaadt
49a6317888Sderaadt struct maxtmp_softc {
50a6317888Sderaadt struct device sc_dev;
51a6317888Sderaadt i2c_tag_t sc_tag;
52a6317888Sderaadt i2c_addr_t sc_addr;
53a6317888Sderaadt
5464d0e8eeSdjm u_int8_t sc_temp_invalid[2];
55af76b4b6Skettenis u_int8_t sc_temp2_mask;
56af76b4b6Skettenis
57275cbf62Sderaadt struct ksensor sc_sensor[MAXTMP_NUM_SENSORS];
58275cbf62Sderaadt struct ksensordev sc_sensordev;
59a6317888Sderaadt };
60a6317888Sderaadt
61a6317888Sderaadt int maxtmp_match(struct device *, void *, void *);
62a6317888Sderaadt void maxtmp_attach(struct device *, struct device *, void *);
63a6317888Sderaadt void maxtmp_refresh(void *);
64a6317888Sderaadt
65*471aeecfSnaddy const struct cfattach maxtmp_ca = {
66a6317888Sderaadt sizeof(struct maxtmp_softc), maxtmp_match, maxtmp_attach
67a6317888Sderaadt };
68a6317888Sderaadt
69a6317888Sderaadt struct cfdriver maxtmp_cd = {
70a6317888Sderaadt NULL, "maxtmp", DV_DULL
71a6317888Sderaadt };
72a6317888Sderaadt
73a6317888Sderaadt int
maxtmp_match(struct device * parent,void * match,void * aux)74a6317888Sderaadt maxtmp_match(struct device *parent, void *match, void *aux)
75a6317888Sderaadt {
76a6317888Sderaadt struct i2c_attach_args *ia = aux;
77a6317888Sderaadt
789b06f7aeSderaadt if (strcmp(ia->ia_name, "max6642") == 0 ||
79d48aa296Sderaadt strcmp(ia->ia_name, "max6690") == 0 ||
806d16e8d6Sdjm strcmp(ia->ia_name, "max6657") == 0 ||
816d16e8d6Sdjm strcmp(ia->ia_name, "max6658") == 0 ||
826d16e8d6Sdjm strcmp(ia->ia_name, "max6659") == 0 ||
83a692f098Skettenis strcmp(ia->ia_name, "lm63") == 0 ||
84d48aa296Sderaadt strcmp(ia->ia_name, "lm86") == 0 ||
85d48aa296Sderaadt strcmp(ia->ia_name, "lm89") == 0 ||
86b7b8e57cSkettenis strcmp(ia->ia_name, "lm89-1") == 0 ||
87d48aa296Sderaadt strcmp(ia->ia_name, "lm90") == 0 ||
88d48aa296Sderaadt strcmp(ia->ia_name, "lm99") == 0 ||
89d48aa296Sderaadt strcmp(ia->ia_name, "lm99-1") == 0)
90a6317888Sderaadt return (1);
91a6317888Sderaadt return (0);
92a6317888Sderaadt }
93a6317888Sderaadt
94a6317888Sderaadt void
maxtmp_attach(struct device * parent,struct device * self,void * aux)95a6317888Sderaadt maxtmp_attach(struct device *parent, struct device *self, void *aux)
96a6317888Sderaadt {
97a6317888Sderaadt struct maxtmp_softc *sc = (struct maxtmp_softc *)self;
98a6317888Sderaadt struct i2c_attach_args *ia = aux;
99a6317888Sderaadt int i;
100a6317888Sderaadt
101a6317888Sderaadt sc->sc_tag = ia->ia_tag;
102a6317888Sderaadt sc->sc_addr = ia->ia_addr;
103a6317888Sderaadt
1049b06f7aeSderaadt if (strcmp(ia->ia_name, "max6642") == 0) {
10564d0e8eeSdjm sc->sc_temp_invalid[0] = MAX6642_TEMP_INVALID;
10664d0e8eeSdjm sc->sc_temp_invalid[1] = MAX6642_TEMP_INVALID;
107af76b4b6Skettenis sc->sc_temp2_mask = MAX6642_TEMP2_MASK;
10864d0e8eeSdjm } else if (strcmp(ia->ia_name, "max6690") == 0 ||
10964d0e8eeSdjm strcmp(ia->ia_name, "max6657") == 0 ||
1106d16e8d6Sdjm strcmp(ia->ia_name, "max6658") == 0 ||
1116d16e8d6Sdjm strcmp(ia->ia_name, "max6659") == 0) {
11264d0e8eeSdjm sc->sc_temp_invalid[0] = MAX6690_TEMP_INVALID;
11364d0e8eeSdjm sc->sc_temp_invalid[1] = MAX6690_TEMP_INVALID2;
114af76b4b6Skettenis sc->sc_temp2_mask = MAX6690_TEMP2_MASK;
115d48aa296Sderaadt } else {
11664d0e8eeSdjm sc->sc_temp_invalid[0] = LM90_TEMP_INVALID;
11764d0e8eeSdjm sc->sc_temp_invalid[1] = LM90_TEMP_INVALID;
118d48aa296Sderaadt sc->sc_temp2_mask = LM90_TEMP2_MASK;
119af76b4b6Skettenis }
120d48aa296Sderaadt printf(": %s", ia->ia_name);
121a6317888Sderaadt
122a6317888Sderaadt /* Initialize sensor data. */
12327515a6bSderaadt strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
12427515a6bSderaadt sizeof(sc->sc_sensordev.xname));
125a6317888Sderaadt
126a6317888Sderaadt sc->sc_sensor[MAXTMP_INT].type = SENSOR_TEMP;
12727515a6bSderaadt strlcpy(sc->sc_sensor[MAXTMP_INT].desc, "Internal",
128a6317888Sderaadt sizeof(sc->sc_sensor[MAXTMP_INT].desc));
129a6317888Sderaadt
130a6317888Sderaadt sc->sc_sensor[MAXTMP_EXT].type = SENSOR_TEMP;
13127515a6bSderaadt strlcpy(sc->sc_sensor[MAXTMP_EXT].desc, "External",
132a6317888Sderaadt sizeof(sc->sc_sensor[MAXTMP_EXT].desc));
133a6317888Sderaadt
134abd9fc28Sdlg if (sensor_task_register(sc, maxtmp_refresh, 5) == NULL) {
135a6317888Sderaadt printf(", unable to register update task\n");
136a6317888Sderaadt return;
137a6317888Sderaadt }
138a6317888Sderaadt
139a6317888Sderaadt for (i = 0; i < MAXTMP_NUM_SENSORS; i++)
14027515a6bSderaadt sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
14127515a6bSderaadt sensordev_install(&sc->sc_sensordev);
142a6317888Sderaadt
143a6317888Sderaadt printf("\n");
144a6317888Sderaadt }
145a6317888Sderaadt
146a6317888Sderaadt void maxtmp_readport(struct maxtmp_softc *, u_int8_t, u_int8_t, int);
147a6317888Sderaadt
148a6317888Sderaadt void
maxtmp_readport(struct maxtmp_softc * sc,u_int8_t cmd1,u_int8_t cmd2,int index)149a6317888Sderaadt maxtmp_readport(struct maxtmp_softc *sc, u_int8_t cmd1, u_int8_t cmd2,
150a6317888Sderaadt int index)
151a6317888Sderaadt {
152a6317888Sderaadt u_int8_t data, data2;
153a6317888Sderaadt
154a6317888Sderaadt if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
155a6317888Sderaadt sc->sc_addr, &cmd1, sizeof cmd1, &data, sizeof data, 0))
156a6317888Sderaadt goto invalid;
15764d0e8eeSdjm if (data == sc->sc_temp_invalid[0] || data == sc->sc_temp_invalid[1])
158a6317888Sderaadt goto invalid;
159a6317888Sderaadt if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
160a6317888Sderaadt sc->sc_addr, &cmd2, sizeof cmd2, &data2, sizeof data2, 0))
161a6317888Sderaadt goto invalid;
162a6317888Sderaadt
163af76b4b6Skettenis /* Set any meaningless bits to zero. */
164af76b4b6Skettenis data2 &= sc->sc_temp2_mask;
165af76b4b6Skettenis
166a6317888Sderaadt sc->sc_sensor[index].value = 273150000 +
167af76b4b6Skettenis 1000000 * data + (data2 >> 5) * 1000000 / 8;
168a6317888Sderaadt return;
169a6317888Sderaadt
170a6317888Sderaadt invalid:
171a6317888Sderaadt sc->sc_sensor[index].flags |= SENSOR_FINVALID;
172a6317888Sderaadt }
173a6317888Sderaadt
174a6317888Sderaadt void
maxtmp_refresh(void * arg)175a6317888Sderaadt maxtmp_refresh(void *arg)
176a6317888Sderaadt {
177a6317888Sderaadt struct maxtmp_softc *sc = arg;
178a6317888Sderaadt
179a6317888Sderaadt iic_acquire_bus(sc->sc_tag, 0);
180a6317888Sderaadt
181af76b4b6Skettenis maxtmp_readport(sc, MAX6690_INT_TEMP, MAX6690_INT_TEMP2, MAXTMP_INT);
182af76b4b6Skettenis maxtmp_readport(sc, MAX6690_EXT_TEMP, MAX6690_EXT_TEMP2, MAXTMP_EXT);
183a6317888Sderaadt
184a6317888Sderaadt iic_release_bus(sc->sc_tag, 0);
185a6317888Sderaadt }
186