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>
25 #include <sys/module.h>
29 #include <bus/isa/isavar.h>
31 #include <sys/systm.h>
33 #include <sys/sensors.h>
41 extern struct cfdriver lm_cd
;
44 #define DPRINTF(x) do { printf x; } while (0)
50 struct lm_softc sc_lmsc
;
52 struct resource
*sc_iores
;
54 bus_space_tag_t sc_iot
;
55 bus_space_handle_t sc_ioh
;
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);
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
),
70 /* Terminate method list */
74 static driver_t lm_isa_driver
= {
77 sizeof (struct lm_isa_softc
)
80 static devclass_t lm_devclass
;
82 DRIVER_MODULE(lm
, isa
, lm_isa_driver
, lm_devclass
, NULL
, NULL
);
85 lm_isa_probe(struct device
*dev
)
87 struct lm_isa_softc
*sc
= device_get_softc(dev
);
88 struct resource
*iores
;
91 bus_space_handle_t ioh
;
92 int banksel
, vendid
, chipid
, addr
;
94 iores
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &iorid
,
95 0ul, ~0ul, 8, RF_ACTIVE
);
97 DPRINTF(("%s: can't map i/o space\n", __func__
));
100 iot
= rman_get_bustag(iores
);
101 ioh
= rman_get_bushandle(iores
);
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)))
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*/)
119 * Probe for National Semiconductor LM78/79/81.
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.
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
);
132 switch (chipid
& LM_CHIPID_MASK
) {
134 case LM_CHIPID_LM78J
:
142 bus_release_resource(dev
, SYS_RES_IOPORT
, iorid
, iores
);
147 /* Bus-independent probe */
148 sc
->sc_lmsc
.sc_dev
= dev
;
151 sc
->sc_lmsc
.lm_writereg
= lm_isa_writereg
;
152 sc
->sc_lmsc
.lm_readreg
= lm_isa_readreg
;
153 lm_probe(&sc
->sc_lmsc
);
155 bus_release_resource(dev
, SYS_RES_IOPORT
, iorid
, iores
);
163 lm_isa_attach(struct device
*dev
)
165 struct lm_isa_softc
*sc
= device_get_softc(dev
);
167 struct lm_softc
*lmsc
;
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");
178 sc
->sc_iot
= rman_get_bustag(sc
->sc_iores
);
179 sc
->sc_ioh
= rman_get_bushandle(sc
->sc_iores
);
181 /* Bus-independent attachment */
182 lm_attach(&sc
->sc_lmsc
);
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.
194 sbusaddr
= lm_isa_readreg(&sc
->sc_lmsc
, LM_SBUSADDR
);
198 for (i
= 0; i
< lm_cd
.cd_ndevs
; i
++) {
199 lmsc
= lm_cd
.cd_devs
[i
];
200 if (lmsc
== &sc
->sc_lmsc
)
202 if (lmsc
&& lmsc
->sbusaddr
== sbusaddr
&&
203 lmsc
->chipid
== sc
->sc_lmsc
.chipid
)
204 config_detach(&lmsc
->sc_dev
, 0);
211 lm_isa_detach(struct device
*dev
)
213 struct lm_isa_softc
*sc
= device_get_softc(dev
);
216 /* Bus-independent detachment */
217 error
= lm_detach(&sc
->sc_lmsc
);
221 error
= bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->sc_iorid
,
230 lm_isa_readreg(struct lm_softc
*lmsc
, int reg
)
232 struct lm_isa_softc
*sc
= (struct lm_isa_softc
*)lmsc
;
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
));
239 lm_isa_writereg(struct lm_softc
*lmsc
, int reg
, int val
)
241 struct lm_isa_softc
*sc
= (struct lm_isa_softc
*)lmsc
;
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
);