/*
- * OHCI HCD (Host Controller Driver) for USB.
+ * ADM5120 HCD (Host Controller Driver) for USB
*
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2007,2008 Gabor Juhos <juhosg at 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.
*
- * This file is licenced under the GPL.
*/
/*
struct list_head urb_list; /* list of our URBs */
- struct list_head ed_list; /* list of all EDs*/
- struct list_head rm_list; /* for remove list */
-
/* 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 ed *ed_soft_list; /* on software int list */
struct list_head td_list; /* "shadow list" of our TDs */
/* create --> IDLE --> OPER --> ... --> IDLE --> destroy
#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_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_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_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 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 */
struct ed *ed_tails[4];
struct ed *ed_rm_list; /* to be removed */
- struct ed *ed_halt_list; /* halted due to an error */
- struct ed *ed_soft_list; /* for software interrupt processing */
struct ed *periodic[NUM_INTS]; /* shadow int_table */
#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 */
#define STUB_DEBUG_FILES
#endif /* DEBUG */
-#define admhc_dbg(ahcd, fmt, args...) \
- dev_dbg(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
+#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...) \
- dev_err(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
-#define ahcd_info(ahcd, fmt, args...) \
- dev_info(admhcd_to_hcd(ahcd)->self.controller , 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...) \
- dev_warn(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
+ printk(KERN_WARNING "adm5120-hcd: " fmt , ## args )
#ifdef ADMHC_VERBOSE_DEBUG
# define admhc_vdbg admhc_dbg
static inline void admhc_writel_flush(const struct admhcd *ahcd)
{
-#if 0 /* TODO: needed? */
- (void) admhc_readl(ahcd, &ahcd->regs->control);
+#if 0
+ /* TODO: remove? */
+ (void) admhc_readl(ahcd, &ahcd->regs->gencontrol);
#endif
}
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) - 210)) / 7))
-#define FIT ADMHC_SFI_FIT
-#define LSTHRESH 0x628 /* lowspeed bit threshold */
+#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);
+ &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_get_rhdesc(struct admhcd *ahcd)
+static inline u32 admhc_read_rhdesc(struct admhcd *ahcd)
{
return admhc_readl(ahcd, &ahcd->regs->rhdesc);
}
-static inline u32 admhc_get_portstatus(struct admhcd *ahcd, int port)
+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 */
static inline void admhc_dma_enable(struct admhcd *ahcd)
{
- ahcd->host_control = admhc_readl(ahcd, &ahcd->regs->host_control);
- if (ahcd->host_control & ADMHC_HC_DMAE)
+ u32 t;
+
+ t = admhc_readl(ahcd, &ahcd->regs->host_control);
+ if (t & ADMHC_HC_DMAE)
return;
- ahcd->host_control |= ADMHC_HC_DMAE;
- admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control);
+ 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)
{
- ahcd->host_control = admhc_readl(ahcd, &ahcd->regs->host_control);
- ahcd->host_control &= ~ADMHC_HC_DMAE;
- admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control);
+ 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");
}