From 815d7d92c10a1537eb9aeccf26c2777f66c1135d Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Sun, 29 May 2011 18:35:57 +0000 Subject: [PATCH] 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. --- sys/dev/iicbus/ad7417.c | 162 +++++++++++++++++++++++++++---------- sys/dev/iicbus/ds1775.c | 65 +++++++-------- sys/dev/iicbus/max6690.c | 50 +++++++++--- sys/powerpc/powermac/fcu.c | 129 +++++++++++++++++------------ 4 files changed, 264 insertions(+), 142 deletions(-) diff --git a/sys/dev/iicbus/ad7417.c b/sys/dev/iicbus/ad7417.c index aa26d6fbbc3..084b9f587e6 100644 --- a/sys/dev/iicbus/ad7417.c +++ b/sys/dev/iicbus/ad7417.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #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 0edc074a255..faa4a1ac31c 100644 --- a/sys/dev/iicbus/ds1775.c +++ b/sys/dev/iicbus/ds1775.c @@ -49,33 +49,31 @@ __FBSDID("$FreeBSD$"); #include #include +#include #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 cbfdc26619e..43d6c848738 100644 --- a/sys/dev/iicbus/max6690.c +++ b/sys/dev/iicbus/max6690.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #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; diff --git a/sys/powerpc/powermac/fcu.c b/sys/powerpc/powermac/fcu.c index 004b4dbfb47..51dd96b6f4d 100644 --- a/sys/powerpc/powermac/fcu.c +++ b/sys/powerpc/powermac/fcu.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include /* FCU registers * /u3@0,f8000000/i2c@f8001000/fan@15e @@ -66,10 +67,10 @@ __FBSDID("$FreeBSD$"); #define FCU_PWM_SGET(x) 0x30 + (x) * 2 /* Set or get PWM. */ struct fcu_fan { + struct pmac_fan fan; + device_t dev; + int id; - cell_t min; - cell_t max; - char location[32]; enum { FCU_FAN_RPM, FCU_FAN_PWM @@ -103,9 +104,9 @@ static int fcu_attach(device_t); /* Utility functions */ static void fcu_attach_fans(device_t dev); static int fcu_fill_fan_prop(device_t dev); -static int fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm); -static int fcu_fan_get_rpm(device_t dev, struct fcu_fan *fan, int *rpm); -static int fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm); +static int fcu_fan_set_rpm(struct fcu_fan *fan, int rpm); +static int fcu_fan_get_rpm(struct fcu_fan *fan); +static int fcu_fan_set_pwm(struct fcu_fan *fan, int pwm); static int fcu_fan_get_pwm(device_t dev, struct fcu_fan *fan, int *pwm, int *rpm); static int fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS); @@ -249,23 +250,23 @@ fcu_start(void *xdev) } static int -fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm) +fcu_fan_set_rpm(struct fcu_fan *fan, int rpm) { uint8_t reg; struct fcu_softc *sc; unsigned char buf[2]; - sc = device_get_softc(dev); + sc = device_get_softc(fan->dev); /* Clamp to allowed range */ - rpm = max(fan->min, rpm); - rpm = min(fan->max, rpm); + rpm = max(fan->fan.min_rpm, rpm); + rpm = min(fan->fan.max_rpm, rpm); if (fan->type == FCU_FAN_RPM) { reg = FCU_RPM_SET(fan->id); fan->setpoint = rpm; } else { - device_printf(dev, "Unknown fan type: %d\n", fan->type); + device_printf(fan->dev, "Unknown fan type: %d\n", fan->type); return (EIO); } @@ -278,66 +279,68 @@ fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm) } static int -fcu_fan_get_rpm(device_t dev, struct fcu_fan *fan, int *rpm) +fcu_fan_get_rpm(struct fcu_fan *fan) { uint8_t reg; struct fcu_softc *sc; uint8_t buff[2] = { 0, 0 }; uint8_t active = 0, avail = 0, fail = 0; + int rpm; - sc = device_get_softc(dev); + sc = device_get_softc(fan->dev); if (fan->type == FCU_FAN_RPM) { /* Check if the fan is available. */ reg = FCU_RPM_AVAILABLE; fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail); if ((avail & (1 << fan->id)) == 0) { - device_printf(dev, "RPM Fan not available ID: %d\n", - fan->id); - return (EIO); + device_printf(fan->dev, + "RPM Fan not available ID: %d\n", fan->id); + return (-1); } /* Check if we have a failed fan. */ reg = FCU_RPM_FAIL; fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &fail); if ((fail & (1 << fan->id)) != 0) { - device_printf(dev, "RPM Fan failed ID: %d\n", fan->id); - return (EIO); + device_printf(fan->dev, + "RPM Fan failed ID: %d\n", fan->id); + return (-1); } /* Check if fan is active. */ reg = FCU_RPM_ACTIVE; fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &active); if ((active & (1 << fan->id)) == 0) { - device_printf(dev, "RPM Fan not active ID: %d\n", + device_printf(fan->dev, "RPM Fan not active ID: %d\n", fan->id); - return (ENXIO); + return (-1); } reg = FCU_RPM_READ(fan->id); } else { - device_printf(dev, "Unknown fan type: %d\n", fan->type); - return (EIO); + device_printf(fan->dev, "Unknown fan type: %d\n", fan->type); + return (-1); } /* It seems that we can read the fans rpm. */ fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buff); - *rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift; + rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift; - return (0); + return (rpm); } static int -fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm) +fcu_fan_set_pwm(struct fcu_fan *fan, int pwm) { uint8_t reg; struct fcu_softc *sc; uint8_t buf[2]; - sc = device_get_softc(dev); + sc = device_get_softc(fan->dev); /* Clamp to allowed range */ - pwm = max(fan->min, pwm); - pwm = min(fan->max, pwm); + pwm = max(fan->fan.min_rpm, pwm); + pwm = min(fan->fan.max_rpm, pwm); if (fan->type == FCU_FAN_PWM) { reg = FCU_PWM_SGET(fan->id); @@ -347,7 +350,7 @@ fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm) pwm = 30; fan->setpoint = pwm; } else { - device_printf(dev, "Unknown fan type: %d\n", fan->type); + device_printf(fan->dev, "Unknown fan type: %d\n", fan->type); return (EIO); } @@ -434,7 +437,7 @@ fcu_fill_fan_prop(device_t dev) sizeof(location)); while (len < prop_len) { if (sc->sc_fans != NULL) { - strcpy(sc->sc_fans[i].location, location + len); + strcpy(sc->sc_fans[i].fan.name, location + len); } prev_len = strlen(location + len) + 1; len += prev_len; @@ -463,6 +466,33 @@ fcu_fill_fan_prop(device_t dev) for (j = 0; j < i; j++) sc->sc_fans[j].id = ((id[j] >> 8) & 0x0f) % 8; + /* Fill the fan zone property. */ + prop_len = OF_getprop(child, "hwctrl-zone", id, sizeof(id)); + for (j = 0; j < i; j++) + sc->sc_fans[j].fan.zone = id[j]; + + /* Finish setting up fan properties */ + for (j = 0; j < i; j++) { + sc->sc_fans[j].dev = sc->sc_dev; + if (sc->sc_fans[j].type == FCU_FAN_RPM) { + sc->sc_fans[j].fan.min_rpm = 4800 >> fcu_rpm_shift; + sc->sc_fans[j].fan.max_rpm = 56000 >> fcu_rpm_shift; + sc->sc_fans[j].setpoint = + fcu_fan_get_rpm(&sc->sc_fans[j]); + sc->sc_fans[j].fan.read = + (int (*)(struct pmac_fan *))(fcu_fan_get_rpm); + sc->sc_fans[j].fan.set = + (int (*)(struct pmac_fan *, int))(fcu_fan_set_rpm); + } else { + sc->sc_fans[j].fan.min_rpm = 40; /* Percent */ + sc->sc_fans[j].fan.max_rpm = 100; + sc->sc_fans[j].fan.read = NULL; + sc->sc_fans[j].fan.set = + (int (*)(struct pmac_fan *, int))(fcu_fan_set_pwm); + } + sc->sc_fans[j].fan.default_rpm = sc->sc_fans[j].fan.max_rpm; + } + return (i); } @@ -478,7 +508,7 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) sc = device_get_softc(fcu); fan = &sc->sc_fans[arg2 & 0x00ff]; if (fan->type == FCU_FAN_RPM) { - fcu_fan_get_rpm(fcu, fan, &rpm); + rpm = fcu_fan_get_rpm(fan); error = sysctl_handle_int(oidp, &rpm, 0, req); } else { fcu_fan_get_pwm(fcu, fan, &pwm, &rpm); @@ -504,9 +534,9 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) return (error); if (fan->type == FCU_FAN_RPM) - return (fcu_fan_set_rpm(fcu, fan, rpm)); + return (fcu_fan_set_rpm(fan, rpm)); else - return (fcu_fan_set_pwm(fcu, fan, pwm)); + return (fcu_fan_set_pwm(fan, pwm)); } static void @@ -543,39 +573,36 @@ fcu_attach_fans(device_t dev) /* Now we can fill the properties into the allocated struct. */ sc->sc_nfans = fcu_fill_fan_prop(dev); + /* Register fans with pmac_thermal */ + for (i = 0; i < sc->sc_nfans; i++) + pmac_thermal_fan_register(&sc->sc_fans[i].fan); + /* Add sysctls for the fans. */ for (i = 0; i < sc->sc_nfans; i++) { - for (j = 0; j < strlen(sc->sc_fans[i].location); j++) { - sysctl_name[j] = tolower(sc->sc_fans[i].location[j]); + for (j = 0; j < strlen(sc->sc_fans[i].fan.name); j++) { + sysctl_name[j] = tolower(sc->sc_fans[i].fan.name[j]); if (isspace(sysctl_name[j])) sysctl_name[j] = '_'; } sysctl_name[j] = 0; if (sc->sc_fans[i].type == FCU_FAN_RPM) { - sc->sc_fans[i].min = 2400 >> fcu_rpm_shift; - sc->sc_fans[i].max = 56000 >> fcu_rpm_shift; - fcu_fan_get_rpm(dev, &sc->sc_fans[i], - &sc->sc_fans[i].setpoint); - oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid), OID_AUTO, sysctl_name, CTLFLAG_RD, 0, "Fan Information"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minrpm", CTLTYPE_INT | CTLFLAG_RD, - &(sc->sc_fans[i].min), sizeof(cell_t), - "Minimum allowed RPM"); + &(sc->sc_fans[i].fan.min_rpm), + sizeof(int), "Minimum allowed RPM"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm", CTLTYPE_INT | CTLFLAG_RD, - &(sc->sc_fans[i].max), sizeof(cell_t), - "Maximum allowed RPM"); + &(sc->sc_fans[i].fan.max_rpm), + sizeof(int), "Maximum allowed RPM"); /* I use i to pass the fan id. */ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "rpm", CTLTYPE_INT | CTLFLAG_RW, dev, i, fcu_fanrpm_sysctl, "I", "Fan RPM"); } else { - sc->sc_fans[i].min = 30; - sc->sc_fans[i].max = 100; fcu_fan_get_pwm(dev, &sc->sc_fans[i], &sc->sc_fans[i].setpoint, &sc->sc_fans[i].rpm); @@ -585,12 +612,12 @@ fcu_attach_fans(device_t dev) CTLFLAG_RD, 0, "Fan Information"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minpwm", CTLTYPE_INT | CTLFLAG_RD, - &(sc->sc_fans[i].min), sizeof(cell_t), - "Minimum allowed PWM in %"); + &(sc->sc_fans[i].fan.min_rpm), + sizeof(int), "Minimum allowed PWM in %"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxpwm", CTLTYPE_INT | CTLFLAG_RD, - &(sc->sc_fans[i].max), sizeof(cell_t), - "Maximum allowed PWM in %"); + &(sc->sc_fans[i].fan.max_rpm), + sizeof(int), "Maximum allowed PWM in %"); /* I use i to pass the fan id or'ed with the type * of info I want to display/modify. */ @@ -610,7 +637,7 @@ fcu_attach_fans(device_t dev) device_printf(dev, "Fans\n"); for (i = 0; i < sc->sc_nfans; i++) { device_printf(dev, "Location: %s type: %d ID: %d " - "RPM: %d\n", sc->sc_fans[i].location, + "RPM: %d\n", sc->sc_fans[i].fan.name, sc->sc_fans[i].type, sc->sc_fans[i].id, (sc->sc_fans[i].type == FCU_FAN_RPM) ? sc->sc_fans[i].setpoint : -- 2.45.2