11d03db02SHasso Tepper /*
21d03db02SHasso Tepper * Copyright (c) 2005, 2006 Mark Kettenis
31d03db02SHasso Tepper * Copyright (c) 2007 Constantine A. Murenin, Google Summer of Code
41d03db02SHasso Tepper *
51d03db02SHasso Tepper * Permission to use, copy, modify, and distribute this software for any
61d03db02SHasso Tepper * purpose with or without fee is hereby granted, provided that the above
71d03db02SHasso Tepper * copyright notice and this permission notice appear in all copies.
81d03db02SHasso Tepper *
91d03db02SHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101d03db02SHasso Tepper * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111d03db02SHasso Tepper * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121d03db02SHasso Tepper * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131d03db02SHasso Tepper * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141d03db02SHasso Tepper * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151d03db02SHasso Tepper * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161d03db02SHasso Tepper *
171d03db02SHasso Tepper * $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $
181d03db02SHasso Tepper */
191d03db02SHasso Tepper
201d03db02SHasso Tepper #include <sys/param.h>
211d03db02SHasso Tepper #include <sys/kernel.h>
221d03db02SHasso Tepper #include <sys/bus.h>
231d03db02SHasso Tepper #include <sys/module.h>
241d03db02SHasso Tepper #include <sys/rman.h>
251d03db02SHasso Tepper
261d03db02SHasso Tepper #include <bus/isa/isavar.h>
271d03db02SHasso Tepper
281d03db02SHasso Tepper #include <sys/systm.h>
291d03db02SHasso Tepper
301d03db02SHasso Tepper #include <sys/sensors.h>
311d03db02SHasso Tepper
321d03db02SHasso Tepper #include "lm78var.h"
331d3c4164SMatthew Dillon #include "../wbsio/wbsioreg.h"
341d3c4164SMatthew Dillon #include "../wbsio/wbsiovar.h"
351d03db02SHasso Tepper
361d03db02SHasso Tepper /* ISA registers */
371d03db02SHasso Tepper #define LMC_ADDR 0x05
381d03db02SHasso Tepper #define LMC_DATA 0x06
391d03db02SHasso Tepper
401d03db02SHasso Tepper #if defined(LMDEBUG)
416ab5c081SSascha Wildner #define DPRINTF(x) do { kprintf x; } while (0)
421d03db02SHasso Tepper #else
431d03db02SHasso Tepper #define DPRINTF(x)
441d03db02SHasso Tepper #endif
451d03db02SHasso Tepper
461d03db02SHasso Tepper struct lm_isa_softc {
471d03db02SHasso Tepper struct lm_softc sc_lmsc;
481d03db02SHasso Tepper
491d03db02SHasso Tepper struct resource *sc_iores;
501d03db02SHasso Tepper int sc_iorid;
511d03db02SHasso Tepper bus_space_tag_t sc_iot;
521d03db02SHasso Tepper bus_space_handle_t sc_ioh;
531d03db02SHasso Tepper };
541d03db02SHasso Tepper
55*5d302545SFrançois Tigeot static int lm_isa_probe(device_t);
56*5d302545SFrançois Tigeot static int lm_isa_attach(device_t);
57*5d302545SFrançois Tigeot static int lm_isa_detach(device_t);
581d03db02SHasso Tepper u_int8_t lm_isa_readreg(struct lm_softc *, int);
591d03db02SHasso Tepper void lm_isa_writereg(struct lm_softc *, int, int);
601d03db02SHasso Tepper
611d03db02SHasso Tepper static device_method_t lm_isa_methods[] = {
621d03db02SHasso Tepper /* Methods from the device interface */
631d03db02SHasso Tepper DEVMETHOD(device_probe, lm_isa_probe),
641d03db02SHasso Tepper DEVMETHOD(device_attach, lm_isa_attach),
651d03db02SHasso Tepper DEVMETHOD(device_detach, lm_isa_detach),
661d03db02SHasso Tepper
671d03db02SHasso Tepper /* Terminate method list */
68d3c9c58eSSascha Wildner DEVMETHOD_END
691d03db02SHasso Tepper };
701d03db02SHasso Tepper
711d03db02SHasso Tepper static driver_t lm_isa_driver = {
721d03db02SHasso Tepper "lm",
731d03db02SHasso Tepper lm_isa_methods,
741d03db02SHasso Tepper sizeof (struct lm_isa_softc)
751d03db02SHasso Tepper };
761d03db02SHasso Tepper
771d03db02SHasso Tepper static devclass_t lm_devclass;
781d03db02SHasso Tepper
791d03db02SHasso Tepper DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL);
801d3c4164SMatthew Dillon DRIVER_MODULE(lm, wbsio, lm_isa_driver, lm_devclass, NULL, NULL);
811d03db02SHasso Tepper
820d4e06bcSSascha Wildner static int
lm_isa_probe(device_t dev)83*5d302545SFrançois Tigeot lm_isa_probe(device_t dev)
841d03db02SHasso Tepper {
851d03db02SHasso Tepper struct lm_isa_softc *sc = device_get_softc(dev);
861d3c4164SMatthew Dillon struct wbsio_softc *wbsc = NULL;
871d03db02SHasso Tepper struct resource *iores;
881d3c4164SMatthew Dillon struct devclass *parent_devclass;
891d3c4164SMatthew Dillon const char *parent_name;
901d03db02SHasso Tepper int iorid = 0;
911d03db02SHasso Tepper bus_space_tag_t iot;
921d03db02SHasso Tepper bus_space_handle_t ioh;
931d03db02SHasso Tepper int banksel, vendid, chipid, addr;
941d03db02SHasso Tepper
951d3c4164SMatthew Dillon parent_devclass = device_get_devclass(device_get_parent(dev));
961d3c4164SMatthew Dillon parent_name = devclass_get_name(parent_devclass);
971d3c4164SMatthew Dillon if (strcmp("wbsio", parent_name) == 0) {
981d3c4164SMatthew Dillon wbsc = device_get_softc(device_get_parent(dev));
991d3c4164SMatthew Dillon sc->sc_lmsc.sioid = wbsc->sc_devid;
1001d3c4164SMatthew Dillon } else {
1011d3c4164SMatthew Dillon sc->sc_lmsc.sioid = 0;
1021d3c4164SMatthew Dillon }
1031d3c4164SMatthew Dillon
1041d03db02SHasso Tepper iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
1051d03db02SHasso Tepper 0ul, ~0ul, 8, RF_ACTIVE);
1061d03db02SHasso Tepper if (iores == NULL) {
1071d03db02SHasso Tepper DPRINTF(("%s: can't map i/o space\n", __func__));
1081d03db02SHasso Tepper return (1);
1091d03db02SHasso Tepper }
1101d03db02SHasso Tepper iot = rman_get_bustag(iores);
1111d03db02SHasso Tepper ioh = rman_get_bushandle(iores);
1121d03db02SHasso Tepper
1131d03db02SHasso Tepper /* Probe for Winbond chips. */
1141d03db02SHasso Tepper bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
1151d03db02SHasso Tepper banksel = bus_space_read_1(iot, ioh, LMC_DATA);
1161d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
1171d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_DATA, WB_BANKSEL_HBAC);
1181d03db02SHasso Tepper bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
1191d3c4164SMatthew Dillon vendid = bus_space_read_1(iot, ioh, LMC_DATA) << 8;
1201d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
1211d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_DATA, 0);
1221d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
1231d3c4164SMatthew Dillon vendid |= bus_space_read_1(iot, ioh, LMC_DATA);
1241d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
1251d3c4164SMatthew Dillon bus_space_write_1(iot, ioh, LMC_DATA, banksel);
1261d3c4164SMatthew Dillon if (vendid == WB_VENDID_WINBOND)
1271d03db02SHasso Tepper goto found;
1281d03db02SHasso Tepper
1291d03db02SHasso Tepper /* Probe for ITE chips (and don't attach if we find one). */
1301d03db02SHasso Tepper bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/);
1311d03db02SHasso Tepper vendid = bus_space_read_1(iot, ioh, LMC_DATA);
1321d03db02SHasso Tepper if (vendid == 0x90 /*IT_ID_IT87*/)
1331d03db02SHasso Tepper goto notfound;
1341d03db02SHasso Tepper
1351d03db02SHasso Tepper /*
1361d03db02SHasso Tepper * Probe for National Semiconductor LM78/79/81.
1371d03db02SHasso Tepper *
1381d03db02SHasso Tepper * XXX This assumes the address has not been changed from the
1391d03db02SHasso Tepper * power up default. This is probably a reasonable
1401d03db02SHasso Tepper * assumption, and if it isn't true, we should be able to
1411d03db02SHasso Tepper * access the chip using the serial bus.
1421d03db02SHasso Tepper */
1431d03db02SHasso Tepper bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR);
1441d03db02SHasso Tepper addr = bus_space_read_1(iot, ioh, LMC_DATA);
1451d03db02SHasso Tepper if ((addr & 0xfc) == 0x2c) {
1461d03db02SHasso Tepper bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID);
1471d03db02SHasso Tepper chipid = bus_space_read_1(iot, ioh, LMC_DATA);
1481d03db02SHasso Tepper
1491d03db02SHasso Tepper switch (chipid & LM_CHIPID_MASK) {
1501d03db02SHasso Tepper case LM_CHIPID_LM78:
1511d03db02SHasso Tepper case LM_CHIPID_LM78J:
1521d03db02SHasso Tepper case LM_CHIPID_LM79:
1531d03db02SHasso Tepper case LM_CHIPID_LM81:
1541d03db02SHasso Tepper goto found;
1551d03db02SHasso Tepper }
1561d03db02SHasso Tepper }
1571d03db02SHasso Tepper
1581d03db02SHasso Tepper notfound:
1591d03db02SHasso Tepper bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
1601d03db02SHasso Tepper
1611d03db02SHasso Tepper return (1);
1621d03db02SHasso Tepper
1631d03db02SHasso Tepper found:
1641d03db02SHasso Tepper /* Bus-independent probe */
1651d03db02SHasso Tepper sc->sc_lmsc.sc_dev = dev;
1661d03db02SHasso Tepper sc->sc_iot = iot;
1671d03db02SHasso Tepper sc->sc_ioh = ioh;
1681d03db02SHasso Tepper sc->sc_lmsc.lm_writereg = lm_isa_writereg;
1691d03db02SHasso Tepper sc->sc_lmsc.lm_readreg = lm_isa_readreg;
1701d03db02SHasso Tepper lm_probe(&sc->sc_lmsc);
1711d03db02SHasso Tepper
1721d03db02SHasso Tepper bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
1731d03db02SHasso Tepper sc->sc_iot = 0;
1741d03db02SHasso Tepper sc->sc_ioh = 0;
1751d03db02SHasso Tepper
1761d03db02SHasso Tepper return (0);
1771d03db02SHasso Tepper }
1781d03db02SHasso Tepper
1790d4e06bcSSascha Wildner static int
lm_isa_attach(device_t dev)180*5d302545SFrançois Tigeot lm_isa_attach(device_t dev)
1811d03db02SHasso Tepper {
1821d03db02SHasso Tepper struct lm_isa_softc *sc = device_get_softc(dev);
1831d03db02SHasso Tepper #ifdef notyet
1841d03db02SHasso Tepper struct lm_softc *lmsc;
1851d03db02SHasso Tepper int i;
1861d03db02SHasso Tepper u_int8_t sbusaddr;
1871d03db02SHasso Tepper #endif
1881d03db02SHasso Tepper
1891d03db02SHasso Tepper sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
1901d03db02SHasso Tepper 0ul, ~0ul, 8, RF_ACTIVE);
1911d03db02SHasso Tepper if (sc->sc_iores == NULL) {
1921d03db02SHasso Tepper device_printf(dev, "can't map i/o space\n");
1931d03db02SHasso Tepper return (1);
1941d03db02SHasso Tepper }
1951d03db02SHasso Tepper sc->sc_iot = rman_get_bustag(sc->sc_iores);
1961d03db02SHasso Tepper sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
1971d03db02SHasso Tepper
1981d03db02SHasso Tepper /* Bus-independent attachment */
1991d03db02SHasso Tepper lm_attach(&sc->sc_lmsc);
2001d03db02SHasso Tepper
2011d03db02SHasso Tepper #ifdef notyet
2021d03db02SHasso Tepper /*
2031d03db02SHasso Tepper * Most devices supported by this driver can attach to iic(4)
2041d03db02SHasso Tepper * as well. However, we prefer to attach them to isa(4) since
2051d03db02SHasso Tepper * that causes less overhead and is more reliable. We look
2061d03db02SHasso Tepper * through all previously attached devices, and if we find an
2071d03db02SHasso Tepper * identical chip at the same serial bus address, we stop
2081d03db02SHasso Tepper * updating its sensors and mark them as invalid.
2091d03db02SHasso Tepper */
2101d03db02SHasso Tepper
2111d03db02SHasso Tepper sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
2121d03db02SHasso Tepper if (sbusaddr == 0)
2131d03db02SHasso Tepper return (0);
2141d03db02SHasso Tepper
2151d03db02SHasso Tepper for (i = 0; i < lm_cd.cd_ndevs; i++) {
2161d03db02SHasso Tepper lmsc = lm_cd.cd_devs[i];
2171d03db02SHasso Tepper if (lmsc == &sc->sc_lmsc)
2181d03db02SHasso Tepper continue;
2191d03db02SHasso Tepper if (lmsc && lmsc->sbusaddr == sbusaddr &&
2201d03db02SHasso Tepper lmsc->chipid == sc->sc_lmsc.chipid)
2211d03db02SHasso Tepper config_detach(&lmsc->sc_dev, 0);
2221d03db02SHasso Tepper }
2231d03db02SHasso Tepper #endif
2241d03db02SHasso Tepper return (0);
2251d03db02SHasso Tepper }
2261d03db02SHasso Tepper
2270d4e06bcSSascha Wildner static int
lm_isa_detach(device_t dev)228*5d302545SFrançois Tigeot lm_isa_detach(device_t dev)
2291d03db02SHasso Tepper {
2301d03db02SHasso Tepper struct lm_isa_softc *sc = device_get_softc(dev);
2311d03db02SHasso Tepper int error;
2321d03db02SHasso Tepper
2331d03db02SHasso Tepper /* Bus-independent detachment */
2341d03db02SHasso Tepper error = lm_detach(&sc->sc_lmsc);
2351d03db02SHasso Tepper if (error)
2361d03db02SHasso Tepper return (error);
2371d03db02SHasso Tepper
2381d03db02SHasso Tepper error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
2391d03db02SHasso Tepper sc->sc_iores);
2401d03db02SHasso Tepper if (error)
2411d03db02SHasso Tepper return (error);
2421d03db02SHasso Tepper
2431d03db02SHasso Tepper return (0);
2441d03db02SHasso Tepper }
2451d03db02SHasso Tepper
2461d03db02SHasso Tepper u_int8_t
lm_isa_readreg(struct lm_softc * lmsc,int reg)2471d03db02SHasso Tepper lm_isa_readreg(struct lm_softc *lmsc, int reg)
2481d03db02SHasso Tepper {
2491d03db02SHasso Tepper struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
2501d03db02SHasso Tepper
2511d03db02SHasso Tepper bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
2521d03db02SHasso Tepper return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA));
2531d03db02SHasso Tepper }
2541d03db02SHasso Tepper
2551d03db02SHasso Tepper void
lm_isa_writereg(struct lm_softc * lmsc,int reg,int val)2561d03db02SHasso Tepper lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
2571d03db02SHasso Tepper {
2581d03db02SHasso Tepper struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
2591d03db02SHasso Tepper
2601d03db02SHasso Tepper bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
2611d03db02SHasso Tepper bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val);
2621d03db02SHasso Tepper }
263