code:
/*	$OpenBSD: iopi2creg.h,v 1.2 2006/07/10 15:39:56 drahn Exp $	*/
/*	$NetBSD: iopi2creg.h,v 1.2 2005/12/11 12:16:51 christos Exp $	*/

/*
 * Copyright (c) 2003 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed for the NetBSD Project by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _ARM_XSCALE_IOPIICREG_H_
#define _ARM_XSCALE_IOPIICREG_H_

#define	IIC_ICR		0x00	/* i2c control register */
#define	IIC_ISR		0x04	/* i2c status register */
#define	IIC_ISAR	0x08	/* i2c slave address register */
#define	IIC_IDBR	0x0c	/* i2c data buffer register */
#define	IIC_ICCR	0x10	/* i2c clock control register (i80312 only) */
#define	IIC_IBMR	0x14	/* i2c bus monitor register */

#define	IIC_ICR_FM		(1U << 15)	/* fast mode (i80321 only) */
#define	IIC_ICR_RESET		(1U << 14)	/* i2c unit reset */
#define	IIC_ICR_SADIE		(1U << 13)	/* slave addr det int en */
#define	IIC_ICR_ALDIE		(1U << 12)	/* arb loss det int en */
#define	IIC_ICR_SSDIE		(1U << 11)	/* slave stop det in en */
#define	IIC_ICR_BEIE		(1U << 10)	/* bus error int en */
#define	IIC_ICR_IRFIE		(1U << 9)	/* IDBR Rx full int en */
#define	IIC_ICR_ITEIE		(1U << 8)	/* IDBR Tx empty int en */
#define	IIC_ICR_GCD		(1U << 7)	/* general call disable */
#define	IIC_ICR_UE		(1U << 6)	/* i2c unit enable */
#define	IIC_ICR_SCLE		(1U << 5)	/* SCL master enable */
#define	IIC_ICR_MA		(1U << 4)	/* abort as master */
#define	IIC_ICR_TB		(1U << 3)	/* transfer byte */
#define	IIC_ICR_NACK		(1U << 2)	/* 0=ACK, 1=NACK */
#define	IIC_ICR_STOP		(1U << 1)	/* initiate STOP condition */
#define	IIC_ICR_START		(1U << 0)	/* initiate START condition */

#define	IIC_ISR_BED		(1U << 10)	/* bus error detected */
#define	IIC_ISR_SAD		(1U << 9)	/* slave address detected */
#define	IIC_ISR_GCAD		(1U << 8)	/* general call addr detected */
#define	IIC_ISR_IRF		(1U << 7)	/* IDBR Rx full */
#define	IIC_ISR_ITE		(1U << 6)	/* IDBR Tx empty */
#define	IIC_ISR_ALD		(1U << 5)	/* arb loss detected */
#define	IIC_ISR_SSD		(1U << 4)	/* slave STOP detected */
#define	IIC_ISR_IBB		(1U << 3)	/* i2c bus busy */
#define	IIC_ISR_UB		(1U << 2)	/* unit busy */
#define	IIC_ISR_NACK		(1U << 1)	/* NACK received */
#define	IIC_ISR_RW		(1U << 0)	/* 0=mt/sr, 1=mr/st */

#endif /* _ARM_XSCALE_IOPIICREG_H_  */


code:
/*	$OpenBSD: iopi2cvar.h,v 1.3 2009/03/27 16:02:41 oga Exp $	*/
/*	$NetBSD: iopi2cvar.h,v 1.2 2005/12/11 12:16:51 christos Exp $	*/

/*
 * Copyright (c) 2003 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed for the NetBSD Project by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _ARM_XSCALE_IOPIICVAR_H_
#define _ARM_XSCALE_IOPIICVAR_H_

struct iopiic_softc {
	struct device sc_dev;
	bus_space_tag_t sc_st;
	bus_space_handle_t sc_sh;

	void *sc_ih;

	struct i2c_controller sc_i2c;
	struct rwlock sc_buslock;
	uint32_t sc_icr;
};

void iopiic_attach(struct iopiic_softc *sc);

#endif /* _ARM_XSCALE_IOPIICVAR_H_  */

license: unknown


code:
/*	$OpenBSD: pxa27x_kpc.c,v 1.3 2014/01/26 17:48:07 miod Exp $	*/
/*
 * Copyright (c) 2009 Marek Vasut <marex@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/timeout.h>
#include <sys/systm.h>

#include <arch/arm/xscale/pxa2x0_gpio.h>
#include <arch/arm/xscale/pxa2x0reg.h>
#include <arch/arm/xscale/pxa2x0var.h>
#include <arch/arm/xscale/pxa27x_kpc.h>

int  pxa27x_kpc_enable(void *, int);
void pxa27x_kpc_setleds(void *, int);
int  pxa27x_kpc_ioctl(void *, u_long, caddr_t, int, struct proc *);

inline void pxa27x_kpc_submit(struct pxa27x_kpc_softc *, int);
int  pxa27x_kpc_intr(void *);

struct cfdriver pxa27x_kpc_cd = {
	NULL, "pxa27x_kpc", DV_DULL,
};

struct wskbd_accessops pxa27x_kpc_accessops = {
	pxa27x_kpc_enable,
	pxa27x_kpc_setleds,
	pxa27x_kpc_ioctl,
};

struct wscons_keydesc pxa27x_kpc_keydesctab[] = {
	{KB_US, 0, 0, 0},
	{0, 0, 0, 0},
};

struct wskbd_mapdata pxa27x_kpc_mapdata = {
	pxa27x_kpc_keydesctab, KB_US | KB_DEFAULT,
};

void pxa27x_kpc_cngetc(void *, u_int *, int *);
void pxa27x_kpc_cnpollc(void *, int);
void pxa27x_kpc_cnbell(void *, u_int, u_int, u_int);

struct wskbd_consops pxa27x_kpc_consops = {
	pxa27x_kpc_cngetc,
	pxa27x_kpc_cnpollc,
	pxa27x_kpc_cnbell,
};

int
pxa27x_kpc_match(void *aux)
{
	struct pxaip_attach_args *pxa = aux;

	if (pxa->pxa_addr != PXA2X0_KPC_BASE)
		return 0;	/* Wrong device */

	if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X)
		return 0;	/* Wrong CPU */

	pxa->pxa_size = PXA2X0_KPC_SIZE;
	return 1;
}

void
pxa27x_kpc_attach(struct pxa27x_kpc_softc *sc, void *aux)
{
	struct pxaip_attach_args *pxa = aux;
	struct wskbddev_attach_args a;

	sc->sc_iot = pxa->pxa_sa.sa_iot;
	if (bus_space_map(sc->sc_iot, pxa->pxa_addr, pxa->pxa_size, 0,
	    &sc->sc_ioh) != 0) {
		printf(": can't map regs\n");
		goto err;
	}

	pxa2x0_clkman_config(CKEN_KEY, 1);

	sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_KPC, IPL_TTY,
		pxa27x_kpc_intr, sc, sc->sc_dev.dv_xname);
	if (!sc->sc_ih) {
		printf(": can't establish interrupt\n");
		goto err2;
	}

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, KPC_KPC, KPC_MIE | KPC_ME |
		KPC_MS(0xff) | KPC_IMKP | KPC_MI | KPC_MKCN(sc->sc_cols) |
		KPC_MKRN(sc->sc_rows) | KPC_ASACT);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, KPC_KPKDI, 0x30);

	pxa27x_kpc_keydesctab[0].map_size = sc->sc_ksize;
	pxa27x_kpc_keydesctab[0].map = sc->sc_kcodes;

	a.console	= 1;
	a.keymap	= &pxa27x_kpc_mapdata;
	a.accessops	= &pxa27x_kpc_accessops;
	a.accesscookie	= sc;

	printf("\n");

	wskbd_cnattach(&pxa27x_kpc_consops, sc, &pxa27x_kpc_mapdata);

	sc->sc_wskbddev	= config_found((struct device *)sc, &a, wskbddevprint);

	return;

err2:
	bus_space_unmap(sc->sc_iot, sc->sc_ioh, PXA2X0_KPC_SIZE);
err:
	return;
}

inline void
pxa27x_kpc_submit(struct pxa27x_kpc_softc *sc, int event)
{
#ifdef WSDISPLAY_COMPAT_RAWKBD
	u_char key;

	if (sc->sc_rawkbd) {
		key = sc->sc_key;
		if (event == WSCONS_EVENT_KEY_DOWN)
			key |= 0x80;
		wskbd_rawinput(sc->sc_wskbddev, &key, 1);
	} else
#endif
		wskbd_input(sc->sc_wskbddev, event, sc->sc_key);
}

int
pxa27x_kpc_intr(void *arg)
{
	u_int32_t val;
	int row = -1, col = -1;
	int i = 0;
	struct pxa27x_kpc_softc *sc = arg;

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, KPC_KPC);
	if (!(val & KPC_MI))	/* interrupt didn't happen .. what ?! */
		return 0;

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, KPC_KPAS);
	if (val & KPAS_SO)	/* bogus interrupt */
		return 0;

	if (val & KPAS_MUKP) {	/* keypress */
		col = val & KPAS_CP;
		row = (val & KPAS_RP) >> 4;
		for (i = 0; i < sc->sc_ksize; i++)
			if (sc->sc_kmap[i].row == row &&
				sc->sc_kmap[i].col == col) {
				sc->sc_key = sc->sc_kmap[i].key;
				pxa27x_kpc_submit(sc, WSCONS_EVENT_KEY_DOWN);
				break;
			}
	} else	/* no keypress aka keyrelease */
		pxa27x_kpc_submit(sc, WSCONS_EVENT_KEY_UP);

	return 1;
}

int
pxa27x_kpc_enable(void *v, int power)
{
	return 0;
}

void
pxa27x_kpc_setleds(void *v, int power)
{
}

int
pxa27x_kpc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
#ifdef WSDISPLAY_COMPAT_RAWKBD
	struct pxa27x_kpc_softc *sc = v;
#endif

	switch (cmd) {
	case WSKBDIO_GTYPE:
		*(int *)data = WSKBD_TYPE_KPC;
		return 0;
	case WSKBDIO_SETLEDS:
		return 0;
	case WSKBDIO_GETLEDS:
		*(int *)data = 0;
		return 0;
#ifdef WSDISPLAY_COMPAT_RAWKBD
	case WSKBDIO_SETMODE:
		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
		return 0;
#endif
	}
	return -1;
}

void
pxa27x_kpc_cnbell(void *v, u_int pitch, u_int period, u_int volume)
{
}

