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