diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c index e50981758723..bc542faf4637 100644 --- a/sys/dev/i2c/files.i2c +++ b/sys/dev/i2c/files.i2c @@ -1,4 +1,4 @@ -# $NetBSD: files.i2c,v 1.27 2010/03/24 00:31:41 pgoyette Exp $ +# $NetBSD: files.i2c,v 1.28 2010/10/02 06:07:37 kiyohara Exp $ defflag opt_i2cbus.h I2C_SCAN define i2cbus { } @@ -119,3 +119,8 @@ file dev/i2c/adm1021.c admtemp device smscmon: sysmon_envsys attach smscmon at iic file dev/i2c/smscmon.c smscmon + +# G760a FAN controller +device g760a: sysmon_envsys +attach g760a at iic +file dev/i2c/g760a.c g760a diff --git a/sys/dev/i2c/g760a.c b/sys/dev/i2c/g760a.c new file mode 100644 index 000000000000..69b0fdaa5165 --- /dev/null +++ b/sys/dev/i2c/g760a.c @@ -0,0 +1,261 @@ +/* $NetBSD: g760a.c,v 1.1 2010/10/02 06:07:37 kiyohara Exp $ */ + +/*- + * Copyright (C) 2008 A.Leo. + * + * 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. + */ + +/* + * The driver for the G760A FAN Speed PWM controller. + */ + +#include + +__KERNEL_RCSID(0, "$NetBSD: g760a.c,v 1.1 2010/10/02 06:07:37 kiyohara Exp $"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +struct g760a_softc { + device_t sc_dev; + struct sysmon_envsys *sc_sme; + + envsys_data_t sc_sensor; + i2c_tag_t sc_tag; + int sc_addr; +}; + +static int g760a_match(device_t, struct cfdata*, void*); +static void g760a_attach(device_t, device_t, void*); +static void g760a_setup(struct g760a_softc*); +static uint8_t g760a_readreg(struct g760a_softc*, uint8_t); +static void g760a_writereg(struct g760a_softc*, uint8_t, uint8_t); + +static int g760a_reg2rpm(int); + +static void g760a_refresh(struct sysmon_envsys*, envsys_data_t*); +static int sysctl_g760a_rpm(SYSCTLFN_PROTO); + +CFATTACH_DECL_NEW(g760a, sizeof(struct g760a_softc), + g760a_match, g760a_attach, NULL, NULL); + +static int +g760a_match(device_t parent, struct cfdata* cf, void* arg) +{ + struct i2c_attach_args* ia = arg; + + if (ia->ia_addr == G760A_ADDR) { + /* + * TODO: set up minimal speed? + */ + return 1; + } + + return 0; +} + + +static void +g760a_attach(device_t parent, device_t self, void* arg) +{ + struct i2c_attach_args* ia = arg; + struct g760a_softc* sc = device_private(self); + + aprint_normal(": G760A Fan Controller\n"); + + sc->sc_dev = self; + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + g760a_setup(sc); +} + + +static int +g760a_reg2rpm(int n) +{ + if(n == 255) + return 0; + + if(n == 0) + return 255; + + return G760A_N2RPM(n); +} + + +static uint8_t +g760a_readreg(struct g760a_softc* sc, uint8_t reg) +{ + uint8_t data; + + if (iic_acquire_bus(sc->sc_tag, 0)) { + aprint_error_dev(sc->sc_dev, "unable to acquire the iic bus\n"); + return 0; + } + + iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, ®, 1, + &data, 1, 0); + iic_release_bus(sc->sc_tag, 0); + + return data; +} + + +static void +g760a_writereg(struct g760a_softc* sc, uint8_t reg, uint8_t data) +{ + + if (iic_acquire_bus(sc->sc_tag, 0)) { + aprint_error_dev(sc->sc_dev, "unable to acquire the iic bus\n"); + return; + } + + iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, ®, 1, + &data, 1, 0); + iic_release_bus(sc->sc_tag, 0); +} + + +SYSCTL_SETUP(sysctl_g760a_setup, "sysctl g760a subtree setup") +{ + + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "machdep", NULL, + NULL, 0, NULL, 0, + CTL_MACHDEP, CTL_EOL); +} + + +/*ARGUSED*/ +static int +sysctl_g760a_rpm(SYSCTLFN_ARGS) +{ + int error, t; + struct sysctlnode node; + struct g760a_softc* sc; + + node = *rnode; + sc = node.sysctl_data; + + t = g760a_readreg(sc, G760A_REG_SET_CNT); + t = g760a_reg2rpm(t); + + node.sysctl_data = &t; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + + if (error || newp == NULL) + return error; + + if (t > 20000 || t < G760A_N2RPM(254)) + return EINVAL; + + t = g760a_reg2rpm(t); + + g760a_writereg(sc, G760A_REG_SET_CNT, t); + + return 0; +} + + +static void +g760a_refresh(struct sysmon_envsys* sme, envsys_data_t* edata) +{ + struct g760a_softc* sc = sme->sme_cookie; + + switch (edata->units) { + case ENVSYS_SFANRPM: + { + uint8_t n; + + n = g760a_readreg(sc, G760A_REG_ACT_CNT); + edata->value_cur = g760a_reg2rpm(n); + } + break; + default: + aprint_error_dev(sc->sc_dev, "oops\n"); + } + + edata->state = ENVSYS_SVALID; +} + + +static void +g760a_setup(struct g760a_softc* sc) +{ + int error; + int ret; + struct sysctlnode* me = NULL, * node = NULL; + + sc->sc_sme = sysmon_envsys_create(); + + ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode**)&me, + CTLFLAG_READWRITE, + CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, + NULL, 0, NULL, 0, + CTL_MACHDEP, CTL_CREATE, CTL_EOL); + + (void)strlcpy(sc->sc_sensor.desc, "sysfan rpm", + sizeof(sc->sc_sensor.desc)); + sc->sc_sensor.units = ENVSYS_SFANRPM; + + if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) + goto out; + + ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode**)&node, + CTLFLAG_READWRITE, + CTLTYPE_INT, "rpm", sc->sc_sensor.desc, + sysctl_g760a_rpm, 0x42, NULL, 0, + CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL); + if (node != NULL) + node->sysctl_data = sc; + + sc->sc_sme->sme_name = device_xname(sc->sc_dev); + sc->sc_sme->sme_cookie = sc; + sc->sc_sme->sme_refresh = g760a_refresh; + + error = sysmon_envsys_register(sc->sc_sme); + + if (error) { + aprint_error_dev(sc->sc_dev, + "unable to register with sysmon. errorcode %i\n", error); + goto out; + } + + return; +out: + sysmon_envsys_destroy(sc->sc_sme); +} diff --git a/sys/dev/i2c/g760areg.h b/sys/dev/i2c/g760areg.h new file mode 100644 index 000000000000..b040dab0a7aa --- /dev/null +++ b/sys/dev/i2c/g760areg.h @@ -0,0 +1,53 @@ +/* $NetBSD: g760areg.h,v 1.1 2010/10/02 06:07:37 kiyohara Exp $ */ + +/*- + * Copyright (C) 2008 A.Leo. + * + * 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. + */ + + +#ifndef _DEV_I2C_G760aREG_H_ +#define _DEV_I2C_G760aREG_H_ + +#define G760A_ADDR 0x3e + +#define G760A_REG_SET_CNT 0x00 /* RW, Programmed fan speed + register, it contains the + count number of the + desired fan speed. */ + +#define G760A_REG_ACT_CNT 0x01 /* RO, Actual fan speed. */ +#define G760A_REG_FAN_STA 0x02 /* RO, Fan status. */ +#define G760A_REG_FAN_STA_MASK 0x03u /* 2 lower bits */ + +#define G760A_CLK 32768 +#define G760A_P 2 + + + +#define G760A_N2RPM(a) (G760A_CLK*30/G760A_P/(a)) +#define G760A_RPM2N(a) (G760A_CLK*30/G760A_P/(a)) /* wow */ + + +#endif /* !_DEV_I2C_G760AREG_H_ */