Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Jan 2011 21:18:29 +0000 (UTC)
From:      Andreas Tobler <andreast@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r217286 - head/sys/powerpc/powermac
Message-ID:  <201101112118.p0BLITne036045@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andreast
Date: Tue Jan 11 21:18:29 2011
New Revision: 217286
URL: http://svn.freebsd.org/changeset/base/217286

Log:
  Add new functions, fcu_fan_set_pwm and fcu_fan_get_pwm, to set and get
  the pwm values. We can now set the fan's speed of a PWM controlled fan
  with % numbers between 30 and 100 % instead of trying to model a
  % number based on rpm.
  The fcu chip offers both, the dutycycle and the rpm value of the PWM
  controlled fans. I added the rpm value to the list of information
  available via sysctl(8).
  
  Tested by: Paul Mather <paul at gromit dlib vt edu>
  
  Approved by: nwhitehorn (mentor)

Modified:
  head/sys/powerpc/powermac/fcu.c

Modified: head/sys/powerpc/powermac/fcu.c
==============================================================================
--- head/sys/powerpc/powermac/fcu.c	Tue Jan 11 21:05:21 2011	(r217285)
+++ head/sys/powerpc/powermac/fcu.c	Tue Jan 11 21:18:29 2011	(r217286)
@@ -62,19 +62,20 @@ __FBSDID("$FreeBSD$");
 #define FCU_PWM_FAIL      0x2b
 #define FCU_PWM_AVAILABLE 0x2c
 #define FCU_PWM_ACTIVE    0x2d
-#define FCU_PWM_READ(x)   0x31 + (x) * 2
-#define FCU_PWM_SET(x)    0x30 + (x) * 2
+#define FCU_PWM_RPM(x)    0x31 + (x) * 2 /* Get RPM. */
+#define FCU_PWM_SGET(x)   0x30 + (x) * 2 /* Set or get PWM. */
 
 struct fcu_fan {
 	int     id;
-	cell_t	min_rpm;
-	cell_t	max_rpm;
+	cell_t	min;
+	cell_t	max;
 	char	location[32];
 	enum {
 		FCU_FAN_RPM,
 		FCU_FAN_PWM
 	} type;
 	int     setpoint;
+	int     rpm;
 };
 
 struct fcu_softc {
@@ -85,6 +86,14 @@ struct fcu_softc {
 	int			sc_nfans;
 };
 
+/* We can read the PWM and the RPM from a PWM controlled fan.
+ * Offer both values via sysctl.
+ */
+enum {
+	FCU_PWM_SYSCTL_PWM   = 1 << 8,
+	FCU_PWM_SYSCTL_RPM   = 2 << 8
+};
+
 static int fcu_rpm_shift;
 
 /* Regular bus attachment functions */
@@ -96,6 +105,9 @@ 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_get_pwm(device_t dev, struct fcu_fan *fan, int *pwm,
+			    int *rpm);
 static int  fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS);
 static void fcu_start(void *xdev);
 static int  fcu_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buf,
@@ -246,34 +258,21 @@ fcu_fan_set_rpm(device_t dev, struct fcu
 	sc = device_get_softc(dev);
 
 	/* Clamp to allowed range */
-	rpm = max(fan->min_rpm, rpm);
-	rpm = min(fan->max_rpm, rpm);
+	rpm = max(fan->min, rpm);
+	rpm = min(fan->max, rpm);
 
 	if (fan->type == FCU_FAN_RPM) {
 		reg = FCU_RPM_SET(fan->id);
 		fan->setpoint = rpm;
-	} else if (fan->type == FCU_FAN_PWM) {
-		reg = FCU_PWM_SET(fan->id);
-		if (rpm > 3500)
-			rpm = 3500;
-		if (rpm < 500)
-			rpm = 500;
-		fan->setpoint = rpm;
-		/* PWM 30: 550 rpm, PWM 255: 3400 rpm.  */
-		rpm = (rpm * 255) / 3500;
 	} else {
 		device_printf(dev, "Unknown fan type: %d\n", fan->type);
 		return (EIO);
 	}
 
-	if (fan->type == FCU_FAN_RPM) {
-		buf[0] = rpm >> (8 - fcu_rpm_shift);
-		buf[1] = rpm << fcu_rpm_shift;
-		fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 2);
-	} else {
-		buf[0] = rpm;
-		fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 1);
-	}
+	buf[0] = rpm >> (8 - fcu_rpm_shift);
+	buf[1] = rpm << fcu_rpm_shift;
+
+	fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 2);
 
 	return (0);
 }
@@ -313,7 +312,63 @@ fcu_fan_get_rpm(device_t dev, struct fcu
 			return (ENXIO);
 		}
 		reg = FCU_RPM_READ(fan->id);
-	} else if (fan->type == FCU_FAN_PWM) {
+
+	} else {
+		device_printf(dev, "Unknown fan type: %d\n", fan->type);
+		return (EIO);
+	}
+
+	/* 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;
+
+	return (0);
+}
+
+static int
+fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm)
+{
+	uint8_t reg;
+	struct fcu_softc *sc;
+	uint8_t buf[2];
+
+	sc = device_get_softc(dev);
+
+	/* Clamp to allowed range */
+	pwm = max(fan->min, pwm);
+	pwm = min(fan->max, pwm);
+
+	if (fan->type == FCU_FAN_PWM) {
+		reg = FCU_PWM_SGET(fan->id);
+		if (pwm > 100)
+			pwm = 100;
+		if (pwm < 30)
+			pwm = 30;
+		fan->setpoint = pwm;
+	} else {
+		device_printf(dev, "Unknown fan type: %d\n", fan->type);
+		return (EIO);
+	}
+
+	buf[0] = (pwm * 2550) / 1000;
+
+	fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 1);
+
+	return (0);
+}
+
+static int
+fcu_fan_get_pwm(device_t dev, struct fcu_fan *fan, int *pwm, int *rpm)
+{
+	uint8_t reg;
+	struct fcu_softc *sc;
+	uint8_t buf[2];
+	uint8_t active = 0, avail = 0, fail = 0;
+
+	sc = device_get_softc(dev);
+
+	if (fan->type == FCU_FAN_PWM) {
 		/* Check if the fan is available. */
 		reg = FCU_PWM_AVAILABLE;
 		fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail);
@@ -337,16 +392,21 @@ fcu_fan_get_rpm(device_t dev, struct fcu
 				      fan->id);
 			return (ENXIO);
 		}
