1 /* $NetBSD: adm1021.c,v 1.1 2008/10/29 17:26:56 jkunz 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.1 2008/10/29 17:26:56 jkunz 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_STEPPING 0xff /* contains 0x3? */ 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 struct device sc_dev; 50 i2c_tag_t sc_tag; 51 i2c_addr_t sc_addr; 52 53 int sc_noexternal; 54 struct sysmon_envsys *sc_sme; 55 envsys_data_t sc_sensor[ADMTEMP_NUM_SENSORS]; 56 }; 57 58 int admtemp_match(struct device *, cfdata_t, void *); 59 void admtemp_attach(struct device *, struct device *, void *); 60 void admtemp_refresh(struct sysmon_envsys *, envsys_data_t *); 61 62 CFATTACH_DECL_NEW(admtemp, sizeof(struct admtemp_softc), 63 admtemp_match, admtemp_attach, NULL, NULL); 64 65 66 int 67 admtemp_match(struct device *parent, cfdata_t match, void *aux) 68 { 69 struct i2c_attach_args *ia = aux; 70 71 if (((ia->ia_addr >= 0x18) && (ia->ia_addr <= 0x1a)) || 72 ((ia->ia_addr >= 0x29) && (ia->ia_addr <= 0x2b)) || 73 ((ia->ia_addr >= 0x4c) && (ia->ia_addr <= 0x4e))) 74 return (1); 75 76 return (0); 77 } 78 79 80 void 81 admtemp_attach(struct device *parent, struct device *self, void *aux) 82 { 83 struct admtemp_softc *sc = device_private(self); 84 struct i2c_attach_args *ia = aux; 85 u_int8_t cmd, data, stat; 86 87 sc->sc_tag = ia->ia_tag; 88 sc->sc_addr = ia->ia_addr; 89 90 aprint_normal(": ADM1021 or compatible environmental sensor\n"); 91 92 iic_acquire_bus(sc->sc_tag, 0); 93 cmd = ADM1021_CONFIG_READ; 94 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 95 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 96 iic_release_bus(sc->sc_tag, 0); 97 aprint_error_dev(&sc->sc_dev, "cannot get control register\n"); 98 return; 99 } 100 if (data & ADM1021_CONFIG_RUN) { 101 cmd = ADM1021_STATUS; 102 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 103 sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 0)) { 104 iic_release_bus(sc->sc_tag, 0); 105 aprint_error_dev(&sc->sc_dev, 106 "cannot read status register\n"); 107 return; 108 } 109 if ((stat & ADM1021_STATUS_INVAL) == ADM1021_STATUS_INVAL) { 110 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 111 sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 112 0)) { 113 iic_release_bus(sc->sc_tag, 0); 114 aprint_error_dev(&sc->sc_dev, 115 "cannot read status register\n"); 116 return; 117 } 118 } 119 120 /* means external is dead */ 121 if ((stat & ADM1021_STATUS_INVAL) != ADM1021_STATUS_INVAL && 122 (stat & ADM1021_STATUS_NOEXT)) 123 sc->sc_noexternal = 1; 124 125 data &= ~ADM1021_CONFIG_RUN; 126 cmd = ADM1021_CONFIG_WRITE; 127 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 128 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 129 iic_release_bus(sc->sc_tag, 0); 130 aprint_error_dev(&sc->sc_dev, 131 "cannot set control register\n"); 132 return; 133 } 134 } 135 iic_release_bus(sc->sc_tag, 0); 136 137 /* Initialize sensor data. */ 138 sc->sc_sensor[ADMTEMP_INT].units = ENVSYS_STEMP; 139 sc->sc_sensor[ADMTEMP_EXT].units = ENVSYS_STEMP; 140 strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, "internal",sizeof("internal")); 141 strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, "external",sizeof("external")); 142 sc->sc_sme = sysmon_envsys_create(); 143 if (sysmon_envsys_sensor_attach( 144 sc->sc_sme, &sc->sc_sensor[ADMTEMP_INT])) { 145 sysmon_envsys_destroy(sc->sc_sme); 146 aprint_error_dev(&sc->sc_dev, 147 "unable to attach internal at sysmon\n"); 148 return; 149 } 150 if (sc->sc_noexternal == 0 && 151 sysmon_envsys_sensor_attach( 152 sc->sc_sme, &sc->sc_sensor[ADMTEMP_EXT])) { 153 sysmon_envsys_destroy(sc->sc_sme); 154 aprint_error_dev(&sc->sc_dev, 155 "unable to attach external at sysmon\n"); 156 return; 157 } 158 sc->sc_sme->sme_name = device_xname(self); 159 sc->sc_sme->sme_cookie = sc; 160 sc->sc_sme->sme_refresh = admtemp_refresh; 161 if (sysmon_envsys_register(sc->sc_sme)) { 162 aprint_error_dev(&sc->sc_dev, 163 "unable to register with sysmon\n"); 164 sysmon_envsys_destroy(sc->sc_sme); 165 return; 166 } 167 } 168 169 170 void 171 admtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 172 { 173 struct admtemp_softc *sc = sme->sme_cookie; 174 u_int8_t cmd; 175 int8_t sdata; 176 177 iic_acquire_bus(sc->sc_tag, 0); 178 179 if (edata->sensor == ADMTEMP_INT) 180 cmd = ADM1021_INT_TEMP; 181 else 182 cmd = ADM1021_EXT_TEMP; 183 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 184 &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) { 185 if (sdata == ADM1021_STATUS_INVAL) { 186 edata->state = ENVSYS_SINVALID; 187 } else { 188 edata->value_cur = 273150000 + 1000000 * sdata; 189 edata->state = ENVSYS_SVALID; 190 } 191 } 192 193 iic_release_bus(sc->sc_tag, 0); 194 } 195