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.
This commit is contained in:
Nathan Whitehorn 2011-05-29 18:35:57 +00:00
parent 3204c8e596
commit 815d7d92c1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=222458
4 changed files with 264 additions and 142 deletions

View file

@ -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(dev);
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(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);
value = sens->therm.read(&sens->therm);
if (value < 0)
return (ENXIO);
temp = value;
error = sysctl_handle_int(oidp, &temp, 0, req);
error = sysctl_handle_int(oidp, &value, 0, req);
return (error);
}

View file

@ -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);

View file

@ -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;

View file

@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <powerpc/powermac/powermac_thermal.h>
/* 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 :