1 /* $NetBSD: adm1021.c,v 1.8 2012/10/27 17:18:17 chs Exp $ */ 2 /* $OpenBSD: adm1021.c,v 1.27 2007/06/24 05:34:35 dlg Exp $ */ 3 4 /* 5 * Copyright (c) 2005 Theo de Raadt 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/cdefs.h> 21 __KERNEL_RCSID(0, "$NetBSD: adm1021.c,v 1.8 2012/10/27 17:18:17 chs Exp $"); 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 #include <dev/sysmon/sysmonvar.h> 27 28 #include <dev/i2c/i2cvar.h> 29 30 31 /* ADM 1021 registers */ 32 #define ADM1021_INT_TEMP 0x00 33 #define ADM1021_EXT_TEMP 0x01 34 #define ADM1021_STATUS 0x02 35 #define ADM1021_STATUS_INVAL 0x7f 36 #define ADM1021_STATUS_NOEXT 0x40 37 #define ADM1021_CONFIG_READ 0x03 38 #define ADM1021_CONFIG_WRITE 0x09 39 #define ADM1021_CONFIG_RUN 0x40 40 #define ADM1021_COMPANY 0xfe /* contains 0x41 */ 41 #define ADM1021_DIE_REVISION 0xff 42 43 /* Sensors */ 44 #define ADMTEMP_INT 0 45 #define ADMTEMP_EXT 1 46 #define ADMTEMP_NUM_SENSORS 2 47 48 struct admtemp_softc { 49 i2c_tag_t sc_tag; 50 i2c_addr_t sc_addr; 51 52 int sc_noexternal; 53 struct sysmon_envsys *sc_sme; 54 envsys_data_t sc_sensor[ADMTEMP_NUM_SENSORS]; 55 }; 56 57 int admtemp_match(device_t, cfdata_t, void *); 58 void admtemp_attach(device_t, device_t, void *); 59 void admtemp_refresh(struct sysmon_envsys *, envsys_data_t *); 60 61 CFATTACH_DECL_NEW(admtemp, sizeof(struct admtemp_softc), 62 admtemp_match, admtemp_attach, NULL, NULL); 63 64 static const char * admtemp_compats[] = { 65 "i2c-max1617", 66 NULL 67 }; 68 69 int 70 admtemp_match(device_t parent, cfdata_t match, void *aux) 71 { 72 struct i2c_attach_args *ia = aux; 73 74 if (ia->ia_name == NULL) { 75 /* 76 * Indirect config - not much we can do! 77 * Check typical addresses. 78 */ 79 if (((ia->ia_addr >= 0x18) && (ia->ia_addr <= 0x1a)) || 80 ((ia->ia_addr >= 0x29) && (ia->ia_addr <= 0x2b)) || 81 ((ia->ia_addr >= 0x4c) && (ia->ia_addr <= 0x4e))) 82 return (1); 83 } else { 84 /* 85 * Direct config - match via the list of compatible 86 * hardware. 87 */ 88 if (iic_compat_match(ia, admtemp_compats)) 89 return 1; 90 } 91 92 return 0; 93 } 94 95 96 void 97 admtemp_attach(device_t parent, device_t self, void *aux) 98 { 99 struct admtemp_softc *sc = device_private(self); 100 struct i2c_attach_args *ia = aux; 101 u_int8_t cmd, data, stat; 102 103 sc->sc_tag = ia->ia_tag; 104 sc->sc_addr = ia->ia_addr; 105 106 aprint_normal(": ADM1021 or compatible environmental sensor\n"); 107 aprint_naive(": Environmental sensor\n"); 108 109 iic_acquire_bus(sc->sc_tag, 0); 110 cmd = ADM1021_CONFIG_READ; 111 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 112 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 113 iic_release_bus(sc->sc_tag, 0); 114 aprint_error_dev(self, "cannot get control register\n"); 115 return; 116 } 117 if (data & ADM1021_CONFIG_RUN) { 118 cmd = ADM1021_STATUS; 119 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 120 sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 0)) { 121 iic_release_bus(sc->sc_tag, 0); 122 aprint_error_dev(self, 123 "cannot read status register\n"); 124 return; 125 } 126 if ((stat & ADM1021_STATUS_INVAL) == ADM1021_STATUS_INVAL) { 127 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 128 sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 129 0)) { 130 iic_release_bus(sc->sc_tag, 0); 131 aprint_error_dev(self, 132 "cannot read status register\n"); 133 return; 134 } 135 } 136 137 /* means external is dead */ 138 if ((stat & ADM1021_STATUS_INVAL) != ADM1021_STATUS_INVAL && 139 (stat & ADM1021_STATUS_NOEXT)) 140 sc->sc_noexternal = 1; 141 142 data &= ~ADM1021_CONFIG_RUN; 143 cmd = ADM1021_CONFIG_WRITE; 144 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 145 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 146 iic_release_bus(sc->sc_tag, 0); 147 aprint_error_dev(self, 148 "cannot set control register\n"); 149 return; 150 } 151 } 152 iic_release_bus(sc->sc_tag, 0); 153 154 /* Initialize sensor data. */ 155 sc->sc_sensor[ADMTEMP_INT].state = ENVSYS_SINVALID; 156 sc->sc_sensor[ADMTEMP_INT].units = ENVSYS_STEMP; 157 sc->sc_sensor[ADMTEMP_EXT].state = ENVSYS_SINVALID; 158 sc->sc_sensor[ADMTEMP_EXT].units = ENVSYS_STEMP; 159 sc->sc_sensor[ADMTEMP_INT].state = ENVSYS_SINVALID; 160 sc->sc_sensor[ADMTEMP_EXT].state = ENVSYS_SINVALID; 161 strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, "internal",sizeof("internal")); 162 strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, "external",sizeof("external")); 163 sc->sc_sme = sysmon_envsys_create(); 164 if (sysmon_envsys_sensor_attach( 165 sc->sc_sme, &sc->sc_sensor[ADMTEMP_INT])) { 166 sysmon_envsys_destroy(sc->sc_sme); 167 aprint_error_dev(self, 168 "unable to attach internal at sysmon\n"); 169 return; 170 } 171 if (sc->sc_noexternal == 0 && 172 sysmon_envsys_sensor_attach( 173 sc->sc_sme, &sc->sc_sensor[ADMTEMP_EXT])) { 174 sysmon_envsys_destroy(sc->sc_sme); 175 aprint_error_dev(self, 176 "unable to attach external at sysmon\n"); 177 return; 178 } 179 sc->sc_sme->sme_name = device_xname(self); 180 sc->sc_sme->sme_cookie = sc; 181 sc->sc_sme->sme_refresh = admtemp_refresh; 182 if (sysmon_envsys_register(sc->sc_sme)) { 183 aprint_error_dev(self, 184 "unable to register with sysmon\n"); 185 sysmon_envsys_destroy(sc->sc_sme); 186 return; 187 } 188 } 189 190 191 void 192 admtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 193 { 194 struct admtemp_softc *sc = sme->sme_cookie; 195 u_int8_t cmd; 196 int8_t sdata; 197 198 iic_acquire_bus(sc->sc_tag, 0); 199 200 if (edata->sensor == ADMTEMP_INT) 201 cmd = ADM1021_INT_TEMP; 202 else 203 cmd = ADM1021_EXT_TEMP; 204 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 205 &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) { 206 if (sdata == ADM1021_STATUS_INVAL) { 207 edata->state = ENVSYS_SINVALID; 208 } else { 209 edata->value_cur = 273150000 + 1000000 * sdata; 210 edata->state = ENVSYS_SVALID; 211 } 212 } 213 214 iic_release_bus(sc->sc_tag, 0); 215 } 216