1 /* 2 * Copyright (c) 2005, 2006 Mark Kettenis 3 * Copyright (c) 2007 Constantine A. Murenin, Google Summer of Code 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $ 18 */ 19 20 #include <sys/param.h> 21 #include <sys/kernel.h> 22 #include <sys/bus.h> 23 #include <sys/module.h> 24 25 #include <sys/module.h> 26 #include <sys/bus.h> 27 #include <sys/rman.h> 28 29 #include <bus/isa/isavar.h> 30 31 #include <sys/systm.h> 32 33 #include <sys/sensors.h> 34 35 #include "lm78var.h" 36 37 /* ISA registers */ 38 #define LMC_ADDR 0x05 39 #define LMC_DATA 0x06 40 41 extern struct cfdriver lm_cd; 42 43 #if defined(LMDEBUG) 44 #define DPRINTF(x) do { kprintf x; } while (0) 45 #else 46 #define DPRINTF(x) 47 #endif 48 49 struct lm_isa_softc { 50 struct lm_softc sc_lmsc; 51 52 struct resource *sc_iores; 53 int sc_iorid; 54 bus_space_tag_t sc_iot; 55 bus_space_handle_t sc_ioh; 56 }; 57 58 static int lm_isa_probe(struct device *); 59 static int lm_isa_attach(struct device *); 60 static int lm_isa_detach(struct device *); 61 u_int8_t lm_isa_readreg(struct lm_softc *, int); 62 void lm_isa_writereg(struct lm_softc *, int, int); 63 64 static device_method_t lm_isa_methods[] = { 65 /* Methods from the device interface */ 66 DEVMETHOD(device_probe, lm_isa_probe), 67 DEVMETHOD(device_attach, lm_isa_attach), 68 DEVMETHOD(device_detach, lm_isa_detach), 69 70 /* Terminate method list */ 71 { 0, 0 } 72 }; 73 74 static driver_t lm_isa_driver = { 75 "lm", 76 lm_isa_methods, 77 sizeof (struct lm_isa_softc) 78 }; 79 80 static devclass_t lm_devclass; 81 82 DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL); 83 84 int 85 lm_isa_probe(struct device *dev) 86 { 87 struct lm_isa_softc *sc = device_get_softc(dev); 88 struct resource *iores; 89 int iorid = 0; 90 bus_space_tag_t iot; 91 bus_space_handle_t ioh; 92 int banksel, vendid, chipid, addr; 93 94 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 95 0ul, ~0ul, 8, RF_ACTIVE); 96 if (iores == NULL) { 97 DPRINTF(("%s: can't map i/o space\n", __func__)); 98 return (1); 99 } 100 iot = rman_get_bustag(iores); 101 ioh = rman_get_bushandle(iores); 102 103 /* Probe for Winbond chips. */ 104 bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); 105 banksel = bus_space_read_1(iot, ioh, LMC_DATA); 106 bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID); 107 vendid = bus_space_read_1(iot, ioh, LMC_DATA); 108 if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) || 109 (!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff))) 110 goto found; 111 112 /* Probe for ITE chips (and don't attach if we find one). */ 113 bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/); 114 vendid = bus_space_read_1(iot, ioh, LMC_DATA); 115 if (vendid == 0x90 /*IT_ID_IT87*/) 116 goto notfound; 117 118 /* 119 * Probe for National Semiconductor LM78/79/81. 120 * 121 * XXX This assumes the address has not been changed from the 122 * power up default. This is probably a reasonable 123 * assumption, and if it isn't true, we should be able to 124 * access the chip using the serial bus. 125 */ 126 bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR); 127 addr = bus_space_read_1(iot, ioh, LMC_DATA); 128 if ((addr & 0xfc) == 0x2c) { 129 bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID); 130 chipid = bus_space_read_1(iot, ioh, LMC_DATA); 131 132 switch (chipid & LM_CHIPID_MASK) { 133 case LM_CHIPID_LM78: 134 case LM_CHIPID_LM78J: 135 case LM_CHIPID_LM79: 136 case LM_CHIPID_LM81: 137 goto found; 138 } 139 } 140 141 notfound: 142 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 143 144 return (1); 145 146 found: 147 /* Bus-independent probe */ 148 sc->sc_lmsc.sc_dev = dev; 149 sc->sc_iot = iot; 150 sc->sc_ioh = ioh; 151 sc->sc_lmsc.lm_writereg = lm_isa_writereg; 152 sc->sc_lmsc.lm_readreg = lm_isa_readreg; 153 lm_probe(&sc->sc_lmsc); 154 155 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 156 sc->sc_iot = 0; 157 sc->sc_ioh = 0; 158 159 return (0); 160 } 161 162 int 163 lm_isa_attach(struct device *dev) 164 { 165 struct lm_isa_softc *sc = device_get_softc(dev); 166 #ifdef notyet 167 struct lm_softc *lmsc; 168 int i; 169 u_int8_t sbusaddr; 170 #endif 171 172 sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 173 0ul, ~0ul, 8, RF_ACTIVE); 174 if (sc->sc_iores == NULL) { 175 device_printf(dev, "can't map i/o space\n"); 176 return (1); 177 } 178 sc->sc_iot = rman_get_bustag(sc->sc_iores); 179 sc->sc_ioh = rman_get_bushandle(sc->sc_iores); 180 181 /* Bus-independent attachment */ 182 lm_attach(&sc->sc_lmsc); 183 184 #ifdef notyet 185 /* 186 * Most devices supported by this driver can attach to iic(4) 187 * as well. However, we prefer to attach them to isa(4) since 188 * that causes less overhead and is more reliable. We look 189 * through all previously attached devices, and if we find an 190 * identical chip at the same serial bus address, we stop 191 * updating its sensors and mark them as invalid. 192 */ 193 194 sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR); 195 if (sbusaddr == 0) 196 return (0); 197 198 for (i = 0; i < lm_cd.cd_ndevs; i++) { 199 lmsc = lm_cd.cd_devs[i]; 200 if (lmsc == &sc->sc_lmsc) 201 continue; 202 if (lmsc && lmsc->sbusaddr == sbusaddr && 203 lmsc->chipid == sc->sc_lmsc.chipid) 204 config_detach(&lmsc->sc_dev, 0); 205 } 206 #endif 207 return (0); 208 } 209 210 int 211 lm_isa_detach(struct device *dev) 212 { 213 struct lm_isa_softc *sc = device_get_softc(dev); 214 int error; 215 216 /* Bus-independent detachment */ 217 error = lm_detach(&sc->sc_lmsc); 218 if (error) 219 return (error); 220 221 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, 222 sc->sc_iores); 223 if (error) 224 return (error); 225 226 return (0); 227 } 228 229 u_int8_t 230 lm_isa_readreg(struct lm_softc *lmsc, int reg) 231 { 232 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; 233 234 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); 235 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA)); 236 } 237 238 void 239 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val) 240 { 241 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; 242 243 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); 244 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val); 245 } 246