void
pxa27x_kpc_cngetc(void *v, u_int *type, int *data)
{
}

void
pxa27x_kpc_cnpollc(void *v, int on)
{
}


code:
/*	$OpenBSD: pxa27x_kpc.h,v 1.2 2013/10/24 22:40:10 aalm Exp $	*/
/*
 * Copyright (c) 2009 Marek Vasut <marex@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wskbdraw.h>
#include <dev/wscons/wskbdvar.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/wscons/wsksymvar.h>

struct pxa27x_kpc_keymap {
	int		row;
	int		col;
	keysym_t	key;
};

struct pxa27x_kpc_softc {
	struct device		sc_dev;
	struct device		*sc_wskbddev;
	void			*sc_ih;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	int			sc_key;
	int			sc_rawkbd;

	int			sc_rows;
	int			sc_cols;
	const struct pxa27x_kpc_keymap	*sc_kmap;
	const keysym_t		*sc_kcodes;
	const keysym_t		*sc_xt_kcodes;
	int			sc_ksize;
};

int  pxa27x_kpc_match(void *);
void pxa27x_kpc_attach(struct pxa27x_kpc_softc *, void *);


code:
/*	$OpenBSD: pxa27x_udc.c,v 1.31 2015/05/15 13:32:08 jsg Exp $ */

/*
 * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/timeout.h>

#include <machine/intr.h>
#include <machine/bus.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usbf.h>
#include <dev/usb/usbfvar.h>

#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0var.h>
#include <arm/xscale/pxa2x0_gpio.h>

#include <arm/xscale/pxa27x_udc.h>

#include "usbf.h"

struct pxaudc_xfer {
	struct usbf_xfer	 xfer;
	u_int16_t		 frmlen;
};

struct pxaudc_pipe {
	struct usbf_pipe	 pipe;
//	LIST_ENTRY(pxaudc_pipe)	 list;
};

void		 pxaudc_enable(struct pxaudc_softc *);
void		 pxaudc_disable(struct pxaudc_softc *);
void		 pxaudc_read_ep0(struct pxaudc_softc *, struct usbf_xfer *);
void		 pxaudc_read_epN(struct pxaudc_softc *sc, int ep);
void		 pxaudc_write_ep0(struct pxaudc_softc *, struct usbf_xfer *);
void		 pxaudc_write(struct pxaudc_softc *, struct usbf_xfer *);
void		 pxaudc_write_epN(struct pxaudc_softc *sc, int ep);

int		 pxaudc_connect_intr(void *);
int		 pxaudc_intr(void *);
void		 pxaudc_intr1(struct pxaudc_softc *);
void		 pxaudc_ep0_intr(struct pxaudc_softc *);
void		 pxaudc_epN_intr(struct pxaudc_softc *sc, int ep, int isr);

usbf_status	 pxaudc_open(struct usbf_pipe *);
void		 pxaudc_softintr(void *);
usbf_status	 pxaudc_allocm(struct usbf_bus *, struct usb_dma *, u_int32_t);
void		 pxaudc_freem(struct usbf_bus *, struct usb_dma *);
struct usbf_xfer *pxaudc_allocx(struct usbf_bus *);
void		 pxaudc_freex(struct usbf_bus *, struct usbf_xfer *);

usbf_status	 pxaudc_ctrl_transfer(struct usbf_xfer *);
usbf_status	 pxaudc_ctrl_start(struct usbf_xfer *);
void		 pxaudc_ctrl_abort(struct usbf_xfer *);
void		 pxaudc_ctrl_done(struct usbf_xfer *);
void		 pxaudc_ctrl_close(struct usbf_pipe *);

usbf_status	 pxaudc_bulk_transfer(struct usbf_xfer *);
usbf_status	 pxaudc_bulk_start(struct usbf_xfer *);
void		 pxaudc_bulk_abort(struct usbf_xfer *);
void		 pxaudc_bulk_done(struct usbf_xfer *);
void		 pxaudc_bulk_close(struct usbf_pipe *);

struct cfdriver pxaudc_cd = {
	NULL, "pxaudc", DV_DULL
};

#if NUSBF > 0

struct usbf_bus_methods pxaudc_bus_methods = {
	pxaudc_open,
	pxaudc_softintr,
	pxaudc_allocm,
	pxaudc_freem,
	pxaudc_allocx,
	pxaudc_freex
};

struct usbf_pipe_methods pxaudc_ctrl_methods = {
	pxaudc_ctrl_transfer,
	pxaudc_ctrl_start,
	pxaudc_ctrl_abort,
	pxaudc_ctrl_done,
	pxaudc_ctrl_close
};

struct usbf_pipe_methods pxaudc_bulk_methods = {
	pxaudc_bulk_transfer,
	pxaudc_bulk_start,
	pxaudc_bulk_abort,
	pxaudc_bulk_done,
	pxaudc_bulk_close
};

#endif /* NUSBF > 0 */

#define DEVNAME(sc)	((sc)->sc_bus.bdev.dv_xname)

#define CSR_READ_4(sc, reg) \
	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
#define CSR_WRITE_4(sc, reg, val) \
	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define CSR_WRITE_1(sc, reg, val) \
	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define CSR_SET_4(sc, reg, val) \
	CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) | (val))
#define CSR_CLR_4(sc, reg, val) \
	CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) & ~(val))

#ifndef PXAUDC_DEBUG
#define DPRINTF(l, x)	do {} while (0)
#else
int pxaudcdebug = 0;
#define DPRINTF(l, x)	if ((l) <= pxaudcdebug) printf x; else {}
#endif

int
pxaudc_match(void)
{
	if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X)
		return (0);

	return (1);
}

void
pxaudc_attach(struct pxaudc_softc *sc, void *aux)
{
	struct pxaip_attach_args	*pxa = aux;
#if NUSBF > 0
	int i;
#endif

	sc->sc_iot = pxa->pxa_iot;
	if (bus_space_map(sc->sc_iot, PXA2X0_USBDC_BASE, PXA2X0_USBDC_SIZE, 0,
	    &sc->sc_ioh)) {
		printf(": cannot map mem space\n");
		return;
	}
	sc->sc_size = PXA2X0_USBDC_SIZE;

	printf(": USB Device Controller\n");

	bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_size,
	    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);

	/* Set up GPIO pins and disable the controller. */
	pxaudc_disable(sc);

#if NUSBF > 0
	/* Establish USB device interrupt. */
	sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_USB, IPL_USB,
	    pxaudc_intr, sc, DEVNAME(sc));
	if (sc->sc_ih == NULL) {
		printf(": unable to establish interrupt\n");
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
		sc->sc_size = 0;
		return;
	}

	/* Establish device connect interrupt. */
#if 0
	sc->sc_conn_ih = pxa2x0_gpio_intr_establish(PXA_USB_DEVICE_PIN, /* XXX */
	    IST_EDGE_BOTH, IPL_USB, pxaudc_connect_intr, sc, "usbc");
#endif
	sc->sc_conn_ih = pxa2x0_gpio_intr_establish(sc->sc_gpio_detect,
	    IST_EDGE_BOTH, IPL_USB, pxaudc_connect_intr, sc, "usbc");
	if (sc->sc_conn_ih == NULL) {
		printf(": unable to establish connect interrupt\n");
		pxa2x0_intr_disestablish(sc->sc_ih);
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
		sc->sc_ioh = 0;
		sc->sc_size = 0;
		return;
	}

	/* Set up the bus struct. */
	sc->sc_bus.methods = &pxaudc_bus_methods;
	sc->sc_bus.pipe_size = sizeof(struct pxaudc_pipe);
	sc->sc_bus.ep0_maxp = PXAUDC_EP0MAXP;
	sc->sc_bus.usbrev = USBREV_1_1;
	sc->sc_bus.dmatag = pxa->pxa_dmat;
	sc->sc_npipe = 0;	/* ep0 is always there. */

	sc->sc_ep_map[0] = 0;
	/* 16 == max logical endpoints */
	for (i = 1; i < 16; i++) {
		sc->sc_ep_map[i] = -1;
	}

	/* Attach logical device and function. */
	(void)config_found((struct device *)sc, &sc->sc_bus, NULL);

	/* Enable the controller unless we're now acting as a host. */
	if (!sc->sc_is_host())
		pxaudc_enable(sc);
#endif
}

int
pxaudc_detach(struct pxaudc_softc *sc, int flags)
{
	if (sc->sc_conn_ih != NULL)
		pxa2x0_gpio_intr_disestablish(sc->sc_conn_ih);

	if (sc->sc_ih != NULL)
		pxa2x0_intr_disestablish(sc->sc_ih);

	if (sc->sc_size) {
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
		sc->sc_size = 0;
	}

	return (0);
}

int
pxaudc_activate(struct pxaudc_softc *self, int act)
{
	struct pxaudc_softc *sc = (struct pxaudc_softc *)self;

	switch (act) {
	case DVACT_SUSPEND:
		pxaudc_disable(sc);
		break;
	case DVACT_RESUME:
		pxaudc_enable(sc);
		break;
	}
	return 0;
}

/*
 * Register manipulation
 */

#if 0
static void
pxaudc_dump_regs(struct pxaudc_softc *sc)
{
	printf("UDCCR\t%b\n", CSR_READ_4(sc, USBDC_UDCCR),
	    USBDC_UDCCR_BITS);
	printf("UDCICR0\t%b\n", CSR_READ_4(sc, USBDC_UDCICR0),
	    USBDC_UDCISR0_BITS);
	printf("UDCICR1\t%b\n", CSR_READ_4(sc, USBDC_UDCICR1),
	    USBDC_UDCISR1_BITS);
	printf("OTGICR\t%b\n", CSR_READ_4(sc, USBDC_UDCOTGICR),
	    USBDC_UDCOTGISR_BITS);
}
#endif

void
pxaudc_enable(struct pxaudc_softc *sc)
{
	int i;

	DPRINTF(10,("pxaudc_enable\n"));

	/* Start the clocks. */
	pxa2x0_clkman_config(CKEN_USBDC, 1);

#if 0
	/* Configure Port 2 for USB device. */
	CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DMPUE |
	    USBDC_UP2OCR_DPPUE | USBDC_UP2OCR_HXOE);
#else
	/* Configure Port 2 for USB device. */
	CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DPPUE | USBDC_UP2OCR_HXOE);
