Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 28 May 2011 13:46:41 -0400
From:      Justin Hibbits <jrh29@alumni.cwru.edu>
To:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>
Subject:   CFT: G4 MDD fan driver take 2
Message-ID:  <28099850-93EB-48CD-A186-8A1DAE2D7C8C@alumni.cwru.edu>

next in thread | raw e-mail | index | archive | help

--Apple-Mail-8--267396345
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed;
	delsp=yes
Content-Transfer-Encoding: 7bit

Some slight modifications to my driver posted January.  I'd like for  
someone to get this in before the 9.0 freeze, so please test and  
comment.  Someone can style(9) it, too, if they notice any problems.

I hope the list doesn't eat my patch this time.

- Justin

--Apple-Mail-8--267396345
Content-Disposition: attachment;
	filename=windtunnel.patch
Content-Type: application/octet-stream; x-unix-mode=0644;
	name="windtunnel.patch"
Content-Transfer-Encoding: 7bit

Index: sys/conf/files.powerpc
===================================================================
--- sys/conf/files.powerpc	(revision 221779)
+++ sys/conf/files.powerpc	(working copy)
@@ -143,6 +143,7 @@
 powerpc/powermac/cpcht.c	optional	powermac pci
 powerpc/powermac/dbdma.c	optional	powermac pci
 powerpc/powermac/fcu.c		optional	powermac fcu
+powerpc/powermac/windtunnel.c		optional	powermac windtunnel
 powerpc/powermac/grackle.c	optional	powermac pci
 powerpc/powermac/hrowpic.c	optional	powermac pci
 powerpc/powermac/kiic.c		optional	powermac kiic
