adm5120: add 3.18 support
[openwrt/svn-archive/archive.git] / target / linux / adm5120 / files-3.18 / drivers / usb / host / adm5120.h
diff --git a/target/linux/adm5120/files-3.18/drivers/usb/host/adm5120.h b/target/linux/adm5120/files-3.18/drivers/usb/host/adm5120.h
new file mode 100644 (file)
index 0000000..e47aac8
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * ADM5120 HCD (Host Controller Driver) for USB
+ *
+ * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file was derived from: drivers/usb/host/ohci.h
+ *   (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ *   (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given OHCI_BIG_ENDIAN), depending on the
+ * host controller implementation.
+ */
+typedef __u32 __bitwise __hc32;
+typedef __u16 __bitwise __hc16;
+
+/*
+ * OHCI Endpoint Descriptor (ED) ... holds TD queue
+ * See OHCI spec, section 4.2
+ *
+ * This is a "Queue Head" for those transfers, which is why
+ * both EHCI and UHCI call similar structures a "QH".
+ */
+
+#define TD_DATALEN_MAX 4096
+
+#define ED_ALIGN       16
+#define ED_MASK        ((u32)~(ED_ALIGN-1))    /* strip hw status in low addr bits */
+
+struct ed {
+       /* first fields are hardware-specified */
+       __hc32                  hwINFO;      /* endpoint config bitmap */
+       /* info bits defined by hcd */
+#define ED_DEQUEUE     (1 << 27)
+       /* info bits defined by the hardware */
+#define ED_MPS_SHIFT   16
+#define ED_MPS_MASK    ((1 << 11)-1)
+#define ED_MPS_GET(x)  (((x) >> ED_MPS_SHIFT) & ED_MPS_MASK)
+#define ED_ISO         (1 << 15)               /* isochronous endpoint */
+#define ED_SKIP                (1 << 14)
+#define ED_SPEED_FULL  (1 << 13)               /* fullspeed device */
+#define ED_INT         (1 << 11)               /* interrupt endpoint */
+#define ED_EN_SHIFT    7                       /* endpoint shift */
+#define ED_EN_MASK     ((1 << 4)-1)            /* endpoint mask */
+#define ED_EN_GET(x)   (((x) >> ED_EN_SHIFT) & ED_EN_MASK)
+#define ED_FA_MASK     ((1 << 7)-1)            /* function address mask */
+#define ED_FA_GET(x)   ((x) & ED_FA_MASK)
+       __hc32                  hwTailP;        /* tail of TD list */
+       __hc32                  hwHeadP;        /* head of TD list (hc r/w) */
+#define ED_C           (0x02)                  /* toggle carry */
+#define ED_H           (0x01)                  /* halted */
+       __hc32                  hwNextED;       /* next ED in list */
+
+       /* rest are purely for the driver's use */
+       dma_addr_t              dma;            /* addr of ED */
+       struct td               *dummy;         /* next TD to activate */
+
+       struct list_head        urb_list;       /* list of our URBs */
+
+       /* host's view of schedule */
+       struct ed               *ed_next;       /* on schedule list */
+       struct ed               *ed_prev;       /* for non-interrupt EDs */
+       struct ed               *ed_rm_next;    /* on rm list */
+       struct list_head        td_list;        /* "shadow list" of our TDs */
+
+       /* create --> IDLE --> OPER --> ... --> IDLE --> destroy
+        * usually:  OPER --> UNLINK --> (IDLE | OPER) --> ...
+        */
+       u8                      state;          /* ED_{IDLE,UNLINK,OPER} */
+#define ED_IDLE                0x00            /* NOT linked to HC */
+#define ED_UNLINK      0x01            /* being unlinked from hc */
+#define ED_OPER                0x02            /* IS linked to hc */
+
+       u8                      type;           /* PIPE_{BULK,...} */
+
+       /* periodic scheduling params (for intr and iso) */
+       u8                      branch;
+       u16                     interval;
+       u16                     load;
+       u16                     last_iso;       /* iso only */
+
+       /* HC may see EDs on rm_list until next frame (frame_no == tick) */
+       u16                     tick;
+} __attribute__ ((aligned(ED_ALIGN)));
+
+/*
+ * OHCI Transfer Descriptor (TD) ... one per transfer segment
+ * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
+ * and 4.3.2 (iso)
+ */
+
+#define TD_ALIGN       32
+#define TD_MASK        ((u32)~(TD_ALIGN-1))    /* strip hw status in low addr bits */
+
+struct td {
+       /* first fields are hardware-specified */
+       __hc32          hwINFO;         /* transfer info bitmask */
+
+       /* hwINFO bits */
+#define TD_OWN         (1 << 31)               /* owner of the descriptor */
+#define TD_CC_SHIFT    27                      /* condition code */
+#define TD_CC_MASK     0xf
+#define TD_CC          (TD_CC_MASK << TD_CC_SHIFT)
+#define TD_CC_GET(x)   (((x) >> TD_CC_SHIFT) & TD_CC_MASK)
+
+#define TD_EC_SHIFT    25                      /* error count */
+#define TD_EC_MASK     0x3
+#define TD_EC          (TD_EC_MASK << TD_EC_SHIFT)
+#define TD_EC_GET(x)   ((x >> TD_EC_SHIFT) & TD_EC_MASK)
+#define TD_T_SHIFT     23                      /* data toggle state */
+#define TD_T_MASK      0x3
+#define TD_T           (TD_T_MASK << TD_T_SHIFT)
+#define TD_T_DATA0     (0x2 << TD_T_SHIFT)     /* DATA0 */
+#define TD_T_DATA1     (0x3 << TD_T_SHIFT)     /* DATA1 */
+#define TD_T_CARRY     (0x0 << TD_T_SHIFT)     /* uses ED_C */
+#define TD_T_GET(x)    (((x) >> TD_T_SHIFT) & TD_T_MASK)
+#define TD_DP_SHIFT    21                      /* direction/pid */
+#define TD_DP_MASK     0x3
+#define TD_DP          (TD_DP_MASK << TD_DP_SHIFT)
+#define TD_DP_GET      (((x) >> TD_DP_SHIFT) & TD_DP_MASK)
+#define TD_DP_SETUP    (0x0 << TD_DP_SHIFT)    /* SETUP pid */
+#define TD_DP_OUT      (0x1 << TD_DP_SHIFT)    /* OUT pid */
+#define TD_DP_IN       (0x2 << TD_DP_SHIFT)    /* IN pid */
+#define TD_ISI_SHIFT   8                       /* Interrupt Service Interval */
+#define TD_ISI_MASK    0x3f
+#define TD_ISI_GET(x)  (((x) >> TD_ISI_SHIFT) & TD_ISI_MASK)
+#define TD_FN_MASK     0x3f                    /* frame number */
+#define TD_FN_GET(x)   ((x) & TD_FN_MASK)
+
+       __hc32          hwDBP;          /* Data Buffer Pointer (or 0) */
+       __hc32          hwCBL;          /* Controller/Buffer Length */
+
+       /* hwCBL bits */
+#define TD_BL_MASK     0xffff          /* buffer length */
+#define TD_BL_GET(x)   ((x) & TD_BL_MASK)
+#define TD_IE          (1 << 16)       /* interrupt enable */
+       __hc32          hwNextTD;       /* Next TD Pointer */
+
+       /* rest are purely for the driver's use */
+       __u8            index;
+       struct ed       *ed;
+       struct td       *td_hash;       /* dma-->td hashtable */
+       struct td       *next_dl_td;
+       struct urb      *urb;
+
+       dma_addr_t      td_dma;         /* addr of this TD */
+       dma_addr_t      data_dma;       /* addr of data it points to */
+
+       struct list_head td_list;       /* "shadow list", TDs on same ED */
+
+       u32             flags;
+#define TD_FLAG_DONE   (1 << 17)       /* retired to done list */
+#define TD_FLAG_ISO    (1 << 16)       /* copy of ED_ISO */
+} __attribute__ ((aligned(TD_ALIGN))); /* c/b/i need 16; only iso needs 32 */
+
+/*
+ * Hardware transfer status codes -- CC from td->hwINFO
+ */
+#define TD_CC_NOERROR          0x00
+#define TD_CC_CRC              0x01
+#define TD_CC_BITSTUFFING      0x02
+#define TD_CC_DATATOGGLEM      0x03
+#define TD_CC_STALL            0x04
+#define TD_CC_DEVNOTRESP       0x05
+#define TD_CC_PIDCHECKFAIL     0x06
+#define TD_CC_UNEXPECTEDPID    0x07
+#define TD_CC_DATAOVERRUN      0x08
+#define TD_CC_DATAUNDERRUN     0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_CC_BUFFEROVERRUN    0x0C
+#define TD_CC_BUFFERUNDERRUN   0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_CC_HCD0             0x0E
+#define TD_CC_NOTACCESSED      0x0F
+
+/*
+ * preshifted status codes
+ */
+#define TD_SCC_NOTACCESSED     (TD_CC_NOTACCESSED << TD_CC_SHIFT)
+
+
+/* map OHCI TD status codes (CC) to errno values */
+static const int cc_to_error[16] = {
+       /* No  Error  */        0,
+       /* CRC Error  */        -EILSEQ,
+       /* Bit Stuff  */        -EPROTO,
+       /* Data Togg  */        -EILSEQ,
+       /* Stall      */        -EPIPE,
+       /* DevNotResp */        -ETIME,
+       /* PIDCheck   */        -EPROTO,
+       /* UnExpPID   */        -EPROTO,
+       /* DataOver   */        -EOVERFLOW,
+       /* DataUnder  */        -EREMOTEIO,
+       /* (for hw)   */        -EIO,
+       /* (for hw)   */        -EIO,
+       /* BufferOver */        -ECOMM,
+       /* BuffUnder  */        -ENOSR,
+       /* (for HCD)  */        -EALREADY,
+       /* (for HCD)  */        -EALREADY
+};
+
+#define NUM_INTS       32
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O region.
+ * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
+ * Layout is in section 7 (and appendix B) of the spec.
+ */
+struct admhcd_regs {
+       __hc32  gencontrol;     /* General Control */
+       __hc32  int_status;     /* Interrupt Status */
+       __hc32  int_enable;     /* Interrupt Enable */
+       __hc32  reserved00;
+       __hc32  host_control;   /* Host General Control */
+       __hc32  reserved01;
+       __hc32  fminterval;     /* Frame Interval */
+       __hc32  fmnumber;       /* Frame Number */
+       __hc32  reserved02;
+       __hc32  reserved03;
+       __hc32  reserved04;
+       __hc32  reserved05;
+       __hc32  reserved06;
+       __hc32  reserved07;
+       __hc32  reserved08;
+       __hc32  reserved09;
+       __hc32  reserved10;
+       __hc32  reserved11;
+       __hc32  reserved12;
+       __hc32  reserved13;
+       __hc32  reserved14;
+       __hc32  reserved15;
+       __hc32  reserved16;
+       __hc32  reserved17;
+       __hc32  reserved18;
+       __hc32  reserved19;
+       __hc32  reserved20;
+       __hc32  reserved21;
+       __hc32  lsthresh;       /* Low Speed Threshold */
+       __hc32  rhdesc;         /* Root Hub Descriptor */
+#define MAX_ROOT_PORTS 2
+       __hc32  portstatus[MAX_ROOT_PORTS]; /* Port Status */
+       __hc32  hosthead;       /* Host Descriptor Head */
+} __attribute__ ((aligned(32)));
+
+/*
+ * General Control register bits
+ */
+#define ADMHC_CTRL_UHFE        (1 << 0)        /* USB Host Function Enable */
+#define ADMHC_CTRL_SIR (1 << 1)        /* Software Interrupt request */
+#define ADMHC_CTRL_DMAA        (1 << 2)        /* DMA Arbitration Control */
+#define ADMHC_CTRL_SR  (1 << 3)        /* Software Reset */
+
+/*
+ * Host General Control register bits
+ */
+#define ADMHC_HC_BUSS          0x3             /* USB bus state */
+#define   ADMHC_BUSS_RESET     0x0
+#define   ADMHC_BUSS_RESUME    0x1
+#define   ADMHC_BUSS_OPER      0x2
+#define   ADMHC_BUSS_SUSPEND   0x3
+#define ADMHC_HC_DMAE          (1 << 2)        /* DMA enable */
+
+/*
+ * Interrupt Status/Enable register bits
+ */
+#define ADMHC_INTR_SOFI        (1 << 4)        /* start of frame */
+#define ADMHC_INTR_RESI        (1 << 5)        /* resume detected */
+#define ADMHC_INTR_6   (1 << 6)        /* unknown */
+#define ADMHC_INTR_7   (1 << 7)        /* unknown */
+#define ADMHC_INTR_BABI        (1 << 8)        /* babble detected */
+#define ADMHC_INTR_INSM        (1 << 9)        /* root hub status change */
+#define ADMHC_INTR_SO  (1 << 10)       /* scheduling overrun */
+#define ADMHC_INTR_FNO (1 << 11)       /* frame number overflow */
+#define ADMHC_INTR_TDC (1 << 20)       /* transfer descriptor completed */
+#define ADMHC_INTR_SWI (1 << 29)       /* software interrupt */
+#define ADMHC_INTR_FATI        (1 << 30)       /* fatal error */
+#define ADMHC_INTR_INTA        (1 << 31)       /* interrupt active */
+
+#define ADMHC_INTR_MIE (1 << 31)       /* master interrupt enable */
+
+/*
+ * SOF Frame Interval register bits
+ */
+#define ADMHC_SFI_FI_MASK      ((1 << 14)-1)   /* Frame Interval value */
+#define ADMHC_SFI_FSLDP_SHIFT  16
+#define ADMHC_SFI_FSLDP_MASK   ((1 << 15)-1)
+#define ADMHC_SFI_FIT          (1 << 31)       /* Frame Interval Toggle */
+
+/*
+ * SOF Frame Number register bits
+ */
+#define ADMHC_SFN_FN_MASK      ((1 << 16)-1)   /* Frame Number Mask */
+#define ADMHC_SFN_FR_SHIFT     16              /* Frame Remaining Shift */
+#define ADMHC_SFN_FR_MASK      ((1 << 14)-1)   /* Frame Remaining Mask */
+#define ADMHC_SFN_FRT          (1 << 31)       /* Frame Remaining Toggle */
+
+/*
+ * Root Hub Descriptor register bits
+ */
+#define ADMHC_RH_NUMP  0xff            /* number of ports */
+#define        ADMHC_RH_PSM    (1 << 8)        /* power switching mode */
+#define        ADMHC_RH_NPS    (1 << 9)        /* no power switching */
+#define        ADMHC_RH_OCPM   (1 << 10)       /* over current protection mode */
+#define        ADMHC_RH_NOCP   (1 << 11)       /* no over current protection */
+#define        ADMHC_RH_PPCM   (0xff << 16)    /* port power control */
+
+#define ADMHC_RH_LPS   (1 << 24)       /* local power switch */
+#define ADMHC_RH_OCI   (1 << 25)       /* over current indicator */
+
+/* status change bits */
+#define ADMHC_RH_LPSC  (1 << 26)       /* local power switch change */
+#define ADMHC_RH_OCIC  (1 << 27)       /* over current indicator change */
+
+#define ADMHC_RH_DRWE  (1 << 28)       /* device remote wakeup enable */
+#define ADMHC_RH_CRWE  (1 << 29)       /* clear remote wakeup enable */
+
+#define ADMHC_RH_CGP   (1 << 24)       /* clear global power */
+#define ADMHC_RH_SGP   (1 << 26)       /* set global power */
+
+/*
+ * Port Status register bits
+ */
+#define ADMHC_PS_CCS   (1 << 0)        /* current connect status */
+#define ADMHC_PS_PES   (1 << 1)        /* port enable status */
+#define ADMHC_PS_PSS   (1 << 2)        /* port suspend status */
+#define ADMHC_PS_POCI  (1 << 3)        /* port over current indicator */
+#define ADMHC_PS_PRS   (1 << 4)        /* port reset status */
+#define ADMHC_PS_PPS   (1 << 8)        /* port power status */
+#define ADMHC_PS_LSDA  (1 << 9)        /* low speed device attached */
+
+/* status change bits */
+#define ADMHC_PS_CSC   (1 << 16)       /* connect status change */
+#define ADMHC_PS_PESC  (1 << 17)       /* port enable status change */
+#define ADMHC_PS_PSSC  (1 << 18)       /* port suspend status change */
+#define ADMHC_PS_OCIC  (1 << 19)       /* over current indicator change */
+#define ADMHC_PS_PRSC  (1 << 20)       /* port reset status change */
+
+/* port feature bits */
+#define ADMHC_PS_CPE   (1 << 0)        /* clear port enable */
+#define ADMHC_PS_SPE   (1 << 1)        /* set port enable */
+#define ADMHC_PS_SPS   (1 << 2)        /* set port suspend */
+#define ADMHC_PS_CPS   (1 << 3)        /* clear suspend status */
+#define ADMHC_PS_SPR   (1 << 4)        /* set port reset */
+#define ADMHC_PS_SPP   (1 << 8)        /* set port power */
+#define ADMHC_PS_CPP   (1 << 9)        /* clear port power */
+
+/*
+ * the POTPGT value is not defined in the ADMHC, so define a dummy value
+ */
+#define ADMHC_POTPGT   2               /* in ms */
+
+/* hcd-private per-urb state */
+struct urb_priv {
+       struct ed               *ed;
+       struct list_head        pending;        /* URBs on the same ED */
+
+       u32                     td_cnt;         /* # tds in this request */
+       u32                     td_idx;         /* index of the current td */
+       struct td               *td[0];         /* all TDs in this request */
+};
+
+#define TD_HASH_SIZE    64    /* power'o'two */
+/* sizeof (struct td) ~= 64 == 2^6 ... */
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
+
+/*
+ * This is the full ADMHCD controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+struct admhcd {
+       spinlock_t              lock;
+
+       /*
+        * I/O memory used to communicate with the HC (dma-consistent)
+        */
+       struct admhcd_regs __iomem *regs;
+
+       /*
+        * hcd adds to schedule for a live hc any time, but removals finish
+        * only at the start of the next frame.
+        */
+
+       struct ed               *ed_head;
+       struct ed               *ed_tails[4];
+
+       struct ed               *ed_rm_list;    /* to be removed */
+
+       struct ed               *periodic[NUM_INTS];    /* shadow int_table */
+
+#if 0  /* TODO: remove? */
+       /*
+        * OTG controllers and transceivers need software interaction;
+        * other external transceivers should be software-transparent
+        */
+       struct otg_transceiver  *transceiver;
+       void (*start_hnp)(struct admhcd *ahcd);
+#endif
+
+       /*
+        * memory management for queue data structures
+        */
+       struct dma_pool         *td_cache;
+       struct dma_pool         *ed_cache;
+       struct td               *td_hash[TD_HASH_SIZE];
+       struct list_head        pending;
+
+       /*
+        * driver state
+        */
+       int                     num_ports;
+       int                     load[NUM_INTS];
+       u32                     host_control;   /* copy of the host_control reg */
+       unsigned long           next_statechange;       /* suspend/resume */
+       u32                     fminterval;             /* saved register */
+       unsigned                autostop:1;     /* rh auto stopping/stopped */
+
+       unsigned long           flags;          /* for HC bugs */
+#define        OHCI_QUIRK_AMD756       0x01                    /* erratum #4 */
+#define        OHCI_QUIRK_SUPERIO      0x02                    /* natsemi */
+#define        OHCI_QUIRK_INITRESET    0x04                    /* SiS, OPTi, ... */
+#define        OHCI_QUIRK_BE_DESC      0x08                    /* BE descriptors */
+#define        OHCI_QUIRK_BE_MMIO      0x10                    /* BE registers */
+#define        OHCI_QUIRK_ZFMICRO      0x20                    /* Compaq ZFMicro chipset*/
+       /* there are also chip quirks/bugs in init logic */
+
+#ifdef DEBUG
+       struct dentry           *debug_dir;
+       struct dentry           *debug_async;
+       struct dentry           *debug_periodic;
+       struct dentry           *debug_registers;
+#endif
+};
+
+/* convert between an hcd pointer and the corresponding ahcd_hcd */
+static inline struct admhcd *hcd_to_admhcd(struct usb_hcd *hcd)
+{
+       return (struct admhcd *)(hcd->hcd_priv);
+}
+static inline struct usb_hcd *admhcd_to_hcd(const struct admhcd *ahcd)
+{
+       return container_of((void *)ahcd, struct usb_hcd, hcd_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif /* DEBUG */
+
+#ifdef DEBUG
+#      define admhc_dbg(ahcd, fmt, args...) \
+               printk(KERN_DEBUG "adm5120-hcd: " fmt, ## args)
+#else
+#      define admhc_dbg(ahcd, fmt, args...) do { } while (0)
+#endif
+
+#define admhc_err(ahcd, fmt, args...) \
+       printk(KERN_ERR "adm5120-hcd: " fmt, ## args)
+#define admhc_info(ahcd, fmt, args...) \
+       printk(KERN_INFO "adm5120-hcd: " fmt, ## args)
+#define admhc_warn(ahcd, fmt, args...) \
+       printk(KERN_WARNING "adm5120-hcd: " fmt, ## args)
+
+#ifdef ADMHC_VERBOSE_DEBUG
+#      define admhc_vdbg admhc_dbg
+#else
+#      define admhc_vdbg(ahcd, fmt, args...) do { } while (0)
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * While most USB host controllers implement their registers and
+ * in-memory communication descriptors in little-endian format,
+ * a minority (notably the IBM STB04XXX and the Motorola MPC5200
+ * processors) implement them in big endian format.
+ *
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type              Kconfig options needed
+ * ---------------              ----------------------
+ * little endian                CONFIG_USB_ADMHC_LITTLE_ENDIAN
+ *
+ * fully big endian             CONFIG_USB_ADMHC_BIG_ENDIAN_DESC _and_
+ *                              CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO
+ *
+ * mixed endian                 CONFIG_USB_ADMHC_LITTLE_ENDIAN _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_ADMHC_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
+ */
+
+#ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_ADMHC_LITTLE_ENDIAN
+#define big_endian_desc(ahcd)  (ahcd->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ahcd)  1               /* only big endian */
+#endif
+#else
+#define big_endian_desc(ahcd)  0               /* only little endian */
+#endif
+
+#ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO
+#ifdef CONFIG_USB_ADMHC_LITTLE_ENDIAN
+#define big_endian_mmio(ahcd)  (ahcd->flags & OHCI_QUIRK_BE_MMIO)
+#else
+#define big_endian_mmio(ahcd)  1               /* only big endian */
+#endif
+#else
+#define big_endian_mmio(ahcd)  0               /* only little endian */
+#endif
+
+/*
+ * Big-endian read/write functions are arch-specific.
+ * Other arches can be added if/when they're needed.
+ *
+ */
+static inline unsigned int admhc_readl(const struct admhcd *ahcd,
+       __hc32 __iomem *regs)
+{
+#ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO
+       return big_endian_mmio(ahcd) ?
+               readl_be(regs) :
+               readl(regs);
+#else
+       return readl(regs);
+#endif
+}
+
+static inline void admhc_writel(const struct admhcd *ahcd,
+       const unsigned int val, __hc32 __iomem *regs)
+{
+#ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO
+       big_endian_mmio(ahcd) ?
+               writel_be(val, regs) :
+               writel(val, regs);
+#else
+               writel(val, regs);
+#endif
+}
+
+static inline void admhc_writel_flush(const struct admhcd *ahcd)
+{
+#if 0
+       /* TODO: remove? */
+       (void) admhc_readl(ahcd, &ahcd->regs->gencontrol);
+#endif
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* cpu to ahcd */
+static inline __hc16 cpu_to_hc16(const struct admhcd *ahcd, const u16 x)
+{
+       return big_endian_desc(ahcd) ?
+               (__force __hc16)cpu_to_be16(x) :
+               (__force __hc16)cpu_to_le16(x);
+}
+
+static inline __hc16 cpu_to_hc16p(const struct admhcd *ahcd, const u16 *x)
+{
+       return big_endian_desc(ahcd) ?
+               cpu_to_be16p(x) :
+               cpu_to_le16p(x);
+}
+
+static inline __hc32 cpu_to_hc32(const struct admhcd *ahcd, const u32 x)
+{
+       return big_endian_desc(ahcd) ?
+               (__force __hc32)cpu_to_be32(x) :
+               (__force __hc32)cpu_to_le32(x);
+}
+
+static inline __hc32 cpu_to_hc32p(const struct admhcd *ahcd, const u32 *x)
+{
+       return big_endian_desc(ahcd) ?
+               cpu_to_be32p(x) :
+               cpu_to_le32p(x);
+}
+
+/* ahcd to cpu */
+static inline u16 hc16_to_cpu(const struct admhcd *ahcd, const __hc16 x)
+{
+       return big_endian_desc(ahcd) ?
+               be16_to_cpu((__force __be16)x) :
+               le16_to_cpu((__force __le16)x);
+}
+
+static inline u16 hc16_to_cpup(const struct admhcd *ahcd, const __hc16 *x)
+{
+       return big_endian_desc(ahcd) ?
+               be16_to_cpup((__force __be16 *)x) :
+               le16_to_cpup((__force __le16 *)x);
+}
+
+static inline u32 hc32_to_cpu(const struct admhcd *ahcd, const __hc32 x)
+{
+       return big_endian_desc(ahcd) ?
+               be32_to_cpu((__force __be32)x) :
+               le32_to_cpu((__force __le32)x);
+}
+
+static inline u32 hc32_to_cpup(const struct admhcd *ahcd, const __hc32 *x)
+{
+       return big_endian_desc(ahcd) ?
+               be32_to_cpup((__force __be32 *)x) :
+               le32_to_cpup((__force __le32 *)x);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline u16 admhc_frame_no(const struct admhcd *ahcd)
+{
+       u32     t;
+
+       t = admhc_readl(ahcd, &ahcd->regs->fmnumber) & ADMHC_SFN_FN_MASK;
+       return (u16)t;
+}
+
+static inline u16 admhc_frame_remain(const struct admhcd *ahcd)
+{
+       u32     t;
+
+       t = admhc_readl(ahcd, &ahcd->regs->fmnumber) >> ADMHC_SFN_FR_SHIFT;
+       t &= ADMHC_SFN_FR_MASK;
+       return (u16)t;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void admhc_disable(struct admhcd *ahcd)
+{
+       admhcd_to_hcd(ahcd)->state = HC_STATE_HALT;
+}
+
+#define        FI              0x2edf          /* 12000 bits per frame (-1) */
+#define        FSLDP(fi)       (0x7fff & ((6 * ((fi) - 1200)) / 7))
+#define        FIT             ADMHC_SFI_FIT
+#define LSTHRESH       0x628           /* lowspeed bit threshold */
+
+static inline void periodic_reinit(struct admhcd *ahcd)
+{
+#if 0
+       u32     fi = ahcd->fminterval & ADMHC_SFI_FI_MASK;
+       u32     fit = admhc_readl(ahcd, &ahcd->regs->fminterval) & FIT;
+
+       /* TODO: adjust FSLargestDataPacket value too? */
+       admhc_writel(ahcd, (fit ^ FIT) | ahcd->fminterval,
+                                       &ahcd->regs->fminterval);
+#else
+       u32     fit = admhc_readl(ahcd, &ahcd->regs->fminterval) & FIT;
+
+       /* TODO: adjust FSLargestDataPacket value too? */
+       admhc_writel(ahcd, (fit ^ FIT) | ahcd->fminterval,
+                                       &ahcd->regs->fminterval);
+#endif
+}
+
+static inline u32 admhc_read_rhdesc(struct admhcd *ahcd)
+{
+       return admhc_readl(ahcd, &ahcd->regs->rhdesc);
+}
+
+static inline u32 admhc_read_portstatus(struct admhcd *ahcd, int port)
+{
+       return admhc_readl(ahcd, &ahcd->regs->portstatus[port]);
+}
+
+static inline void admhc_write_portstatus(struct admhcd *ahcd, int port,
+               u32 value)
+{
+       admhc_writel(ahcd, value, &ahcd->regs->portstatus[port]);
+}
+
+static inline void roothub_write_status(struct admhcd *ahcd, u32 value)
+{
+       /* FIXME: read-only bits must be masked out */
+       admhc_writel(ahcd, value, &ahcd->regs->rhdesc);
+}
+
+static inline void admhc_intr_disable(struct admhcd *ahcd, u32 ints)
+{
+       u32     t;
+
+       t = admhc_readl(ahcd, &ahcd->regs->int_enable);
+       t &= ~(ints);
+       admhc_writel(ahcd, t, &ahcd->regs->int_enable);
+       /* TODO: flush writes ?*/
+}
+
+static inline void admhc_intr_enable(struct admhcd *ahcd, u32 ints)
+{
+       u32     t;
+
+       t = admhc_readl(ahcd, &ahcd->regs->int_enable);
+       t |= ints;
+       admhc_writel(ahcd, t, &ahcd->regs->int_enable);
+       /* TODO: flush writes ?*/
+}
+
+static inline void admhc_intr_ack(struct admhcd *ahcd, u32 ints)
+{
+       admhc_writel(ahcd, ints, &ahcd->regs->int_status);
+}
+
+static inline void admhc_dma_enable(struct admhcd *ahcd)
+{
+       u32 t;
+
+       t = admhc_readl(ahcd, &ahcd->regs->host_control);
+       if (t & ADMHC_HC_DMAE)
+               return;
+
+       t |= ADMHC_HC_DMAE;
+       admhc_writel(ahcd, t, &ahcd->regs->host_control);
+       admhc_vdbg(ahcd, "DMA enabled\n");
+}
+
+static inline void admhc_dma_disable(struct admhcd *ahcd)
+{
+       u32 t;
+
+       t = admhc_readl(ahcd, &ahcd->regs->host_control);
+       if (!(t & ADMHC_HC_DMAE))
+               return;
+
+       t &= ~ADMHC_HC_DMAE;
+       admhc_writel(ahcd, t, &ahcd->regs->host_control);
+       admhc_vdbg(ahcd, "DMA disabled\n");
+}