at91_pio.c revision 157089
1157089Simp/*-
2157089Simp * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
3157089Simp *
4157089Simp * Redistribution and use in source and binary forms, with or without
5157089Simp * modification, are permitted provided that the following conditions
6157089Simp * are met:
7157089Simp * 1. Redistributions of source code must retain the above copyright
8157089Simp *    notice, this list of conditions and the following disclaimer.
9157089Simp * 2. Redistributions in binary form must reproduce the above copyright
10157089Simp *    notice, this list of conditions and the following disclaimer in the
11157089Simp *    documentation and/or other materials provided with the distribution.
12157089Simp *
13157089Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14157089Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15157089Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16157089Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17157089Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18157089Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19157089Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20157089Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21157089Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22157089Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23157089Simp */
24157089Simp
25157089Simp#include <sys/cdefs.h>
26157089Simp__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pio.c 157089 2006-03-24 07:39:29Z imp $");
27157089Simp
28157089Simp#include <sys/param.h>
29157089Simp#include <sys/systm.h>
30157089Simp#include <sys/bus.h>
31157089Simp#include <sys/conf.h>
32157089Simp#include <sys/kernel.h>
33157089Simp#include <sys/lock.h>
34157089Simp#include <sys/mbuf.h>
35157089Simp#include <sys/malloc.h>
36157089Simp#include <sys/module.h>
37157089Simp#include <sys/mutex.h>
38157089Simp#include <sys/rman.h>
39157089Simp#include <machine/bus.h>
40157089Simp
41157089Simp#include <arm/at91/at91_pioreg.h>
42157089Simp
43157089Simpstruct at91_pio_softc
44157089Simp{
45157089Simp	device_t dev;			/* Myself */
46157089Simp	void *intrhand;			/* Interrupt handle */
47157089Simp	struct resource *irq_res;	/* IRQ resource */
48157089Simp	struct resource	*mem_res;	/* Memory resource */
49157089Simp	struct mtx sc_mtx;		/* basically a perimeter lock */
50157089Simp	struct cdev *cdev;
51157089Simp	int flags;
52157089Simp#define OPENED 1
53157089Simp};
54157089Simp
55157089Simpstatic inline uint32_t
56157089SimpRD4(struct at91_pio_softc *sc, bus_size_t off)
57157089Simp{
58157089Simp	return bus_read_4(sc->mem_res, off);
59157089Simp}
60157089Simp
61157089Simpstatic inline void
62157089SimpWR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val)
63157089Simp{
64157089Simp	bus_write_4(sc->mem_res, off, val);
65157089Simp}
66157089Simp
67157089Simp#define AT91_PIO_LOCK(_sc)		mtx_lock_spin(&(_sc)->sc_mtx)
68157089Simp#define	AT91_PIO_UNLOCK(_sc)		mtx_unlock_spin(&(_sc)->sc_mtx)
69157089Simp#define AT91_PIO_LOCK_INIT(_sc) \
70157089Simp	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
71157089Simp	    "pio", MTX_SPIN)
72157089Simp#define AT91_PIO_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
73157089Simp#define AT91_PIO_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
74157089Simp#define AT91_PIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
75157089Simp#define CDEV2SOFTC(dev)		((dev)->si_drv1)
76157089Simp
77157089Simpstatic devclass_t at91_pio_devclass;
78157089Simp
79157089Simp/* bus entry points */
80157089Simp
81157089Simpstatic int at91_pio_probe(device_t dev);
82157089Simpstatic int at91_pio_attach(device_t dev);
83157089Simpstatic int at91_pio_detach(device_t dev);
84157089Simpstatic void at91_pio_intr(void *);
85157089Simp
86157089Simp/* helper routines */
87157089Simpstatic int at91_pio_activate(device_t dev);
88157089Simpstatic void at91_pio_deactivate(device_t dev);
89157089Simp
90157089Simp/* cdev routines */
91157089Simpstatic d_open_t at91_pio_open;
92157089Simpstatic d_close_t at91_pio_close;
93157089Simpstatic d_ioctl_t at91_pio_ioctl;
94157089Simp
95157089Simpstatic struct cdevsw at91_pio_cdevsw =
96157089Simp{
97157089Simp	.d_version = D_VERSION,
98157089Simp	.d_open = at91_pio_open,
99157089Simp	.d_close = at91_pio_close,
100157089Simp	.d_ioctl = at91_pio_ioctl
101157089Simp};
102157089Simp
103157089Simpstatic int
104157089Simpat91_pio_probe(device_t dev)
105157089Simp{
106157089Simp	device_set_desc(dev, "PIO");
107157089Simp	return (0);
108157089Simp}
109157089Simp
110157089Simpstatic int
111157089Simpat91_pio_attach(device_t dev)
112157089Simp{
113157089Simp	struct at91_pio_softc *sc = device_get_softc(dev);
114157089Simp	int err;
115157089Simp
116157089Simp	sc->dev = dev;
117157089Simp	err = at91_pio_activate(dev);
118157089Simp	if (err)
119157089Simp		goto out;
120157089Simp
121157089Simp	AT91_PIO_LOCK_INIT(sc);
122157089Simp
123157089Simp	/*
124157089Simp	 * Activate the interrupt, but disable all interrupts in the hardware
125157089Simp	 */
126157089Simp	WR4(sc, PIO_IDR, 0xffffffff);
127157089Simp	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_FAST,
128157089Simp	    at91_pio_intr, sc, &sc->intrhand);
129157089Simp	if (err) {
130157089Simp		AT91_PIO_LOCK_DESTROY(sc);
131157089Simp		goto out;
132157089Simp	}
133157089Simp	sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT
134157089Simp	    , GID_WHEEL, 0600, "pio%d", device_get_unit(dev));
135157089Simp	if (sc->cdev == NULL) {
136157089Simp		err = ENOMEM;
137157089Simp		goto out;
138157089Simp	}
139157089Simp	sc->cdev->si_drv1 = sc;
140157089Simpout:;
141157089Simp	if (err)
142157089Simp		at91_pio_deactivate(dev);
143157089Simp	return (err);
144157089Simp}
145157089Simp
146157089Simpstatic int
147157089Simpat91_pio_detach(device_t dev)
148157089Simp{
149157089Simp	return (EBUSY);	/* XXX */
150157089Simp}
151157089Simp
152157089Simpstatic int
153157089Simpat91_pio_activate(device_t dev)
154157089Simp{
155157089Simp	struct at91_pio_softc *sc;
156157089Simp	int rid;
157157089Simp
158157089Simp	sc = device_get_softc(dev);
159157089Simp	rid = 0;
160157089Simp	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
161157089Simp	    RF_ACTIVE);
162157089Simp	if (sc->mem_res == NULL)
163157089Simp		goto errout;
164157089Simp	rid = 0;
165157089Simp	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
166157089Simp	    RF_ACTIVE | RF_SHAREABLE);
167157089Simp	if (sc->irq_res == NULL)
168157089Simp		goto errout;
169157089Simp	return (0);
170157089Simperrout:
171157089Simp	at91_pio_deactivate(dev);
172157089Simp	return (ENOMEM);
173157089Simp}
174157089Simp
175157089Simpstatic void
176157089Simpat91_pio_deactivate(device_t dev)
177157089Simp{
178157089Simp	struct at91_pio_softc *sc;
179157089Simp
180157089Simp	sc = device_get_softc(dev);
181157089Simp	if (sc->intrhand)
182157089Simp		bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
183157089Simp	sc->intrhand = 0;
184157089Simp	bus_generic_detach(sc->dev);
185157089Simp	if (sc->mem_res)
186157089Simp		bus_release_resource(dev, SYS_RES_IOPORT,
187157089Simp		    rman_get_rid(sc->mem_res), sc->mem_res);
188157089Simp	sc->mem_res = 0;
189157089Simp	if (sc->irq_res)
190157089Simp		bus_release_resource(dev, SYS_RES_IRQ,
191157089Simp		    rman_get_rid(sc->irq_res), sc->irq_res);
192157089Simp	sc->irq_res = 0;
193157089Simp	return;
194157089Simp}
195157089Simp
196157089Simpstatic void
197157089Simpat91_pio_intr(void *xsc)
198157089Simp{
199157089Simp	struct at91_pio_softc *sc = xsc;
200157089Simp#if 0
201157089Simp	uint32_t status;
202157089Simp
203157089Simp	/* Reading the status also clears the interrupt */
204157089Simp	status = RD4(sc, PIO_SR);
205157089Simp	if (status == 0)
206157089Simp		return;
207157089Simp	AT91_PIO_LOCK(sc);
208157089Simp	AT91_PIO_UNLOCK(sc);
209157089Simp#endif
210157089Simp	wakeup(sc);
211157089Simp	return;
212157089Simp}
213157089Simp
214157089Simpstatic int
215157089Simpat91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
216157089Simp{
217157089Simp	struct at91_pio_softc *sc;
218157089Simp
219157089Simp	sc = CDEV2SOFTC(dev);
220157089Simp	AT91_PIO_LOCK(sc);
221157089Simp	if (!(sc->flags & OPENED)) {
222157089Simp		sc->flags |= OPENED;
223157089Simp#if 0
224157089Simp	// Enable interrupts
225157089Simp#endif
226157089Simp	}
227157089Simp	AT91_PIO_UNLOCK(sc);
228157089Simp    	return (0);
229157089Simp}
230157089Simp
231157089Simpstatic int
232157089Simpat91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
233157089Simp{
234157089Simp	struct at91_pio_softc *sc;
235157089Simp
236157089Simp	sc = CDEV2SOFTC(dev);
237157089Simp	AT91_PIO_LOCK(sc);
238157089Simp	sc->flags &= ~OPENED;
239157089Simp#if 0
240157089Simp	// Disable interrupts
241157089Simp#endif
242157089Simp	AT91_PIO_UNLOCK(sc);
243157089Simp	return (0);
244157089Simp}
245157089Simp
246157089Simpstatic int
247157089Simpat91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
248157089Simp    struct thread *td)
249157089Simp{
250157089Simp	return (ENXIO);
251157089Simp}
252157089Simp
253157089Simpstatic device_method_t at91_pio_methods[] = {
254157089Simp	/* Device interface */
255157089Simp	DEVMETHOD(device_probe,		at91_pio_probe),
256157089Simp	DEVMETHOD(device_attach,	at91_pio_attach),
257157089Simp	DEVMETHOD(device_detach,	at91_pio_detach),
258157089Simp
259157089Simp	{ 0, 0 }
260157089Simp};
261157089Simp
262157089Simpstatic driver_t at91_pio_driver = {
263157089Simp	"at91_pio",
264157089Simp	at91_pio_methods,
265157089Simp	sizeof(struct at91_pio_softc),
266157089Simp};
267157089Simp
268157089SimpDRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, 0, 0);
269