Index: sys/powerpc/powermac/windtunnel.c
===================================================================
--- sys/powerpc/powermac/windtunnel.c	(revision 0)
+++ sys/powerpc/powermac/windtunnel.c	(revision 0)
@@ -0,0 +1,306 @@
+/*-
+ * Copyright (c) 2011 Justin Hibbits
+ * Copyright (c) 2010 Andreas Tobler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/callout.h>
+#include <sys/conf.h>
+#include <sys/cpu.h>
+#include <sys/ctype.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/limits.h>
+#include <sys/reboot.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+
+#define ADM1030_FANMGT_INTERVAL	1000	/* ms */
+
+#define ADM1030_FAN_TEMPS_COUNT	15
+
+/* Temperatures read are half-degrees, so don't go any finer than that. */
+#define T(x,y)	(x << 8 | ((y / 5) << 7))
+static int	adm1030_fan_temps[] =
+{
+	T(55, 0),
+	T(57, 0),
+	T(57, 5),
+	T(58, 5),
+	T(59, 0),
+	T(59, 0),
+	T(59, 5),
+	T(59, 5),
+	T(60, 0),
+	T(60, 5),
+	T(61, 0),
+	T(61, 5),
+	T(62, 0),
+	T(62, 0),
+	T(62, 0),
+};
+
+struct adm1030_softc {
+	device_t	sc_dev;
+	struct proc    *sc_management_proc;
+	struct intr_config_hook enum_hook;
+	uint32_t	sc_addr;
+	int		current_speed;
+	phandle_t	sc_thermostat_phandle;
+	device_t	sc_thermostat_dev;
+};
+
+/* Regular bus attachment functions */
+static int	adm1030_probe(device_t);
+static int	adm1030_attach(device_t);
+
+/* Utility functions */
+static void	adm1030_start(void *xdev);
+static int	adm1030_write_byte(device_t dev, uint32_t addr, uint8_t reg, uint8_t buf);
+static int	read_reg(device_t dev, uint32_t addr, uint8_t reg, uint16_t * data);
+static void	adm1030_fan_manage(void *xdev);
+static void	adm1030_manage_fans(device_t fan);
+
+static device_method_t adm1030_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, adm1030_probe),
+	DEVMETHOD(device_attach, adm1030_attach),
+	{0, 0},
+};
+
+static driver_t	adm1030_driver = {
+	"adm1030",
+	adm1030_methods,
+	sizeof(struct adm1030_softc)
+};
+
+static devclass_t adm1030_devclass;
+
+DRIVER_MODULE(adm1030, iicbus, adm1030_driver, adm1030_devclass, 0, 0);
+MALLOC_DEFINE(M_ADM1030, "adm1030", "ADM1030 Sensor Information");
+
+static device_t 
+device_node_from_phandle(phandle_t handle, device_t parent_node)
+{
+	int		children_count;
+	device_t       *child_list;
+	device_t	retval;
+	int		i;
+
+	retval = NULL;
+	if (device_get_children(parent_node, &child_list, &children_count) < 0) {
+		return NULL;
+	}
+	for (i = 0; i < children_count; i++) {
+		if (ofw_bus_get_node(child_list[i]) == handle) {
+			retval = child_list[i];
+			break;
+		}
+	}
+
+	free(child_list, M_TEMP);
+	return retval;
+}
+
+static int
+adm1030_write_byte(device_t dev, uint32_t addr, uint8_t reg, uint8_t byte)
+{
+	unsigned char	buf[4];
+	struct iic_msg	msg[] = {
+		{addr, IIC_M_WR, 0, buf}
+	};
+
+	msg[0].len = 2;
+	buf[0] = reg;
+	buf[1] = byte;
+	if (iicbus_transfer(dev, msg, 1) != 0) {
+		device_printf(dev, "iicbus write failed\n");
+		return (EIO);
+	}
+	return (0);
+}
+
+static int
+read_reg(device_t dev, uint32_t addr, uint8_t reg, uint16_t * data)
+{
+	uint8_t		buf    [4];
+
+	struct iic_msg	msg[2] = {
+		{addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg},
+		{addr, IIC_M_RD, 2, buf},
+	};
+
+	if (iicbus_transfer(dev, msg, 2) != 0) {
+		device_printf(dev, "iicbus read failed\n");
+		return (EIO);
+	}
+	*data = *((uint16_t *) buf);
+
+	return (0);
+}
+
+static int
+adm1030_probe(device_t dev)
+{
+	const char     *name, *compatible;
+	struct adm1030_softc *sc;
+	phandle_t	handle;
+	phandle_t	thermostat;
+
+	name = ofw_bus_get_name(dev);
+	compatible = ofw_bus_get_compat(dev);
+	handle = ofw_bus_get_node(dev);
+
+	if (!name)
+		return (ENXIO);
+
+	if (strcmp(name, "fan") != 0 || strcmp(compatible, "adm1030") != 0)
+		return (ENXIO);
+
+	/* This driver can only be used if there's an associated temp sensor. */
+	if (OF_getprop(handle, "platform-getTemp", &thermostat, sizeof(thermostat)) < 0)
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_addr = iicbus_get_addr(dev);
+	sc->sc_thermostat_phandle = thermostat;
+
+	device_set_desc(dev, "G4 MDD Fan driver");
+
+	return (0);
+}
+
+static int
+adm1030_attach(device_t dev)
+{
+	struct adm1030_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	sc->enum_hook.ich_func = adm1030_start;
+	sc->enum_hook.ich_arg = dev;
+
+	/*
+	 * We have to wait until interrupts are enabled. I2C read and write
+	 * only works if the interrupts are available. The unin/i2c is
+	 * controlled by the htpic on unin. But this is not the master. The
+	 * openpic on mac-io is controlling the htpic. This one gets attached
+	 * after the mac-io probing and then the interrupts will be
+	 * available.
+	 */
+
+	if (config_intrhook_establish(&sc->enum_hook) != 0)
+		return (ENOMEM);
+
+	return (0);
+}
+
+static void
+adm1030_start(void *xdev)
+{
+	struct adm1030_softc *sc;
+
+	device_t	dev = (device_t) xdev;
+
+	sc = device_get_softc(dev);
+
+	/* Start the adm1030 device. */
+	adm1030_write_byte(sc->sc_dev, sc->sc_addr, 0x1, 0x1);
+	adm1030_write_byte(sc->sc_dev, sc->sc_addr, 0x0, 0x95);
+	adm1030_write_byte(sc->sc_dev, sc->sc_addr, 0x23, 0x91);
+
+	config_intrhook_disestablish(&sc->enum_hook);
+
+	sc->sc_thermostat_dev = device_node_from_phandle(sc->sc_thermostat_phandle, device_get_parent(dev));
+	sc->current_speed = 0;
+
+	kproc_create(adm1030_fan_manage, dev, &sc->sc_management_proc,
+		     RFHIGHPID, 0, "adm1030_fan");
+}
+
+static void
+adm1030_fan_manage(void *xdev)
+{
+	device_t	adm1030_dev = xdev;
+
+	while (1) {
+		adm1030_manage_fans(adm1030_dev);
+		pause("adm1030", ADM1030_FANMGT_INTERVAL * hz / 1000);
+	}
+}
+
+static int 
+thermostat_get_temp(device_t dev)
+{
+	uint16_t	temp = 0;
+	struct iicbus_ivar *devi = IICBUS_IVAR(dev);
+
+	if (read_reg(dev, devi->addr, 0, &temp) < 0)
+		return -1;
+
+	return temp;
+}
+
+static void 
+adm1030_manage_fans(device_t fan)
+{
+	int		temp;
+	struct adm1030_softc *sc;
+	uint8_t		fan_idx;
+
+	sc = device_get_softc(fan);
+
+	temp = thermostat_get_temp(sc->sc_thermostat_dev);
+	if (temp < 0)
+		return;
+
+	fan_idx = sc->current_speed;
+
+	// Only adjust the fan one index per second.
+	if (temp < adm1030_fan_temps[fan_idx] && fan_idx > 0) {
+		fan_idx--;
+	} else if (fan_idx < 15) {
+		fan_idx++;
+	}
+	sc->current_speed = fan_idx;
+	adm1030_write_byte(fan, sc->sc_addr, 0x22, fan_idx);
+}

--Apple-Mail-8--267396345
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed
Content-Transfer-Encoding: 7bit



--Apple-Mail-8--267396345--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?28099850-93EB-48CD-A186-8A1DAE2D7C8C>