#endif

	CSR_SET_4(sc, USBDC_UDCCR, 0);
	sc->sc_icr0 = 0;
	sc->sc_icr1 = 0;

	for (i = 1; i < PXAUDC_NEP; i++)
		CSR_WRITE_4(sc, USBDC_UDCECR(i), 0); /* disable endpoints */

	for (i = 1; i < sc->sc_npipe; i++) {
		if (sc->sc_pipe[i] != NULL)  {
			struct usbf_endpoint *ep =
			    sc->sc_pipe[i]->pipe.endpoint;
			u_int32_t cr;
			int dir = usbf_endpoint_dir(ep);
			usb_endpoint_descriptor_t *ed = ep->edesc;

			if (i < 16)
				sc->sc_icr0 |= USBDC_UDCICR0_IE(i);
			else
				sc->sc_icr1 |= USBDC_UDCICR1_IE(i-16);

			cr = USBDC_UDCECR_EE | USBDC_UDCECR_DE;
			cr |= USBDC_UDCECR_ENs(
			    UE_GET_ADDR(ed->bEndpointAddress));
			cr |= USBDC_UDCECR_MPSs(UGETW(ed->wMaxPacketSize));
			cr |= USBDC_UDCECR_ETs(ed->bmAttributes & UE_XFERTYPE);
			if (dir == UE_DIR_IN)
				cr |= USBDC_UDCECR_ED;

			/* XXX - until pipe has cn/in/ain */
			cr |=   USBDC_UDCECR_AISNs(0) | USBDC_UDCECR_INs(0) |
			    USBDC_UDCECR_CNs(1);

			CSR_WRITE_4(sc, USBDC_UDCECR(i), cr);

			/* clear old status */
			CSR_WRITE_4(sc, USBDC_UDCCSR(1),
			    USBDC_UDCCSR_PC | USBDC_UDCCSR_TRN |
			    USBDC_UDCCSR_SST | USBDC_UDCCSR_FEF);
		}
	}

	CSR_WRITE_4(sc, USBDC_UDCISR0, 0xffffffff); /* clear all */
	CSR_WRITE_4(sc, USBDC_UDCISR1, 0xffffffff); /* clear all */
	CSR_SET_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_ACM);

	/* Enable interrupts for configured endpoints. */
	CSR_WRITE_4(sc, USBDC_UDCICR0, USBDC_UDCICR0_IE(0) |
	    sc->sc_icr0);

	CSR_WRITE_4(sc, USBDC_UDCICR1, USBDC_UDCICR1_IERS |
	    USBDC_UDCICR1_IESU | USBDC_UDCICR1_IERU |
	    USBDC_UDCICR1_IECC | sc->sc_icr1);

	/* Enable the controller. */
	CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_EMCE);
	CSR_SET_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE);

	/* Enable USB client on port 2. */
	pxa2x0_gpio_clear_bit(37); /* USB_P2_8 */
}

void
pxaudc_disable(struct pxaudc_softc *sc)
{
	DPRINTF(10,("pxaudc_disable\n"));

	/* Disable the controller. */
	CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE);

	/* Disable all interrupts. */
	CSR_WRITE_4(sc, USBDC_UDCICR0, 0);
	CSR_WRITE_4(sc, USBDC_UDCICR1, 0);
	CSR_WRITE_4(sc, USBDC_UDCOTGICR, 0);

	/* Set Port 2 output to "Non-OTG Host with Differential Port". */
	CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_HXS | USBDC_UP2OCR_HXOE);

	/* Set "Host Port 2 Transceiver D� Pull Down Enable". */
	CSR_SET_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DMPDE);

	/* Stop the clocks. */
	pxa2x0_clkman_config(CKEN_USBDC, 0);

	/* Enable USB host on port 2. */
	pxa2x0_gpio_set_bit(37); /* USB_P2_8 */
}

#if NUSBF > 0

/*
 * Endpoint FIFO handling
 */

void
pxaudc_read_ep0(struct pxaudc_softc *sc, struct usbf_xfer *xfer)
{
	size_t len;
	u_int8_t *p;

	xfer->actlen = CSR_READ_4(sc, USBDC_UDCBCR(0));
	len = MIN(xfer->actlen, xfer->length);
	p = xfer->buffer;

	while (CSR_READ_4(sc, USBDC_UDCCSR0) & USBDC_UDCCSR0_RNE) {
		u_int32_t v = CSR_READ_4(sc, USBDC_UDCDR(0));

		if (len > 0) {
			if (((unsigned)p & 0x3) == 0)
				*(u_int32_t *)p = v;
			else {
				*(p+0) = v & 0xff;
				*(p+1) = (v >> 8) & 0xff;
				*(p+2) = (v >> 16) & 0xff;
				*(p+3) = (v >> 24) & 0xff;
			}
			p += 4;
			len -= 4;
		}
	}

	CSR_WRITE_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_SA | USBDC_UDCCSR0_OPC);

	xfer->status = USBF_NORMAL_COMPLETION;
	usbf_transfer_complete(xfer);
}

void
pxaudc_read_epN(struct pxaudc_softc *sc, int ep)
{
	size_t len, tlen;
	u_int8_t *p;
	struct pxaudc_pipe *ppipe;
	struct usbf_pipe *pipe = NULL;
	struct usbf_xfer *xfer = NULL;
	int count;
	u_int32_t csr;

	ppipe = sc->sc_pipe[ep];

	if (ppipe == NULL) {
		return;
	}
	pipe = &ppipe->pipe;
again:
	xfer = SIMPLEQ_FIRST(&pipe->queue);

	if (xfer == NULL) {
		printf("pxaudc_read_epN: ep %d, no xfer\n", ep);
		return;
	}

	count = CSR_READ_4(sc, USBDC_UDCBCR(ep));
	tlen = len = MIN(count, xfer->length - xfer->actlen);
	p = xfer->buffer + xfer->actlen;
	csr = CSR_READ_4(sc, USBDC_UDCCSR(ep));

	if ((csr & USBDC_UDCCSR_PC) && count == 0)
	{
#ifdef DEBUG_RX
	        printf("trans1 complete\n");
#endif
		xfer->status = USBF_NORMAL_COMPLETION;
		usbf_transfer_complete(xfer);
		CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_PC);
		return;
	}

#ifdef DEBUG_RX
	printf("reading data from endpoint %x, len %x csr %x",
		ep, count, csr);
#endif

	while (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_BNE) {
		u_int32_t v = CSR_READ_4(sc, USBDC_UDCDR(ep));

		/* double buffering? */
		if (len > 0) {
			if (((unsigned)p & 0x3) == 0)
				*(u_int32_t *)p = v;
			else {
				*(p+0) = v & 0xff;
				*(p+1) = (v >> 8) & 0xff;
				*(p+2) = (v >> 16) & 0xff;
				*(p+3) = (v >> 24) & 0xff;
			}
			p += 4;
			len -= 4;
			xfer->actlen += 4;
		}
		count -= 4;
	}
	CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_PC);

	if (xfer->length == xfer->actlen || (tlen == 0 && xfer->actlen != 0) ||
	    csr & USBDC_UDCCSR_SP) {
#ifdef DEBUG_RX
		printf("trans2 complete\n");
#endif
		xfer->status = USBF_NORMAL_COMPLETION;
		usbf_transfer_complete(xfer);
	}
	csr = CSR_READ_4(sc, USBDC_UDCCSR(ep));
#ifdef DEBUG_RX
	printf("csr now %x len %x\n",
	    csr, CSR_READ_4(sc, USBDC_UDCBCR(ep)));
#endif
	if (csr & USBDC_UDCCSR_PC)
		goto again;
}

void
pxaudc_write_ep0(struct pxaudc_softc *sc, struct usbf_xfer *xfer)
{
	struct pxaudc_xfer *lxfer = (struct pxaudc_xfer *)xfer;
	u_int32_t len;
	u_int8_t *p;

	if (lxfer->frmlen > 0) {
		xfer->actlen += lxfer->frmlen;
		lxfer->frmlen = 0;
	}

	DPRINTF(11,("%s: ep0 ctrl-in, xfer=%p, len=%u, actlen=%u\n",
	    DEVNAME(sc), xfer, xfer->length, xfer->actlen));

	if (xfer->actlen >= xfer->length) {
		sc->sc_ep0state = EP0_SETUP;
		usbf_transfer_complete(xfer);
		return;
	}

	sc->sc_ep0state = EP0_IN;

	p = (u_char *)xfer->buffer + xfer->actlen;
	len = xfer->length - xfer->actlen;
	len = MIN(len, PXAUDC_EP0MAXP);
	lxfer->frmlen = len;

	while (len >= 4) {
		u_int32_t v;

		if (((unsigned)p & 0x3) == 0)
			v = *(u_int32_t *)p;
		else {
			v = *(p+0);
			v |= *(p+1) << 8;
			v |= *(p+2) << 16;
			v |= *(p+3) << 24;
		}

		CSR_WRITE_4(sc, USBDC_UDCDR(0), v);
		len -= 4;
		p += 4;
	}

	while (len > 0) {
		CSR_WRITE_1(sc, USBDC_UDCDR(0), *p);
		len--;
		p++;
	}

	/* (12.6.7) Set IPR only for short packets. */
	if (lxfer->frmlen < PXAUDC_EP0MAXP)
		CSR_SET_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_IPR);
}

