diff options
author | nwhitehorn <nwhitehorn@FreeBSD.org> | 2011-05-29 18:35:57 +0000 |
---|---|---|
committer | nwhitehorn <nwhitehorn@FreeBSD.org> | 2011-05-29 18:35:57 +0000 |
commit | 95e41991d897ca4ff49ab75bcbf9c81b72c1864f (patch) | |
tree | 059a5a044ae0b870bfdd97208a26b7a06d2bda2f /sys/dev | |
parent | 1dfa9ab8735324b683e437551bc3829f83c6e8f0 (diff) | |
download | FreeBSD-src-95e41991d897ca4ff49ab75bcbf9c81b72c1864f.zip FreeBSD-src-95e41991d897ca4ff49ab75bcbf9c81b72c1864f.tar.gz |
Update the I2C-based temperature/fan drivers to connect to the Powermac
thermal control module. This provides automatic fan management on all G5
PowerMacs and Xserves.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/iicbus/ad7417.c | 162 | ||||
-rw-r--r-- | sys/dev/iicbus/ds1775.c | 65 | ||||
-rw-r--r-- | sys/dev/iicbus/max6690.c | 50 |
3 files changed, 186 insertions, 91 deletions
diff --git a/sys/dev/iicbus/ad7417.c b/sys/dev/iicbus/ad7417.c index aa26d6f..084b9f5 100644 --- a/sys/dev/iicbus/ad7417.c +++ b/sys/dev/iicbus/ad7417.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_bus.h> +#include <powerpc/powermac/powermac_thermal.h> #define FCU_ZERO_C_TO_K 2732 @@ -63,8 +64,9 @@ __FBSDID("$FreeBSD$"); uint8_t adc741x_config; struct ad7417_sensor { + struct pmac_therm therm; + device_t dev; int id; - char location[32]; enum { ADC7417_TEMP_SENSOR, ADC7417_ADC_SENSOR @@ -83,6 +85,9 @@ static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data); static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data); +static int ad7417_diode_read(struct ad7417_sensor *sens); +static int ad7417_adc_read(struct ad7417_sensor *sens); +static int ad7417_sensor_read(struct ad7417_sensor *sens); struct ad7417_softc { device_t sc_dev; @@ -243,7 +248,7 @@ ad7417_fill_sensor_prop(device_t dev) sizeof(location)); while (len < prop_len) { if (sc->sc_sensors != NULL) - strcpy(sc->sc_sensors[i].location, location + len); + strcpy(sc->sc_sensors[i].therm.name, location + len); prev_len = strlen(location + len) + 1; len += prev_len; i++; @@ -251,7 +256,7 @@ ad7417_fill_sensor_prop(device_t dev) if (sc->sc_sensors == NULL) return (i); - /* Fill the fan type property. */ + /* Fill the sensor type property. */ len = 0; i = 0; prev_len = 0; @@ -271,6 +276,36 @@ ad7417_fill_sensor_prop(device_t dev) for (j = 0; j < i; j++) sc->sc_sensors[j].id = id[j]; + /* Fill the sensor zone property. Taken from OF. */ + prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id)); + for (j = 0; j < i; j++) + sc->sc_sensors[j].therm.zone = id[j]; + + /* Finish setting up sensor properties */ + for (j = 0; j < i; j++) { + sc->sc_sensors[j].dev = dev; + + /* HACK: Apple wired a random diode to the ADC line */ + if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP") + != NULL) { + sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR; + sc->sc_sensors[j].therm.read = + (int (*)(struct pmac_therm *))(ad7417_diode_read); + } else { + sc->sc_sensors[j].therm.read = + (int (*)(struct pmac_therm *))(ad7417_sensor_read); + } + + if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR) + continue; + + /* Make up some ranges */ + sc->sc_sensors[j].therm.target_temp = 500 + 2732; + sc->sc_sensors[j].therm.max_temp = 900 + 2732; + + pmac_thermal_sensor_register(&sc->sc_sensors[j].therm); + } + return (i); } @@ -310,8 +345,9 @@ ad7417_attach(device_t dev) /* Add sysctls for the sensors. */ for (i = 0; i < sc->sc_nsensors; i++) { - for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) { - sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]); + for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) { + sysctl_name[j] = + tolower(sc->sc_sensors[i].therm.name[j]); if (isspace(sysctl_name[j])) sysctl_name[j] = '_'; } @@ -341,7 +377,7 @@ ad7417_attach(device_t dev) device_printf(dev, "Sensors\n"); for (i = 0; i < sc->sc_nsensors; i++) { device_printf(dev, "Location: %s ID: %d type: %d\n", - sc->sc_sensors[i].location, + sc->sc_sensors[i].therm.name, sc->sc_sensors[i].id, sc->sc_sensors[i].type); } @@ -391,44 +427,91 @@ ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value, } static int -ad7417_sensor_read(device_t dev, struct ad7417_sensor *sens, int *temp) +ad7417_diode_read(struct ad7417_sensor *sens) +{ + static int eeprom_read = 0; + static cell_t eeprom[2][40]; + phandle_t eeprom_node; + int rawval, diode_slope, diode_offset; + int temp; + + if (!eeprom_read) { + eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0"); + OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0])); + eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2"); + OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1])); + eeprom_read = 1; + } + + rawval = ad7417_adc_read(sens); + if (strstr(sens->therm.name, "CPU B") != NULL) { + diode_slope = eeprom[1][0x11] >> 16; + diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12; + } else { + diode_slope = eeprom[0][0x11] >> 16; + diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12; + } + + temp = (rawval*diode_slope + diode_offset) >> 2; + temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16); + + return (temp + FCU_ZERO_C_TO_K); +} + +static int +ad7417_adc_read(struct ad7417_sensor *sens) +{ + struct ad7417_softc *sc; + uint8_t chan; + int temp; + + sc = device_get_softc(sens->dev); + + switch (sens->id) { + case 11: + case 16: + chan = 1; + break; + case 12: + case 17: + chan = 2; + break; + case 13: + case 18: + chan = 3; + break; + case 14: + case 19: + chan = 4; + break; + default: + chan = 1; + } + + ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan); + + return (temp); +} + + +static int +ad7417_sensor_read(struct ad7417_sensor *sens) { struct ad7417_softc *sc; + int temp; - sc = device_get_softc(dev); + sc = device_get_softc(sens->dev); /* Init the ADC. */ ad7417_init_adc(sc->sc_dev, sc->sc_addr); if (sens->type == ADC7417_TEMP_SENSOR) { - ad7417_get_temp(sc->sc_dev, sc->sc_addr, temp); - *temp += FCU_ZERO_C_TO_K; + ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp); + temp += FCU_ZERO_C_TO_K; } else { - uint8_t chan; - switch (sens->id) { - case 11: - case 16: - chan = 1; - break; - case 12: - case 17: - chan = 2; - break; - case 13: - case 18: - chan = 3; - break; - case 14: - case 19: - chan = 4; - break; - default: - chan = 1; - } - - ad7417_get_adc(sc->sc_dev, sc->sc_addr, temp, chan); + temp = ad7417_adc_read(sens); } - return (0); + return (temp); } static int @@ -439,19 +522,16 @@ ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS) struct ad7417_sensor *sens; int value = 0; int error; - int temp; dev = arg1; sc = device_get_softc(dev); sens = &sc->sc_sensors[arg2]; - error = ad7417_sensor_read(dev, sens, &value); - if (error != 0) - return (error); - - temp = value; + value = sens->therm.read(&sens->therm); + if (value < 0) + return (ENXIO); - error = sysctl_handle_int(oidp, &temp, 0, req); + error = sysctl_handle_int(oidp, &value, 0, req); return (error); } diff --git a/sys/dev/iicbus/ds1775.c b/sys/dev/iicbus/ds1775.c index 0edc074..faa4a1a 100644 --- a/sys/dev/iicbus/ds1775.c +++ b/sys/dev/iicbus/ds1775.c @@ -49,33 +49,31 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_bus.h> +#include <powerpc/powermac/powermac_thermal.h> #define FCU_ZERO_C_TO_K 2732 /* Drivebay sensor: LM75/DS1775. */ #define DS1775_TEMP 0x0 -struct ds1775_sensor { - char location[32]; -}; - /* Regular bus attachment functions */ static int ds1775_probe(device_t); static int ds1775_attach(device_t); +struct ds1775_softc { + struct pmac_therm sc_sensor; + device_t sc_dev; + struct intr_config_hook enum_hook; + uint32_t sc_addr; +}; + /* Utility functions */ +static int ds1775_sensor_read(struct ds1775_softc *sc); static int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS); static void ds1775_start(void *xdev); static int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data); -struct ds1775_softc { - device_t sc_dev; - struct intr_config_hook enum_hook; - uint32_t sc_addr; - struct ds1775_sensor *sc_sensors; - -}; static device_method_t ds1775_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ds1775_probe), @@ -92,7 +90,6 @@ static driver_t ds1775_driver = { static devclass_t ds1775_devclass; DRIVER_MODULE(ds1755, iicbus, ds1775_driver, ds1775_devclass, 0, 0); -MALLOC_DEFINE(M_DS1775, "ds1775", "Temp-Monitor DS1775"); static int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) @@ -169,7 +166,6 @@ ds1775_start(void *xdev) { phandle_t child; struct ds1775_softc *sc; - struct ds1775_sensor *sens; struct sysctl_oid *sensroot_oid; struct sysctl_ctx_list *ctx; ssize_t plen; @@ -183,30 +179,34 @@ ds1775_start(void *xdev) child = ofw_bus_get_node(dev); - sc->sc_sensors = malloc (sizeof(struct ds1775_sensor), - M_DS1775, M_WAITOK | M_ZERO); - - sens = sc->sc_sensors; - ctx = device_get_sysctl_ctx(dev); sensroot_oid = device_get_sysctl_tree(dev); - plen = OF_getprop(child, "hwsensor-location", sens->location, - sizeof(sens->location)); + OF_getprop(child, "hwsensor-zone", &sc->sc_sensor.zone, sizeof(int)); + plen = OF_getprop(child, "hwsensor-location", sc->sc_sensor.name, + sizeof(sc->sc_sensor.name)); units = "C"; if (plen == -1) { strcpy(sysctl_name, "sensor"); } else { - for (i = 0; i < strlen(sens->location); i++) { - sysctl_name[i] = tolower(sens->location[i]); + for (i = 0; i < strlen(sc->sc_sensor.name); i++) { + sysctl_name[i] = tolower(sc->sc_sensor.name[i]); if (isspace(sysctl_name[i])) sysctl_name[i] = '_'; } sysctl_name[i] = 0; } - sprintf(sysctl_desc,"%s (%s)", sens->location, units); + /* Make up target temperatures. These are low, for the drive bay. */ + sc->sc_sensor.target_temp = 300 + FCU_ZERO_C_TO_K; + sc->sc_sensor.max_temp = 600 + FCU_ZERO_C_TO_K; + + sc->sc_sensor.read = + (int (*)(struct pmac_therm *sc))(ds1775_sensor_read); + pmac_thermal_sensor_register(&sc->sc_sensor); + + sprintf(sysctl_desc,"%s (%s)", sc->sc_sensor.name, units); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO, sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, @@ -216,14 +216,11 @@ ds1775_start(void *xdev) } static int -ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp) +ds1775_sensor_read(struct ds1775_softc *sc) { - struct ds1775_softc *sc; uint16_t buf[2]; uint16_t read; - sc = device_get_softc(dev); - ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf); read = *((int16_t *)buf); @@ -231,29 +228,21 @@ ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp) /* The default mode of the ADC is 9 bit, the resolution is 0.5 C per bit. The temperature is in tenth kelvin. */ - *temp = ((int16_t)(read) >> 7) * 5; - - return (0); + return (((int16_t)(read) >> 7) * 5 + FCU_ZERO_C_TO_K); } + static int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS) { device_t dev; struct ds1775_softc *sc; - struct ds1775_sensor *sens; - int value; int error; unsigned int temp; dev = arg1; sc = device_get_softc(dev); - sens = &sc->sc_sensors[arg2]; - - error = ds1775_sensor_read(dev, sens, &value); - if (error != 0) - return (error); - temp = value + FCU_ZERO_C_TO_K; + temp = ds1775_sensor_read(sc); error = sysctl_handle_int(oidp, &temp, 0, req); diff --git a/sys/dev/iicbus/max6690.c b/sys/dev/iicbus/max6690.c index cbfdc26..43d6c84 100644 --- a/sys/dev/iicbus/max6690.c +++ b/sys/dev/iicbus/max6690.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_bus.h> +#include <powerpc/powermac/powermac_thermal.h> #define FCU_ZERO_C_TO_K 2732 @@ -61,8 +62,10 @@ __FBSDID("$FreeBSD$"); #define MAX6690_TEMP_MASK 0xe0 struct max6690_sensor { + struct pmac_therm therm; + device_t dev; + int id; - char location[32]; }; /* Regular bus attachment functions */ @@ -70,6 +73,7 @@ static int max6690_probe(device_t); static int max6690_attach(device_t); /* Utility functions */ +static int max6690_sensor_read(struct max6690_sensor *sens); static int max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS); static void max6690_start(void *xdev); static int max6690_read_1(device_t dev, uint32_t addr, uint8_t reg, @@ -167,7 +171,7 @@ max6690_fill_sensor_prop(device_t dev) sizeof(location)); while (len < prop_len) { if (sc->sc_sensors != NULL) - strcpy(sc->sc_sensors[i].location, location + len); + strcpy(sc->sc_sensors[i].therm.name, location + len); prev_len = strlen(location + len) + 1; len += prev_len; i++; @@ -180,6 +184,22 @@ max6690_fill_sensor_prop(device_t dev) for (j = 0; j < i; j++) sc->sc_sensors[j].id = (id[j] & 0xf); + /* Fill the sensor zone property. */ + prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id)); + for (j = 0; j < i; j++) + sc->sc_sensors[j].therm.zone = id[j]; + + /* Set up remaining sensor properties */ + for (j = 0; j < i; j++) { + sc->sc_sensors[j].dev = dev; + + sc->sc_sensors[j].therm.target_temp = 400 + 2732; + sc->sc_sensors[j].therm.max_temp = 800 + 2732; + + sc->sc_sensors[j].therm.read = + (int (*)(struct pmac_therm *))(max6690_sensor_read); + } + return (i); } static int @@ -240,10 +260,15 @@ max6690_start(void *xdev) /* Now we can fill the properties into the allocated struct. */ sc->sc_nsensors = max6690_fill_sensor_prop(dev); + /* Register with powermac_thermal */ + for (i = 0; i < sc->sc_nsensors; i++) + pmac_thermal_sensor_register(&sc->sc_sensors[i].therm); + /* Add sysctls for the sensors. */ for (i = 0; i < sc->sc_nsensors; i++) { - for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) { - sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]); + for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) { + sysctl_name[j] = + tolower(sc->sc_sensors[i].therm.name[j]); if (isspace(sysctl_name[j])) sysctl_name[j] = '_'; } @@ -265,7 +290,7 @@ max6690_start(void *xdev) device_printf(dev, "Sensors\n"); for (i = 0; i < sc->sc_nsensors; i++) { device_printf(dev, "Location : %s ID: %d\n", - sc->sc_sensors[i].location, + sc->sc_sensors[i].therm.name, sc->sc_sensors[i].id); } } @@ -274,14 +299,15 @@ max6690_start(void *xdev) } static int -max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp) +max6690_sensor_read(struct max6690_sensor *sens) { uint8_t reg_int = 0, reg_ext = 0; uint8_t integer; uint8_t fraction; + int temp; struct max6690_softc *sc; - sc = device_get_softc(dev); + sc = device_get_softc(sens->dev); /* The internal sensor id's are even, the external ar odd. */ if ((sens->id % 2) == 0) { @@ -301,9 +327,9 @@ max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp) /* The temperature is in tenth kelvin, the fractional part resolution is 0.125. */ - *temp = (integer * 10) + (fraction >> 5) * 10 / 8; + temp = (integer * 10) + (fraction >> 5) * 10 / 8; - return (0); + return (temp); } static int @@ -320,9 +346,9 @@ max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS) sc = device_get_softc(dev); sens = &sc->sc_sensors[arg2]; - error = max6690_sensor_read(dev, sens, &value); - if (error != 0) - return (error); + value = max6690_sensor_read(sens); + if (value < 0) + return (EIO); temp = value + FCU_ZERO_C_TO_K; |