1 /* $OpenBSD: maxim6690.c,v 1.16 2007/10/20 22:06:43 cnst 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 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 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 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 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 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