xref: /openbsd-src/sys/dev/isa/lm78_isa.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: lm78_isa.c,v 1.5 2011/07/26 18:43:36 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/sensors.h>
23 #include <machine/bus.h>
24 
25 #include <dev/isa/isareg.h>
26 #include <dev/isa/isavar.h>
27 
28 #include <dev/ic/lm78var.h>
29 
30 /* ISA registers */
31 #define LMC_ADDR	0x05
32 #define LMC_DATA	0x06
33 
34 extern struct cfdriver lm_cd;
35 
36 #if defined(LMDEBUG)
37 #define DPRINTF(x)		do { printf x; } while (0)
38 #else
39 #define DPRINTF(x)
40 #endif
41 
42 struct lm_isa_softc {
43 	struct lm_softc sc_lmsc;
44 
45 	bus_space_tag_t sc_iot;
46 	bus_space_handle_t sc_ioh;
47 };
48 
49 int  lm_isa_match(struct device *, void *, void *);
50 void lm_isa_attach(struct device *, struct device *, void *);
51 u_int8_t lm_isa_readreg(struct lm_softc *, int);
52 void lm_isa_writereg(struct lm_softc *, int, int);
53 
54 struct cfattach lm_isa_ca = {
55 	sizeof(struct lm_isa_softc),
56 	lm_isa_match,
57 	lm_isa_attach
58 };
59 
60 struct cfattach lm_wbsio_ca = {
61 	sizeof(struct lm_isa_softc),
62 	lm_isa_match,
63 	lm_isa_attach
64 };
65 
66 int
67 lm_isa_match(struct device *parent, void *match, void *aux)
68 {
69 	bus_space_tag_t iot;
70 	bus_addr_t iobase;
71 	bus_space_handle_t ioh;
72 	struct isa_attach_args *ia = aux;
73 	int banksel, vendid, chipid, addr;
74 
75 	iot = ia->ia_iot;
76 	iobase = ia->ipa_io[0].base;
77 
78 	if (bus_space_map(iot, iobase, 8, 0, &ioh)) {
79 		DPRINTF(("%s: can't map i/o space\n", __func__));
80 		return (0);
81 	}
82 
83 	/* Probe for Winbond chips. */
84 	bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
85 	banksel = bus_space_read_1(iot, ioh, LMC_DATA);
86 	bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
87 	vendid = bus_space_read_1(iot, ioh, LMC_DATA);
88 	if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) ||
89 	    (!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff)))
90 		goto found;
91 
92 	/* Probe for ITE chips (and don't attach if we find one). */
93 	bus_space_write_1(iot, ioh, LMC_ADDR, 0x58);
94 	if ((vendid = bus_space_read_1(iot, ioh, LMC_DATA)) == 0x90)
95 		goto notfound;
96 
97 	/*
98 	 * Probe for National Semiconductor LM78/79/81.
99 	 *
100 	 * XXX This assumes the address has not been changed from the
101 	 * power up default.  This is probably a reasonable
102 	 * assumption, and if it isn't true, we should be able to
103 	 * access the chip using the serial bus.
104 	 */
105 	bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR);
106 	addr = bus_space_read_1(iot, ioh, LMC_DATA);
107 	if ((addr & 0xfc) == 0x2c) {
108 		bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID);
109 		chipid = bus_space_read_1(iot, ioh, LMC_DATA);
110 
111 		switch (chipid & LM_CHIPID_MASK) {
112 		case LM_CHIPID_LM78:
113 		case LM_CHIPID_LM78J:
114 		case LM_CHIPID_LM79:
115 		case LM_CHIPID_LM81:
116 			goto found;
117 		}
118 	}
119 
120  notfound:
121 	bus_space_unmap(iot, ioh, 8);
122 
123 	return (0);
124 
125  found:
126 	bus_space_unmap(iot, ioh, 8);
127 
128 	ia->ipa_nio = 1;
129 	ia->ipa_io[0].length = 8;
130 
131 	ia->ipa_nmem = 0;
132 	ia->ipa_nirq = 0;
133 	ia->ipa_ndrq = 0;
134 
135 	return (1);
136 }
137 
138 void
139 lm_isa_attach(struct device *parent, struct device *self, void *aux)
140 {
141 	struct lm_isa_softc *sc = (struct lm_isa_softc *)self;
142 	struct isa_attach_args *ia = aux;
143 	struct lm_softc *lmsc;
144 	bus_addr_t iobase;
145 	int i;
146 	u_int8_t sbusaddr;
147 
148 	sc->sc_iot = ia->ia_iot;
149 	iobase = ia->ipa_io[0].base;
150 
151 	if (bus_space_map(sc->sc_iot, iobase, 8, 0, &sc->sc_ioh)) {
152 		printf(": can't map i/o space\n");
153 		return;
154 	}
155 
156 	/* Bus-independant attachment */
157 	sc->sc_lmsc.lm_writereg = lm_isa_writereg;
158 	sc->sc_lmsc.lm_readreg = lm_isa_readreg;
159 	lm_attach(&sc->sc_lmsc);
160 
161 	/*
162 	 * Most devices supported by this driver can attach to iic(4)
163 	 * as well.  However, we prefer to attach them to isa(4) since
164 	 * that causes less overhead and is more reliable.  We look
165 	 * through all previously attached devices, and if we find an
166 	 * identical chip at the same serial bus address, we stop
167 	 * updating its sensors and mark them as invalid.
168 	 */
169 
170 	sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
171 	if (sbusaddr == 0)
172 		return;
173 
174 	for (i = 0; i < lm_cd.cd_ndevs; i++) {
175 		lmsc = lm_cd.cd_devs[i];
176 		if (lmsc == &sc->sc_lmsc)
177 			continue;
178 		if (lmsc && lmsc->sbusaddr == sbusaddr &&
179 		    lmsc->chipid == sc->sc_lmsc.chipid)
180 			lmsc->flags = LM78_DEAD;
181 	}
182 }
183 
184 u_int8_t
185 lm_isa_readreg(struct lm_softc *lmsc, int reg)
186 {
187 	struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
188 
189 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
190 	return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA));
191 }
192 
193 void
194 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
195 {
196 	struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
197 
198 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
199 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val);
200 }
201