Annotation of sys/dev/i2c/fintek.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: fintek.c,v 1.6 2007/06/24 05:34:35 dlg Exp $ */
! 2: /*
! 3: * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: #include <sys/param.h>
! 19: #include <sys/systm.h>
! 20: #include <sys/device.h>
! 21: #include <sys/sensors.h>
! 22:
! 23: #include <dev/i2c/i2cvar.h>
! 24:
! 25: /* Sensors */
! 26: #define F_VCC 0
! 27: #define F_V1 1
! 28: #define F_V2 2
! 29: #define F_V3 3
! 30: #define F_TEMP1 4
! 31: #define F_TEMP2 5
! 32: #define F_FAN1 6
! 33: #define F_FAN2 7
! 34: #define F_NUM_SENSORS 8
! 35:
! 36: struct fintek_softc {
! 37: struct device sc_dev;
! 38: i2c_tag_t sc_tag;
! 39: i2c_addr_t sc_addr;
! 40:
! 41: struct ksensor sc_sensor[F_NUM_SENSORS];
! 42: struct ksensordev sc_sensordev;
! 43: };
! 44:
! 45: int fintek_match(struct device *, void *, void *);
! 46: void fintek_attach(struct device *, struct device *, void *);
! 47:
! 48: void fintek_refresh(void *);
! 49: int fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
! 50: size_t size);
! 51: int fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
! 52: size_t size);
! 53: void fintek_fullspeed(struct fintek_softc *sc);
! 54:
! 55: struct cfattach fintek_ca = {
! 56: sizeof(struct fintek_softc), fintek_match, fintek_attach
! 57: };
! 58:
! 59: struct cfdriver fintek_cd = {
! 60: NULL, "fintek", DV_DULL
! 61: };
! 62:
! 63: #define FINTEK_CONFIG1 0x01
! 64: #define FINTEK_FAN1_LINEAR_MODE 0x10
! 65: #define FINTEK_FAN2_LINEAR_MODE 0x20
! 66: #define FINTEK_VOLT0 0x10
! 67: #define FINTEK_VOLT1 0x11
! 68: #define FINTEK_VOLT2 0x12
! 69: #define FINTEK_VOLT3 0x13
! 70: #define FINTEK_TEMP1 0x14
! 71: #define FINTEK_TEMP2 0x15
! 72: #define FINTEK_FAN1 0x16
! 73: #define FINTEK_FAN2 0x18
! 74: #define FINTEK_VERSION 0x5c
! 75: #define FINTEK_RSTCR 0x60
! 76: #define FINTEK_FAN1_MODE_MANUAL 0x30
! 77: #define FINTEK_FAN2_MODE_MANUAL 0xc0
! 78: #define FINTEK_PWM_DUTY1 0x76
! 79: #define FINTEK_PWM_DUTY2 0x86
! 80:
! 81: /* Options passed via the 'flags' config keyword. */
! 82: #define FINTEK_OPTION_FULLSPEED 0x0001
! 83:
! 84: int
! 85: fintek_match(struct device *parent, void *match, void *aux)
! 86: {
! 87: struct i2c_attach_args *ia = aux;
! 88:
! 89: if (strcmp(ia->ia_name, "f75375") == 0)
! 90: return (1);
! 91: return (0);
! 92: }
! 93:
! 94: int
! 95: fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
! 96: size_t size)
! 97: {
! 98: return iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 99: sc->sc_addr, &cmd, sizeof cmd, data, size, 0);
! 100: }
! 101:
! 102: int
! 103: fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
! 104: size_t size)
! 105: {
! 106: return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
! 107: sc->sc_addr, &cmd, sizeof cmd, data, size, 0);
! 108: }
! 109:
! 110: void
! 111: fintek_attach(struct device *parent, struct device *self, void *aux)
! 112: {
! 113: struct fintek_softc *sc = (struct fintek_softc *)self;
! 114: struct i2c_attach_args *ia = aux;
! 115: u_int8_t cmd, data;
! 116: int i;
! 117:
! 118: sc->sc_tag = ia->ia_tag;
! 119: sc->sc_addr = ia->ia_addr;
! 120:
! 121: iic_acquire_bus(sc->sc_tag, 0);
! 122:
! 123: cmd = FINTEK_VERSION;
! 124: if (fintek_read_reg(sc, cmd, &data, sizeof data))
! 125: goto failread;
! 126:
! 127: printf(": F75375 rev %d.%d", data>> 4, data & 0xf);
! 128:
! 129: /*
! 130: * It seems the fan in the Thecus n2100 doesn't provide a
! 131: * reliable fan count. As a result the automatic fan
! 132: * controlling mode that the chip comes up in after reset
! 133: * doesn't work reliably. So we have a flag to drive the fan
! 134: * at maximum voltage such that the box doesn't overheat.
! 135: */
! 136: if (sc->sc_dev.dv_cfdata->cf_flags & FINTEK_OPTION_FULLSPEED)
! 137: fintek_fullspeed(sc);
! 138:
! 139: iic_release_bus(sc->sc_tag, 0);
! 140:
! 141: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
! 142: sizeof(sc->sc_sensordev.xname));
! 143:
! 144: sc->sc_sensor[F_VCC].type = SENSOR_VOLTS_DC;
! 145: strlcpy(sc->sc_sensor[F_VCC].desc, "Vcc",
! 146: sizeof(sc->sc_sensor[F_VCC].desc));
! 147:
! 148: sc->sc_sensor[F_V1].type = SENSOR_VOLTS_DC;
! 149: sc->sc_sensor[F_V2].type = SENSOR_VOLTS_DC;
! 150: sc->sc_sensor[F_V3].type = SENSOR_VOLTS_DC;
! 151:
! 152: sc->sc_sensor[F_TEMP1].type = SENSOR_TEMP;
! 153: sc->sc_sensor[F_TEMP2].type = SENSOR_TEMP;
! 154:
! 155: sc->sc_sensor[F_FAN1].type = SENSOR_FANRPM;
! 156: sc->sc_sensor[F_FAN2].type = SENSOR_FANRPM;
! 157:
! 158: if (sensor_task_register(sc, fintek_refresh, 5) == NULL) {
! 159: printf(", unable to register update task\n");
! 160: return;
! 161: }
! 162:
! 163: for (i = 0; i < F_NUM_SENSORS; i++) {
! 164: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
! 165: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
! 166: }
! 167: sensordev_install(&sc->sc_sensordev);
! 168:
! 169: printf("\n");
! 170: return;
! 171:
! 172: failread:
! 173: printf("unable to read reg %d\n", cmd);
! 174: iic_release_bus(sc->sc_tag, 0);
! 175: return;
! 176: }
! 177:
! 178:
! 179: struct {
! 180: char sensor;
! 181: u_int8_t cmd;
! 182: } fintek_worklist[] = {
! 183: { F_VCC, FINTEK_VOLT0 },
! 184: { F_V1, FINTEK_VOLT1 },
! 185: { F_V2, FINTEK_VOLT2 },
! 186: { F_V3, FINTEK_VOLT3 },
! 187: { F_TEMP1, FINTEK_TEMP1 },
! 188: { F_TEMP2, FINTEK_TEMP2 },
! 189: { F_FAN1, FINTEK_FAN1 },
! 190: { F_FAN2, FINTEK_FAN2 }
! 191: };
! 192: #define FINTEK_WORKLIST_SZ (sizeof(fintek_worklist) / sizeof(fintek_worklist[0]))
! 193:
! 194: void
! 195: fintek_refresh(void *arg)
! 196: {
! 197: struct fintek_softc *sc = arg;
! 198: u_int8_t cmd, data, data2;
! 199: int i;
! 200:
! 201: iic_acquire_bus(sc->sc_tag, 0);
! 202:
! 203: for (i = 0; i < FINTEK_WORKLIST_SZ; i++){
! 204: cmd = fintek_worklist[i].cmd;
! 205: if (fintek_read_reg(sc, cmd, &data, sizeof data)) {
! 206: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 207: continue;
! 208: }
! 209: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
! 210: switch (fintek_worklist[i].sensor) {
! 211: case F_VCC:
! 212: sc->sc_sensor[i].value = data * 16000;
! 213: break;
! 214: case F_V1:
! 215: /* FALLTHROUGH */
! 216: case F_V2:
! 217: /* FALLTHROUGH */
! 218: case F_V3:
! 219: sc->sc_sensor[i].value = data * 8000;
! 220: break;
! 221: case F_TEMP1:
! 222: /* FALLTHROUGH */
! 223: case F_TEMP2:
! 224: sc->sc_sensor[i].value = 273150000 + data * 1000000;
! 225: break;
! 226: case F_FAN1:
! 227: /* FALLTHROUGH */
! 228: case F_FAN2:
! 229: /* FANx LSB follows FANx MSB */
! 230: cmd = fintek_worklist[i].cmd + 1;
! 231: if (fintek_read_reg(sc, cmd, &data2, sizeof data2)) {
! 232: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 233: continue;
! 234: }
! 235: if ((data == 0xff && data2 == 0xff) ||
! 236: (data == 0 && data2 == 0))
! 237: sc->sc_sensor[i].value = 0;
! 238: else
! 239: sc->sc_sensor[i].value = 1500000 /
! 240: (data << 8 | data2);
! 241: break;
! 242: default:
! 243: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 244: break;
! 245: }
! 246: }
! 247:
! 248: iic_release_bus(sc->sc_tag, 0);
! 249: }
! 250:
! 251: void
! 252: fintek_fullspeed(struct fintek_softc *sc)
! 253: {
! 254: u_int8_t data;
! 255:
! 256: data = FINTEK_FAN1_LINEAR_MODE | FINTEK_FAN2_LINEAR_MODE;
! 257: fintek_write_reg(sc, FINTEK_CONFIG1, &data, sizeof data);
! 258:
! 259: data = FINTEK_FAN1_MODE_MANUAL | FINTEK_FAN2_MODE_MANUAL;
! 260: fintek_write_reg(sc, FINTEK_RSTCR, &data, sizeof data);
! 261:
! 262: data = 0xff; /* Maximum voltage */
! 263: fintek_write_reg(sc, FINTEK_PWM_DUTY1, &data, sizeof data);
! 264: fintek_write_reg(sc, FINTEK_PWM_DUTY2, &data, sizeof data);
! 265: }
CVSweb