Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 May 2011 18:35:58 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r222458 - in head/sys: dev/iicbus powerpc/powermac
Message-ID:  <201105291835.p4TIZw50041673@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Sun May 29 18:35:57 2011
New Revision: 222458
URL: http://svn.freebsd.org/changeset/base/222458

Log:
  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.

Modified:
  head/sys/dev/iicbus/ad7417.c
  head/sys/dev/iicbus/ds1775.c
  head/sys/dev/iicbus/max6690.c
  head/sys/powerpc/powermac/fcu.c

Modified: head/sys/dev/iicbus/ad7417.c
==============================================================================
--- head/sys/dev/iicbus/ad7417.c	Sun May 29 18:33:13 2011	(r222457)
+++ head/sys/dev/iicbus/ad7417.c	Sun May 29 18:35:57 2011	(r222458)
@@ -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, u
 			 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 ad
 }
 
 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);
 }

Modified: head/sys/dev/iicbus/ds1775.c
==============================================================================
--- head/sys/dev/iicbus/ds1775.c	Sun May 29 18:33:13 2011	(r222457)
+++ head/sys/dev/iicbus/ds1775.c	Sun May 29 18:35:57 2011	(r222458)
@@ -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 
 	/* 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);
 

Modified: head/sys/dev/iicbus/max6690.c
==============================================================================
--- head/sys/dev/iicbus/max6690.c	Sun May 29 18:33:13 2011	(r222457)
+++ head/sys/dev/iicbus/max6690.c	Sun May 29 18:35:57 2011	(r222458)
@@ -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
 	/* 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_ARG
 	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;
 

Modified: head/sys/powerpc/powermac/fcu.c
==============================================================================
--- head/sys/powerpc/powermac/fcu.c	Sun May 29 18:33:13 2011	(r222457)
+++ head/sys/powerpc/powermac/fcu.c	Sun May 29 18:35:57 2011	(r222458)
@@ -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
 }
 
 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
 			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 :



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105291835.p4TIZw50041673>