ad741x.c revision 1.12
1/* $OpenBSD: ad741x.c,v 1.12 2007/06/24 05:34:35 dlg 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/* AD741x registers */ 27#define AD741X_TEMP 0x00 28#define AD741X_CONFIG 0x01 29#define AD741X_THYST 0x02 30#define AD741X_TOTI 0x03 31#define AD741X_ADC 0x04 32#define AD741X_CONFIG2 0x05 33 34#define AD741X_CONFMASK 0xe0 35 36/* Sensors */ 37#define ADC_TEMP 0 38#define ADC_ADC0 1 39#define ADC_ADC1 2 40#define ADC_ADC2 3 41#define ADC_ADC3 4 42#define ADC_MAX_SENSORS 5 43 44struct adc_softc { 45 struct device sc_dev; 46 i2c_tag_t sc_tag; 47 i2c_addr_t sc_addr; 48 int sc_chip; 49 u_int8_t sc_config; 50 51 struct ksensor sc_sensor[ADC_MAX_SENSORS]; 52 struct ksensordev sc_sensordev; 53}; 54 55int adc_match(struct device *, void *, void *); 56void adc_attach(struct device *, struct device *, void *); 57int adc_check(struct i2c_attach_args *, u_int8_t *, u_int8_t *); 58void adc_refresh(void *); 59 60struct cfattach adc_ca = { 61 sizeof(struct adc_softc), adc_match, adc_attach 62}; 63 64struct cfdriver adc_cd = { 65 NULL, "adc", DV_DULL 66}; 67 68int 69adc_match(struct device *parent, void *match, void *aux) 70{ 71 struct i2c_attach_args *ia = aux; 72 73 if (strcmp(ia->ia_name, "ad7417") == 0 || 74 strcmp(ia->ia_name, "ad7418") == 0) 75 return (1); 76 return (0); 77} 78 79void 80adc_attach(struct device *parent, struct device *self, void *aux) 81{ 82 struct adc_softc *sc = (struct adc_softc *)self; 83 struct i2c_attach_args *ia = aux; 84 u_int8_t cmd, data; 85 int nsens = 0, i; 86 87 sc->sc_tag = ia->ia_tag; 88 sc->sc_addr = ia->ia_addr; 89 90 printf(": %s", ia->ia_name); 91 92 sc->sc_chip = 0; 93 if (strcmp(ia->ia_name, "ad7417") == 0) 94 sc->sc_chip = 7417; 95 if (strcmp(ia->ia_name, "ad7418") == 0) 96 sc->sc_chip = 7418; 97 98 if (sc->sc_chip != 0) { 99 cmd = AD741X_CONFIG2; 100 data = 0; 101 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 102 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 103 printf(", config2 reset failed\n"); 104 return; 105 } 106 } 107 108 cmd = AD741X_CONFIG; 109 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 110 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 111 printf(", config reset failed\n"); 112 return; 113 } 114 data &= 0xfe; 115 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 116 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 117 printf(", config reset failed\n"); 118 return; 119 } 120 sc->sc_config = data; 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[ADC_TEMP].type = SENSOR_TEMP; 127 strlcpy(sc->sc_sensor[ADC_TEMP].desc, "Internal", 128 sizeof(sc->sc_sensor[ADC_TEMP].desc)); 129 nsens = 1; 130 131 if (sc->sc_chip == 7417 || sc->sc_chip == 7418) { 132 sc->sc_sensor[ADC_ADC0].type = SENSOR_INTEGER; 133 nsens++; 134 } 135 if (sc->sc_chip == 7417 || sc->sc_chip == 7418) { 136 sc->sc_sensor[ADC_ADC1].type = SENSOR_INTEGER; 137 sc->sc_sensor[ADC_ADC2].type = SENSOR_INTEGER; 138 sc->sc_sensor[ADC_ADC3].type = SENSOR_INTEGER; 139 nsens += 3; 140 } 141 142 if (sensor_task_register(sc, adc_refresh, 5) == NULL) { 143 printf(", unable to register update task\n"); 144 return; 145 } 146 147 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]); 148 if (sc->sc_chip == 7417 || sc->sc_chip == 7418) 149 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[1]); 150 if (sc->sc_chip == 7417) 151 for (i = 2; i < nsens; i++) 152 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 153 sensordev_install(&sc->sc_sensordev); 154 155 printf("\n"); 156} 157 158void 159adc_refresh(void *arg) 160{ 161 struct adc_softc *sc = arg; 162 u_int8_t cmd, data[2], reg; 163 int i; 164 165 iic_acquire_bus(sc->sc_tag, 0); 166 167 reg = (sc->sc_config & AD741X_CONFMASK) | (0 << 5); 168 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 169 sc->sc_addr, &cmd, sizeof cmd, ®, sizeof reg, 0)) 170 goto done; 171 delay(1000); 172 cmd = AD741X_TEMP; 173 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 174 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 175 goto done; 176 sc->sc_sensor[ADC_TEMP].value = 273150000 + 177 ((data[0] << 8 | data[1]) >> 6) * 250000; 178 179 if (sc->sc_chip == 0) 180 goto done; 181 182 if (sc->sc_chip == 7418) { 183 reg = (reg & AD741X_CONFMASK) | (4 << 5); 184 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 185 sc->sc_addr, &cmd, sizeof cmd, ®, sizeof reg, 0)) 186 goto done; 187 delay(1000); 188 cmd = AD741X_ADC; 189 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 190 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 191 goto done; 192 sc->sc_sensor[ADC_ADC0].value = 193 (data[0] << 8 | data[1]) >> 6; 194 goto done; 195 } 196 197 for (i = 0; i < 4; i++) { 198 reg = (reg & AD741X_CONFMASK) | (i << 5); 199 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 200 sc->sc_addr, &cmd, sizeof cmd, ®, sizeof reg, 0)) 201 goto done; 202 delay(1000); 203 cmd = AD741X_ADC; 204 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 205 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 206 goto done; 207 sc->sc_sensor[ADC_ADC0 + i].value = 208 (data[0] << 8 | data[1]) >> 6; 209 } 210 211done: 212 iic_release_bus(sc->sc_tag, 0); 213} 214