Merge branch 'openssh'
[dragonfly.git] / sys / dev / powermng / lm / lm78_isa.c
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 #include <sys/rman.h>
25
26 #include <bus/isa/isavar.h>
27
28 #include <sys/systm.h>
29
30 #include <sys/sensors.h>
31
32 #include "lm78var.h"
33
34 /* ISA registers */
35 #define LMC_ADDR        0x05
36 #define LMC_DATA        0x06
37
38 #if defined(LMDEBUG)
39 #define DPRINTF(x)              do { kprintf x; } while (0)
40 #else
41 #define DPRINTF(x)
42 #endif
43
44 struct lm_isa_softc {
45         struct lm_softc sc_lmsc;
46
47         struct resource *sc_iores;
48         int sc_iorid;
49         bus_space_tag_t sc_iot;
50         bus_space_handle_t sc_ioh;
51 };
52
53 static int lm_isa_probe(struct device *);
54 static int lm_isa_attach(struct device *);
55 static int lm_isa_detach(struct device *);
56 u_int8_t lm_isa_readreg(struct lm_softc *, int);
57 void lm_isa_writereg(struct lm_softc *, int, int);
58
59 static device_method_t lm_isa_methods[] = {
60         /* Methods from the device interface */
61         DEVMETHOD(device_probe,         lm_isa_probe),
62         DEVMETHOD(device_attach,        lm_isa_attach),
63         DEVMETHOD(device_detach,        lm_isa_detach),
64
65         /* Terminate method list */
66         DEVMETHOD_END
67 };
68
69 static driver_t lm_isa_driver = {
70         "lm",
71         lm_isa_methods,
72         sizeof (struct lm_isa_softc)
73 };
74
75 static devclass_t lm_devclass;
76
77 DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL);
78
79 int
80 lm_isa_probe(struct device *dev)
81 {
82         struct lm_isa_softc *sc = device_get_softc(dev);
83         struct resource *iores;
84         int iorid = 0;
85         bus_space_tag_t iot;
86         bus_space_handle_t ioh;
87         int banksel, vendid, chipid, addr;
88
89         iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
90             0ul, ~0ul, 8, RF_ACTIVE);
91         if (iores == NULL) {
92                 DPRINTF(("%s: can't map i/o space\n", __func__));
93                 return (1);
94         }
95         iot = rman_get_bustag(iores);
96         ioh = rman_get_bushandle(iores);
97
98         /* Probe for Winbond chips. */
99         bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
100         banksel = bus_space_read_1(iot, ioh, LMC_DATA);
101         bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
102         vendid = bus_space_read_1(iot, ioh, LMC_DATA);
103         if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) ||
104             (!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff)))
105                 goto found;
106
107         /* Probe for ITE chips (and don't attach if we find one). */
108         bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/);
109         vendid = bus_space_read_1(iot, ioh, LMC_DATA);
110         if (vendid == 0x90 /*IT_ID_IT87*/)
111                 goto notfound;
112
113         /*
114          * Probe for National Semiconductor LM78/79/81.
115          *
116          * XXX This assumes the address has not been changed from the
117          * power up default.  This is probably a reasonable
118          * assumption, and if it isn't true, we should be able to
119          * access the chip using the serial bus.
120          */
121         bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR);
122         addr = bus_space_read_1(iot, ioh, LMC_DATA);
123         if ((addr & 0xfc) == 0x2c) {
124                 bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID);
125                 chipid = bus_space_read_1(iot, ioh, LMC_DATA);
126
127                 switch (chipid & LM_CHIPID_MASK) {
128                 case LM_CHIPID_LM78:
129                 case LM_CHIPID_LM78J:
130                 case LM_CHIPID_LM79:
131                 case LM_CHIPID_LM81:
132                         goto found;
133                 }
134         }
135
136  notfound:
137         bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
138
139         return (1);
140
141  found:
142         /* Bus-independent probe */
143         sc->sc_lmsc.sc_dev = dev;
144         sc->sc_iot = iot;
145         sc->sc_ioh = ioh;
146         sc->sc_lmsc.lm_writereg = lm_isa_writereg;
147         sc->sc_lmsc.lm_readreg = lm_isa_readreg;
148         lm_probe(&sc->sc_lmsc);
149
150         bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
151         sc->sc_iot = 0;
152         sc->sc_ioh = 0;
153
154         return (0);
155 }
156
157 int
158 lm_isa_attach(struct device *dev)
159 {
160         struct lm_isa_softc *sc = device_get_softc(dev);
161 #ifdef notyet
162         struct lm_softc *lmsc;
163         int i;
164         u_int8_t sbusaddr;
165 #endif
166
167         sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
168             0ul, ~0ul, 8, RF_ACTIVE);
169         if (sc->sc_iores == NULL) {
170                 device_printf(dev, "can't map i/o space\n");
171                 return (1);
172         }
173         sc->sc_iot = rman_get_bustag(sc->sc_iores);
174         sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
175
176         /* Bus-independent attachment */
177         lm_attach(&sc->sc_lmsc);
178
179 #ifdef notyet
180         /*
181          * Most devices supported by this driver can attach to iic(4)
182          * as well.  However, we prefer to attach them to isa(4) since
183          * that causes less overhead and is more reliable.  We look
184          * through all previously attached devices, and if we find an
185          * identical chip at the same serial bus address, we stop
186          * updating its sensors and mark them as invalid.
187          */
188
189         sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
190         if (sbusaddr == 0)
191                 return (0);
192
193         for (i = 0; i < lm_cd.cd_ndevs; i++) {
194                 lmsc = lm_cd.cd_devs[i];
195                 if (lmsc == &sc->sc_lmsc)
196                         continue;
197                 if (lmsc && lmsc->sbusaddr == sbusaddr &&
198                     lmsc->chipid == sc->sc_lmsc.chipid)
199                         config_detach(&lmsc->sc_dev, 0);
200         }
201 #endif
202         return (0);
203 }
204
205 int
206 lm_isa_detach(struct device *dev)
207 {
208         struct lm_isa_softc *sc = device_get_softc(dev);
209         int error;
210
211         /* Bus-independent detachment */
212         error = lm_detach(&sc->sc_lmsc);
213         if (error)
214                 return (error);
215
216         error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
217             sc->sc_iores);
218         if (error)
219                 return (error);
220
221         return (0);
222 }
223
224 u_int8_t
225 lm_isa_readreg(struct lm_softc *lmsc, int reg)
226 {
227         struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
228
229         bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
230         return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA));
231 }
232
233 void
234 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
235 {
236         struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
237
238         bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
239         bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val);
240 }