]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/at91/at91_pio.c
This commit was generated by cvs2svn to compensate for changes in r159952,
[FreeBSD/FreeBSD.git] / sys / arm / at91 / at91_pio.c
1 /*-
2  * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD$");
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31 #include <sys/conf.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.h>
34 #include <sys/mbuf.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/mutex.h>
38 #include <sys/rman.h>
39 #include <machine/bus.h>
40
41 #include <arm/at91/at91_pioreg.h>
42
43 struct at91_pio_softc
44 {
45         device_t dev;                   /* Myself */
46         void *intrhand;                 /* Interrupt handle */
47         struct resource *irq_res;       /* IRQ resource */
48         struct resource *mem_res;       /* Memory resource */
49         struct mtx sc_mtx;              /* basically a perimeter lock */
50         struct cdev *cdev;
51         int flags;
52 #define OPENED 1
53 };
54
55 static inline uint32_t
56 RD4(struct at91_pio_softc *sc, bus_size_t off)
57 {
58         return bus_read_4(sc->mem_res, off);
59 }
60
61 static inline void
62 WR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val)
63 {
64         bus_write_4(sc->mem_res, off, val);
65 }
66
67 #define AT91_PIO_LOCK(_sc)              mtx_lock_spin(&(_sc)->sc_mtx)
68 #define AT91_PIO_UNLOCK(_sc)            mtx_unlock_spin(&(_sc)->sc_mtx)
69 #define AT91_PIO_LOCK_INIT(_sc) \
70         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
71             "pio", MTX_SPIN)
72 #define AT91_PIO_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
73 #define AT91_PIO_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
74 #define AT91_PIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
75 #define CDEV2SOFTC(dev)         ((dev)->si_drv1)
76
77 static devclass_t at91_pio_devclass;
78
79 /* bus entry points */
80
81 static int at91_pio_probe(device_t dev);
82 static int at91_pio_attach(device_t dev);
83 static int at91_pio_detach(device_t dev);
84 static void at91_pio_intr(void *);
85
86 /* helper routines */
87 static int at91_pio_activate(device_t dev);
88 static void at91_pio_deactivate(device_t dev);
89
90 /* cdev routines */
91 static d_open_t at91_pio_open;
92 static d_close_t at91_pio_close;
93 static d_ioctl_t at91_pio_ioctl;
94
95 static struct cdevsw at91_pio_cdevsw =
96 {
97         .d_version = D_VERSION,
98         .d_open = at91_pio_open,
99         .d_close = at91_pio_close,
100         .d_ioctl = at91_pio_ioctl
101 };
102
103 static int
104 at91_pio_probe(device_t dev)
105 {
106         device_set_desc(dev, "PIO");
107         return (0);
108 }
109
110 static int
111 at91_pio_attach(device_t dev)
112 {
113         struct at91_pio_softc *sc = device_get_softc(dev);
114         int err;
115
116         sc->dev = dev;
117         err = at91_pio_activate(dev);
118         if (err)
119                 goto out;
120
121         AT91_PIO_LOCK_INIT(sc);
122
123         /*
124          * Activate the interrupt, but disable all interrupts in the hardware
125          */
126         WR4(sc, PIO_IDR, 0xffffffff);
127         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_FAST,
128             at91_pio_intr, sc, &sc->intrhand);
129         if (err) {
130                 AT91_PIO_LOCK_DESTROY(sc);
131                 goto out;
132         }
133         sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT
134             , GID_WHEEL, 0600, "pio%d", device_get_unit(dev));
135         if (sc->cdev == NULL) {
136                 err = ENOMEM;
137                 goto out;
138         }
139         sc->cdev->si_drv1 = sc;
140 out:;
141         if (err)
142                 at91_pio_deactivate(dev);
143         return (err);
144 }
145
146 static int
147 at91_pio_detach(device_t dev)
148 {
149         return (EBUSY); /* XXX */
150 }
151
152 static int
153 at91_pio_activate(device_t dev)
154 {
155         struct at91_pio_softc *sc;
156         int rid;
157
158         sc = device_get_softc(dev);
159         rid = 0;
160         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
161             RF_ACTIVE);
162         if (sc->mem_res == NULL)
163                 goto errout;
164         rid = 0;
165         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
166             RF_ACTIVE | RF_SHAREABLE);
167         if (sc->irq_res == NULL)
168                 goto errout;
169         return (0);
170 errout:
171         at91_pio_deactivate(dev);
172         return (ENOMEM);
173 }
174
175 static void
176 at91_pio_deactivate(device_t dev)
177 {
178         struct at91_pio_softc *sc;
179
180         sc = device_get_softc(dev);
181         if (sc->intrhand)
182                 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
183         sc->intrhand = 0;
184         bus_generic_detach(sc->dev);
185         if (sc->mem_res)
186                 bus_release_resource(dev, SYS_RES_IOPORT,
187                     rman_get_rid(sc->mem_res), sc->mem_res);
188         sc->mem_res = 0;
189         if (sc->irq_res)
190                 bus_release_resource(dev, SYS_RES_IRQ,
191                     rman_get_rid(sc->irq_res), sc->irq_res);
192         sc->irq_res = 0;
193         return;
194 }
195
196 static void
197 at91_pio_intr(void *xsc)
198 {
199         struct at91_pio_softc *sc = xsc;
200 #if 0
201         uint32_t status;
202
203         /* Reading the status also clears the interrupt */
204         status = RD4(sc, PIO_SR);
205         if (status == 0)
206                 return;
207         AT91_PIO_LOCK(sc);
208         AT91_PIO_UNLOCK(sc);
209 #endif
210         wakeup(sc);
211         return;
212 }
213
214 static int 
215 at91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
216 {
217         struct at91_pio_softc *sc;
218
219         sc = CDEV2SOFTC(dev);
220         AT91_PIO_LOCK(sc);
221         if (!(sc->flags & OPENED)) {
222                 sc->flags |= OPENED;
223 #if 0
224         // Enable interrupts
225 #endif
226         }
227         AT91_PIO_UNLOCK(sc);
228         return (0);
229 }
230
231 static int
232 at91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
233 {
234         struct at91_pio_softc *sc;
235
236         sc = CDEV2SOFTC(dev);
237         AT91_PIO_LOCK(sc);
238         sc->flags &= ~OPENED;
239 #if 0
240         // Disable interrupts
241 #endif
242         AT91_PIO_UNLOCK(sc);
243         return (0);
244 }
245
246 static int
247 at91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
248     struct thread *td)
249 {
250         return (ENXIO);
251 }
252
253 static device_method_t at91_pio_methods[] = {
254         /* Device interface */
255         DEVMETHOD(device_probe,         at91_pio_probe),
256         DEVMETHOD(device_attach,        at91_pio_attach),
257         DEVMETHOD(device_detach,        at91_pio_detach),
258
259         { 0, 0 }
260 };
261
262 static driver_t at91_pio_driver = {
263         "at91_pio",
264         at91_pio_methods,
265         sizeof(struct at91_pio_softc),
266 };
267
268 DRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, 0, 0);