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 #include <sys/rman.h> 25 26 #include <bus/isa/isavar.h> 27 28 #include <sys/systm.h> 29 30 #include <sys/sensors.h> 31 32 #include "lm78var.h" 33 #include "../wbsio/wbsioreg.h" 34 #include "../wbsio/wbsiovar.h" 35 36 /* ISA registers */ 37 #define LMC_ADDR 0x05 38 #define LMC_DATA 0x06 39 40 #if defined(LMDEBUG) 41 #define DPRINTF(x) do { kprintf x; } while (0) 42 #else 43 #define DPRINTF(x) 44 #endif 45 46 struct lm_isa_softc { 47 struct lm_softc sc_lmsc; 48 49 struct resource *sc_iores; 50 int sc_iorid; 51 bus_space_tag_t sc_iot; 52 bus_space_handle_t sc_ioh; 53 }; 54 55 static int lm_isa_probe(struct device *); 56 static int lm_isa_attach(struct device *); 57 static int lm_isa_detach(struct device *); 58 u_int8_t lm_isa_readreg(struct lm_softc *, int); 59 void lm_isa_writereg(struct lm_softc *, int, int); 60 61 static device_method_t lm_isa_methods[] = { 62 /* Methods from the device interface */ 63 DEVMETHOD(device_probe, lm_isa_probe), 64 DEVMETHOD(device_attach, lm_isa_attach), 65 DEVMETHOD(device_detach, lm_isa_detach), 66 67 /* Terminate method list */ 68 DEVMETHOD_END 69 }; 70 71 static driver_t lm_isa_driver = { 72 "lm", 73 lm_isa_methods, 74 sizeof (struct lm_isa_softc) 75 }; 76 77 static devclass_t lm_devclass; 78 79 DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL); 80 DRIVER_MODULE(lm, wbsio, lm_isa_driver, lm_devclass, NULL, NULL); 81 82 int 83 lm_isa_probe(struct device *dev) 84 { 85 struct lm_isa_softc *sc = device_get_softc(dev); 86 struct wbsio_softc *wbsc = NULL; 87 struct resource *iores; 88 struct devclass *parent_devclass; 89 const char *parent_name; 90 int iorid = 0; 91 bus_space_tag_t iot; 92 bus_space_handle_t ioh; 93 int banksel, vendid, chipid, addr; 94 95 parent_devclass = device_get_devclass(device_get_parent(dev)); 96 parent_name = devclass_get_name(parent_devclass); 97 if (strcmp("wbsio", parent_name) == 0) { 98 wbsc = device_get_softc(device_get_parent(dev)); 99 sc->sc_lmsc.sioid = wbsc->sc_devid; 100 } else { 101 sc->sc_lmsc.sioid = 0; 102 } 103 104 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 105 0ul, ~0ul, 8, RF_ACTIVE); 106 if (iores == NULL) { 107 DPRINTF(("%s: can't map i/o space\n", __func__)); 108 return (1); 109 } 110 iot = rman_get_bustag(iores); 111 ioh = rman_get_bushandle(iores); 112 113 /* Probe for Winbond chips. */ 114 bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); 115 banksel = bus_space_read_1(iot, ioh, LMC_DATA); 116 bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); 117 bus_space_write_1(iot, ioh, LMC_DATA, WB_BANKSEL_HBAC); 118 bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID); 119 vendid = bus_space_read_1(iot, ioh, LMC_DATA) << 8; 120 bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); 121 bus_space_write_1(iot, ioh, LMC_DATA, 0); 122 bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID); 123 vendid |= bus_space_read_1(iot, ioh, LMC_DATA); 124 bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); 125 bus_space_write_1(iot, ioh, LMC_DATA, banksel); 126 if (vendid == WB_VENDID_WINBOND) 127 goto found; 128 129 /* Probe for ITE chips (and don't attach if we find one). */ 130 bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/); 131 vendid = bus_space_read_1(iot, ioh, LMC_DATA); 132 if (vendid == 0x90 /*IT_ID_IT87*/) 133 goto notfound; 134 135 /* 136 * Probe for National Semiconductor LM78/79/81. 137 * 138 * XXX This assumes the address has not been changed from the 139 * power up default. This is probably a reasonable 140 * assumption, and if it isn't true, we should be able to 141 * access the chip using the serial bus. 142 */ 143 bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR); 144 addr = bus_space_read_1(iot, ioh, LMC_DATA); 145 if ((addr & 0xfc) == 0x2c) { 146 bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID); 147 chipid = bus_space_read_1(iot, ioh, LMC_DATA); 148 149 switch (chipid & LM_CHIPID_MASK) { 150 case LM_CHIPID_LM78: 151 case LM_CHIPID_LM78J: 152 case LM_CHIPID_LM79: 153 case LM_CHIPID_LM81: 154 goto found; 155 } 156 } 157 158 notfound: 159 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 160 161 return (1); 162 163 found: 164 /* Bus-independent probe */ 165 sc->sc_lmsc.sc_dev = dev; 166 sc->sc_iot = iot; 167 sc->sc_ioh = ioh; 168 sc->sc_lmsc.lm_writereg = lm_isa_writereg; 169 sc->sc_lmsc.lm_readreg = lm_isa_readreg; 170 lm_probe(&sc->sc_lmsc); 171 172 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 173 sc->sc_iot = 0; 174 sc->sc_ioh = 0; 175 176 return (0); 177 } 178 179 int 180 lm_isa_attach(struct device *dev) 181 { 182 struct lm_isa_softc *sc = device_get_softc(dev); 183 #ifdef notyet 184 struct lm_softc *lmsc; 185 int i; 186 u_int8_t sbusaddr; 187 #endif 188 189 sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 190 0ul, ~0ul, 8, RF_ACTIVE); 191 if (sc->sc_iores == NULL) { 192 device_printf(dev, "can't map i/o space\n"); 193 return (1); 194 } 195 sc->sc_iot = rman_get_bustag(sc->sc_iores); 196 sc->sc_ioh = rman_get_bushandle(sc->sc_iores); 197 198 /* Bus-independent attachment */ 199 lm_attach(&sc->sc_lmsc); 200 201 #ifdef notyet 202 /* 203 * Most devices supported by this driver can attach to iic(4) 204 * as well. However, we prefer to attach them to isa(4) since 205 * that causes less overhead and is more reliable. We look 206 * through all previously attached devices, and if we find an 207 * identical chip at the same serial bus address, we stop 208 * updating its sensors and mark them as invalid. 209 */ 210 211 sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR); 212 if (sbusaddr == 0) 213 return (0); 214 215 for (i = 0; i < lm_cd.cd_ndevs; i++) { 216 lmsc = lm_cd.cd_devs[i]; 217 if (lmsc == &sc->sc_lmsc) 218 continue; 219 if (lmsc && lmsc->sbusaddr == sbusaddr && 220 lmsc->chipid == sc->sc_lmsc.chipid) 221 config_detach(&lmsc->sc_dev, 0); 222 } 223 #endif 224 return (0); 225 } 226 227 int 228 lm_isa_detach(struct device *dev) 229 { 230 struct lm_isa_softc *sc = device_get_softc(dev); 231 int error; 232 233 /* Bus-independent detachment */ 234 error = lm_detach(&sc->sc_lmsc); 235 if (error) 236 return (error); 237 238 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, 239 sc->sc_iores); 240 if (error) 241 return (error); 242 243 return (0); 244 } 245 246 u_int8_t 247 lm_isa_readreg(struct lm_softc *lmsc, int reg) 248 { 249 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; 250 251 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); 252 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA)); 253 } 254 255 void 256 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val) 257 { 258 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; 259 260 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); 261 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val); 262 } 263