Module Name: src
Committed By: martin
Date: Sun Feb 28 11:49:44 UTC 2010
Modified Files:
src/sys/arch/sparc64/conf: GENERIC SCHIZO files.sparc64
Added Files:
src/sys/arch/sparc64/dev: pcf8591_envctrl.c pcfiic_ebus.c tda.c
Removed Files:
src/sys/arch/sparc64/dev: envctrl.c envctrlreg.h
Log Message:
Remove the envctrl driver, it is superseeded by the more general pcfiic @
ebus. Add the SB1000/SB2000 fan controll driver (tda). From OpenBSD.
Move config files over to direct configuration of i2c devices.
To generate a diff of this commit:
cvs rdiff -u -r1.117 -r1.118 src/sys/arch/sparc64/conf/GENERIC
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/sparc64/conf/SCHIZO
cvs rdiff -u -r1.124 -r1.125 src/sys/arch/sparc64/conf/files.sparc64
cvs rdiff -u -r1.11 -r0 src/sys/arch/sparc64/dev/envctrl.c
cvs rdiff -u -r1.5 -r0 src/sys/arch/sparc64/dev/envctrlreg.h
cvs rdiff -u -r0 -r1.1 src/sys/arch/sparc64/dev/pcf8591_envctrl.c \
src/sys/arch/sparc64/dev/pcfiic_ebus.c src/sys/arch/sparc64/dev/tda.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/sparc64/conf/GENERIC
diff -u src/sys/arch/sparc64/conf/GENERIC:1.117 src/sys/arch/sparc64/conf/GENERIC:1.118
--- src/sys/arch/sparc64/conf/GENERIC:1.117 Sat Feb 13 08:54:58 2010
+++ src/sys/arch/sparc64/conf/GENERIC Sun Feb 28 11:49:44 2010
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.117 2010/02/13 08:54:58 mrg Exp $
+# $NetBSD: GENERIC,v 1.118 2010/02/28 11:49:44 martin Exp $
#
# GENERIC machine description file
#
@@ -22,7 +22,7 @@
options INCLUDE_CONFIG_FILE # embed config file in kernel binary
-#ident "GENERIC-$Revision: 1.117 $"
+#ident "GENERIC-$Revision: 1.118 $"
maxusers 64
@@ -906,17 +906,20 @@
#### Other device configuration
psm* at ebus? # Ultrabook IIi microcontroller
-envctrl* at ebus? # Ultra E450 environmental monitoring
+pcfiic* at ebus? # various environmental monitoring
+iic* at pcfiic?
lom* at ebus? # LOMlite lights out management
# Netra X1 / T1 style environmental monitoring
alipm* at pci?
iic* at alipm?
-spdmem* at iic? addr 0x54
-spdmem* at iic? addr 0x55
-spdmem* at iic? addr 0x56
-spdmem* at iic? addr 0x57
-admtemp* at iic? addr 0x18
+
+# I2C devices
+spdmem* at iic? addr?
+admtemp* at iic? addr?
+ecadc* at iic? addr? # envctrl/envctrltwo on E250/E450
+lmtemp* at iic? addr?
+tda* at iic? addr? # fan controll on SB1000/2000
### Other pseudo-devices
Index: src/sys/arch/sparc64/conf/SCHIZO
diff -u src/sys/arch/sparc64/conf/SCHIZO:1.6 src/sys/arch/sparc64/conf/SCHIZO:1.7
--- src/sys/arch/sparc64/conf/SCHIZO:1.6 Sat Feb 13 22:24:09 2010
+++ src/sys/arch/sparc64/conf/SCHIZO Sun Feb 28 11:49:44 2010
@@ -1,4 +1,4 @@
-# $NetBSD: SCHIZO,v 1.6 2010/02/13 22:24:09 mrg Exp $
+# $NetBSD: SCHIZO,v 1.7 2010/02/28 11:49:44 martin Exp $
#
# GENERIC with schizo support enabled, with the annoying schizo interupt
# option
@@ -7,7 +7,7 @@
include "arch/sparc64/conf/GENERIC.MP"
#include "arch/sparc64/conf/GENERIC"
-#ident "SCHIZO.$Revision: 1.6 $"
+#ident "SCHIZO.$Revision: 1.7 $"
options CHEETAH
@@ -20,6 +20,3 @@
# this crashes when attaching.
#no machfb
-
-# this matches when it isn't present. ugh.
-no admtemp
Index: src/sys/arch/sparc64/conf/files.sparc64
diff -u src/sys/arch/sparc64/conf/files.sparc64:1.124 src/sys/arch/sparc64/conf/files.sparc64:1.125
--- src/sys/arch/sparc64/conf/files.sparc64:1.124 Mon Feb 22 22:28:58 2010
+++ src/sys/arch/sparc64/conf/files.sparc64 Sun Feb 28 11:49:44 2010
@@ -1,4 +1,4 @@
-# $NetBSD: files.sparc64,v 1.124 2010/02/22 22:28:58 mrg Exp $
+# $NetBSD: files.sparc64,v 1.125 2010/02/28 11:49:44 martin Exp $
# @(#)files.sparc64 8.1 (Berkeley) 7/19/93
# sparc64-specific configuration info
@@ -68,9 +68,17 @@
attach power at sbus, ebus
file arch/sparc64/dev/power.c power
-device envctrl: sysmon_envsys, pcf8584, i2cbus
-attach envctrl at ebus
-file arch/sparc64/dev/envctrl.c envctrl
+device tda
+attach tda at iic
+file arch/sparc64/dev/tda.c tda
+
+device pcfiic: sysmon_envsys, pcf8584, i2cbus
+attach pcfiic at ebus
+file arch/sparc64/dev/pcfiic_ebus.c pcfiic
+
+device ecadc
+attach ecadc at iic
+file arch/sparc64/dev/pcf8591_envctrl.c
device lom: sysmon_envsys, sysmon_wdog
attach lom at ebus
Added files:
Index: src/sys/arch/sparc64/dev/pcf8591_envctrl.c
diff -u /dev/null src/sys/arch/sparc64/dev/pcf8591_envctrl.c:1.1
--- /dev/null Sun Feb 28 11:49:44 2010
+++ src/sys/arch/sparc64/dev/pcf8591_envctrl.c Sun Feb 28 11:49:44 2010
@@ -0,0 +1,255 @@
+/* $NetBSD: pcf8591_envctrl.c,v 1.1 2010/02/28 11:49:44 martin Exp $ */
+/* $OpenBSD: pcf8591_envctrl.c,v 1.6 2007/10/25 21:17:20 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2006 Damien Miller <[email protected]>
+ * Copyright (c) 2007 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/i2c/i2cvar.h>
+
+#define PCF8591_CHANNELS 4
+
+#define PCF8591_CTRL_CH0 0x00
+#define PCF8591_CTRL_CH1 0x01
+#define PCF8591_CTRL_CH2 0x02
+#define PCF8591_CTRL_CH3 0x03
+#define PCF8591_CTRL_AUTOINC 0x04
+#define PCF8591_CTRL_OSCILLATOR 0x40
+
+struct ecadc_channel {
+ u_int chan_num;
+ envsys_data_t chan_sensor;
+ u_char *chan_xlate;
+ int64_t chan_factor;
+ int64_t chan_min;
+ int64_t chan_warn;
+ int64_t chan_crit;
+};
+
+struct ecadc_softc {
+ device_t sc_dev;
+ i2c_tag_t sc_tag;
+ i2c_addr_t sc_addr;
+ u_char sc_ps_xlate[256];
+ u_char sc_cpu_xlate[256];
+ u_int sc_nchan;
+ struct ecadc_channel sc_channels[PCF8591_CHANNELS];
+ struct sysmon_envsys *sc_sme;
+};
+
+static int ecadc_match(device_t, cfdata_t, void *);
+static void ecadc_attach(device_t, device_t, void *);
+static void ecadc_refresh(struct sysmon_envsys *, envsys_data_t *);
+static void ecadc_get_limits(struct sysmon_envsys *, envsys_data_t *,
+ sysmon_envsys_lim_t *, uint32_t *);
+
+CFATTACH_DECL_NEW(ecadc, sizeof(struct ecadc_softc),
+ ecadc_match, ecadc_attach, NULL, NULL);
+
+static const char * ecadc_compats[] = {
+ "ecadc",
+ NULL
+};
+
+static int
+ecadc_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+
+ if (iic_compat_match(ia, ecadc_compats))
+ return 1;
+
+ return 0;
+}
+
+static void
+ecadc_attach(device_t parent, device_t self, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+ struct ecadc_softc *sc = device_private(self);
+ u_char term[256];
+ u_char *cp, *desc;
+ int64_t minv, warnv, crit, num, den;
+ u_int8_t junk[PCF8591_CHANNELS + 1];
+ envsys_data_t *sensor;
+ int len, error, addr, chan, node = (int)ia->ia_cookie;
+ u_int i;
+
+ sc->sc_dev = self;
+ if ((len = OF_getprop(node, "thermisters", term,
+ sizeof(term))) < 0) {
+ aprint_error(": couldn't find \"thermisters\" property\n");
+ return;
+ }
+
+ if (OF_getprop(node, "cpu-temp-factors", &sc->sc_cpu_xlate[2],
+ sizeof(sc->sc_cpu_xlate) - 2) < 0) {
+ aprint_error(": couldn't find \"cpu-temp-factors\" property\n");
+ return;
+ }
+ sc->sc_cpu_xlate[0] = sc->sc_cpu_xlate[1] = sc->sc_cpu_xlate[2];
+
+ /* Only the Sun Enterprise 450 has these. */
+ OF_getprop(node, "ps-temp-factors", &sc->sc_ps_xlate[2],
+ sizeof(sc->sc_ps_xlate) - 2);
+ sc->sc_ps_xlate[0] = sc->sc_ps_xlate[1] = sc->sc_ps_xlate[2];
+
+ cp = term;
+ while (cp < term + len) {
+ addr = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ chan = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ minv = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ warnv = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ crit = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ num = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ den = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4;
+ desc = cp;
+ while (cp < term + len && *cp++);
+
+ if (addr != (ia->ia_addr << 1))
+ continue;
+
+ if (num == 0 || den == 0)
+ num = den = 1;
+
+ sc->sc_channels[sc->sc_nchan].chan_num = chan;
+
+ sensor = &sc->sc_channels[sc->sc_nchan].chan_sensor;
+ sensor->units = ENVSYS_STEMP;
+ strlcpy(sensor->desc, desc, sizeof(sensor->desc));
+
+ if (strncmp(desc, "CPU", 3) == 0)
+ sc->sc_channels[sc->sc_nchan].chan_xlate =
+ sc->sc_cpu_xlate;
+ else if (strncmp(desc, "PS", 2) == 0)
+ sc->sc_channels[sc->sc_nchan].chan_xlate =
+ sc->sc_ps_xlate;
+ else
+ sc->sc_channels[sc->sc_nchan].chan_factor =
+ (1000000 * num) / den;
+ sc->sc_channels[sc->sc_nchan].chan_min =
+ 273150000 + 1000000 * minv;
+ sc->sc_channels[sc->sc_nchan].chan_warn =
+ 273150000 + 1000000 * warnv;
+ sc->sc_channels[sc->sc_nchan].chan_crit =
+ 273150000 + 1000000 * crit;
+ sc->sc_nchan++;
+ }
+
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_addr = ia->ia_addr;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+
+ /* Try a read now, so we can fail if it doesn't work */
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+ NULL, 0, junk, sc->sc_nchan + 1, 0)) {
+ aprint_error(": read failed\n");
+ iic_release_bus(sc->sc_tag, 0);
+ return;
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+
+ /* Hook us into the sysmon_envsys subsystem */
+ sc->sc_sme = sysmon_envsys_create();
+ sc->sc_sme->sme_name = device_xname(self);
+ sc->sc_sme->sme_cookie = sc;
+ sc->sc_sme->sme_flags |= ENVSYS_FMONNOTSUPP;
+ sc->sc_sme->sme_refresh = ecadc_refresh;
+ sc->sc_sme->sme_get_limits = ecadc_get_limits;
+
+ /* Initialize sensor data. */
+ for (i = 0; i < sc->sc_nchan; i++)
+ sysmon_envsys_sensor_attach(sc->sc_sme,
+ &sc->sc_channels[i].chan_sensor);
+
+ error = sysmon_envsys_register(sc->sc_sme);
+ if (error) {
+ aprint_error_dev(self, "error %d registering with sysmon\n",
+ error);
+ sysmon_envsys_destroy(sc->sc_sme);
+ return;
+ }
+
+ aprint_naive(": Temp Sensors\n");
+ aprint_normal("%s Temp Sensors\n", ia->ia_name);
+}
+
+static void
+ecadc_refresh(struct sysmon_envsys *sme, envsys_data_t *sensor)
+{
+ struct ecadc_softc *sc = sme->sme_cookie;
+ u_int i;
+ u_int8_t data[PCF8591_CHANNELS + 1];
+ u_int8_t ctrl = PCF8591_CTRL_CH0 | PCF8591_CTRL_AUTOINC |
+ PCF8591_CTRL_OSCILLATOR;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+ if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
+ &ctrl, 1, NULL, 0, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ return;
+ }
+ /* NB: first byte out is stale, so read num_channels + 1 */
+ if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+ NULL, 0, data, PCF8591_CHANNELS + 1, 0)) {
+ iic_release_bus(sc->sc_tag, 0);
+ return;
+ }
+ iic_release_bus(sc->sc_tag, 0);
+
+ /* We only support temperature channels. */
+ for (i = 0; i < sc->sc_nchan; i++) {
+ struct ecadc_channel *chp = &sc->sc_channels[i];
+
+ if (chp->chan_xlate)
+ chp->chan_sensor.value_cur = 273150000 + 1000000 *
+ chp->chan_xlate[data[1 + chp->chan_num]];
+ else
+ chp->chan_sensor.value_cur = 273150000 +
+ chp->chan_factor * data[1 + chp->chan_num];
+
+ chp->chan_sensor.state = ENVSYS_SVALID;
+ chp->chan_sensor.flags &= ~ENVSYS_FNEED_REFRESH;
+ chp->chan_sensor.flags |= ENVSYS_FMONLIMITS;
+ }
+}
+
+static void
+ecadc_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
+ sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+ struct ecadc_softc *sc = sme->sme_cookie;
+ int i;
+
+ for (i = 0; i < sc->sc_nchan; i++) {
+ if (edata != &sc->sc_channels[i].chan_sensor)
+ continue;
+ *props |= PROP_WARNMIN|PROP_WARNMAX|PROP_CRITMAX;
+ limits->sel_warnmin = sc->sc_channels[i].chan_min;
+ limits->sel_warnmax = sc->sc_channels[i].chan_warn;
+ limits->sel_critmax = sc->sc_channels[i].chan_crit;
+ return;
+ }
+}
Index: src/sys/arch/sparc64/dev/pcfiic_ebus.c
diff -u /dev/null src/sys/arch/sparc64/dev/pcfiic_ebus.c:1.1
--- /dev/null Sun Feb 28 11:49:44 2010
+++ src/sys/arch/sparc64/dev/pcfiic_ebus.c Sun Feb 28 11:49:44 2010
@@ -0,0 +1,222 @@
+/* $NetBSD: pcfiic_ebus.c,v 1.1 2010/02/28 11:49:44 martin Exp $ */
+/* $OpenBSD: pcfiic_ebus.c,v 1.13 2008/06/08 03:07:40 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2006 David Gwynne <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Device specific driver for the EBus i2c devices found on some sun4u
+ * systems. On systems not having a boot-bus controller the i2c devices
+ * are PCF8584.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/rwlock.h>
+
+#include <machine/bus.h>
+#include <machine/openfirm.h>
+#include <machine/autoconf.h>
+
+#include <dev/ebus/ebusreg.h>
+#include <dev/ebus/ebusvar.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/ic/pcf8584var.h>
+
+int pcfiic_ebus_match(device_t, struct cfdata *, void *);
+void pcfiic_ebus_attach(device_t, device_t, void *);
+
+struct pcfiic_ebus_softc {
+ struct pcfiic_softc esc_sc;
+
+ int esc_node;
+ void *esc_ih;
+};
+
+CFATTACH_DECL_NEW(pcfiic, sizeof(struct pcfiic_ebus_softc),
+ pcfiic_ebus_match, pcfiic_ebus_attach, NULL, NULL);
+
+static prop_array_t create_dict(device_t);
+static void add_prop(prop_array_t, const char *, const char *, u_int, int);
+static void envctrl_props(prop_array_t, int);
+static void envctrltwo_props(prop_array_t, int);
+
+int
+pcfiic_ebus_match(device_t parent, struct cfdata *match, void *aux)
+{
+ struct ebus_attach_args *ea = aux;
+ char compat[32];
+
+ if (strcmp(ea->ea_name, "SUNW,envctrl") == 0 ||
+ strcmp(ea->ea_name, "SUNW,envctrltwo") == 0)
+ return (1);
+
+ if (strcmp(ea->ea_name, "i2c") != 0)
+ return (0);
+
+ if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
+ return (0);
+
+ if (strcmp(compat, "pcf8584") == 0 ||
+ strcmp(compat, "i2cpcf,8584") == 0 ||
+ strcmp(compat, "SUNW,i2c-pic16f747") == 0 ||
+ strcmp(compat, "SUNW,bbc-i2c") == 0)
+ return (1);
+
+ return (0);
+}
+
+void
+pcfiic_ebus_attach(device_t parent, device_t self, void *aux)
+{
+ struct pcfiic_ebus_softc *esc = device_private(self);
+ struct pcfiic_softc *sc = &esc->esc_sc;
+ struct ebus_attach_args *ea = aux;
+ char compat[32];
+ u_int64_t addr;
+ u_int8_t clock = PCF_CLOCK_12 | PCF_FREQ_90;
+ int swapregs = 0;
+
+ if (ea->ea_nreg < 1 || ea->ea_nreg > 2) {
+ printf(": expected 1 or 2 registers, got %d\n", ea->ea_nreg);
+ return;
+ }
+
+ sc->sc_dev = self;
+ if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) > 0 &&
+ strcmp(compat, "SUNW,bbc-i2c") == 0) {
+ /*
+ * On BBC-based machines, Sun swapped the order of
+ * the registers on their clone pcf, plus they feed
+ * it a non-standard clock.
+ */
+ int clk = prom_getpropint(findroot(), "clock-frequency", 0);
+
+ if (clk < 105000000)
+ clock = PCF_CLOCK_3 | PCF_FREQ_90;
+ else if (clk < 160000000)
+ clock = PCF_CLOCK_4_43 | PCF_FREQ_90;
+ swapregs = 1;
+ }
+
+ if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) {
+ addr = 0xaa;
+ } else if (addr == 0x00 || addr > 0xff) {
+ printf(": invalid address on I2C bus");
+ return;
+ }
+
+ if (bus_space_map(ea->ea_bustag,
+ EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
+ ea->ea_reg[0].size, 0, &sc->sc_ioh) == 0) {
+ sc->sc_iot = ea->ea_bustag;
+ } else {
+ printf(": can't map register space\n");
+ return;
+ }
+
+ if (ea->ea_nreg == 2) {
+ /*
+ * Second register only occurs on BBC-based machines,
+ * and is likely not prom mapped
+ */
+ if (bus_space_map(sc->sc_iot, EBUS_ADDR_FROM_REG(&ea->ea_reg[1]),
+ ea->ea_reg[1].size, 0, &sc->sc_ioh2) != 0) {
+ printf(": can't map 2nd register space\n");
+ return;
+ }
+ sc->sc_master = 1;
+ }
+
+ if (ea->ea_nintr >= 1)
+ esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intr[0],
+ IPL_BIO, pcfiic_intr, sc);
+ else
+ esc->esc_ih = NULL;
+
+
+ if (esc->esc_ih == NULL)
+ sc->sc_poll = 1;
+
+ if (strcmp(ea->ea_name, "SUNW,envctrl") == 0) {
+ envctrl_props(create_dict(self), ea->ea_node);
+ pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0);
+ } else if (strcmp(ea->ea_name, "SUNW,envctrltwo") == 0) {
+ envctrltwo_props(create_dict(self), ea->ea_node);
+ pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0);
+ } else
+ pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs);
+}
+
+static prop_array_t
+create_dict(device_t parent)
+{
+ prop_dictionary_t props = device_properties(parent);
+ prop_array_t cfg = prop_dictionary_get(props, "i2c-child-devices");
+ if (cfg) return cfg;
+ cfg = prop_array_create();
+ prop_dictionary_set(props, "i2c-child-devices", cfg);
+ prop_object_release(cfg);
+ return cfg;
+}
+
+static void
+add_prop(prop_array_t c, const char *name, const char *compat, u_int addr,
+ int node)
+{
+ prop_dictionary_t dev;
+ prop_data_t data;
+
+ dev = prop_dictionary_create();
+ prop_dictionary_set_cstring(dev, "name", name);
+ data = prop_data_create_data(compat, strlen(compat)+1);
+ prop_dictionary_set(dev, "compatible", data);
+ prop_object_release(data);
+ prop_dictionary_set_uint32(dev, "addr", addr);
+ prop_dictionary_set_uint64(dev, "cookie", node);
+ prop_array_add(c, dev);
+ prop_object_release(dev);
+}
+
+static void
+envctrl_props(prop_array_t c, int node)
+{
+ /* Power supply 1 temperature. */
+ add_prop(c, "PSU-1", "ecadc", 0x48, node);
+
+ /* Power supply 2 termperature. */
+ add_prop(c, "PSU-2", "ecadc", 0x49, node);
+
+ /* Power supply 3 tempterature. */
+ add_prop(c, "PSU-3", "ecadc", 0x4a, node);
+
+ /* Ambient tempterature. */
+ add_prop(c, "ambient", "i2c-lm75", 0x4d, node);
+
+ /* CPU temperatures. */
+ add_prop(c, "CPU", "ecadc", 0x4f, node);
+}
+
+static void
+envctrltwo_props(prop_array_t c, int node)
+{
+ add_prop(c, "PSU", "ecadc", 0x4a, node);
+ add_prop(c, "CPU", "ecadc", 0x4f, node);
+}
Index: src/sys/arch/sparc64/dev/tda.c
diff -u /dev/null src/sys/arch/sparc64/dev/tda.c:1.1
--- /dev/null Sun Feb 28 11:49:44 2010
+++ src/sys/arch/sparc64/dev/tda.c Sun Feb 28 11:49:44 2010
@@ -0,0 +1,228 @@
+/* $NetBSD: tda.c,v 1.1 2010/02/28 11:49:44 martin Exp $ */
+/* $OpenBSD: tda.c,v 1.4 2008/02/27 17:25:00 robert Exp $ */
+
+/*
+ * Copyright (c) 2008 Robert Nagy <[email protected]>
+ * Copyright (c) 2008 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/sysmon/sysmon_taskq.h>
+
+#include <machine/autoconf.h>
+#include <machine/openfirm.h>
+
+#include <dev/i2c/i2cvar.h>
+
+/* fan control registers */
+#define TDA_SYSFAN_REG 0xf0
+#define TDA_CPUFAN_REG 0xf2
+#define TDA_PSFAN_REG 0xf4
+
+#define TDA_FANSPEED_MIN 0x0c
+#define TDA_FANSPEED_MAX 0x3f
+
+#define TDA_PSFAN_ON 0x1f
+#define TDA_PSFAN_OFF 0x00
+
+/* Internal and External temperature senor numbers */
+#define SENSOR_TEMP_EXT 0
+#define SENSOR_TEMP_INT 1
+
+#define CPU_TEMP_MAX (67 * 1000000 + 273150000)
+#define CPU_TEMP_MIN (57 * 1000000 + 273150000)
+#define SYS_TEMP_MAX (30 * 1000000 + 273150000)
+#define SYS_TEMP_MIN (20 * 1000000 + 273150000)
+
+struct tda_softc {
+ device_t sc_dev;
+ i2c_tag_t sc_tag;
+ i2c_addr_t sc_addr;
+
+ u_int16_t sc_cfan_speed; /* current CPU fan speed */
+ u_int16_t sc_sfan_speed; /* current SYS fan speed */
+
+ callout_t sc_timer;
+};
+
+int tda_match(struct device *, struct cfdata *, void *);
+void tda_attach(struct device *, struct device *, void *);
+
+void tda_setspeed(struct tda_softc *);
+static void tda_adjust(void *);
+static void tda_timeout(void *);
+
+
+CFATTACH_DECL_NEW(tda, sizeof(struct tda_softc),
+ tda_match, tda_attach, NULL, NULL);
+
+int
+tda_match(struct device *parent, struct cfdata *match, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+ char name[32];
+
+ /* Only attach on the Sun Blade 1000/2000. */
+ if (OF_getprop(findroot(), "name", name, sizeof(name)) <= 0)
+ return (0);
+ if (strcmp(name, "SUNW,Sun-Blade-1000") != 0)
+ return (0);
+
+ /*
+ * No need for "compatible" matching, we know exactly what
+ * firmware calls us.
+ */
+ return strcmp(ia->ia_name, "fan-control") == 0;
+}
+
+void
+tda_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct tda_softc *sc = device_private(self);
+ struct i2c_attach_args *ia = aux;
+
+ sc->sc_dev = self;
+ sc->sc_tag = ia->ia_tag;
+ sc->sc_addr = ia->ia_addr;
+
+ aprint_normal(": %s\n", ia->ia_name);
+
+ /*
+ * Set the fans to maximum speed and save the power levels;
+ * the controller is write-only.
+ */
+ sc->sc_cfan_speed = sc->sc_sfan_speed = (TDA_FANSPEED_MAX+TDA_FANSPEED_MIN)/2;
+ tda_setspeed(sc);
+
+ callout_init(&sc->sc_timer, CALLOUT_MPSAFE);
+ callout_reset(&sc->sc_timer, hz*20, tda_timeout, sc);
+}
+
+static void
+tda_timeout(void *v)
+{
+ struct tda_softc *sc = v;
+
+ sysmon_task_queue_sched(0, tda_adjust, sc);
+ callout_reset(&sc->sc_timer, hz*60, tda_timeout, sc);
+}
+
+void
+tda_setspeed(struct tda_softc *sc)
+{
+ u_int8_t cmd[2];
+
+ if (sc->sc_cfan_speed < TDA_FANSPEED_MIN)
+ sc->sc_cfan_speed = TDA_FANSPEED_MIN;
+ if (sc->sc_sfan_speed < TDA_FANSPEED_MIN)
+ sc->sc_sfan_speed = TDA_FANSPEED_MIN;
+ if (sc->sc_cfan_speed > TDA_FANSPEED_MAX)
+ sc->sc_cfan_speed = TDA_FANSPEED_MAX;
+ if (sc->sc_sfan_speed > TDA_FANSPEED_MAX)
+ sc->sc_sfan_speed = TDA_FANSPEED_MAX;
+
+ iic_acquire_bus(sc->sc_tag, 0);
+
+ cmd[0] = TDA_CPUFAN_REG;
+ cmd[1] = sc->sc_cfan_speed;
+ if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) {
+ aprint_error_dev(sc->sc_dev, "cannot write cpu-fan register\n");
+ iic_release_bus(sc->sc_tag, 0);
+ return;
+ }
+
+ cmd[0] = TDA_SYSFAN_REG;
+ cmd[1] = sc->sc_sfan_speed;
+ if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) {
+ aprint_error_dev(sc->sc_dev, "cannot write system-fan register\n");
+ iic_release_bus(sc->sc_tag, 0);
+ return;
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+
+ aprint_debug_dev(sc->sc_dev, "changed fan speed to cpu=%d system=%d\n",
+ sc->sc_cfan_speed, sc->sc_sfan_speed);
+}
+
+static bool
+is_cpu_sensor(const envsys_data_t *edata)
+{
+ if (edata->units != ENVSYS_STEMP)
+ return false;
+ return strcmp(edata->desc, "external") == 0;
+}
+
+static bool
+is_system_sensor(const envsys_data_t *edata)
+{
+ if (edata->units != ENVSYS_STEMP)
+ return false;
+ return strcmp(edata->desc, "internal") == 0;
+}
+
+static void
+tda_adjust(void *v)
+{
+ struct tda_softc *sc = v;
+ u_int64_t ctemp, stemp;
+ u_int16_t cspeed, sspeed;
+
+ /* Default to running the fans at maximum speed. */
+ sspeed = cspeed = TDA_FANSPEED_MAX;
+
+ /* fetch maximum current temperature */
+ ctemp = sysmon_envsys_get_max_value(is_cpu_sensor, true);
+ stemp = sysmon_envsys_get_max_value(is_system_sensor, true);
+
+ /* the predicates for selecting sensors must have gone wrong */
+ if (ctemp == 0 || stemp == 0) {
+ aprint_error_dev(sc->sc_dev, "skipping temp adjustment"
+ " - no sensor values\n");
+ return;
+ }
+
+ aprint_debug_dev(sc->sc_dev, "current temperature: cpu %lu system %lu\n",
+ ctemp, stemp);
+
+ if (ctemp < CPU_TEMP_MIN)
+ cspeed = TDA_FANSPEED_MIN;
+ else if (ctemp < CPU_TEMP_MAX)
+ cspeed = TDA_FANSPEED_MIN +
+ (ctemp - CPU_TEMP_MIN) *
+ (TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) /
+ (CPU_TEMP_MAX - CPU_TEMP_MIN);
+
+ if (stemp < SYS_TEMP_MIN)
+ sspeed = TDA_FANSPEED_MIN;
+ else if (stemp < SYS_TEMP_MAX)
+ sc->sc_sfan_speed = TDA_FANSPEED_MIN +
+ (stemp - SYS_TEMP_MIN) *
+ (TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) /
+ (SYS_TEMP_MAX - SYS_TEMP_MIN);
+
+ if (sspeed == sc->sc_sfan_speed && cspeed == sc->sc_cfan_speed)
+ return;
+
+ sc->sc_sfan_speed = sspeed;
+ sc->sc_cfan_speed = cspeed;
+ tda_setspeed(sc);
+}