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