diff options
Diffstat (limited to 'sys/dev/i2c/fintek.c')
-rw-r--r-- | sys/dev/i2c/fintek.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/sys/dev/i2c/fintek.c b/sys/dev/i2c/fintek.c new file mode 100644 index 00000000000..e3e3e76915a --- /dev/null +++ b/sys/dev/i2c/fintek.c @@ -0,0 +1,530 @@ +/* $OpenBSD: fintek.c,v 1.1 2006/06/15 20:50:44 drahn Exp $ */ +/* + * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/sensors.h> + +#include <dev/i2c/i2cvar.h> + +/* Sensors */ +#define F_VCC 0 +#define F_V1 1 +#define F_V2 2 +#define F_V3 3 +#define F_TEMP1 4 +#define F_TEMP2 5 +#define F_FAN1 6 +#define F_FAN2 7 +#define F_NUM_SENSORS 8 + + +struct fintek_softc { + struct device sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; + + struct sensor sc_sensor[F_NUM_SENSORS]; +}; + +int fintek_match(struct device *, void *, void *); +void fintek_attach(struct device *, struct device *, void *); + +void fintek_refresh(void *); + +int fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data, + size_t size); +int fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data, + size_t size); + +void fintek_setspeed(struct fintek_softc *sc); +void fintek_setauto(struct fintek_softc *sc); +void fintek_setpwm(struct fintek_softc *sc); + +struct cfattach fintek_ca = { + sizeof(struct fintek_softc), fintek_match, fintek_attach +}; + +struct cfdriver fintek_cd = { + NULL, "fintek", DV_DULL +}; + +#define FINTEK_VOLT0 0x10 +#define FINTEK_VOLT1 0x11 +#define FINTEK_VOLT2 0x12 +#define FINTEK_VOLT3 0x13 +#define FINTEK_TEMP1 0x14 +#define FINTEK_TEMP2 0x15 +#define FINTEK_FAN1 0x16 +#define FINTEK_FAN2 0x18 +#define FINTEK_VERSION 0x5c +#define FINTEK_RSTCR 0x60 + +int +fintek_match(struct device *parent, void *match, void *aux) +{ + struct i2c_attach_args *ia = aux; + + if (strcmp(ia->ia_name, "f75375") == 0) + return (1); + return (0); +} + +int +fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data, + size_t size) +{ + return iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, + sc->sc_addr, &cmd, sizeof cmd, data, size, 0); +} +int +fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data, + size_t size) +{ + return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, + sc->sc_addr, &cmd, sizeof cmd, data, size, 0); +} + +void +fintek_attach(struct device *parent, struct device *self, void *aux) +{ + struct fintek_softc *sc = (struct fintek_softc *)self; + struct i2c_attach_args *ia = aux; + u_int8_t cmd, data, data2; + int i; + + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + iic_acquire_bus(sc->sc_tag, 0); + + cmd = FINTEK_VERSION; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + + + printf(": F75375 rev %d.%d", data>> 4, data & 0xf); + + + cmd = FINTEK_RSTCR; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; +#if 1 + data = 0x81; + cmd = 0; + if (fintek_write_reg(sc, cmd, &data, sizeof data)) + goto failwrite; + if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, + sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { + iic_release_bus(sc->sc_tag, 0); + printf(": cannot read ID register\n"); + return; + } +#endif + + +#ifdef NOISY_DEBUG + cmd = 0; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" conf 0 %x", data); + + cmd = 0x1; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" conf 1 %x", data); + + cmd = 0x2; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + + printf(" conf 2 %x", data); + cmd = 0x3; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" conf 3 %x\n", data); + cmd = 0x70; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + cmd = 0x71; + if (fintek_read_reg(sc, cmd, &data2, sizeof data2)) + goto failread; + printf(" fan full speed %x %x\n", data, data2); + + cmd = 0xa0; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" temp 1 b %x\n", data); + + cmd = 0xa1; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" temp 2 b %x\n", data); + + cmd = 0xa2; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" temp 3 b %x\n", data); + + cmd = 0xa3; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + printf(" temp 4 b %x\n", data); + + cmd = 0xa4; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + cmd = 0xa5; + if (fintek_read_reg(sc, cmd, &data2, sizeof data)) + goto failread; + printf(" sec1speed %x %x\n", data, data2); + + cmd = 0xa6; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + cmd = 0xa7; + if (fintek_read_reg(sc, cmd, &data2, sizeof data)) + goto failread; + printf(" sec2speed %x %x\n", data, data2); + + cmd = 0xa8; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + cmd = 0xa9; + if (fintek_read_reg(sc, cmd, &data2, sizeof data)) + goto failread; + printf(" sec3speed %x %x\n", data, data2); + + cmd = 0xaa; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + cmd = 0xab; + if (fintek_read_reg(sc, cmd, &data2, sizeof data)) + goto failread; + printf(" sec4speed %x %x\n", data, data2); + + cmd = 0xac; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) + goto failread; + cmd = 0xad; + if (fintek_read_reg(sc, cmd, &data2, sizeof data)) + goto failread; + printf(" sec5speed %x %x\n", data, data2); +#endif + +#if 0 + fintek_setpwm(sc); +#endif +#if 0 + fintek_setauto(sc); +#endif + data2 = data2; +#if 1 + fintek_setspeed(sc); +#endif + iic_release_bus(sc->sc_tag, 0); + +for (i = 0; i < F_NUM_SENSORS; i++) + strlcpy(sc->sc_sensor[i].device, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensor[i].device)); + + sc->sc_sensor[F_VCC].type = SENSOR_VOLTS_DC; + strlcpy(sc->sc_sensor[F_VCC].desc, "VCC", + sizeof(sc->sc_sensor[F_VCC].desc)); + + sc->sc_sensor[F_V1].type = SENSOR_VOLTS_DC; + strlcpy(sc->sc_sensor[F_V1].desc, "Volt 1", + sizeof(sc->sc_sensor[F_V1].desc)); + + sc->sc_sensor[F_V2].type = SENSOR_VOLTS_DC; + strlcpy(sc->sc_sensor[F_V2].desc, "Volt 2", + sizeof(sc->sc_sensor[F_V2].desc)); + + sc->sc_sensor[F_V3].type = SENSOR_VOLTS_DC; + strlcpy(sc->sc_sensor[F_V3].desc, "Volt 3", + sizeof(sc->sc_sensor[F_V3].desc)); + + sc->sc_sensor[F_TEMP1].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[F_TEMP1].desc, "Temp 1", + sizeof(sc->sc_sensor[F_TEMP1].desc)); + + sc->sc_sensor[F_TEMP2].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[F_TEMP2].desc, "Temp 2", + sizeof(sc->sc_sensor[F_TEMP2].desc)); + + sc->sc_sensor[F_FAN1].type = SENSOR_FANRPM; + strlcpy(sc->sc_sensor[F_FAN1].desc, "FAN1", + sizeof(sc->sc_sensor[F_FAN1].desc)); + + sc->sc_sensor[F_FAN2].type = SENSOR_FANRPM; + strlcpy(sc->sc_sensor[F_FAN2].desc, "FAN1", + sizeof(sc->sc_sensor[F_FAN2].desc)); + + if (sensor_task_register(sc, fintek_refresh, 5)) { + printf(", unable to register update task\n"); + return; + } + + for (i = 0; i < F_NUM_SENSORS; i++) { + sc->sc_sensor[i].flags &= ~SENSOR_FINVALID; + sensor_add(&sc->sc_sensor[i]); + } + return; + +failread: + printf("unable to read reg %d\n", cmd); + iic_release_bus(sc->sc_tag, 0); + return; +#if 1 +failwrite: + printf("unable to write reg %d\n", cmd); + iic_release_bus(sc->sc_tag, 0); +#endif +} + + +struct { + char sensor; + u_int8_t cmd; +} fintek_worklist[] = { + { F_VCC, FINTEK_VOLT0 }, + { F_V1, FINTEK_VOLT1 }, + { F_V2, FINTEK_VOLT2 }, + { F_V3, FINTEK_VOLT3 }, + { F_TEMP1, FINTEK_TEMP1 }, + { F_TEMP2, FINTEK_TEMP2 }, + { F_FAN1, FINTEK_FAN1 }, + { F_FAN2, FINTEK_FAN2 } +}; +#define FINTEK_WORKLIST_SZ (sizeof fintek_worklist/sizeof(fintek_worklist[0])) + +void +fintek_refresh(void *arg) +{ + struct fintek_softc *sc = arg; + u_int8_t cmd, data, data2; + int i; + + iic_acquire_bus(sc->sc_tag, 0); + + for (i = 0; i < FINTEK_WORKLIST_SZ; i++){ + cmd = fintek_worklist[i].cmd; + if (fintek_read_reg(sc, cmd, &data, sizeof data)) { + sc->sc_sensor[i].flags |= SENSOR_FINVALID; + continue; + } + sc->sc_sensor[i].flags &= ~SENSOR_FINVALID; + switch (fintek_worklist[i].sensor) { + case F_VCC: + /* FALLTHROUGH */ + case F_V1: + /* FALLTHROUGH */ + case F_V2: + /* FALLTHROUGH */ + case F_V3: + sc->sc_sensor[i].value = 1000 * (data*8); + break; + case F_TEMP1: + /* FALLTHROUGH */ + case F_TEMP2: + sc->sc_sensor[i].value = 273150000 + 1000000 * (data); + break; + case F_FAN1: + /* FALLTHROUGH */ + case F_FAN2: + /* FANxLSB follows FANxMSB */ + cmd = fintek_worklist[i].cmd + 1; + if (fintek_read_reg(sc, cmd, &data2, sizeof data2)) { + sc->sc_sensor[i].flags |= SENSOR_FINVALID; + continue; + } +// printf("fan speed %x: %x %x\n", fintek_worklist[i].cmd, +// data, data2); + if ((data == 0xff && data2 == 0xff) || + (data == 0 && data2 == 0)) + sc->sc_sensor[i].value = 0; + else + sc->sc_sensor[i].value = 1500000/ + (data << 8 | data2); + { + extern long hostid; + static long currentspeed; + int i; + if (currentspeed != hostid) { + currentspeed = hostid; + printf("setting speed to %d\n", hostid); + +#if 0 + data = hostid & 0xff; + cmd = 0x76; + fintek_write_reg(sc, cmd, &data, + sizeof data); +#else + cmd = 0x6d; + fintek_read_reg(sc, cmd, &data, + sizeof data); + printf("reg 6d contains %x setting to 0x11\n", data); + fintek_write_reg(sc, cmd, &data, + sizeof data); + i = hostid ; /* desired value */ + cmd = 0x74; + data = i >> 8; + fintek_write_reg(sc, cmd, &data, + sizeof data); + + cmd = 0x75; + data = i & 0xff; + fintek_write_reg(sc, cmd, &data, + sizeof data); +#endif + } + } + break; + default: + sc->sc_sensor[i].flags |= SENSOR_FINVALID; + break; + } + } + + iic_release_bus(sc->sc_tag, 0); +} +void +fintek_setspeed(struct fintek_softc *sc) +{ + u_int8_t cmd, data; + int i; + + cmd = 0x1; + fintek_read_reg(sc, cmd, &data, sizeof data); + + data |= (1<<4); + fintek_write_reg(sc, cmd, &data, sizeof data); + + i = 300; /* desired speed */ + i = 1500000/i; + cmd = 0x74; + data = i >> 8; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0x75; + data = i & 0xff; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0x60; + fintek_read_reg(sc, cmd, &data, sizeof data); + + data &= ~(0x1 << 4); + data |= (0x2 << 4); /* manual */ + fintek_write_reg(sc, cmd, &data, sizeof data); + printf("\n"); +} + +void +fintek_setauto(struct fintek_softc *sc) +{ + u_int8_t cmd, data, data2; + int i; + + i = 2000; /* desired speed */ + i = 1500000/i; + data2 = i >> 8; + data = i & 0xff; + + cmd = 0xa4; + fintek_write_reg(sc, cmd, &data, sizeof data); + fintek_write_reg(sc, cmd, &data2, sizeof data2); + + i = 0x3A98; + data2 = i >> 8; + data = i & 0xff; + cmd = 0xa6; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0xa7; + fintek_write_reg(sc, cmd, &data2, sizeof data2); + + i = 0x3A98; + data2 = i >> 8; + data = i & 0xff; + cmd = 0xa8; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0xa9; + fintek_write_reg(sc, cmd, &data2, sizeof data2); + + i = 0x3A98; + data2 = i >> 8; + data = i & 0xff; + cmd = 0xaa; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0xab; + fintek_write_reg(sc, cmd, &data2, sizeof data2); + + i = 0x3A98; + data2 = i >> 8; + data = i & 0xff; + cmd = 0xac; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0xad; + fintek_write_reg(sc, cmd, &data2, sizeof data2); + + cmd = 0x74; + fintek_read_reg(sc, cmd, &data, sizeof data); + + cmd = 0x75; + fintek_read_reg(sc, cmd, &data2, sizeof data); + + printf("fan speed %x %x\n", data, data2); + + cmd = 0x60; + fintek_read_reg(sc, cmd, &data, sizeof data); + + data &= ~(0x3 << 4); + data |= (1 << 4); + fintek_write_reg(sc, cmd, &data, sizeof data); + + printf("\n"); + +} +void +fintek_setpwm(struct fintek_softc *sc) +{ + u_int8_t cmd, data; + + cmd = 0x01; + fintek_read_reg(sc, cmd, &data, sizeof data); + data |= 1<<4; + fintek_write_reg(sc, cmd, &data, sizeof data); + + cmd = 0x60; + fintek_read_reg(sc, cmd, &data, sizeof data); + + data |= 0x3 << 4; + + fintek_write_reg(sc, cmd, &data, sizeof data); + + + data = 0x28; + cmd = 0x76; + fintek_write_reg(sc, cmd, &data, sizeof data); + + printf("\n"); + +} |