xref: /dragonfly/sys/dev/powermng/lm/lm78_isa.c (revision 2020c8fe)
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 
25 #include <sys/module.h>
26 #include <sys/bus.h>
27 #include <sys/rman.h>
28 
29 #include <bus/isa/isavar.h>
30 
31 #include <sys/systm.h>
32 
33 #include <sys/sensors.h>
34 
35 #include "lm78var.h"
36 
37 /* ISA registers */
38 #define LMC_ADDR	0x05
39 #define LMC_DATA	0x06
40 
41 extern struct cfdriver lm_cd;
42 
43 #if defined(LMDEBUG)
44 #define DPRINTF(x)		do { kprintf x; } while (0)
45 #else
46 #define DPRINTF(x)
47 #endif
48 
49 struct lm_isa_softc {
50 	struct lm_softc sc_lmsc;
51 
52 	struct resource *sc_iores;
53 	int sc_iorid;
54 	bus_space_tag_t sc_iot;
55 	bus_space_handle_t sc_ioh;
56 };
57 
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);
63 
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),
69 
70 	/* Terminate method list */
71 	{ 0, 0 }
72 };
73 
74 static driver_t lm_isa_driver = {
75 	"lm",
76 	lm_isa_methods,
77 	sizeof (struct lm_isa_softc)
78 };
79 
80 static devclass_t lm_devclass;
81 
82 DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL);
83 
84 int
85 lm_isa_probe(struct device *dev)
86 {
87 	struct lm_isa_softc *sc = device_get_softc(dev);
88 	struct resource *iores;
89 	int iorid = 0;
90 	bus_space_tag_t iot;
91 	bus_space_handle_t ioh;
92 	int banksel, vendid, chipid, addr;
93 
94 	iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
95 	    0ul, ~0ul, 8, RF_ACTIVE);
96 	if (iores == NULL) {
97 		DPRINTF(("%s: can't map i/o space\n", __func__));
98 		return (1);
99 	}
100 	iot = rman_get_bustag(iores);
101 	ioh = rman_get_bushandle(iores);
102 
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)))
110 		goto found;
111 
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*/)
116 		goto notfound;
117 
118 	/*
119 	 * Probe for National Semiconductor LM78/79/81.
120 	 *
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.
125 	 */
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);
131 
132 		switch (chipid & LM_CHIPID_MASK) {
133 		case LM_CHIPID_LM78:
134 		case LM_CHIPID_LM78J:
135 		case LM_CHIPID_LM79:
136 		case LM_CHIPID_LM81:
137 			goto found;
138 		}
139 	}
140 
141  notfound:
142 	bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
143 
144 	return (1);
145 
146  found:
147 	/* Bus-independent probe */
148 	sc->sc_lmsc.sc_dev = dev;
149 	sc->sc_iot = iot;
150 	sc->sc_ioh = ioh;
151 	sc->sc_lmsc.lm_writereg = lm_isa_writereg;
152 	sc->sc_lmsc.lm_readreg = lm_isa_readreg;
153 	lm_probe(&sc->sc_lmsc);
154 
155 	bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
156 	sc->sc_iot = 0;
157 	sc->sc_ioh = 0;
158 
159 	return (0);
160 }
161 
162 int
163 lm_isa_attach(struct device *dev)
164 {
165 	struct lm_isa_softc *sc = device_get_softc(dev);
166 #ifdef notyet
167 	struct lm_softc *lmsc;
168 	int i;
169 	u_int8_t sbusaddr;
170 #endif
171 
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");
176 		return (1);
177 	}
178 	sc->sc_iot = rman_get_bustag(sc->sc_iores);
179 	sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
180 
181 	/* Bus-independent attachment */
182 	lm_attach(&sc->sc_lmsc);
183 
184 #ifdef notyet
185 	/*
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.
192 	 */
193 
194 	sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
195 	if (sbusaddr == 0)
196 		return (0);
197 
198 	for (i = 0; i < lm_cd.cd_ndevs; i++) {
199 		lmsc = lm_cd.cd_devs[i];
200 		if (lmsc == &sc->sc_lmsc)
201 			continue;
202 		if (lmsc && lmsc->sbusaddr == sbusaddr &&
203 		    lmsc->chipid == sc->sc_lmsc.chipid)
204 			config_detach(&lmsc->sc_dev, 0);
205 	}
206 #endif
207 	return (0);
208 }
209 
210 int
211 lm_isa_detach(struct device *dev)
212 {
213 	struct lm_isa_softc *sc = device_get_softc(dev);
214 	int error;
215 
216 	/* Bus-independent detachment */
217 	error = lm_detach(&sc->sc_lmsc);
218 	if (error)
219 		return (error);
220 
221 	error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
222 	    sc->sc_iores);
223 	if (error)
224 		return (error);
225 
226 	return (0);
227 }
228 
229 u_int8_t
230 lm_isa_readreg(struct lm_softc *lmsc, int reg)
231 {
232 	struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
233 
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));
236 }
237 
238 void
239 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
240 {
241 	struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
242 
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);
245 }
246