-		reg = FCU_PWM_READ(fan->id);
+		reg = FCU_PWM_SGET(fan->id);
 	} else {
 		device_printf(dev, "Unknown fan type: %d\n", fan->type);
 		return (EIO);
 	}
 
-	/* It seems that we can read the fans rpm. */
-	fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buff);
+	/* It seems that we can read the fans pwm. */
+	fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buf);
 
-	*rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift;
+	*pwm = (buf[0] * 1000) / 2550;
+
+	/* Now read the rpm. */
+	reg = FCU_PWM_RPM(fan->id);
+	fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buf);
+	*rpm = (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
 
 	return (0);
 }
@@ -412,18 +472,41 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
 	device_t fcu;
 	struct fcu_softc *sc;
 	struct fcu_fan *fan;
-	int rpm = 0, error;
+	int rpm = 0, pwm = 0, error;
 
 	fcu = arg1;
 	sc = device_get_softc(fcu);
-	fan = &sc->sc_fans[arg2];
-	fcu_fan_get_rpm(fcu, fan, &rpm);
-	error = sysctl_handle_int(oidp, &rpm, 0, req);
+	fan = &sc->sc_fans[arg2 & 0x00ff];
+	if (fan->type == FCU_FAN_RPM) {
+		fcu_fan_get_rpm(fcu, fan, &rpm);
+		error = sysctl_handle_int(oidp, &rpm, 0, req);
+	} else {
+		fcu_fan_get_pwm(fcu, fan, &pwm, &rpm);
+
+		switch (arg2 & 0xff00) {
+		case FCU_PWM_SYSCTL_PWM:
+			error = sysctl_handle_int(oidp, &pwm, 0, req);
+			break;
+		case FCU_PWM_SYSCTL_RPM:
+			error = sysctl_handle_int(oidp, &rpm, 0, req);
+			break;
+		default:
+			/* This should never happen */
+			error = -1;
+		};
+	}
+
+	/* We can only read the RPM from a PWM controlled fan, so return. */
+	if ((arg2 & 0xff00) == FCU_PWM_SYSCTL_RPM)
+		return (0);
 
 	if (error || !req->newptr)
 		return (error);
 
-	return (fcu_fan_set_rpm(fcu, fan, rpm));
+	if (fan->type == FCU_FAN_RPM)
+		return (fcu_fan_set_rpm(fcu, fan, rpm));
+	else
+		return (fcu_fan_set_pwm(fcu, fan, pwm));
 }
 
 static void
@@ -432,7 +515,6 @@ fcu_attach_fans(device_t dev)
 	struct fcu_softc *sc;
 	struct sysctl_oid *oid, *fanroot_oid;
 	struct sysctl_ctx_list *ctx;
-	phandle_t child;
 	char sysctl_name[32];
 	int i, j;
 
@@ -440,8 +522,6 @@ fcu_attach_fans(device_t dev)
 
 	sc->sc_nfans = 0;
 
-	child = ofw_bus_get_node(dev);
-
 	/* Count the actual number of fans. */
 	sc->sc_nfans = fcu_fill_fan_prop(dev);
 
@@ -472,35 +552,69 @@ fcu_attach_fans(device_t dev)
 		}
 		sysctl_name[j] = 0;
 
-		sc->sc_fans[i].min_rpm = 2400 >> fcu_rpm_shift;
-		sc->sc_fans[i].max_rpm = 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_rpm), sizeof(cell_t),
-			       "Minimum allowed RPM");
-		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm",
-			       CTLTYPE_INT | CTLFLAG_RD,
-			       &(sc->sc_fans[i].max_rpm), sizeof(cell_t),
-			       "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");
+		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");
+			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");
+			/* 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);
+
+			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,
+				       "minpwm", CTLTYPE_INT | CTLFLAG_RD,
+				       &(sc->sc_fans[i].min), sizeof(cell_t),
+				       "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 %");
+			/* I use i to pass the fan id or'ed with the type
+			 * of info I want to display/modify.
+			 */
+			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
+					"pwm", CTLTYPE_INT | CTLFLAG_RW, dev,
+					FCU_PWM_SYSCTL_PWM | i,
+					fcu_fanrpm_sysctl, "I", "Fan PWM in %");
+			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
+					"rpm", CTLTYPE_INT | CTLFLAG_RD, dev,
+					FCU_PWM_SYSCTL_RPM | i,
+					fcu_fanrpm_sysctl, "I", "Fan RPM");
+		}
 	}
 
 	/* Dump fan location, type & RPM. */
 	if (bootverbose) {
 		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,
+			device_printf(dev, "Location: %s type: %d ID: %d "
+				      "RPM: %d\n", sc->sc_fans[i].location,
 				      sc->sc_fans[i].type, sc->sc_fans[i].id,
-				      sc->sc_fans[i].setpoint);
+				      (sc->sc_fans[i].type == FCU_FAN_RPM) ?
+				      sc->sc_fans[i].setpoint :
+				      sc->sc_fans[i].rpm );
 	    }
 	}
 }



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