void
pxaudc_write(struct pxaudc_softc *sc, struct usbf_xfer *xfer)
{
	u_int8_t *p;
	int ep = sc->sc_ep_map[usbf_endpoint_index(xfer->pipe->endpoint)];
	int tlen = 0;
	int maxp = UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
	u_int32_t csr, csr_o;

#ifdef DEBUG_TX_PKT
	if (xfer->actlen == 0)
		printf("new packet len %x\n", xfer->length);
#endif

#ifdef DEBUG_TX
	printf("writing data to endpoint %x, xlen %x xact %x\n",
		ep, xfer->length, xfer->actlen);
#endif

	if (xfer->actlen == xfer->length) {
		/*
		 * If the packet size is wMaxPacketSize byte multiple
		 * send a zero packet to indicate termiation.
		 */
		if ((xfer->actlen % maxp) == 0 &&
		    xfer->status != USBF_NORMAL_COMPLETION &&
		    xfer->flags & USBD_FORCE_SHORT_XFER) {
			if (CSR_READ_4(sc, USBDC_UDCCSR(ep))
			    & USBDC_UDCCSR_BNF) {
				CSR_SET_4(sc, USBDC_UDCCSR(ep),
				    USBDC_UDCCSR_SP);
				/*
				 * if we send a zero packet, we are 'done', but
				 * dont to usbf_transfer_complete() just yet
				 * because the short packet will cause another
				 * interrupt.
				 */
				xfer->status = USBF_NORMAL_COMPLETION;
				return;
			} else  {
				printf("fifo full when trying to set short packet\n");
			}
		}
		xfer->status = USBF_NORMAL_COMPLETION;
#ifdef DEBUG_TX_PKT
		printf("packet complete %x\n", xfer->actlen);
#endif
		usbf_transfer_complete(xfer);
		return;
	}

	p = xfer->buffer + xfer->actlen;

	csr_o = 0;
	csr = CSR_READ_4(sc, USBDC_UDCCSR(ep));
	if (csr & USBDC_UDCCSR_PC)
		csr_o |= USBDC_UDCCSR_PC;
	if (csr & USBDC_UDCCSR_TRN)
		csr_o |= USBDC_UDCCSR_TRN;
	if (csr & USBDC_UDCCSR_SST)
		csr_o |= USBDC_UDCCSR_SST;
	if (csr_o != 0)
		CSR_WRITE_4(sc, USBDC_UDCCSR(ep), csr_o);

	while (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_BNF) {
		u_int32_t v;

		if (xfer->length - xfer->actlen < 4) {
			while (xfer->actlen < xfer->length) {
				CSR_WRITE_1(sc, USBDC_UDCDR(ep), *p);
				p++;
				xfer->actlen++;
				tlen++;
			}
			break;
		}
		if (((unsigned)p & 0x3) == 0)
			v = *(u_int32_t *)p;
		else {
			v = *(p+0);
			v |= *(p+1) << 8;
			v |= *(p+2) << 16;
			v |= *(p+3) << 24;
		}
		CSR_WRITE_4(sc, USBDC_UDCDR(ep), v);

		p += 4;
		xfer->actlen += 4;

		tlen += 4;
	}
#ifdef DEBUG_TX
	printf(" wrote tlen %x %x\n", tlen, xfer->actlen);
	if (xfer->actlen == 0) {
		printf("whoa, write_ep called, but no free space\n");
	}
#endif
	if (xfer->actlen == xfer->length) {
		if ((xfer->actlen % maxp) != 0) {
			if (xfer->flags & USBD_FORCE_SHORT_XFER) {
				CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_SP);
#ifdef DEBUG_TX
				printf("setting short packet on %x csr\n", ep,
				    CSR_READ_4(sc, USBDC_UDCCSR(ep)));
#endif
			} else {
				/* fill buffer to maxpacket size??? */
			}
		}
	}
}

/*
 * Interrupt handling
 */

int
pxaudc_connect_intr(void *v)
{
	struct pxaudc_softc *sc = v;

	DPRINTF(10,("pxaudc_connect_intr: connect=%d\n",
	    pxa2x0_gpio_get_bit(sc->sc_gpio_detect)));

	/* XXX only set a flag here */
	if (sc->sc_is_host()) {
#if 0
		printf("%s:switching to host\n", sc->sc_bus.bdev.dv_xname);
#endif
		pxaudc_disable(sc);
	} else {
#if 0
		printf("%s:switching to client\n", sc->sc_bus.bdev.dv_xname);
#endif
		pxaudc_enable(sc);
	}

	/* Claim this interrupt. */
	return 1;
}

int
pxaudc_intr(void *v)
{
	struct pxaudc_softc *sc = v;
	u_int32_t isr0, isr1, otgisr;

	isr0 = CSR_READ_4(sc, USBDC_UDCISR0);
	isr1 = CSR_READ_4(sc, USBDC_UDCISR1);
	otgisr = CSR_READ_4(sc, USBDC_UDCOTGISR);

	DPRINTF(10,("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n",
	    isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS,
	    otgisr, USBDC_UDCOTGISR_BITS));

	if (isr0 || isr1 || otgisr) {
		sc->sc_isr0 |= isr0;
		sc->sc_isr1 |= isr1;
		sc->sc_otgisr |= otgisr;

		//usbf_schedsoftintr(&sc->sc_bus);
		pxaudc_intr1(sc); /* XXX */
	}

	CSR_WRITE_4(sc, USBDC_UDCISR0, isr0);
	CSR_WRITE_4(sc, USBDC_UDCISR1, isr1);
	CSR_WRITE_4(sc, USBDC_UDCOTGISR, otgisr);

	/* Claim this interrupt. */
	return 1;
}
u_int32_t csr1, csr2;

void
pxaudc_intr1(struct pxaudc_softc *sc)
{
	u_int32_t isr0, isr1, otgisr;
	int i;
	//int s;

	//s = splhardusb();
	isr0 = sc->sc_isr0;
	isr1 = sc->sc_isr1;
	otgisr = sc->sc_otgisr;
	sc->sc_isr0 = 0;
	sc->sc_isr1 = 0;
	sc->sc_otgisr = 0;
	//splx(s);

	sc->sc_bus.intr_context++;

	if (isr1 & USBDC_UDCISR1_IRCC) {
		u_int32_t ccr;
                CSR_SET_4(sc, USBDC_UDCCR, USBDC_UDCCR_SMAC);

		/* wait for reconfig to finish (SMAC auto clears) */
		while (CSR_READ_4(sc, USBDC_UDCCR)  & USBDC_UDCCR_SMAC)
			delay(10);

		ccr = CSR_READ_4(sc, USBDC_UDCCR);
		sc->sc_cn = USBDC_UDCCR_ACNr(ccr);
		sc->sc_in = USBDC_UDCCR_AINr(ccr);
		sc->sc_isn = USBDC_UDCCR_AAISNr(ccr);
		goto ret;
	}
#if 0
	printf("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n",
	    isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS,
	    otgisr, USBDC_UDCOTGISR_BITS);
#endif

	/* Handle USB RESET condition. */
	if (isr1 & USBDC_UDCISR1_IRRS) {
		sc->sc_ep0state = EP0_SETUP;
		usbf_host_reset(&sc->sc_bus);
		/* Discard all other interrupts. */
		goto ret;
	}

	/* Service control pipe interrupts. */
	if (isr0 & USBDC_UDCISR0_IR(0))
		pxaudc_ep0_intr(sc);

	for (i = 1; i < 24; i++) {
		if (i < 16) {
			if (USBDC_UDCISR0_IRs(isr0,i))
				pxaudc_epN_intr(sc, i,
				    USBDC_UDCISR0_IRs(isr0,i));
		} else {
			if (USBDC_UDCISR1_IRs(isr1,i))
				pxaudc_epN_intr(sc, i,
				    USBDC_UDCISR1_IRs(isr1,i));
		}
	}

	if (isr1 & USBDC_UDCISR1_IRSU) {
		/* suspend ?? */
	}
	if (isr1 & USBDC_UDCISR1_IRRU) {
		/* resume ?? */
	}

ret:
	sc->sc_bus.intr_context--;
}

void
pxaudc_epN_intr(struct pxaudc_softc *sc, int ep, int isr)
{
	struct pxaudc_pipe *ppipe;
	struct usbf_pipe *pipe;
	int dir;

	/* should not occur before device is configured */
	if (sc->sc_cn == 0)
		return;
	if (isr &  2)
		printf("ep%d: fifo error\n", ep); /* XXX */

	/* faster method of determining direction? */
	ppipe = sc->sc_pipe[ep];

	if (ppipe == NULL)
		return;
	pipe = &ppipe->pipe;
	dir = usbf_endpoint_dir(pipe->endpoint);

	if (dir == UE_DIR_IN) {
		pxaudc_write_epN(sc, ep);
	} else {
		pxaudc_read_epN(sc, ep);
	}

}

void
pxaudc_write_epN(struct pxaudc_softc *sc, int ep)
{
	struct pxaudc_pipe *ppipe;
	struct usbf_pipe *pipe = NULL;
	struct usbf_xfer *xfer = NULL;

	ppipe = sc->sc_pipe[ep];

	if (ppipe == NULL) {
		return;
	}
	pipe = &ppipe->pipe;
	xfer = SIMPLEQ_FIRST(&pipe->queue);
	if (xfer != NULL)
		pxaudc_write(sc, xfer);
}
void
pxaudc_ep0_intr(struct pxaudc_softc *sc)
{
	struct pxaudc_pipe *ppipe;
	struct usbf_pipe *pipe = NULL;
	struct usbf_xfer *xfer = NULL;
	u_int32_t csr0;

	csr0 = CSR_READ_4(sc, USBDC_UDCCSR0);
	DPRINTF(10,("pxaudc_ep0_intr: csr0=%b\n", csr0, USBDC_UDCCSR0_BITS));
	delay (25);

	ppipe = sc->sc_pipe[0];
	if (ppipe != NULL) {
		pipe = &ppipe->pipe;
		xfer = SIMPLEQ_FIRST(&pipe->queue);
	}

	if (sc->sc_ep0state == EP0_SETUP && (csr0 & USBDC_UDCCSR0_OPC)) {
		if (pipe == NULL) {
			DPRINTF(10,("pxaudc_ep0_intr: no control pipe\n"));
			return;
		}

		if (xfer == NULL) {
			DPRINTF(10,("pxaudc_ep0_intr: no xfer\n"));
			return;
		}

		pxaudc_read_ep0(sc, xfer);
	} else if (sc->sc_ep0state == EP0_IN &&
	    (csr0 & USBDC_UDCCSR0_IPR) == 0 && xfer) {
		pxaudc_write_ep0(sc, xfer);
	}
}

/*
 * Bus methods
 */

usbf_status
pxaudc_open(struct usbf_pipe *pipe)
{
	struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
	struct pxaudc_pipe *ppipe = (struct pxaudc_pipe *)pipe;
	int ep_idx;
	int s;

	ep_idx = usbf_endpoint_index(pipe->endpoint);
	if (ep_idx >= PXAUDC_NEP)
		return USBF_BAD_ADDRESS;

	DPRINTF(10,("pxaudc_open\n"));
	s = splhardusb();

	switch (usbf_endpoint_type(pipe->endpoint)) {
	case UE_CONTROL:
		pipe->methods = &pxaudc_ctrl_methods;
		break;

	case UE_BULK:
		pipe->methods = &pxaudc_bulk_methods;
		break;

	case UE_ISOCHRONOUS:
	case UE_INTERRUPT:
	default:
		/* XXX */
		splx(s);
		return USBF_BAD_ADDRESS;
	}

	if (ep_idx != 0 && sc->sc_ep_map[ep_idx] != -1) {
		printf("endpoint %d already used by %c",
		    ep_idx, '@'+ sc->sc_ep_map[0]);
		splx(s);
		return USBF_BAD_ADDRESS;
	}
	sc->sc_ep_map[ep_idx] = sc->sc_npipe;

	sc->sc_pipe[sc->sc_npipe] = ppipe;
	sc->sc_npipe++;

	splx(s);
	return USBF_NORMAL_COMPLETION;
}

