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