/* $OpenBSD: clkbrd.c,v 1.6 2008/01/20 16:41:17 kettenis Exp $ */ /* * Copyright (c) 2004 Jason L. Wright (jason@thought.net) * All rights reserved. * * 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. * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include int clkbrd_match(struct device *, void *, void *); void clkbrd_attach(struct device *, struct device *, void *); void clkbrd_led_blink(void *, int); void clkbrd_refresh(void *); struct cfattach clkbrd_ca = { sizeof(struct clkbrd_softc), clkbrd_match, clkbrd_attach }; struct cfdriver clkbrd_cd = { NULL, "clkbrd", DV_DULL }; int clkbrd_match(struct device *parent, void *match, void *aux) { struct fhc_attach_args *fa = aux; if (strcmp(fa->fa_name, "clock-board") == 0) return (1); return (0); } void clkbrd_attach(struct device *parent, struct device *self, void *aux) { struct clkbrd_softc *sc = (struct clkbrd_softc *)self; struct fhc_attach_args *fa = aux; int slots; u_int8_t r; sc->sc_bt = fa->fa_bustag; if (fa->fa_nreg < 2) { printf(": no registers\n"); return; } if (fhc_bus_map(sc->sc_bt, fa->fa_reg[1].fbr_slot, fa->fa_reg[1].fbr_offset, fa->fa_reg[1].fbr_size, 0, &sc->sc_creg)) { printf(": can't map ctrl regs\n"); return; } if (fa->fa_nreg > 2) { if (fhc_bus_map(sc->sc_bt, fa->fa_reg[2].fbr_slot, fa->fa_reg[2].fbr_offset, fa->fa_reg[2].fbr_size, 0, &sc->sc_vreg)) { printf(": can't map vreg\n"); return; } sc->sc_has_vreg = 1; } slots = 4; r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_STS1); switch (r & 0xc0) { case 0x40: slots = 16; break; case 0xc0: slots = 8; break; case 0x80: if (sc->sc_has_vreg) { r = bus_space_read_1(sc->sc_bt, sc->sc_vreg, 0); if (r != 0 && (r & 0x80) == 0) slots = 5; } } sc->sc_blink.bl_func = clkbrd_led_blink; sc->sc_blink.bl_arg = sc; blink_led_register(&sc->sc_blink); /* Initialize sensor data. */ strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname, sizeof(sc->sc_sensordev.xname)); sc->sc_sensor.type = SENSOR_TEMP; sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); if (sensor_task_register(sc, clkbrd_refresh, 5) == NULL) { printf(": unable to register update task\n"); return; } sensordev_install(&sc->sc_sensordev); printf(": %d slots\n", slots); } void clkbrd_led_blink(void *vsc, int on) { struct clkbrd_softc *sc = vsc; int s; u_int8_t r; s = splhigh(); r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL); if (on) r |= CLK_CTRL_RLED; else r &= ~CLK_CTRL_RLED; bus_space_write_1(sc->sc_bt, sc->sc_creg, CLK_CTRL, r); bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL); splx(s); } /* * Calibration table for temperature sensor. */ int8_t clkbrd_temp[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 38, 38, 39, 40, 40, 41, 42, 42, 43, 44, 44, 45, 46, 46, 47, 48, 48, 49, 50, 50, 51, 52, 52, 53, 54, 54, 55, 56, 57, 57, 58, 59, 59, 60, 60, 61, 62, 63, 63, 64, 65, 65, 66, 67, 68, 68, 69, 70, 70, 71, 72, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82 }; const int8_t clkbrd_temp_warn = 60; const int8_t clkbrd_temp_crit = 68; void clkbrd_refresh(void *arg) { struct clkbrd_softc *sc = arg; u_int8_t val; int8_t temp; val = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_TEMP); if (val == 0xff) { sc->sc_sensor.flags |= SENSOR_FINVALID; return; } if (val < sizeof(clkbrd_temp)) temp = clkbrd_temp[val]; else temp = clkbrd_temp[sizeof(clkbrd_temp) - 1]; sc->sc_sensor.value = val * 1000000 + 273150000; sc->sc_sensor.flags &= ~SENSOR_FINVALID; sc->sc_sensor.status = SENSOR_S_OK; if (temp >= clkbrd_temp_warn) sc->sc_sensor.status = SENSOR_S_WARN; if (temp >= clkbrd_temp_crit) sc->sc_sensor.status = SENSOR_S_CRIT; }