void
pxaudc_softintr(void *v)
{
	struct pxaudc_softc *sc = v;

	pxaudc_intr1(sc);
}

usbf_status
pxaudc_allocm(struct usbf_bus *bus, struct usb_dma *dmap, u_int32_t size)
{
	return usbf_allocmem(bus, size, 0, dmap);
}

void
pxaudc_freem(struct usbf_bus *bus, struct usb_dma *dmap)
{
	usbf_freemem(bus, dmap);
}

struct usbf_xfer *
pxaudc_allocx(struct usbf_bus *bus)
{
	struct pxaudc_softc *sc = (struct pxaudc_softc *)bus;
	struct usbf_xfer *xfer;

	xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
	if (xfer != NULL)
		SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
	else
		xfer = malloc(sizeof(struct pxaudc_xfer), M_USB, M_NOWAIT);
	if (xfer != NULL)
		bzero(xfer, sizeof(struct pxaudc_xfer));
	return xfer;
}

void
pxaudc_freex(struct usbf_bus *bus, struct usbf_xfer *xfer)
{
	struct pxaudc_softc *sc = (struct pxaudc_softc *)bus;

	SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
}

/*
 * Control pipe methods
 */

usbf_status
pxaudc_ctrl_transfer(struct usbf_xfer *xfer)
{
	usbf_status err;

	/* Insert last in queue. */
	err = usbf_insert_transfer(xfer);
	if (err)
		return err;

	/*
	 * Pipe isn't running (otherwise err would be USBF_IN_PROGRESS),
	 * so start first.
	 */
	return pxaudc_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
}

usbf_status
pxaudc_ctrl_start(struct usbf_xfer *xfer)
{
	struct usbf_pipe *pipe = xfer->pipe;
	struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
	int iswrite = !(xfer->rqflags & URQ_REQUEST);
	int s;

	s = splusb();
	xfer->status = USBF_IN_PROGRESS;
	if (iswrite)
		pxaudc_write_ep0(sc, xfer);
	else {
		/* XXX boring message, this case is normally reached if
		 * XXX the xfer for a device request is being queued. */
		DPRINTF(10,("%s: ep[%x] ctrl-out, xfer=%p, len=%u, "
		    "actlen=%u\n", DEVNAME(sc),
		    usbf_endpoint_address(xfer->pipe->endpoint),
		    xfer, xfer->length,
		    xfer->actlen));
	}
	splx(s);
	return USBF_IN_PROGRESS;
}

/* (also used by bulk pipes) */
void
pxaudc_ctrl_abort(struct usbf_xfer *xfer)
{
	int s;
#ifdef PXAUDC_DEBUG
	struct usbf_pipe *pipe = xfer->pipe;
	struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
	int index = usbf_endpoint_index(pipe->endpoint);
	int dir = usbf_endpoint_dir(pipe->endpoint);
	int type = usbf_endpoint_type(pipe->endpoint);
#endif

	DPRINTF(10,("%s: ep%d %s-%s abort, xfer=%p\n", DEVNAME(sc), index,
	    type == UE_CONTROL ? "ctrl" : "bulk", dir == UE_DIR_IN ?
	    "in" : "out", xfer));

	/*
	 * Step 1: Make soft interrupt routine and hardware ignore the xfer.
	 */
	s = splusb();
	xfer->status = USBF_CANCELLED;
	timeout_del(&xfer->timeout_handle);
	splx(s);

	/*
	 * Step 2: Make sure hardware has finished any possible use of the
	 * xfer and the soft interrupt routine has run.
	 */
	s = splusb();
	/* XXX this does not seem right, what if there
	 * XXX are two xfers in the FIFO and we only want to
	 * XXX ignore one? */
#ifdef notyet
	pxaudc_flush(sc, usbf_endpoint_address(pipe->endpoint));
#endif
	/* XXX we're not doing DMA and the soft interrupt routine does not
	   XXX need to clean up anything. */
	splx(s);

	/*
	 * Step 3: Execute callback.
	 */
	s = splusb();
	usbf_transfer_complete(xfer);
	splx(s);
}

void
pxaudc_ctrl_done(struct usbf_xfer *xfer)
{
}

void
pxaudc_ctrl_close(struct usbf_pipe *pipe)
{
	/* XXX */
}

/*
 * Bulk pipe methods
 */

usbf_status
pxaudc_bulk_transfer(struct usbf_xfer *xfer)
{
	usbf_status err;

	/* Insert last in queue. */
	err = usbf_insert_transfer(xfer);
	if (err)
		return err;

	/*
	 * Pipe isn't running (otherwise err would be USBF_IN_PROGRESS),
	 * so start first.
	 */
	return pxaudc_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
}

usbf_status
pxaudc_bulk_start(struct usbf_xfer *xfer)
{
	struct usbf_pipe *pipe = xfer->pipe;
	struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
	int iswrite = (usbf_endpoint_dir(pipe->endpoint) == UE_DIR_IN);
	int s;

	DPRINTF(0,("%s: ep%d bulk-%s start, xfer=%p, len=%u\n", DEVNAME(sc),
	    usbf_endpoint_index(pipe->endpoint), iswrite ? "in" : "out",
	    xfer, xfer->length));

	s = splusb();
	xfer->status = USBF_IN_PROGRESS;
	if (iswrite)
		pxaudc_write(sc, xfer);
	else {
		/* enable interrupt */
	}
	splx(s);
	return USBF_IN_PROGRESS;
}

void
pxaudc_bulk_abort(struct usbf_xfer *xfer)
{
	pxaudc_ctrl_abort(xfer);
}

void
pxaudc_bulk_done(struct usbf_xfer *xfer)
{
#if 0
	int ep = usbf_endpoint_address(xfer->pipe->endpoint);
	struct usbf_pipe *pipe = xfer->pipe;
	struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;

#endif
}

void
pxaudc_bulk_close(struct usbf_pipe *pipe)
{
	/* XXX */
}

#endif /* NUSBF > 0 */


code:
/*	$OpenBSD: pxa27x_udc.h,v 1.4 2013/10/24 22:40:10 aalm Exp $	*/
/*
 * Copyright (c) 2009 Marek Vasut <marex@openbsd.org>
 *
 * Moved from pxa27x_udc.c:
 *
 * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <arm/xscale/pxa27x_udcreg.h>

#define PXAUDC_EP0MAXP	16	/* XXX */
#define PXAUDC_NEP	24	/* total number of endpoints */

struct pxaudc_softc {
	struct usbf_bus		 sc_bus;
	bus_space_tag_t		 sc_iot;
	bus_space_handle_t	 sc_ioh;
	bus_size_t		 sc_size;
	void			*sc_ih;
	void			*sc_conn_ih;
	SIMPLEQ_HEAD(,usbf_xfer) sc_free_xfers;	/* recycled xfers */
	u_int32_t		 sc_icr0;	/* enabled EP interrupts */
	u_int32_t		 sc_icr1;	/* enabled EP interrupts */
	enum {
		EP0_SETUP,
		EP0_IN
	}			 sc_ep0state;
	u_int32_t		 sc_isr0;	/* XXX deferred interrupts */
	u_int32_t		 sc_isr1;	/* XXX deferred interrupts */
	u_int32_t		 sc_otgisr;	/* XXX deferred interrupts */
	struct pxaudc_pipe	*sc_pipe[PXAUDC_NEP];
	int			 sc_npipe;

	int			 sc_cn;
	int			 sc_in;
	int			 sc_isn;
	int8_t			 sc_ep_map[16];

	struct device		*sc_dev;

	int			sc_gpio_detect;
	int			sc_gpio_detect_inv;

	int			sc_gpio_pullup;
	int			sc_gpio_pullup_inv;

	int			(*sc_is_host)(void);
};

int		 pxaudc_match(void);
void		 pxaudc_attach(struct pxaudc_softc *, void *);
int		 pxaudc_detach(struct pxaudc_softc *, int);
int		 pxaudc_activate(struct pxaudc_softc *, int);


code:
/*	$OpenBSD: pxa27x_udcreg.h,v 1.5 2007/02/25 01:40:12 drahn Exp $ */

/*
 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Register Descriptions for the USB Device Controller
 *
 * Reference:
 *  Intel(r) PXA27x Processor Family
 *   Developer's Manual
 *  (2800002.pdf)
 */

#ifndef _ARM_XSCALE_PXA27X_UDCREG_H_
#define _ARM_XSCALE_PXA27X_UDCREG_H_

