2 * Copyright (c) 2005, 2006 Mark Kettenis
3 * Copyright (c) 2007 Constantine A. Murenin, Google Summer of Code
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.
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.
17 * $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $
20 #include <sys/param.h>
21 #include <sys/kernel.h>
23 #include <sys/module.h>
26 #include <bus/isa/isavar.h>
28 #include <sys/systm.h>
30 #include <sys/sensors.h>
33 #include "../wbsio/wbsioreg.h"
34 #include "../wbsio/wbsiovar.h"
41 #define DPRINTF(x) do { kprintf x; } while (0)
47 struct lm_softc sc_lmsc;
49 struct resource *sc_iores;
51 bus_space_tag_t sc_iot;
52 bus_space_handle_t sc_ioh;
55 static int lm_isa_probe(device_t);
56 static int lm_isa_attach(device_t);
57 static int lm_isa_detach(device_t);
58 u_int8_t lm_isa_readreg(struct lm_softc *, int);
59 void lm_isa_writereg(struct lm_softc *, int, int);
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),
67 /* Terminate method list */
71 static driver_t lm_isa_driver = {
74 sizeof (struct lm_isa_softc)
77 static devclass_t lm_devclass;
79 DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL);
80 DRIVER_MODULE(lm, wbsio, lm_isa_driver, lm_devclass, NULL, NULL);
83 lm_isa_probe(device_t dev)
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;
92 bus_space_handle_t ioh;
93 int banksel, vendid, chipid, addr;
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;
101 sc->sc_lmsc.sioid = 0;
104 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
105 0ul, ~0ul, 8, RF_ACTIVE);
107 DPRINTF(("%s: can't map i/o space\n", __func__));
110 iot = rman_get_bustag(iores);
111 ioh = rman_get_bushandle(iores);
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)
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*/)
136 * Probe for National Semiconductor LM78/79/81.
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.
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);
149 switch (chipid & LM_CHIPID_MASK) {
151 case LM_CHIPID_LM78J:
159 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
164 /* Bus-independent probe */
165 sc->sc_lmsc.sc_dev = dev;
168 sc->sc_lmsc.lm_writereg = lm_isa_writereg;
169 sc->sc_lmsc.lm_readreg = lm_isa_readreg;
170 lm_probe(&sc->sc_lmsc);
172 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
180 lm_isa_attach(device_t dev)
182 struct lm_isa_softc *sc = device_get_softc(dev);
184 struct lm_softc *lmsc;
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");
195 sc->sc_iot = rman_get_bustag(sc->sc_iores);
196 sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
198 /* Bus-independent attachment */
199 lm_attach(&sc->sc_lmsc);
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.
211 sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
215 for (i = 0; i < lm_cd.cd_ndevs; i++) {
216 lmsc = lm_cd.cd_devs[i];
217 if (lmsc == &sc->sc_lmsc)
219 if (lmsc && lmsc->sbusaddr == sbusaddr &&
220 lmsc->chipid == sc->sc_lmsc.chipid)
221 config_detach(&lmsc->sc_dev, 0);
228 lm_isa_detach(device_t dev)
230 struct lm_isa_softc *sc = device_get_softc(dev);
233 /* Bus-independent detachment */
234 error = lm_detach(&sc->sc_lmsc);
238 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
247 lm_isa_readreg(struct lm_softc *lmsc, int reg)
249 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
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));
256 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
258 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
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);