[BACK]Return to smsc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / isa

Annotation of src/sys/dev/isa/smsc.c, Revision 1.7

1.7     ! xtraeme     1: /*     $NetBSD: smsc.c,v 1.6 2007/11/17 08:30:35 kefren Exp $ */
1.1       blymn       2:
                      3: /*-
                      4:  * Copyright (c) 2007 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Brett Lymn.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *        This product includes software developed by the NetBSD
                     21:  *        Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
                     38:
                     39: /*
                     40:  * This is a driver for the Standard Microsystems Corp (SMSC)
                     41:  * LPC47B397 "super i/o" chip.  This driver only handles the environment
                     42:  * monitoring capabilities of the chip, the other functions will be
                     43:  * probed/matched as "normal" PC hardware devices (serial ports, fdc, so on).
                     44:  * SMSC has not deigned to release a datasheet for this particular chip
                     45:  * (though they do for others they make) so this driver was written from
                     46:  * information contained in the comment block for the Linux driver.
                     47:  */
                     48:
                     49: #include <sys/cdefs.h>
1.7     ! xtraeme    50: __KERNEL_RCSID(0, "$NetBSD: smsc.c,v 1.6 2007/11/17 08:30:35 kefren Exp $");
1.1       blymn      51:
                     52: #include <sys/param.h>
                     53: #include <sys/systm.h>
                     54: #include <sys/device.h>
1.4       ad         55: #include <sys/bus.h>
1.1       blymn      56:
                     57: #include <dev/isa/isareg.h>
                     58: #include <dev/isa/isavar.h>
                     59:
                     60: #include <dev/sysmon/sysmonvar.h>
                     61: #include <dev/isa/smscvar.h>
                     62:
                     63: #if defined(LMDEBUG)
                     64: #define DPRINTF(x)     do { printf x; } while (0)
                     65: #else
                     66: #define DPRINTF(x)
                     67: #endif
                     68:
1.7     ! xtraeme    69: static int     smsc_match(device_t, cfdata_t, void *);
        !            70: static void    smsc_attach(device_t, device_t, void *);
        !            71: static int     smsc_detach(device_t, int);
        !            72:
        !            73: static uint8_t smsc_readreg(bus_space_tag_t, bus_space_handle_t, int);
        !            74: static void    smsc_writereg(bus_space_tag_t, bus_space_handle_t, int, int);
1.1       blymn      75:
1.5       xtraeme    76: static void    smsc_refresh(struct sysmon_envsys *, envsys_data_t *);
1.1       blymn      77:
1.7     ! xtraeme    78: CFATTACH_DECL_NEW(smsc, sizeof(struct smsc_softc),
1.5       xtraeme    79:     smsc_match, smsc_attach, smsc_detach, NULL);
1.1       blymn      80:
                     81: /*
                     82:  * Probe for the SMSC Super I/O chip
                     83:  */
1.5       xtraeme    84: static int
1.7     ! xtraeme    85: smsc_match(device_t parent, cfdata_t match, void *aux)
1.1       blymn      86: {
                     87:        bus_space_handle_t ioh;
                     88:        struct isa_attach_args *ia = aux;
                     89:        int rv;
                     90:        uint8_t cr;
                     91:
                     92:        /* Must supply an address */
                     93:        if (ia->ia_nio < 1)
                     94:                return 0;
                     95:
                     96:        if (ISA_DIRECT_CONFIG(ia))
                     97:                return 0;
                     98:
                     99:        if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
                    100:                return 0;
                    101:
                    102:        if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh))
                    103:                return 0;
                    104:
                    105:        /* To get the device ID we must enter config mode... */
                    106:        bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START);
                    107:
                    108:        /* Then select the device id register */
1.7     ! xtraeme   109:        cr = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID);
1.1       blymn     110:
                    111:        /* Exit config mode, apparently this is important to do */
                    112:        bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END);
                    113:
1.7     ! xtraeme   114:        switch (cr) {
        !           115:        case SMSC_ID_47B397:
        !           116:        case SMSC_ID_SCH5307NS:
        !           117:        case SMSC_ID_SCH5317:
1.1       blymn     118:                rv = 1;
1.7     ! xtraeme   119:                break;
        !           120:        default:
1.1       blymn     121:                rv = 0;
1.7     ! xtraeme   122:                break;
        !           123:        }