#define USBDC_UDCCR	0x0000  /* UDC Control Register */
#define  USBDC_UDCCR_UDE	(1<<0)	/* UDC Enable */
#define  USBDC_UDCCR_UDA	(1<<1)	/* UDC Active */
#define  USBDC_UDCCR_UDR	(1<<2)	/* UDC Resume */
#define  USBDC_UDCCR_EMCE	(1<<3)	/* Endpoint Mem Config Error */
#define  USBDC_UDCCR_SMAC	(1<<4)	/* Switch EndPt Mem to Active Config */
#define  USBDC_UDCCR_AAISN	(7<<5)	/* Active UDC Alt Iface Setting */
#define  USBDC_UDCCR_AAISNr(x)	((x>>5)&7)	/* Active UDC Config */
#define  USBDC_UDCCR_AIN	(7<<8)	/* Active UDC Iface */
#define  USBDC_UDCCR_AINr(x)	((x>>8)&7)	/* Active UDC Config */
#define  USBDC_UDCCR_ACN	(7<<11)	/* Active UDC Config */
#define  USBDC_UDCCR_ACNr(x)	((x>>11)&7)	/* Active UDC Config */
#define  USBDC_UDCCR_DWRE	(1<<16)	/* Device Remote Wake-Up Feature */
#define  USBDC_UDCCR_BHNP	(1<<28)	/* B-Device Host Neg Proto Enable */
#define  USBDC_UDCCR_AHNP	(1<<29)	/* A-Device Host NEg Proto Support */
#define  USBDC_UDCCR_AALTHNP	(1<<30) /* A-Dev Alt Host Neg Proto Port Sup */
#define  USBDC_UDCCR_OEN	(1<<31)	/* On-The-Go Enable */
#define USBDC_UDCICR0	0x0004	/* UDC Interrupt Control Register 0 */
#define  USBDC_UDCICR0_IE(n)	(3<<((n)*2)) /* Interrupt Enables */
#define USBDC_UDCICR1	0x0008	/* UDC Interrupt Control Register 1 */
#define  USBDC_UDCICR1_IE(n)	(3<<((n)*2)) /* Interrupt Enables */
#define  USBDC_UDCICR1_IERS	(1<<27)	/* Interrupt Enable Reset */
#define  USBDC_UDCICR1_IESU	(1<<28)	/* Interrupt Enable Suspend */
#define  USBDC_UDCICR1_IERU	(1<<29)	/* Interrupt Enable Resume */
#define  USBDC_UDCICR1_IESOF	(1<<30)	/* Interrupt Enable Start of Frame */
#define  USBDC_UDCICR1_IECC	(1<<31)	/* Interrupt Enable Config Change */
#define USBDC_UDCISR0	0x000c	/* UDC Interrupt Status Register 0 */
#define  USBDC_UDCISR0_IR(n)	(3<<((n)*2)) /* Interrupt Requests */
#define  USBDC_UDCISR0_IRs(v,n)	(((v)>>((n)*2))&3) /* Interrupt Requests */
#define USBDC_UDCISR1	0x0010	/* UDC Interrupt Status Register 1 */
#define  USBDC_UDCISR1_IR(n)	(3<<((n)*2)) /* Interrupt Requests */
#define  USBDC_UDCISR1_IRs(v,n)	(((v)>>((n)*2))&3) /* Interrupt Requests */
#define  USBDC_UDCISR1_IRRS	(1<<27)	/* Interrupt Enable Reset */
#define  USBDC_UDCISR1_IRSU	(1<<28)	/* Interrupt Enable Suspend */
#define  USBDC_UDCISR1_IRRU	(1<<29)	/* Interrupt Enable Resume */
#define  USBDC_UDCISR1_IRSOF	(1<<30)	/* Interrupt Enable Start of Frame */
#define  USBDC_UDCISR1_IRCC	(1<<31)	/* Interrupt Enable Config Change */
#define USBDC_UDCFNR	0x0014	/* UDC Frame Number Register */
#define  USBDC_UDCFNR_FN	(1023<<0) /* Frame Number */
#define USBDC_UDCOTGICR	0x0018	/* UDC OTG Interrupt Control Register */
#define  USBDC_UDCOTGICR_IEIDF	(1<<0)	/* OTG ID Change Fall Intr En */
#define  USBDC_UDCOTGICR_IEIDR	(1<<1)	/* OTG ID Change Ris Intr En */
#define  USBDC_UDCOTGICR_IESDF	(1<<2)	/* OTG A-Dev SRP Detect Fall Intr En */
#define  USBDC_UDCOTGICR_IESDR	(1<<3)	/* OTG A-Dev SRP Detect Ris Intr En */
#define  USBDC_UDCOTGICR_IESVF	(1<<4)	/* OTG Session Valid Fall Intr En */
#define  USBDC_UDCOTGICR_IESVR	(1<<5)	/* OTG Session Valid Ris Intr En */
#define  USBDC_UDCOTGICR_IEVV44F (1<<6)	/* OTG Vbus Valid 4.4V Fall Intr En */
#define  USBDC_UDCOTGICR_IEVV44R (1<<7)	/* OTG Vbus Valid 4.4V Ris Intr En */
#define  USBDC_UDCOTGICR_IEVV40F (1<<8)	/* OTG Vbus Valid 4.0V Fall Intr En */
#define  USBDC_UDCOTGICR_IEVV40R (1<<9)	/* OTG Vbus Valid 4.0V Ris Intr En */
#define  USBDC_UDCOTGICR_IEXF	(1<<16)	/* Extern Transceiver Intr Fall En */
#define  USBDC_UDCOTGICR_IEXR	(1<<17)	/* Extern Transceiver Intr Ris En */
#define  USBDC_UDCOTGICR_IESF	(1<<24)	/* OTG SET_FEATURE Command Recvd */
#define USBDC_UDCOTGISR	0x001c	/* UDC OTG Interrupt Status Register */
#define  USBDC_UDCOTGISR_IRIDF	(1<<0)	/* OTG ID Change Fall Intr Req */
#define  USBDC_UDCOTGISR_IRIDR	(1<<1)	/* OTG ID Change Ris Intr Req */
#define  USBDC_UDCOTGISR_IRSDF	(1<<2)	/* OTG A-Dev SRP Detect Fall Intr Req */
#define  USBDC_UDCOTGISR_IRSDR	(1<<3)	/* OTG A-Dev SRP Detect Ris Intr Req */
#define  USBDC_UDCOTGISR_IRSVF	(1<<4)	/* OTG Session Valid Fall Intr Req */
#define  USBDC_UDCOTGISR_IRSVR	(1<<5)	/* OTG Session Valid Ris Intr Req */
#define  USBDC_UDCOTGISR_IRVV44F (1<<6)	/* OTG Vbus Valid 4.4V Fall Intr Req */
#define  USBDC_UDCOTGISR_IRVV44R (1<<7)	/* OTG Vbus Valid 4.4V Ris Intr Req */
#define  USBDC_UDCOTGISR_IRVV40F (1<<8)	/* OTG Vbus Valid 4.0V Fall Intr Req */
#define  USBDC_UDCOTGISR_IRVV40R (1<<9)	/* OTG Vbus Valid 4.0V Ris Intr Req */
#define  USBDC_UDCOTGISR_IRXF	(1<<16)	/* Extern Transceiver Intr Fall Req */
#define  USBDC_UDCOTGISR_IRXR	(1<<17)	/* Extern Transceiver Intr Ris Req */
#define  USBDC_UDCOTGISR_IRSF	(1<<24)	/* OTG SET_FEATURE Command Recvd */
#define USBDC_UP2OCR	0x0020	/* USB Port 2 Output Control Register */
#define  USBDC_UP2OCR_CPVEN	(1<<0)	/* Charge Pump Vbus Enable */
#define  USBDC_UP2OCR_CPVPE	(1<<1)	/* Charge Pump Vbus Pulse Enable */
#define  USBDC_UP2OCR_DPPDE	(1<<2)	/* Host Transc D+ Pull Down En */
#define  USBDC_UP2OCR_DMPDE	(1<<3)	/* Host Transc D- Pull Down En */
#define  USBDC_UP2OCR_DPPUE	(1<<4)	/* Host Transc D+ Pull Up En */
#define  USBDC_UP2OCR_DMPUE	(1<<5)	/* Host Transc D- Pull Up En */
#define  USBDC_UP2OCR_DPPUBE	(1<<6)	/* Host Transc D+ Pull Up Bypass En */
#define  USBDC_UP2OCR_DMPUBE	(1<<7)	/* Host Transc D- Pull Up Bypass En */
#define  USBDC_UP2OCR_EXSP	(1<<8)	/* External Transc Speed Control */
#define  USBDC_UP2OCR_EXSUS	(1<<9)	/* External Transc Suspend Control */
#define  USBDC_UP2OCR_IDON	(1<<10)	/* OTG ID Read Enable */
#define  USBDC_UP2OCR_HXS	(1<<16)	/* Host Transc Output Select */
#define  USBDC_UP2OCR_HXOE	(1<<17)	/* Host Transc Output Enable */
#define  USBDC_UP2OCR_SEOS	(7<<24)	/* Single-Ended Output Select */
#define USBDC_UP3OCR	0x0024	/* USB Port 3 Output Control Register */
#define  USBDC_UP3OCR_CFG	(3<<0)	/* Host Port Configuration */
/* 0x0028 to 0x00fc is reserved */
#define USBDC_UDCCSR0	0x0100	/* UDC Endpoint 0 Control/Status Registers */
#define  USBDC_UDCCSR0_OPC	(1<<0)	/* OUT Packet Complete */
#define  USBDC_UDCCSR0_IPR	(1<<1)	/* IN Packet Ready */
#define  USBDC_UDCCSR0_FTF	(1<<2)	/* Flush Transmit FIFO */
#define  USBDC_UDCCSR0_DME	(1<<3)	/* DMA Enable */
#define  USBDC_UDCCSR0_SST	(1<<4)	/* Sent Stall */
#define  USBDC_UDCCSR0_FST	(1<<5)	/* Force Stall */
#define  USBDC_UDCCSR0_RNE	(1<<6)	/* Receive FIFO Not Empty */
#define  USBDC_UDCCSR0_SA	(1<<7)	/* Setup Active */
#define  USBDC_UDCCSR0_AREN	(1<<8)	/* ACK Response Enable */
#define  USBDC_UDCCSR0_ACM	(1<<9)	/* ACK Control Mode */
#define USBDC_UDCCSR(n)	(0x0100+4*(n)) /* UDC Control/Status Registers */
#define  USBDC_UDCCSR_FS	(1<<0)	/* FIFO Needs Service */
#define  USBDC_UDCCSR_PC	(1<<1)	/* Packet Complete */
#define  USBDC_UDCCSR_TRN	(1<<2)	/* Tx/Rx NAK */
#define  USBDC_UDCCSR_DME	(1<<3)	/* DMA Enable */
#define  USBDC_UDCCSR_SST	(1<<4)	/* Sent STALL */
#define  USBDC_UDCCSR_FST	(1<<5)	/* Force STALL */
#define  USBDC_UDCCSR_BNE	(1<<6)	/* OUT: Buffer Not Empty */
#define  USBDC_UDCCSR_BNF	(1<<6)	/* IN: Buffer Not Full */
#define  USBDC_UDCCSR_SP	(1<<7)	/* Short Packet Control/Status */
#define  USBDC_UDCCSR_FEF	(1<<8)	/* Flush Endpoint FIFO */
#define  USBDC_UDCCSR_DPE	(1<<9)	/* Data Packet Empty (async EP only) */
/* 0x0160 to 0x01fc is reserved */
#define USBDC_UDCBCR(n)	(0x0200+4*(n)) /* UDC Byte Count Registers */
#define  USBDC_UDCBCR_BC	(1023<<0) /* Byte Count */
/* 0x0260 to 0x02fc is reserved */
#define USBDC_UDCDR(n)	(0x0300+4*(n))	/* UDC Data Registers */
/* 0x0360 to 0x03fc is reserved */
/* 0x0400 is reserved */
#define USBDC_UDCECR(n)	(0x0400+4*(n)) /* UDC Configuration Registers */
#define  USBDC_UDCECR_EE	(1<<0)	/* Endpoint Enable */
#define  USBDC_UDCECR_DE	(1<<1)	/* Double-Buffering Enable */
#define  USBDC_UDCECR_MPS	(1023<<2) /* Maximum Packet Size */
#define  USBDC_UDCECR_ED	(1<<12)	/* USB Endpoint Direction 0 OUT, 1 IN */
#define  USBDC_UDCECR_ET	(3<<13)	/* USB Enpoint Type */
#define  USBDC_UDCECR_EN	(15<<15) /* Endpoint Number */
#define  USBDC_UDCECR_AISN	(7<<19)	/* Alternate Interface Number */
#define  USBDC_UDCECR_IN	(7<<22)	/* Interface Number */
#define  USBDC_UDCECR_CN	(3<<25)	/* Configuration Number */

