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