1.1       blymn     124:
                    125:        DPRINTF(("smsc: rv = %d, cr = %x\n", rv, cr));
                    126:
                    127:        bus_space_unmap(ia->ia_iot, ioh, 2);
                    128:
                    129:        if (rv) {
                    130:                ia->ia_nio = 1;
                    131:                ia->ia_io[0].ir_size = 2;
                    132:
                    133:                ia->ia_niomem = 0;
                    134:                ia->ia_nirq = 0;
                    135:                ia->ia_ndrq = 0;
                    136:        }
                    137:
                    138:        return rv;
                    139: }
                    140:
                    141: /*
                    142:  * Get the base address for the monitoring registers and set up the
1.7     ! xtraeme   143:  * sysmon_envsys(9) framework.
1.1       blymn     144:  */
1.5       xtraeme   145: static void
1.7     ! xtraeme   146: smsc_attach(device_t parent, device_t self, void *aux)
1.1       blymn     147: {
1.5       xtraeme   148:        struct smsc_softc *sc = device_private(self);
1.1       blymn     149:        struct isa_attach_args *ia = aux;
                    150:        bus_space_handle_t ioh;
1.7     ! xtraeme   151:        uint8_t rev, msb, lsb, chipid;
1.1       blymn     152:        unsigned address;
1.5       xtraeme   153:        int i;
1.1       blymn     154:
1.5       xtraeme   155:        sc->sc_iot = ia->ia_iot;
1.1       blymn     156:
1.7     ! xtraeme   157:        aprint_naive("\n");
        !           158:
        !           159:        /*
        !           160:         * To attach we need to find the actual Hardware Monitor
        !           161:         * I/O address space.
        !           162:         */
1.1       blymn     163:        if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0,
                    164:            &ioh)) {
                    165:                aprint_error(": can't map base i/o space\n");
                    166:                return;
                    167:        }
                    168:
1.7     ! xtraeme   169:        /* Enter config mode */
1.1       blymn     170:        bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START);
                    171:
1.7     ! xtraeme   172:        /*
        !           173:         * While we have the base registers mapped, grab the chip
        !           174:         * revision and device ID.
        !           175:         */
        !           176:        rev = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_REVISION);
        !           177:        chipid = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID);
        !           178:
        !           179:        /* Select the Hardware Monitor LDN */
        !           180:        smsc_writereg(ia->ia_iot, ioh, SMSC_LOGICAL_DEV_SEL,
        !           181:            SMSC_LOGICAL_DEVICE);
1.1       blymn     182:
                    183:        /* Read the base address for the registers. */
1.7     ! xtraeme   184:        msb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_MSB);
        !           185:        lsb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_LSB);
1.1       blymn     186:        address = (msb << 8) | lsb;
                    187:
                    188:        /* Exit config mode */
                    189:        bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END);
                    190:        bus_space_unmap(ia->ia_iot, ioh, 2);
                    191:
1.7     ! xtraeme   192:        /* Map the Hardware Monitor I/O space. */
1.5       xtraeme   193:        if (bus_space_map(ia->ia_iot, address, 2, 0, &sc->sc_ioh)) {
1.1       blymn     194:                aprint_error(": can't map register i/o space\n");
                    195:                return;
                    196:        }
                    197:
1.5       xtraeme   198:        sc->sc_sme = sysmon_envsys_create();
                    199:
1.7     ! xtraeme   200: #define INITSENSOR(index, string, reg, type)                   \
        !           201:        do {                                                    \
        !           202:                strlcpy(sc->sc_sensor[index].desc, string,      \
        !           203:                    sizeof(sc->sc_sensor[index].desc));         \
        !           204:                sc->sc_sensor[index].units = type;              \
        !           205:                sc->sc_regs[index] = reg;                       \
        !           206:                sc->sc_sensor[index].state = ENVSYS_SVALID;     \
        !           207:        } while (/* CONSTCOND */ 0)
        !           208:
        !           209:        /* Temperature sensors */
        !           210:        INITSENSOR(0, "Temp0", SMSC_TEMP1, ENVSYS_STEMP);
        !           211:        INITSENSOR(1, "Temp1", SMSC_TEMP2, ENVSYS_STEMP);
        !           212:        INITSENSOR(2, "Temp2", SMSC_TEMP3, ENVSYS_STEMP);
        !           213:        INITSENSOR(3, "Temp3", SMSC_TEMP4, ENVSYS_STEMP);
        !           214:
        !           215:        /* Fan sensors */
        !           216:        INITSENSOR(4, "Fan0", SMSC_FAN1_LSB, ENVSYS_SFANRPM);
        !           217:        INITSENSOR(5, "Fan1", SMSC_FAN2_LSB, ENVSYS_SFANRPM);
        !           218:        INITSENSOR(6, "Fan2", SMSC_FAN3_LSB, ENVSYS_SFANRPM);
        !           219:        INITSENSOR(7, "Fan3", SMSC_FAN4_LSB, ENVSYS_SFANRPM);
1.5       xtraeme   220:
1.7     ! xtraeme   221:        for (i = 0; i < SMSC_MAX_SENSORS; i++) {
1.5       xtraeme   222:                if (sysmon_envsys_sensor_attach(sc->sc_sme,
                    223:                                                &sc->sc_sensor[i])) {
                    224:                        sysmon_envsys_destroy(sc->sc_sme);
1.7     ! xtraeme   225:                        bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2);
1.5       xtraeme   226:                        return;
                    227:                }
                    228:        }
                    229:
1.7     ! xtraeme   230:        sc->sc_sme->sme_name = device_xname(self);
1.5       xtraeme   231:        sc->sc_sme->sme_cookie = sc;
                    232:        sc->sc_sme->sme_refresh = smsc_refresh;
                    233:
                    234:        if ((i = sysmon_envsys_register(sc->sc_sme)) != 0) {
1.7     ! xtraeme   235:                aprint_error(": unable to register with sysmon (%d)\n", i);
1.5       xtraeme   236:                sysmon_envsys_destroy(sc->sc_sme);
1.7     ! xtraeme   237:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2);
        !           238:                return;
        !           239:        }
        !           240:
        !           241:        switch (chipid) {
        !           242:        case SMSC_ID_47B397:
        !           243:                aprint_normal(": SMSC LPC47B397 Super I/O");
        !           244:                break;
        !           245:        case SMSC_ID_SCH5307NS:
        !           246:                aprint_normal(": SMSC SCH5307-NS Super I/O");
        !           247:                break;
        !           248:        case SMSC_ID_SCH5317:
        !           249:                aprint_normal(": SMSC SCH5317 Super I/O");
        !           250:                break;
1.5       xtraeme   251:        }
                    252:
1.7     ! xtraeme   253:        aprint_normal(" (rev %u)\n", rev);
        !           254:        aprint_normal_dev(self, "Hardware Monitor registers at 0x%04x\n",
        !           255:            address);
1.1       blymn     256: }
                    257:
1.5       xtraeme   258: static int
1.3       xtraeme   259: smsc_detach(struct device *self, int flags)
                    260: {
                    261:        struct smsc_softc *sc = device_private(self);
                    262:
1.5       xtraeme   263:        sysmon_envsys_unregister(sc->sc_sme);
                    264:        bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2);
1.3       xtraeme   265:        return 0;
                    266: }
1.1       blymn     267:
                    268: /*
                    269:  * Read the value of the given register
                    270:  */
                    271: static uint8_t
1.7     ! xtraeme   272: smsc_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
1.1       blymn     273: {
1.7     ! xtraeme   274:        bus_space_write_1(iot, ioh, SMSC_ADDR, reg);
        !           275:        return bus_space_read_1(iot, ioh, SMSC_DATA);
1.1       blymn     276: }
                    277:
                    278: /*
1.7     ! xtraeme   279:  * Write the given value to the given register.
        !           280:  */
1.1       blymn     281: static void
1.7     ! xtraeme   282: smsc_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, int val)
1.1       blymn     283: {
1.7     ! xtraeme   284:        bus_space_write_1(iot, ioh, SMSC_ADDR, reg);
        !           285:        bus_space_write_1(iot, ioh, SMSC_DATA, val);
1.5       xtraeme   286: }
1.1       blymn     287:
                    288: /* convert temperature read from the chip to micro kelvin */
                    289: static inline int
                    290: smsc_temp2muk(uint8_t t)
                    291: {
                    292:         int temp=t;
                    293:
                    294:         return temp * 1000000 + 273150000U;
                    295: }
                    296:
                    297: /*
                    298:  * convert register value read from chip into rpm using:
                    299:  *
                    300:  * RPM = 60/(Count * 11.111us)
                    301:  *
                    302:  * 1/1.1111us = 90kHz
                    303:  *
                    304:  */
                    305: static inline int
                    306: smsc_reg2rpm(unsigned int r)
                    307: {
                    308:        unsigned long rpm;
                    309:
                    310:         if (r == 0x0)
                    311:                 return 0;
                    312:
                    313:        rpm = (90000 * 60) / ((unsigned long) r);
                    314:         return (int) rpm;
                    315: }
                    316:
                    317: /* min and max temperatures in uK */
                    318: #define SMSC_MIN_TEMP_UK ((-127 * 1000000) + 273150000)
                    319: #define SMSC_MAX_TEMP_UK ((127 * 1000000) + 273150000)
                    320:
                    321: /*
                    322:  * Get the data for the requested sensor, update the sysmon structure
                    323:  * with the retrieved value.
                    324:  */
1.5       xtraeme   325: static void
                    326: smsc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1.1       blymn     327: {
                    328:        struct smsc_softc *sc = sme->sme_cookie;
1.5       xtraeme   329:        int reg;
1.1       blymn     330:        unsigned int rpm;
                    331:        uint8_t msb, lsb;
                    332:
1.5       xtraeme   333:        reg = sc->sc_regs[edata->sensor];
1.1       blymn     334:
1.2       xtraeme   335:        switch (edata->units) {
1.1       blymn     336:        case ENVSYS_STEMP:
1.7     ! xtraeme   337:                edata->value_cur =
        !           338:                    smsc_temp2muk(smsc_readreg(sc->sc_iot, sc->sc_ioh, reg));
1.1       blymn     339:                break;
                    340:
                    341:        case ENVSYS_SFANRPM:
                    342:                /* reading lsb first locks msb... */
1.7     ! xtraeme   343:                lsb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg);
        !           344:                msb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg + 1);
1.1       blymn     345:                rpm = (msb << 8) | lsb;
1.2       xtraeme   346:                edata->value_cur = smsc_reg2rpm(rpm);
1.1       blymn     347:                break;
                    348:        }
                    349: }

CVSweb <webmaster@jp.NetBSD.org>