1 /* $OpenBSD: fcu.c,v 1.7 2007/06/24 05:34:35 dlg Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Mark Kettenis 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 /* FCU registers */ 27 #define FCU_FAN_FAIL 0x0b /* fans states in bits 0<1-6>7 */ 28 #define FCU_FAN_ACTIVE 0x0d 29 #define FCU_FANREAD(x) 0x11 + (x)*2 30 #define FCU_FANSET(x) 0x10 + (x)*2 31 #define FCU_PWM_FAIL 0x2b 32 #define FCU_PWM_ACTIVE 0x2d 33 #define FCU_PWMREAD(x) 0x30 + (x)*2 34 35 /* Sensors */ 36 #define FCU_RPM1 0 37 #define FCU_RPM2 1 38 #define FCU_RPM3 2 39 #define FCU_RPM4 3 40 #define FCU_RPM5 4 41 #define FCU_RPM6 5 42 #define FCU_FANS 6 43 #define FCU_PWM1 6 44 #define FCU_PWM2 7 45 #define FCU_PWMS 2 46 #define FCU_NUM_SENSORS 8 47 48 struct fcu_softc { 49 struct device sc_dev; 50 i2c_tag_t sc_tag; 51 i2c_addr_t sc_addr; 52 53 struct ksensor sc_sensor[FCU_NUM_SENSORS]; 54 struct ksensordev sc_sensordev; 55 }; 56 57 int fcu_match(struct device *, void *, void *); 58 void fcu_attach(struct device *, struct device *, void *); 59 60 void fcu_refresh(void *); 61 62 struct cfattach fcu_ca = { 63 sizeof(struct fcu_softc), fcu_match, fcu_attach 64 }; 65 66 struct cfdriver fcu_cd = { 67 NULL, "fcu", DV_DULL 68 }; 69 70 int 71 fcu_match(struct device *parent, void *match, void *aux) 72 { 73 struct i2c_attach_args *ia = aux; 74 75 if (strcmp(ia->ia_name, "fcu") == 0) 76 return (1); 77 return (0); 78 } 79 80 void 81 fcu_attach(struct device *parent, struct device *self, void *aux) 82 { 83 struct fcu_softc *sc = (struct fcu_softc *)self; 84 struct i2c_attach_args *ia = aux; 85 int i; 86 87 sc->sc_tag = ia->ia_tag; 88 sc->sc_addr = ia->ia_addr; 89 90 /* Initialize sensor data. */ 91 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 92 sizeof(sc->sc_sensordev.xname)); 93 for (i = 0; i < FCU_FANS; i++) 94 sc->sc_sensor[i].type = SENSOR_FANRPM; 95 for (i = 0; i < FCU_PWMS; i++) { 96 sc->sc_sensor[FCU_PWM1 + i].type = SENSOR_PERCENT; 97 strlcpy(sc->sc_sensor[FCU_PWM1 + i].desc, "PWM", 98 sizeof(sc->sc_sensor[FCU_PWM1 + i].desc)); 99 } 100 101 if (sensor_task_register(sc, fcu_refresh, 5) == NULL) { 102 printf(", unable to register update task\n"); 103 return; 104 } 105 106 for (i = 0; i < FCU_NUM_SENSORS; i++) 107 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 108 sensordev_install(&sc->sc_sensordev); 109 110 printf("\n"); 111 } 112 113 void 114 fcu_refresh(void *arg) 115 { 116 struct fcu_softc *sc = arg; 117 u_int8_t cmd, fail, fan[2], active; 118 int i; 119 120 iic_acquire_bus(sc->sc_tag, 0); 121 122 cmd = FCU_FAN_FAIL; 123 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 124 sc->sc_addr, &cmd, sizeof cmd, &fail, sizeof fail, 0)) 125 goto abort; 126 cmd = FCU_FAN_ACTIVE; 127 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 128 sc->sc_addr, &cmd, sizeof cmd, &active, sizeof active, 0)) 129 goto abort; 130 fail &= active; 131 132 for (i = 0; i < FCU_FANS; i++) { 133 if (fail & (1 << (i + 1))) 134 sc->sc_sensor[i].flags |= SENSOR_FINVALID; 135 else 136 sc->sc_sensor[i].flags &= ~SENSOR_FINVALID; 137 } 138 139 cmd = FCU_PWM_FAIL; 140 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 141 sc->sc_addr, &cmd, sizeof cmd, &fail, sizeof fail, 0)) 142 goto abort; 143 cmd = FCU_PWM_ACTIVE; 144 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 145 sc->sc_addr, &cmd, sizeof cmd, &active, sizeof active, 0)) 146 goto abort; 147 fail &= active; 148 149 for (i = 0; i < FCU_PWMS; i++) { 150 if (fail & (1 << (i + 1))) 151 sc->sc_sensor[FCU_PWMS + i].flags |= SENSOR_FINVALID; 152 else 153 sc->sc_sensor[FCU_PWMS + i].flags &= ~SENSOR_FINVALID; 154 } 155 156 for (i = 0; i < FCU_FANS; i++) { 157 cmd = FCU_FANREAD(i + 1); 158 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 159 sc->sc_addr, &cmd, sizeof cmd, &fan, sizeof fan, 0)) { 160 sc->sc_sensor[FCU_RPM1 + i].flags |= SENSOR_FINVALID; 161 continue; 162 } 163 sc->sc_sensor[FCU_RPM1 + i].value = (fan[0] << 5) | (fan[1] >> 3); 164 } 165 166 for (i = 0; i < FCU_PWMS; i++) { 167 cmd = FCU_PWMREAD(i + 1); 168 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 169 sc->sc_addr, &cmd, sizeof cmd, &fan, sizeof fan, 0)) { 170 sc->sc_sensor[FCU_PWM1 + i].flags |= SENSOR_FINVALID; 171 continue; 172 } 173 sc->sc_sensor[FCU_PWM1 + i].value = (fan[0] * 100 * 1000) / 255; 174 } 175 176 abort: 177 iic_release_bus(sc->sc_tag, 0); 178 } 179