#define  USBDC_UDCECR_MPSs(n)	((n)<<2)  /* Maximum Packet Size */
#define  USBDC_UDCECR_ETs(n)	((n)<<13) /* USB Enpoint Type */
#define  USBDC_UDCECR_ET_INT	3
#define  USBDC_UDCECR_ET_BULK	2
#define  USBDC_UDCECR_ET_ISO	1
#define  USBDC_UDCECR_ENs(n)	((n)<<15) /* Endpoint Number */
#define  USBDC_UDCECR_AISNs(n)	((n)<<19) /* Alternate Interface Number */
#define  USBDC_UDCECR_INs(n)	((n)<<22) /* Interface Number */
#define  USBDC_UDCECR_CNs(n)	((n)<<25) /* Configuration Number */

#define USBDC_UDCCR_BITS						\
	"\20\001UDE\002UDA\003UDR\004EMCE\005SMAC\021DWRE"		\
	"\035BHNP\036AHNP\037OEN"
#define USBDC_UDCISR0_BITS						\
	"\20\0010P\0020F\003AP\004AF\005BP\006BF\007CP\010CF"		\
	"\011DP\012DF\013EP\014EF\015FP\016FF\017GP\020GF"		\
	"\031HP\032HF\033IP\034IF\035JP\036JF\037KP\030KF"		\
	"\041LP\042LF\043MP\044MF\045NP\046NF\047PP\040PF"
#define USBDC_UDCISR1_BITS						\
	"\20\001QP\002QF\003RP\004RF\005SP\006SF\007TP\010TF"		\
	"\011UP\012UF\013VP\014VF\015WP\016WF\017XP\020XF"		\
	"\034RS\035SU\036RU\037SOF\040CC"
#define USBDC_UDCOTGISR_BITS						\
	"\20\001IRIDF\002IRIDR\003IRSDF\004IRSDR\005IRSVF\006IRSVR"	\
	"\007IRVV44F\010IRVV44R\011IRVV40F\012IRVV40R"
#define USBDC_UDCCSR0_BITS						\
	"\20\001OPC\002IPR\003FTF\004DME\005SST\006FST\007RNE"		\
	"\010SA\011AREN\012ACM"
#define USBDC_UDCCSRN_BITS						\
	"\20\001FS\002PC\003TRN\004DME\005SST\006FST\007BNEF"		\
	"\010SP\011FEF\012DPE"

#endif /* _ARM_XSCALE_PXA27X_UDCREG_H_ */


code:
/*	$OpenBSD: pxa2x0.c,v 1.19 2014/10/18 12:21:56 miod Exp $ */
/*	$NetBSD: pxa2x0.c,v 1.5 2003/12/12 16:42:44 thorpej Exp $ */

/*
 * Copyright (c) 2002  Genetec Corporation.  All rights reserved.
 * Written by Hiroyuki Bessho for Genetec Corporation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed for the NetBSD Project by
 *	Genetec Corporation.
 * 4. The name of Genetec Corporation may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * Autoconfiguration support for the Intel PXA2[15]0 application
 * processor. This code is derived from arm/sa11x0/sa11x0.c
 */

/*-
 * Copyright (c) 2001, The NetBSD Foundation, Inc.  All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 */
/*-
 * Copyright (c) 1999
 *         Shin Takemura and PocketBSD Project. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the PocketBSD project
 *	and its contributors.
 * 4. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include "pxagpio.h"
#include "pxadmac.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/reboot.h>
#include <sys/timetc.h>

#include <machine/cpu.h>
#include <machine/bus.h>

#include <arm/cpufunc.h>
#include <arm/mainbus/mainbus.h>
#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0var.h>

struct pxaip_softc {
	struct device sc_dev;
	bus_space_tag_t sc_bust;
	bus_dma_tag_t sc_dmat;
	bus_space_handle_t sc_bush_clk;
	bus_space_handle_t sc_bush_rtc;
};

/* prototypes */
int	pxaip_match(struct device *, void *, void *);
void	pxaip_attach(struct device *, struct device *, void *);
int 	pxaip_search(struct device *, void *, void *);
void	pxaip_attach_critical(struct pxaip_softc *);
int	pxaip_print(void *, const char *);

int	pxaip_measure_cpuclock(struct pxaip_softc *);

/* attach structures */
#ifdef __NetBSD__
CFATTACH_DECL(pxaip, sizeof(struct pxaip_softc),
    pxaip_match, pxaip_attach, NULL, NULL);
#else
struct cfattach pxaip_ca = {
	sizeof(struct pxaip_softc), pxaip_match, pxaip_attach
};

struct cfdriver pxaip_cd = {
	NULL, "pxaip", DV_DULL
};
#endif

struct pxaip_softc *pxaip_sc;

int
pxaip_match(struct device *parent, void *match, void *aux)
{

	return 1;
}

void
pxaip_attach(struct device *parent, struct device *self, void *aux)
{
	struct pxaip_softc *sc = (struct pxaip_softc *)self;
#ifdef __APM__
	extern int freq;
#endif
	int cpuclock;

	pxaip_sc = sc;
	sc->sc_bust = &pxa2x0_bs_tag;
	sc->sc_dmat = &pxa2x0_bus_dma_tag;

	if (bus_space_map(sc->sc_bust, PXA2X0_CLKMAN_BASE, PXA2X0_CLKMAN_SIZE,
	    0, &sc->sc_bush_clk))
		panic("pxaip_attach: failed to map CLKMAN");

	if (bus_space_map(sc->sc_bust, PXA2X0_RTC_BASE, PXA2X0_RTC_SIZE,
	    0, &sc->sc_bush_rtc))
		panic("pxaip_attach: failed to map RTC");

	/*
	 * Calculate clock speed
	 * This takes 2 secs at most.
	 */
	cpuclock = pxaip_measure_cpuclock(sc) / 1000;
	if (cpuclock % 1000 > 500)
		cpuclock = cpuclock + 1000 - cpuclock % 1000;
#ifdef __APM__
	freq = cpuclock / 1000;
#endif

	printf(": CPU clock = %d.%03d MHz\n", cpuclock/1000, cpuclock%1000);

	/*
	 * Attach critical devices
	 */
	pxaip_attach_critical(sc);

	/*
	 * Attach all other devices
	 */
	config_search(pxaip_search, self, sc);

}

int
pxaip_search(struct device *parent, void *c, void *aux)
{
	struct pxaip_softc *sc = aux;
	struct pxaip_attach_args aa;
	struct cfdata	*cf = c;

        aa.pxa_iot = sc->sc_bust;
        aa.pxa_dmat = sc->sc_dmat;
#if 0
        aa.pxa_addr = cf->cf_addr;
        aa.pxa_size = cf->cf_size;
        aa.pxa_intr = cf->cf_intr;
	aa.pxa_index = cf->cf_index;
#else
        aa.pxa_addr = (cf->cf_loc)[0];
        aa.pxa_size = (cf->cf_loc)[1];
        aa.pxa_intr = (cf->cf_loc)[2];
	aa.pxa_index = (cf->cf_loc)[3];
#endif

	config_found(parent, &aa, pxaip_print);

        return 0;
}

void
pxaip_attach_critical(struct pxaip_softc *sc)
{
	struct pxaip_attach_args aa;

        aa.pxa_iot = sc->sc_bust;
        aa.pxa_dmat = sc->sc_dmat;
        aa.pxa_addr = PXA2X0_INTCTL_BASE;
        aa.pxa_size = PXA2X0_INTCTL_SIZE;
        aa.pxa_intr = -1;
	if (config_found(&sc->sc_dev, &aa, pxaip_print) == NULL)
		panic("pxaip_attach_critical: failed to attach INTC!");

#if NPXAGPIO > 0
        aa.pxa_iot = sc->sc_bust;
        aa.pxa_dmat = sc->sc_dmat;
        aa.pxa_addr = PXA2X0_GPIO_BASE;
        aa.pxa_size = PXA2X0_GPIO_SIZE;
        aa.pxa_intr = -1;
	if (config_found(&sc->sc_dev, &aa, pxaip_print) == NULL)
		panic("pxaip_attach_critical: failed to attach GPIO!");
#endif

#if NPXADMAC > 0
        aa.pxa_iot = sc->sc_bust;
        aa.pxa_dmat = sc->sc_dmat;
        aa.pxa_addr = PXA2X0_DMAC_BASE;
        aa.pxa_size = PXA2X0_DMAC_SIZE;
        aa.pxa_intr = PXA2X0_INT_DMA;
	if (config_found(&sc->sc_dev, &aa, pxaip_print) == NULL)
		panic("pxaip_attach_critical: failed to attach DMAC!");
#endif
}

int
pxaip_print(void *aux, const char *name)
{
	struct pxaip_attach_args *sa = (struct pxaip_attach_args*)aux;

	if (sa->pxa_addr != -1) {
                printf(" addr 0x%lx", sa->pxa_addr);
	        if (sa->pxa_size > -1)
	                printf("-0x%lx", sa->pxa_addr + sa->pxa_size-1);
	}
        if (sa->pxa_intr != -1)
                printf(" intr %d", sa->pxa_intr);

        return (UNCONF);
}

static inline uint32_t
read_clock_counter(void)
{
  uint32_t x;
  __asm volatile("mrc	p14, 0, %0, c1, c1, 0" : "=r" (x));

  return x;
}

int
pxaip_measure_cpuclock(struct pxaip_softc *sc)
{
	uint32_t rtc0, rtc1, start, end;
	uint32_t pmcr_save;
	bus_space_handle_t ioh;
	int irq;

	ioh = sc->sc_bush_rtc;
	irq = disable_interrupts(I32_bit|F32_bit);

	__asm volatile( "mrc p14, 0, %0, c0, c1, 0" : "=r" (pmcr_save));
	/* Enable clock counter */
	__asm volatile( "mcr p14, 0, %0, c0, c1, 0" : : "r" (0x0001));

	rtc0 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR);
	/* Wait for next second starts */
	while ((rtc1 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) == rtc0)
		;
	start = read_clock_counter();
	while(rtc1 == bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR))
		;		/* Wait for 1sec */
	end = read_clock_counter();

	__asm volatile( "mcr p14, 0, %0, c0, c1, 0" : : "r" (pmcr_save));
	restore_interrupts(irq);

	return end - start;
}

