summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2007-10-20 18:54:43 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2007-10-20 18:54:43 +0000
commit4aa4278abd98f54dd19fb4a0017e0d651b50704e (patch)
tree01986c229b25db6a571c0d83e3a237842a5140d0
parente1c03cbde4f0cdc00a39d923779ffe9ffe7d93c5 (diff)
Add support for the temperature sensors on the SUNW,envctrltwo device found
on the Sun Enterprise 250. This device (and SUNW,envctrl found on the Enterprise 450) is a PCF8584 I2C controller with several generic I2C chips attached to it. ok deraadt@
-rw-r--r--sys/arch/sparc64/conf/GENERIC5
-rw-r--r--sys/arch/sparc64/conf/files.sparc647
-rw-r--r--sys/arch/sparc64/dev/pcf8591_envctrl.c199
-rw-r--r--sys/arch/sparc64/dev/pcfiic_ebus.c38
4 files changed, 241 insertions, 8 deletions
diff --git a/sys/arch/sparc64/conf/GENERIC b/sys/arch/sparc64/conf/GENERIC
index 2844a82fa9e..65fd8fe658c 100644
--- a/sys/arch/sparc64/conf/GENERIC
+++ b/sys/arch/sparc64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.186 2007/10/08 12:56:37 deraadt Exp $
+# $OpenBSD: GENERIC,v 1.187 2007/10/20 18:54:42 kettenis Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -383,7 +383,8 @@ lmenv* at iic? # National Semiconductor LM87
lmtemp* at iic? # NS LM75/LM77 temperature sensor
maxds* at iic? # Maxim DS1631
maxtmp* at iic? # Maxim MAX6642/MAX6690
-pcfadc* at iic? # Philips PCF8591
+pcfadc* at iic? # Philips PCF8591
+ecadc* at iic? # SUNW,envctrl temperature sensors
spdmem* at iic? # SPD memory eeproms
# Framebuffers
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64
index c9150465f13..4b51481f49b 100644
--- a/sys/arch/sparc64/conf/files.sparc64
+++ b/sys/arch/sparc64/conf/files.sparc64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sparc64,v 1.90 2007/10/10 15:53:53 art Exp $
+# $OpenBSD: files.sparc64,v 1.91 2007/10/20 18:54:42 kettenis Exp $
# $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $
# maxpartitions must be first item in files.${ARCH}
@@ -301,6 +301,11 @@ device pcfadc
attach pcfadc at i2c
file arch/sparc64/dev/pcf8591_ofw.c pcfadc
+# PCF8591 ADC I2C Sensor (envctrl, so sparc64 only)
+device ecadc
+attach ecadc at i2c
+file arch/sparc64/dev/pcf8591_envctrl.c ecadc
+
#
# Machine-independent GPIO drivers
#
diff --git a/sys/arch/sparc64/dev/pcf8591_envctrl.c b/sys/arch/sparc64/dev/pcf8591_envctrl.c
new file mode 100644
index 00000000000..016b254af71
--- /dev/null
+++ b/sys/arch/sparc64/dev/pcf8591_envctrl.c
@@ -0,0 +1,199 @@
+/* $OpenBSD: pcf8591_envctrl.c,v 1.1 2007/10/20 18:54:42 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
+ *
+ * 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 <sys/sensors.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;
+ struct ksensor chan_sensor;
+ int64_t chan_factor;
+};
+
+struct ecadc_softc {
+ struct device sc_dev;
+ i2c_tag_t sc_tag;
+ i2c_addr_t sc_addr;
+ u_char sc_xlate[256];
+ u_int sc_nchan;
+ struct ecadc_channel sc_channels[PCF8591_CHANNELS];
+ struct ksensordev sc_sensordev;
+};
+
+int ecadc_match(struct device *, void *, void *);
+void ecadc_attach(struct device *, struct device *, void *);
+void ecadc_refresh(void *);
+
+struct cfattach ecadc_ca = {
+ sizeof(struct ecadc_softc), ecadc_match, ecadc_attach
+};
+
+struct cfdriver ecadc_cd = {
+ NULL, "ecadc", DV_DULL
+};
+
+int
+ecadc_match(struct device *parent, void *match, void *aux)
+{
+ struct i2c_attach_args *ia = aux;
+
+ if (strcmp(ia->ia_name, "ecadc") != 0)
+ return (0);
+
+ return (1);
+}
+
+void
+ecadc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ecadc_softc *sc = (struct ecadc_softc *)self;
+ u_char term[256];
+ u_char *cp, *desc;
+ int64_t num, den;
+ u_int8_t junk[PCF8591_CHANNELS + 1];
+ struct i2c_attach_args *ia = aux;
+ struct ksensor *sensor;
+ int tlen, xlen, addr, chan, node = *(int *)ia->ia_cookie;
+ u_int i;
+
+ if ((tlen = OF_getprop(node, "thermisters", term,
+ sizeof(term))) < 0) {
+ printf(": couldn't find \"thermisters\" property\n");
+ return;
+ }
+
+ if ((xlen = OF_getprop(node, "cpu-temp-factors", &sc->sc_xlate[2],
+ sizeof(sc->sc_xlate) - 2)) < 0) {
+ printf(": couldn't find \"cpu-temp-factors\" property\n");
+ return;
+ }
+ sc->sc_xlate[0] = sc->sc_xlate[1] = sc->sc_xlate[2];
+
+ cp = term;
+ while (cp < term + tlen) {
+ 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;
+ cp += 4; /* Min */
+ cp += 4; /* Warning threshold */
+ cp += 4; /* Shutdown threshold */
+ 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++);
+
+ if (addr != (ia->ia_addr << 1))
+ continue;
+
+ sensor = &sc->sc_channels[sc->sc_nchan].chan_sensor;
+ sensor->type = SENSOR_TEMP;
+ strlcpy(sensor->desc, desc, sizeof(sensor->desc));
+
+ sc->sc_channels[sc->sc_nchan].chan_num = chan;
+ if (num == 0 || den == 0)
+ sc->sc_channels[sc->sc_nchan].chan_factor = 0;
+ else
+ sc->sc_channels[sc->sc_nchan].chan_factor =
+ (1000000 * num) / den;
+ 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)) {
+ printf(": read failed\n");
+ iic_release_bus(sc->sc_tag, 0);
+ return;
+ }
+
+ iic_release_bus(sc->sc_tag, 0);
+
+ /* Initialize sensor data. */
+ strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
+ sizeof(sc->sc_sensordev.xname));
+
+ for (i = 0; i < sc->sc_nchan; i++)
+ if (!(sc->sc_channels[i].chan_sensor.flags & SENSOR_FINVALID))
+ sensor_attach(&sc->sc_sensordev,
+ &sc->sc_channels[i].chan_sensor);
+
+ if (sensor_task_register(sc, ecadc_refresh, 5) == NULL) {
+ printf(": unable to register update task\n");
+ return;
+ }
+
+ sensordev_install(&sc->sc_sensordev);
+
+ printf("\n");
+}
+
+void
+ecadc_refresh(void *arg)
+{
+ struct ecadc_softc *sc = arg;
+ 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_sensor.flags & SENSOR_FINVALID) != 0)
+ continue;
+ if (chp->chan_factor == 0)
+ chp->chan_sensor.value = 273150000 + 1000000 *
+ sc->sc_xlate[data[1 + chp->chan_num]];
+ else
+ chp->chan_sensor.value = 273150000 +
+ chp->chan_factor * data[1 + chp->chan_num];
+ }
+}
diff --git a/sys/arch/sparc64/dev/pcfiic_ebus.c b/sys/arch/sparc64/dev/pcfiic_ebus.c
index ddec757d3db..1a386fc1e12 100644
--- a/sys/arch/sparc64/dev/pcfiic_ebus.c
+++ b/sys/arch/sparc64/dev/pcfiic_ebus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcfiic_ebus.c,v 1.7 2007/05/21 03:11:11 jsg Exp $ */
+/* $OpenBSD: pcfiic_ebus.c,v 1.8 2007/10/20 18:54:42 kettenis Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -54,20 +54,25 @@ struct cfattach pcfiic_ebus_ca = {
sizeof(struct pcfiic_ebus_softc), pcfiic_ebus_match, pcfiic_ebus_attach
};
+void envctrltwo_scan(struct device *, struct i2cbus_attach_args *, void *);
+
int
pcfiic_ebus_match(struct device *parent, void *match, void *aux)
{
struct ebus_attach_args *ea = aux;
char compat[32];
+ if (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, "i2cpcf,8584") ||
- strcmp(compat, "SUNW,bbc-i2c"))
+ if (strcmp(compat, "i2cpcf,8584") == 0 ||
+ strcmp(compat, "SUNW,bbc-i2c") == 0)
return (1);
return (0);
@@ -157,6 +162,29 @@ fail:
if (esc->esc_ih == NULL)
sc->sc_poll = 1;
- pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs,
- ofwiic_scan, &ea->ea_node);
+ if (strcmp(ea->ea_name, "SUNW,envctrltwo") == 0)
+ pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0,
+ envctrltwo_scan, &ea->ea_node);
+ else
+ pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs,
+ ofwiic_scan, &ea->ea_node);
+}
+
+void
+envctrltwo_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
+{
+ extern int iic_print(void *, const char *);
+ struct i2c_attach_args ia;
+
+ memset(&ia, 0, sizeof(ia));
+ ia.ia_tag = iba->iba_tag;
+ ia.ia_cookie = aux;
+
+ ia.ia_addr = 0x4a;
+ ia.ia_name = "ecadc";
+ config_found(self, &ia, iic_print);
+
+ ia.ia_addr = 0x4f;
+ ia.ia_name = "ecadc";
+ config_found(self, &ia, iic_print);
}