Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c added drivers for Analog Devices ADT7467 and ADM...



details:   https://anonhg.NetBSD.org/src/rev/2c59b672c570
branches:  trunk
changeset: 583527:2c59b672c570
user:      macallan <macallan%NetBSD.org@localhost>
date:      Wed Aug 10 14:18:28 2005 +0000

description:
added drivers for Analog Devices ADT7467 and ADM1030 thermal monitor / fan controller chips found in various Apple laptops and probably other machines.

diffstat:

 sys/dev/i2c/adm1030.c    |  334 ++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/i2c/adm1030var.h |   57 +++++++
 sys/dev/i2c/adt7467.c    |  356 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/i2c/adt7467var.h |   58 +++++++
 sys/dev/i2c/files.i2c    |   14 +-
 5 files changed, 818 insertions(+), 1 deletions(-)

diffs (truncated from 846 to 300 lines):

diff -r 01e53a3e4793 -r 2c59b672c570 sys/dev/i2c/adm1030.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/i2c/adm1030.c     Wed Aug 10 14:18:28 2005 +0000
@@ -0,0 +1,334 @@
+/*     $NetBSD: adm1030.c,v 1.1 2005/08/10 14:18:28 macallan Exp $     */
+
+/*-
+ * Copyright (C) 2005 Michael Lorenz.
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+/* 
+ * a driver fot the ADM1030 environmental controller found in some iBook G3 
+ * and probably other Apple machines 
+ */
+
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: adm1030.c,v 1.1 2005/08/10 14:18:28 macallan Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <machine/autoconf.h>
+#include <dev/sysmon/sysmonvar.h>
+#include "sysmon_envsys.h"
+#include <dev/i2c/adm1030var.h>
+
+static void adm1030c_attach(struct device *, struct device *, void *);
+static int adm1030c_match(struct device *, struct cfdata *, void *);
+
+struct adm1030c_sysmon {
+               struct sysmon_envsys sme;
+               struct adm1030c_softc *sc;
+               struct envsys_tre_data adm1030c_info[];
+       };
+
+static uint8_t adm1030c_readreg(struct adm1030c_softc *, uint8_t);
+static void adm1030c_writereg(struct adm1030c_softc *, uint8_t, uint8_t);
+static int adm1030c_temp2muk(uint8_t);
+static int adm1030c_reg2rpm(uint8_t);
+static int adm1030c_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
+static int adm1030c_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
+
+CFATTACH_DECL(adm1030c, sizeof(struct adm1030c_softc),
+    adm1030c_match, adm1030c_attach, NULL, NULL);
+
+static int
+adm1030c_match(parent, cf, aux)
+       struct device *parent;
+       struct cfdata *cf;
+       void *aux;
+{
+       /* no probing when we're attaching to iic */
+       return 1;
+}
+
+static void
+adm1030c_attach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct adm1030c_softc *sc = (struct adm1030c_softc *)self;
+       struct i2c_attach_args *args = aux;
+
+       sc->parent = parent;
+       sc->address = args->ia_addr;
+       printf(" ADM1030 thermal monitor and fan controller\n");
+       sc->sc_i2c = (struct i2c_controller *)args->ia_tag;
+       adm1030c_setup(sc);
+}
+
+static uint8_t
+adm1030c_readreg(struct adm1030c_softc *sc, uint8_t reg)
+{
+       uint8_t data = 0;
+       
+       iic_acquire_bus(sc->sc_i2c,0);
+       iic_exec(sc->sc_i2c, I2C_OP_READ, sc->address, &reg, 1, &data, 1, 0);
+       iic_release_bus(sc->sc_i2c, 0);
+       return data;
+}
+
+static void 
+adm1030c_writereg(struct adm1030c_softc *sc, uint8_t reg, uint8_t data)
+{
+       uint8_t mdata[2]={reg, data};
+       
+       iic_acquire_bus(sc->sc_i2c, 0);
+       iic_exec(sc->sc_i2c, I2C_OP_WRITE, sc->address, &mdata, 2, NULL, 0, 0);
+       iic_release_bus(sc->sc_i2c, 0);
+}
+
+#if NSYSMON_ENVSYS > 0
+
+struct envsys_range *adm1030c_ranges;
+struct envsys_basic_info *adm1030c_info;
+
+/* convert temperature read from the chip to micro kelvin */
+static inline int 
+adm1030c_temp2muk(uint8_t t)
+{
+       int temp=t;
+       
+       return temp * 1000000 + 273150000U;
+}
+
+static inline int
+adm1030c_reg2rpm(uint8_t r)
+{
+       if (r == 0xff)
+               return 0;
+       return (11250 * 60) / (2 * (int)r);
+}
+
+SYSCTL_SETUP(sysctl_adm1030c_setup, "sysctl ADM1030M subtree setup")
+{
+#ifdef ADM1030_DEBUG
+       printf("node setup\n");
+#endif
+       sysctl_createv(NULL, 0, NULL, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "machdep", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_MACHDEP, CTL_EOL);
+}
+
+static int
+sysctl_adm1030c_temp(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node = *rnode;
+       struct adm1030c_softc *sc=(struct adm1030c_softc *)node.sysctl_data;
+       int reg = 12345, nd=0;
+       const int *np = newp;
+       uint8_t chipreg = (uint8_t)(node.sysctl_idata & 0xff);
+       
+       reg = (uint32_t)adm1030c_readreg(sc, chipreg);
+       reg = (reg & 0xf8) >> 1;
+       node.sysctl_idata = reg;
+       if (np) {
+               /* we're asked to write */      
+               nd = *np;
+               node.sysctl_data = &reg;
+               if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
+                       int8_t new_reg;
+                       
+                       new_reg = (int8_t)(max(30, min(85, node.sysctl_idata)));
+                       new_reg = ((new_reg & 0x7c) << 1);      /* 5C range */
+                       adm1030c_writereg(sc, chipreg, new_reg);
+                       return 0;
+               }
+               return EINVAL;
+       } else {
+               node.sysctl_size = 4;
+               return (sysctl_lookup(SYSCTLFN_CALL(&node)));
+       }
+}
+
+void
+adm1030c_setup(struct adm1030c_softc *sc)
+{
+       struct adm1030c_sysmon *datap;
+       int error;
+       struct envsys_range *cur_r;
+       struct envsys_basic_info *cur_i;
+       struct envsys_tre_data *cur_t;
+       int ret;
+       struct sysctlnode *me = NULL, *node = NULL;
+       
+       datap = malloc(sizeof(struct sysmon_envsys) + 3 * 
+           sizeof(struct envsys_tre_data) + sizeof(void *),
+           M_DEVBUF, M_WAITOK | M_ZERO);
+           
+       adm1030c_ranges = malloc (sizeof(struct envsys_range) * 3,
+           M_DEVBUF, M_WAITOK | M_ZERO);
+           
+       adm1030c_info = malloc (sizeof(struct envsys_basic_info) * 3,
+           M_DEVBUF, M_WAITOK | M_ZERO);
+       
+       ret=sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&me,
+              CTLFLAG_READWRITE,
+              CTLTYPE_NODE, sc->sc_dev.dv_xname, NULL,
+              NULL, 0, NULL, 0,
+              CTL_MACHDEP, CTL_CREATE, CTL_EOL);
+
+       cur_r = &adm1030c_ranges[0];
+       cur_i = &adm1030c_info[0];
+       cur_t = &datap->adm1030c_info[0];
+       strcpy(cur_i->desc, "CPU temperature");
+       cur_i->units = ENVSYS_STEMP;
+       cur_i->sensor = 0;
+       sc->regs[0] = 0x0b;     /* remote temperature register */
+       cur_r->low = adm1030c_temp2muk(-127);
+       cur_r->high = adm1030c_temp2muk(127);
+       cur_r->units = ENVSYS_STEMP;
+       ret=sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&node,
+               CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE,
+               CTLTYPE_INT, "temp0", cur_i->desc,
+               sysctl_adm1030c_temp, 0x25, NULL, 0,
+               CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
+               if (node != NULL) {
+                       node->sysctl_data = sc;
+               }
+       cur_i->validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
+       cur_t->sensor = 0;
+       cur_t->warnflags = ENVSYS_WARN_OK;
+       cur_t->validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
+       cur_t->units = cur_i->units;
+
+       cur_r = &adm1030c_ranges[1];
+       cur_i = &adm1030c_info[1];
+       cur_t = &datap->adm1030c_info[1];
+       strcpy(cur_i->desc, "case temperature");
+       
+       cur_i->units = ENVSYS_STEMP;
+       cur_i->sensor = 1;
+       sc->regs[1] = 0x0a;     /* built-in temperature register */
+       cur_r->low = adm1030c_temp2muk(-127);
+       cur_r->high = adm1030c_temp2muk(127);
+       cur_r->units = ENVSYS_STEMP;
+       ret=sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&node,
+               CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE,
+               CTLTYPE_INT, "temp1", cur_i->desc,
+               sysctl_adm1030c_temp,0x24, NULL, 0,
+               CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
+               if(node!=NULL) {
+                       node->sysctl_data = sc;
+               }
+       cur_i->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
+       cur_t->sensor = 1;
+       cur_t->warnflags = ENVSYS_WARN_OK;
+       cur_t->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
+       cur_t->units = cur_i->units;
+
+       cur_r = &adm1030c_ranges[2];
+       cur_i = &adm1030c_info[2];
+       cur_t = &datap->adm1030c_info[2];
+       strcpy(cur_i->desc, "fan speed");
+       cur_i->units = ENVSYS_SFANRPM;
+       cur_i->sensor = 2;
+       sc->regs[2] = 0x08;     /* fan rpm */
+       cur_r->low = 0;
+       cur_r->high = adm1030c_reg2rpm(0xfe);
+       cur_r->units = ENVSYS_SFANRPM;
+
+       cur_i->validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
+       cur_t->sensor = 2;
+       cur_t->warnflags = ENVSYS_WARN_OK;
+       cur_t->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
+       cur_t->units = cur_i->units;
+
+       sc->sc_sysmon_cookie = &datap->sme;
+       datap->sme.sme_nsensors = 3;
+       datap->sme.sme_envsys_version = 1000;
+       datap->sme.sme_ranges = adm1030c_ranges;
+       datap->sme.sme_sensor_info = adm1030c_info;
+       datap->sme.sme_sensor_data = datap->adm1030c_info;
+       
+       datap->sme.sme_cookie = sc;
+       datap->sme.sme_gtredata = adm1030c_gtredata;
+       datap->sme.sme_streinfo = adm1030c_streinfo;
+       datap->sme.sme_flags = 0;
+
+       if ((error = sysmon_envsys_register(&datap->sme)) != 0)
+               aprint_error("%s: unable to register with sysmon (%d)\n",
+                   sc->sc_dev.dv_xname, error);
+}
+
+
+static int
+adm1030c_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred)



Home | Main Index | Thread Index | Old Index