void
pxa2x0_turbo_mode(int f)
{
	__asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r" (f));
}

void
pxa2x0_probe_sdram(vaddr_t memctl_va, paddr_t *start, paddr_t *size)
{
	u_int32_t mdcnfg, dwid, dcac, drac, dnb;
	int i;

	mdcnfg = *((volatile u_int32_t *)(memctl_va + MEMCTL_MDCNFG));

	/*
	 * Scan all 4 SDRAM banks
	 */
	for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) {
		start[i] = 0;
		size[i] = 0;

		switch (i) {
		case 0:
		case 1:
			if ((i == 0 && (mdcnfg & MDCNFG_DE0) == 0) ||
			    (i == 1 && (mdcnfg & MDCNFG_DE1) == 0))
				continue;
			dwid = mdcnfg >> MDCNFD_DWID01_SHIFT;
			dcac = mdcnfg >> MDCNFD_DCAC01_SHIFT;
			drac = mdcnfg >> MDCNFD_DRAC01_SHIFT;
			dnb = mdcnfg >> MDCNFD_DNB01_SHIFT;
			break;

		case 2:
		case 3:
			if ((i == 2 && (mdcnfg & MDCNFG_DE2) == 0) ||
			    (i == 3 && (mdcnfg & MDCNFG_DE3) == 0))
				continue;
			dwid = mdcnfg >> MDCNFD_DWID23_SHIFT;
			dcac = mdcnfg >> MDCNFD_DCAC23_SHIFT;
			drac = mdcnfg >> MDCNFD_DRAC23_SHIFT;
			dnb = mdcnfg >> MDCNFD_DNB23_SHIFT;
			break;
		default:
			panic("pxa2x0_probe_sdram: impossible");
		}

		dwid = 2 << (1 - (dwid & MDCNFD_DWID_MASK));  /* 16/32 width */
		dcac = 1 << ((dcac & MDCNFD_DCAC_MASK) + 8);  /* 8-11 columns */
		drac = 1 << ((drac & MDCNFD_DRAC_MASK) + 11); /* 11-13 rows */
		dnb = 2 << (dnb & MDCNFD_DNB_MASK);	      /* # of banks */

		size[i] = (paddr_t)(dwid * dcac * drac * dnb);
		start[i] = PXA2X0_SDRAM0_START + (i * PXA2X0_SDRAM_BANK_SIZE);
	}
}

void
pxa2x0_clkman_config(u_int clk, int enable)
{
	struct pxaip_softc *sc;
	u_int32_t rv;

	KDASSERT(pxaip_sc != NULL);
	sc = pxaip_sc;

	rv = bus_space_read_4(sc->sc_bust, sc->sc_bush_clk, CLKMAN_CKEN);
	rv &= ~clk;

	if (enable)
		rv |= clk;

	bus_space_write_4(sc->sc_bust, sc->sc_bush_clk, CLKMAN_CKEN, rv);
}

void
pxa2x0_rtc_setalarm(u_int32_t secs)
{
	struct pxaip_softc *sc;
	u_int32_t rv;
	int s;

	KDASSERT(pxaip_sc != NULL);
	sc = pxaip_sc;

	s = splhigh();
	bus_space_write_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RTAR, secs);
	rv = bus_space_read_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RTSR);
	if (secs == 0)
		bus_space_write_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RTSR,
		    (rv | RTSR_AL) & ~RTSR_ALE);
	else
		bus_space_write_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RTSR,
		    (rv | RTSR_AL | RTSR_ALE));
	splx(s);
}

u_int32_t
pxa2x0_rtc_getalarm(void)
{
	struct pxaip_softc *sc;

	KDASSERT(pxaip_sc != NULL);
	sc = pxaip_sc;

	return (bus_space_read_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RTAR));
}

u_int32_t
pxa2x0_rtc_getsecs(void)
{
	struct pxaip_softc *sc;

	KDASSERT(pxaip_sc != NULL);
	sc = pxaip_sc;

	return (bus_space_read_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RCNR));
}

void
resettodr(void)
{
	struct pxaip_softc *sc = pxaip_sc;
	struct timeval tv;

	microtime(&tv);

	bus_space_write_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RCNR,
	    (u_int32_t)tv.tv_sec);
}

void
inittodr(time_t base)
{
	struct pxaip_softc *sc = pxaip_sc;
	struct timespec ts;
	u_int32_t rcnr;

	/* XXX decide if RCNR can be valid, based on the last reset
	 * XXX reason, i.e. RCSR. */
	rcnr = bus_space_read_4(sc->sc_bust, sc->sc_bush_rtc, RTC_RCNR);

	/* XXX check how much RCNR differs from the filesystem date. */
	if (rcnr > base)
		ts.tv_sec = rcnr;
	else {
		printf("WARNING: using filesystem date -- CHECK AND RESET THE DATE!\n");
		ts.tv_sec = base;
	}

	ts.tv_nsec = 0;
	tc_setclock(&ts);
}


code:
/*	$OpenBSD: pxa2x0_a4x_io.S,v 1.2 2005/01/02 19:52:36 drahn Exp $ */
/*	$NetBSD: pxa2x0_a4x_io.S,v 1.1 2002/10/19 19:31:39 bsh Exp $ */

/*
 * Copyright (c) 2002  Genetec Corporation.  All rights reserved.
 * Written by Hiroyuki Bessho for Genetec Corporation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed for the NetBSD Project by
 *	Genetec Corporation.
 * 4. The name of Genetec Corporation may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * There are simple bus space functions for IO registers mapped at
 * 32-bit aligned positions.  offset is multiplied by 4.
 */

#include <machine/asm.h>

/*
 * bus_space I/O functions with offset*4
 */

/*
 * read single
 */

ENTRY(a4x_bs_r_1)
	ldrb	r0, [r1, r2, LSL #2]
	mov	pc, lr

ENTRY(a4x_bs_r_2)
	mov	r2, r2, LSL #2
	ldrh	r0, [r1, r2]
	mov	pc, lr

ENTRY(a4x_bs_r_4)
	ldr	r0, [r1, r2, LSL #2]
	mov	pc, lr

/*
 * write single
 */

ENTRY(a4x_bs_w_1)
	strb	r3, [r1, r2, LSL #2]
	mov	pc, lr

ENTRY(a4x_bs_w_2)
	mov	r2, r2, LSL #2
	strh	r3, [r1, r2]
	mov	pc, lr

ENTRY(a4x_bs_w_4)
	str	r3, [r1, r2, LSL #2]
	mov	pc, lr

/*
 * read multiple
 */
ENTRY(a4x_bs_rm_1)
	mov r2, r2, LSL #2
	b generic_bs_rm_1

ENTRY(a4x_bs_rm_2)
	mov r2, r2, LSL #2
	b generic_armv4_bs_rm_2

/*
 * write multiple
 */
ENTRY(a4x_bs_wm_1)
	mov r2, r2, LSL #2
	b generic_bs_wm_1

ENTRY(a4x_bs_wm_2)
	mov r2, r2, LSL #2
	b generic_armv4_bs_wm_2


code:
/*	$OpenBSD: pxa2x0_a4x_space.c,v 1.3 2008/05/15 22:17:08 brad Exp $ */
/*	$NetBSD: pxa2x0_a4x_space.c,v 1.2 2003/07/15 00:24:54 lukem Exp $ */

/*
 * Copyright (c) 2002  Genetec Corporation.  All rights reserved.
 * Written by Hiroyuki Bessho for Genetec Corporation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed for the NetBSD Project by
 *	Genetec Corporation.
 * 4. The name of Genetec Corporation may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Bus space tag for 8/16-bit devices on 32-bit bus.
 * all registers are located at the address of multiple of 4.
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

/* Prototypes for all the bus_space structure functions */
bs_protos(pxa2x0);
bs_protos(a4x);
bs_protos(generic);
bs_protos(generic_armv4);
bs_protos(bs_notimpl);

struct bus_space pxa2x0_a4x_bs_tag = {
	/* cookie */
	(void *) 0,

	/* mapping/unmapping */
	pxa2x0_bs_map,
	pxa2x0_bs_unmap,
	pxa2x0_bs_subregion,

	/* allocation/deallocation */
	pxa2x0_bs_alloc,	/* not implemented */
	pxa2x0_bs_free,		/* not implemented */

	/* get kernel virtual address */
	pxa2x0_bs_vaddr,

	/* mmap */
	bs_notimpl_bs_mmap,

	/* barrier */
	pxa2x0_bs_barrier,

	/* read (single) */
	a4x_bs_r_1,
	a4x_bs_r_2,
	a4x_bs_r_4,
	bs_notimpl_bs_r_8,

	/* read multiple */
	a4x_bs_rm_1,
	a4x_bs_rm_2,
	bs_notimpl_bs_rm_4,
	bs_notimpl_bs_rm_8,

	/* read region */
	bs_notimpl_bs_rr_1,
	bs_notimpl_bs_rr_2,
	bs_notimpl_bs_rr_4,
	bs_notimpl_bs_rr_8,

	/* write (single) */
	a4x_bs_w_1,
	a4x_bs_w_2,
	a4x_bs_w_4,
	bs_notimpl_bs_w_8,

	/* write multiple */
	a4x_bs_wm_1,
	a4x_bs_wm_2,
	bs_notimpl_bs_wm_4,
	bs_notimpl_bs_wm_8,

	/* write region */
	bs_notimpl_bs_wr_1,
	bs_notimpl_bs_wr_2,
	bs_notimpl_bs_wr_4,
	bs_notimpl_bs_wr_8,

	/* set multiple */
	bs_notimpl_bs_sm_1,
	bs_notimpl_bs_sm_2,
	bs_notimpl_bs_sm_4,
	bs_notimpl_bs_sm_8,

	/* set region */
	bs_notimpl_bs_sr_1,
	bs_notimpl_bs_sr_2,
	bs_notimpl_bs_sr_4,
	bs_notimpl_bs_sr_8,

	/* copy */
	bs_notimpl_bs_c_1,
	bs_notimpl_bs_c_2,
	bs_notimpl_bs_c_4,
	bs_notimpl_bs_c_8,
};