[PATCH v10 03/10] USB/ppc4xx: Add Synopsys DWC OTG Core Interface Layer (CIL)
Keshava Munegowda
keshava_mgowda at ti.com
Tue Mar 29 21:51:57 EST 2011
> +/**
> + * This function initializes the DWC_otg controller registers and
prepares the
> + * core for device mode or host mode operation.
> + */
> +void dwc_otg_core_init(struct core_if *core_if)
> +{
> + u32 i;
> + ulong global_reg = core_if->core_global_regs;
> + struct device_if *dev_if = core_if->dev_if;
> + u32 ahbcfg = 0;
> + u32 i2cctl = 0;
> + u32 gusbcfg;
Tabify the declarations ;
> +
> + /* Common Initialization */
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> +
> + /* Program the ULPI External VBUS bit if needed */
> + gusbcfg |= DWC_USBCFG_ULPI_EXT_VBUS_DRV;
> +
> + /* Set external TS Dline pulsing */
> + if (core_if->core_params->ts_dline == 1)
> + gusbcfg |= DWC_USBCFG_TERM_SEL_DL_PULSE;
> + else
> + gusbcfg = gusbcfg & (~((u32)
DWC_USBCFG_TERM_SEL_DL_PULSE));
> +
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> +
> + /* Reset the Controller */
> + dwc_otg_core_reset(core_if);
> +
> + /* Initialize parameters from Hardware configuration registers. */
> + dev_if->num_in_eps = calc_num_in_eps(core_if);
> + dev_if->num_out_eps = calc_num_out_eps(core_if);
> +
> + for (i = 0; i <
DWC_HWCFG4_NUM_DEV_PERIO_IN_EP_RD(core_if->hwcfg4);
> + i++) {
> + dev_if->perio_tx_fifo_size[i] =
> + dwc_read32(global_reg + DWC_DPTX_FSIZ_DIPTXF(i)) >>
16;
> + }
> + for (i = 0; i < DWC_HWCFG4_NUM_IN_EPS_RD(core_if->hwcfg4); i++) {
> + dev_if->tx_fifo_size[i] =
> + dwc_read32(global_reg + DWC_DPTX_FSIZ_DIPTXF(i)) >>
16;
> + }
> +
> + core_if->total_fifo_size =
DWC_HWCFG3_DFIFO_DEPTH_RD(core_if->hwcfg3);
> + core_if->rx_fifo_size = dwc_read32(global_reg + DWC_GRXFSIZ);
> + core_if->nperio_tx_fifo_size =
> + dwc_read32(global_reg + DWC_GRXFSIZ) >> 16;
> + /*
> + * This programming sequence needs to happen in FS mode before any
> + * other programming occurs
> + */
> + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL &&
> + core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) {
> + /*
> + * core_init() is now called on every switch so only call
the
> + * following for the first time through.
> + */
> + if (!core_if->phy_init_done) {
> + core_if->phy_init_done = 1;
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> + gusbcfg |= DWC_USBCFG_ULPI_UTMI_SEL;
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> +
> + /* Reset after a PHY select */
> + dwc_otg_core_reset(core_if);
> + }
> +
> + /*
> + * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
> + * Also do this on HNP Dev/Host mode switches (done in
dev_init
> + * and host_init).
> + */
> + if (dwc_otg_is_host_mode(core_if))
> + init_fslspclksel(core_if);
> + else
> + init_devspd(core_if);
> +
> + if (core_if->core_params->i2c_enable) {
> + /* Program GUSBCFG.OtgUtmifsSel to I2C */
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> + gusbcfg |= DWC_USBCFG_OTGUTMIFSSEL;
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> +
> + /* Program GI2CCTL.I2CEn */
> + i2cctl = dwc_read32(global_reg + DWC_GI2CCTL);
> + i2cctl |= DWC_I2CCTL_I2CDEVADDR(1);
> + i2cctl &= ~DWC_I2CCTL_I2CEN;
> + dwc_write32(global_reg + DWC_GI2CCTL, i2cctl);
> + i2cctl |= DWC_I2CCTL_I2CEN;
> + dwc_write32(global_reg + DWC_GI2CCTL, i2cctl);
> + }
> + } else if (!core_if->phy_init_done) {
> + /*
> + * High speed PHY. These parameters are preserved during
soft
> + * reset so only program them the first time. Do a soft
reset
> + * immediately after setting phyif.
> + */
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> + core_if->phy_init_done = 1;
> + if (core_if->core_params->phy_type)
> + gusbcfg |= DWC_USBCFG_ULPI_UTMI_SEL;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_ULPI_UTMI_SEL);
> +
> + if (gusbcfg & DWC_USBCFG_ULPI_UTMI_SEL) {
> + /* ULPI interface */
> + gusbcfg |= DWC_USBCFG_PHYIF;
> + if (core_if->core_params->phy_ulpi_ddr)
> + gusbcfg |= DWC_USBCFG_DDRSEL;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_DDRSEL);
> + } else {
> + /* UTMI+ interface */
> + if (core_if->core_params->phy_utmi_width == 16)
> + gusbcfg |= DWC_USBCFG_PHYIF;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_PHYIF);
> + }
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> +
> + /* Reset after setting the PHY parameters */
> + dwc_otg_core_reset(core_if);
> + }
> +
> + if (DWC_HWCFG2_HS_PHY_TYPE_RD(core_if->hwcfg2) == 2 &&
> + DWC_HWCFG2_FS_PHY_TYPE_RD(core_if->hwcfg2) == 1 &&
> + core_if->core_params->ulpi_fs_ls) {
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> + gusbcfg |= DWC_USBCFG_ULPI_FSLS;
> + gusbcfg |= DWC_USBCFG_ULPI_CLK_SUS_M;
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> + } else {
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> + gusbcfg &= ~((u32) DWC_USBCFG_ULPI_FSLS);
> + gusbcfg &= ~((u32) DWC_USBCFG_ULPI_CLK_SUS_M);
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> + }
> +
> + /* Program the GAHBCFG Register. */
> + switch (DWC_HWCFG2_ARCH_RD(core_if->hwcfg2)) {
> + case DWC_SLAVE_ONLY_ARCH:
> + ahbcfg &= ~DWC_AHBCFG_NPFIFO_EMPTY; /* HALF empty */
> + ahbcfg &= ~DWC_AHBCFG_FIFO_EMPTY; /* HALF empty */
> + core_if->dma_enable = 0;
> + break;
> + case DWC_EXT_DMA_ARCH:
> + ahbcfg = (ahbcfg & ~DWC_AHBCFG_BURST_LEN(0xf)) |
> +
DWC_AHBCFG_BURST_LEN(core_if->core_params->dma_burst_size);
> + core_if->dma_enable = (core_if->core_params->dma_enable !=
0);
> + break;
> + case DWC_INT_DMA_ARCH:
> + ahbcfg = (ahbcfg & ~DWC_AHBCFG_BURST_LEN(0xf)) |
> + DWC_AHBCFG_BURST_LEN(DWC_GAHBCFG_INT_DMA_BURST_INCR);
> + core_if->dma_enable = (core_if->core_params->dma_enable !=
0);
> + break;
> + }
> +
> + if (core_if->dma_enable)
> + ahbcfg |= DWC_AHBCFG_DMA_ENA;
> + else
> + ahbcfg &= ~DWC_AHBCFG_DMA_ENA;
> + dwc_write32(global_reg + DWC_GAHBCFG, ahbcfg);
> + core_if->en_multiple_tx_fifo =
> + DWC_HWCFG4_DED_FIFO_ENA_RD(core_if->hwcfg4);
> +
> + /* Program the GUSBCFG register. */
> + gusbcfg = dwc_read32(global_reg + DWC_GUSBCFG);
> + switch (DWC_HWCFG2_OP_MODE_RD(core_if->hwcfg2)) {
> + case DWC_MODE_HNP_SRP_CAPABLE:
> + if (core_if->core_params->otg_cap ==
> + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
> + gusbcfg |= DWC_USBCFG_HNP_CAP;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + if (core_if->core_params->otg_cap !=
> + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)
> + gusbcfg |= DWC_USBCFG_SRP_CAP;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + case DWC_MODE_SRP_ONLY_CAPABLE:
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + if (core_if->core_params->otg_cap !=
> + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)
> + gusbcfg |= DWC_USBCFG_SRP_CAP;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + case DWC_MODE_NO_HNP_SRP_CAPABLE:
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + case DWC_MODE_SRP_CAPABLE_DEVICE:
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + if (core_if->core_params->otg_cap !=
> + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)
> + gusbcfg |= DWC_USBCFG_SRP_CAP;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + case DWC_MODE_SRP_CAPABLE_HOST:
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + if (core_if->core_params->otg_cap !=
> + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)
> + gusbcfg |= DWC_USBCFG_SRP_CAP;
> + else
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + case DWC_MODE_NO_SRP_CAPABLE_HOST:
> + gusbcfg &= ~((u32) DWC_USBCFG_HNP_CAP);
> + gusbcfg &= ~((u32) DWC_USBCFG_SRP_CAP);
> + break;
> + }
> + dwc_write32(global_reg + DWC_GUSBCFG, gusbcfg);
> +
> + /* Enable common interrupts */
> + dwc_otg_enable_common_interrupts(core_if);
> +
> + /*
> + * Do device or host intialization based on mode during PCD
> + * and HCD initialization
> + */
> + if (dwc_otg_is_host_mode(core_if)) {
> + core_if->xceiv->state = OTG_STATE_A_HOST;
> + } else {
> + core_if->xceiv->state = OTG_STATE_B_PERIPHERAL;
> + if (dwc_has_feature(core_if, DWC_DEVICE_ONLY))
> + dwc_otg_core_dev_init(core_if);
> + }
> +}
> +
> +/**
> + * This function enables the Device mode interrupts.
> + *
> + * Note that the bits in the Device IN endpoint mask register are laid
out
> + * exactly the same as the Device IN endpoint interrupt register.
> + */
> +static void dwc_otg_enable_device_interrupts(struct core_if *core_if)
> +{
> + u32 intr_mask = 0;
> + u32 msk = 0;
> + ulong global_regs = core_if->core_global_regs;
> +
> + /* Disable all interrupts. */
> + dwc_write32(global_regs + DWC_GINTMSK, 0);
> +
> + /* Clear any pending interrupts */
> + dwc_write32(global_regs + DWC_GINTSTS, 0xFFFFFFFF);
> +
> + /* Enable the common interrupts */
> + dwc_otg_enable_common_interrupts(core_if);
> +
> + /* Enable interrupts */
> + intr_mask |= DWC_INTMSK_USB_RST;
> + intr_mask |= DWC_INTMSK_ENUM_DONE;
> + intr_mask |= DWC_INTMSK_IN_ENDP;
> + intr_mask |= DWC_INTMSK_OUT_ENDP;
> + intr_mask |= DWC_INTMSK_EARLY_SUSP;
> + if (!core_if->en_multiple_tx_fifo)
> + intr_mask |= DWC_INTMSK_ENDP_MIS_MTCH;
> +
> + /* Periodic EP */
> + intr_mask |= DWC_INTMSK_ISYNC_OUTPKT_DRP;
> + intr_mask |= DWC_INTMSK_END_OF_PFRM;
> + intr_mask |= DWC_INTMSK_INCMP_IN_ATX;
> + intr_mask |= DWC_INTMSK_INCMP_OUT_PTX;
> +
> + dwc_modify32(global_regs + DWC_GINTMSK, intr_mask, intr_mask);
> +
> + msk = DWC_DIEPMSK_TXFIFO_UNDERN_RW(msk, 1);
> + dwc_modify32(core_if->dev_if->dev_global_regs + DWC_DIEPMSK,
> + msk, msk);
> +}
> +
> +/**
> + * Configures the device data fifo sizes when dynamic sizing is
enabled.
> + */
> +static void config_dev_dynamic_fifos(struct core_if *core_if)
> +{
> + u32 i;
> + ulong regs = core_if->core_global_regs;
> + struct core_params *params = core_if->core_params;
> + u32 txsize = 0;
> + u32 nptxsize = 0;
> + u32 ptxsize = 0;
Tabify the declarations ;
> +
> + /* Rx FIFO */
> + dwc_write32(regs + DWC_GRXFSIZ, params->dev_rx_fifo_size);
> +
> + /* Set Periodic and Non-periodic Tx FIFO Mask bits to all 0 */
> + core_if->p_tx_msk = 0;
> + core_if->tx_msk = 0;
> +
> + if (core_if->en_multiple_tx_fifo == 0) {
> + /* Non-periodic Tx FIFO */
> + nptxsize = DWC_RX_FIFO_DEPTH_WR(nptxsize,
> + params->
> + dev_nperio_tx_fifo_size);
> + nptxsize =
> + DWC_RX_FIFO_START_ADDR_WR(nptxsize,
> + params->dev_rx_fifo_size);
> + dwc_write32(regs + DWC_GNPTXFSIZ, nptxsize);
> +
> + /*
> + * Periodic Tx FIFOs These FIFOs are numbered from 1 to
> + * 15. Indexes of the FIFO size module parameters in the
> + * dev_perio_tx_fifo_size array and the FIFO size
> + * registers in the dptxfsiz array run from 0 to 14.
> + */
> + ptxsize = DWC_RX_FIFO_START_ADDR_WR(ptxsize,
> +
(DWC_RX_FIFO_START_ADDR_RD
> + (nptxsize) +
> + DWC_RX_FIFO_DEPTH_RD
> + (nptxsize)));
> + for (i = 0;
> + i <
DWC_HWCFG4_NUM_DEV_PERIO_IN_EP_RD(core_if->hwcfg4);
> + i++) {
> + ptxsize =
> + DWC_RX_FIFO_DEPTH_WR(ptxsize,
> + params->
> +
dev_perio_tx_fifo_size[i]);
> + dwc_write32(regs + DWC_DPTX_FSIZ_DIPTXF(i),
ptxsize);
> + ptxsize = DWC_RX_FIFO_START_ADDR_WR(ptxsize,
> +
(DWC_RX_FIFO_START_ADDR_RD
> + (ptxsize) +
> + DWC_RX_FIFO_DEPTH_RD
> + (ptxsize)));
> + }
> + } else {
> + /*
> + * Non-periodic Tx FIFOs These FIFOs are numbered from
> + * 1 to 15. Indexes of the FIFO size module parameters
> + * in the dev_tx_fifo_size array and the FIFO size
> + * registers in the dptxfsiz_dieptxf array run from 0 to
> + * 14.
> + */
> + nptxsize = DWC_RX_FIFO_DEPTH_WR(nptxsize,
> + params->
> + dev_nperio_tx_fifo_size);
> + nptxsize =
> + DWC_RX_FIFO_START_ADDR_WR(nptxsize,
> + params->dev_rx_fifo_size);
> + dwc_write32(regs + DWC_GNPTXFSIZ, nptxsize);
> +
> + txsize = DWC_RX_FIFO_START_ADDR_WR(txsize,
> +
(DWC_RX_FIFO_START_ADDR_RD
> + (nptxsize) +
> + DWC_RX_FIFO_DEPTH_RD
> + (nptxsize)));
> + for (i = 1;
> + i <
DWC_HWCFG4_NUM_DEV_PERIO_IN_EP_RD(core_if->hwcfg4);
> + i++) {
> + txsize =
> + DWC_RX_FIFO_DEPTH_WR(txsize,
> +
params->dev_tx_fifo_size[i]);
> + dwc_write32(regs + DWC_DPTX_FSIZ_DIPTXF(i - 1),
txsize);
> + txsize = DWC_RX_FIFO_START_ADDR_WR(txsize,
> +
(DWC_RX_FIFO_START_ADDR_RD
> + (txsize) +
> + DWC_RX_FIFO_DEPTH_RD
> + (txsize)));
> + }
> + }
> +}
> +
> +/**
> + * This function initializes the DWC_otg controller registers for
> + * device mode.
> + */
> +void dwc_otg_core_dev_init(struct core_if *c_if)
> +{
> + u32 i;
> + struct device_if *d_if = c_if->dev_if;
> + struct core_params *params = c_if->core_params;
> + u32 dcfg = 0;
> + u32 resetctl = 0;
> + u32 dthrctl = 0;
Tabify the declarations ;
> +
> + /* Restart the Phy Clock */
> + dwc_write32(c_if->pcgcctl, 0);
> +
> + /* Device configuration register */
> + init_devspd(c_if);
> + dcfg = dwc_read32(d_if->dev_global_regs + DWC_DCFG);
> + dcfg = DWC_DCFG_P_FRM_INTRVL_WR(dcfg, DWC_DCFG_FRAME_INTERVAL_80);
> + dwc_write32(d_if->dev_global_regs + DWC_DCFG, dcfg);
> +
> + /* If needed configure data FIFO sizes */
> + if (DWC_HWCFG2_DYN_FIFO_RD(c_if->hwcfg2) &&
params->enable_dynamic_fifo)
> + config_dev_dynamic_fifos(c_if);
> +
> + /* Flush the FIFOs */
> + dwc_otg_flush_tx_fifo(c_if, DWC_GRSTCTL_TXFNUM_ALL);
> + dwc_otg_flush_rx_fifo(c_if);
> +
> + /* Flush the Learning Queue. */
> + resetctl |= DWC_RSTCTL_TKN_QUE_FLUSH;
> + dwc_write32(c_if->core_global_regs + DWC_GRSTCTL, resetctl);
> +
> + /* Clear all pending Device Interrupts */
> + dwc_write32(d_if->dev_global_regs + DWC_DIEPMSK, 0);
> + dwc_write32(d_if->dev_global_regs + DWC_DOEPMSK, 0);
> + dwc_write32(d_if->dev_global_regs + DWC_DAINT, 0xFFFFFFFF);
> + dwc_write32(d_if->dev_global_regs + DWC_DAINTMSK, 0);
> +
> + for (i = 0; i <= d_if->num_in_eps; i++) {
> + u32 depctl = 0;
> +
> + depctl = dwc_read32(d_if->in_ep_regs[i] + DWC_DIEPCTL);
> + if (DWC_DEPCTL_EPENA_RD(depctl)) {
> + depctl = 0;
> + depctl = DWC_DEPCTL_EPDIS_RW(depctl, 1);
> + depctl = DWC_DEPCTL_SET_NAK_RW(depctl, 1);
> + } else {
> + depctl = 0;
> + }
> +
> + dwc_write32(d_if->in_ep_regs[i] + DWC_DIEPCTL, depctl);
> + dwc_write32(d_if->in_ep_regs[i] + DWC_DIEPTSIZ, 0);
> + dwc_write32(d_if->in_ep_regs[i] + DWC_DIEPDMA, 0);
> + dwc_write32(d_if->in_ep_regs[i] + DWC_DIEPINT, 0xFF);
> + }
> +
> + for (i = 0; i <= d_if->num_out_eps; i++) {
> + u32 depctl = 0;
> + depctl = dwc_read32(d_if->out_ep_regs[i] + DWC_DOEPCTL);
> + if (DWC_DEPCTL_EPENA_RD(depctl)) {
> + depctl = 0;
> + depctl = DWC_DEPCTL_EPDIS_RW(depctl, 1);
> + depctl = DWC_DEPCTL_SET_NAK_RW(depctl, 1);
> + } else {
> + depctl = 0;
> + }
> + dwc_write32(d_if->out_ep_regs[i] + DWC_DOEPCTL, depctl);
> + dwc_write32(d_if->out_ep_regs[i] + DWC_DOEPTSIZ, 0);
> + dwc_write32(d_if->out_ep_regs[i] + DWC_DOEPDMA, 0);
> + dwc_write32(d_if->out_ep_regs[i] + DWC_DOEPINT, 0xFF);
> + }
> +
> + if (c_if->en_multiple_tx_fifo && c_if->dma_enable) {
> + d_if->non_iso_tx_thr_en = c_if->core_params->thr_ctl &
0x1;
> + d_if->iso_tx_thr_en = (c_if->core_params->thr_ctl >> 1) &
0x1;
> + d_if->rx_thr_en = (c_if->core_params->thr_ctl >> 2) & 0x1;
> + d_if->rx_thr_length = c_if->core_params->rx_thr_length;
> + d_if->tx_thr_length = c_if->core_params->tx_thr_length;
> +
> + dthrctl = 0;
> + dthrctl = DWC_DTHCTRL_NON_ISO_THR_ENA_RW
> + (dthrctl, d_if->non_iso_tx_thr_en);
> + dthrctl = DWC_DTHCTRL_ISO_THR_EN_RW
> + (dthrctl, d_if->iso_tx_thr_en);
> + dthrctl = DWC_DTHCTRL_TX_THR_LEN_RW
> + (dthrctl, d_if->tx_thr_length);
> + dthrctl = DWC_DTHCTRL_RX_THR_EN_RW(dthrctl,
d_if->rx_thr_en);
> + dthrctl = DWC_DTHCTRL_RX_THR_LEN_RW
> + (dthrctl, d_if->rx_thr_length);
> + dwc_write32(d_if->dev_global_regs +
> + DWC_DTKNQR3_DTHRCTL, dthrctl);
> +
> + }
> +
> + dwc_otg_enable_device_interrupts(c_if);
> +}
> +
> +/**
> + * This function reads a packet from the Rx FIFO into the destination
buffer.
> + * To read SETUP data use dwc_otg_read_setup_packet.
> + */
> +void dwc_otg_read_packet(struct core_if *core_if, u8 * dest, u16
_bytes)
> +{
> + u32 i;
> + int word_count = (_bytes + 3) / 4;
> + u32 fifo = core_if->data_fifo[0];
> + u32 *data_buff = (u32 *) dest;
> +
> + /*
> + * This requires reading data from the FIFO into a u32 temp
buffer,
> + * then moving it into the data buffer.
> + */
> + for (i = 0; i < word_count; i++, data_buff++)
> + *data_buff = dwc_read_fifo32(fifo);
> +}
> +
> +/**
> + * Flush a Tx FIFO.
> + */
> +void dwc_otg_flush_tx_fifo(struct core_if *core_if, const int num)
> +{
> + ulong global_regs = core_if->core_global_regs;
> + u32 greset = 0;
> + int count = 0;
> +
> + greset |= DWC_RSTCTL_TX_FIFO_FLUSH;
> + greset = DWC_RSTCTL_TX_FIFO_NUM(greset, num);
> + dwc_write32(global_regs + DWC_GRSTCTL, greset);
> +
> + do {
> + greset = dwc_read32(global_regs + DWC_GRSTCTL);
> + if (++count > 10000) {
> + pr_warning("%s() HANG! GRSTCTL=%0x "
> + "GNPTXSTS=0x%08x\n", __func__, greset,
> + dwc_read32(global_regs +
DWC_GNPTXSTS));
> + break;
> + }
> + udelay(1);
> + } while (greset & DWC_RSTCTL_TX_FIFO_FLUSH);
> +
> + /* Wait for 3 PHY Clocks */
> + udelay(1);
> +}
> +
> +/**
> + * Flush Rx FIFO.
> + */
> +void dwc_otg_flush_rx_fifo(struct core_if *core_if)
> +{
> + ulong global_regs = core_if->core_global_regs;
> + u32 greset = 0;
> + int count = 0;
> +
> + greset |= DWC_RSTCTL_RX_FIFO_FLUSH;
> + dwc_write32(global_regs + DWC_GRSTCTL, greset);
> +
> + do {
> + greset = dwc_read32(global_regs + DWC_GRSTCTL);
> + if (++count > 10000) {
> + pr_warning("%s() HANG! GRSTCTL=%0x\n",
> + __func__, greset);
> + break;
> + }
> + udelay(1);
> + } while (greset & DWC_RSTCTL_RX_FIFO_FLUSH);
> +
> + /* Wait for 3 PHY Clocks */
> + udelay(1);
> +}
> +
> +/**
> + * Register HCD callbacks.
> + * The callbacks are used to start and stop the HCD for interrupt
processing.
> + */
> +void __devinit dwc_otg_cil_register_hcd_callbacks(struct core_if *c_if,
> + struct cil_callbacks
*cb,
> + void *p)
> +{
> + c_if->hcd_cb = cb;
> + cb->p = p;
> +}
> +
> +/**
> + * Register PCD callbacks.
> + * The callbacks are used to start and stop the PCD for interrupt
processing.
> + */
> +void __devinit dwc_otg_cil_register_pcd_callbacks(struct core_if *c_if,
> + struct cil_callbacks
*cb,
> + void *p)
> +{
> + c_if->pcd_cb = cb;
> + cb->p = p;
> +}
> +
> +/**
> + * This function is called to initialize the DWC_otg CSR data
structures.
> + *
> + * The register addresses in the device and host structures are
initialized from
> + * the base address supplied by the caller. The calling function must
make the
> + * OS calls to get the base address of the DWC_otg controller
registers.
> + *
> + * The params argument holds the parameters that specify how the core
should be
> + * configured.
> + */
> +struct core_if __devinit *dwc_otg_cil_init(const __iomem u32 * base,
> + struct core_params *params)
> +{
> + struct core_if *core_if;
> + struct device_if *dev_if;
> + struct dwc_host_if *host_if;
> + u8 *reg_base = (__force u8 *)base;
> + u32 offset;
> + u32 i;
Tabify the declarations ;
> +
> + core_if = kzalloc(sizeof(*core_if), GFP_KERNEL);
> + if (!core_if)
> + return NULL;
> +
> + core_if->core_params = params;
> + core_if->core_global_regs = (ulong)reg_base;
> +
> + /* Allocate the Device Mode structures. */
> + dev_if = kmalloc(sizeof(*dev_if), GFP_KERNEL);
> + if (!dev_if) {
> + kfree(core_if);
> + return NULL;
> + }
> +
> + dev_if->dev_global_regs = (ulong)(reg_base +
DWC_DEV_GLOBAL_REG_OFFSET);
> +
> + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
> + offset = i * DWC_EP_REG_OFFSET;
> +
> + dev_if->in_ep_regs[i] = (ulong)(reg_base +
> + DWC_DEV_IN_EP_REG_OFFSET +
> + offset);
> +
> + dev_if->out_ep_regs[i] = (ulong)(reg_base +
> + DWC_DEV_OUT_EP_REG_OFFSET
+
> + offset);
> + }
> +
> + dev_if->speed = 0; /* unknown */
> + core_if->dev_if = dev_if;
> +
> + /* Allocate the Host Mode structures. */
> + host_if = kmalloc(sizeof(*host_if), GFP_KERNEL);
> + if (!host_if) {
> + kfree(dev_if);
> + kfree(core_if);
> + return NULL;
> + }
> +
> + host_if->host_global_regs = (ulong)(reg_base +
> +
DWC_OTG_HOST_GLOBAL_REG_OFFSET);
> +
> + host_if->hprt0 = (ulong)(reg_base +
DWC_OTG_HOST_PORT_REGS_OFFSET);
> +
> + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
> + offset = i * DWC_OTG_CHAN_REGS_OFFSET;
> +
> + host_if->hc_regs[i] = (ulong)(reg_base +
> + DWC_OTG_HOST_CHAN_REGS_OFFSET
+
> + offset);
> + }
> +
> + host_if->num_host_channels = MAX_EPS_CHANNELS;
> + core_if->host_if = host_if;
> + for (i = 0; i < MAX_EPS_CHANNELS; i++) {
> + core_if->data_fifo[i] =
> + (ulong)(reg_base + DWC_OTG_DATA_FIFO_OFFSET +
> + (i * DWC_OTG_DATA_FIFO_SIZE));
> + }
> + core_if->pcgcctl = (ulong)(reg_base + DWC_OTG_PCGCCTL_OFFSET);
> +
> + /*
> + * Store the contents of the hardware configuration registers here
for
> + * easy access later.
> + */
> + core_if->hwcfg1 =
> + dwc_read32(core_if->core_global_regs + DWC_GHWCFG1);
> + core_if->hwcfg2 =
> + dwc_read32(core_if->core_global_regs + DWC_GHWCFG2);
> + core_if->hwcfg3 =
> + dwc_read32(core_if->core_global_regs + DWC_GHWCFG3);
> + core_if->hwcfg4 =
> + dwc_read32(core_if->core_global_regs + DWC_GHWCFG4);
> +
> + /* Set the SRP sucess bit for FS-I2c */
> + core_if->srp_success = 0;
> + core_if->srp_timer_started = 0;
> + return core_if;
> +}
> +
> +/**
> + * This function frees the structures allocated by dwc_otg_cil_init().
> + */
> +void dwc_otg_cil_remove(struct core_if *core_if)
> +{
> + /* Disable all interrupts */
> + dwc_modify32(core_if->core_global_regs + DWC_GAHBCFG, 1, 0);
> + dwc_write32(core_if->core_global_regs + DWC_GINTMSK, 0);
> +
> + if (core_if) {
> + kfree(core_if->dev_if);
> + kfree(core_if->host_if);
> + }
> + kfree(core_if);
> +}
> diff --git a/drivers/usb/otg/dwc/cil.h b/drivers/usb/otg/dwc/cil.h
> new file mode 100644
> index 0000000..80b7da5
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/cil.h
> @@ -0,0 +1,1177 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * 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 program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld at apm.com>
> + * Modified by Stefan Roese <sr at denx.de>, DENX Software Engineering
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 SYNOPSYS, 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.
> + *
> + */
> +
> +#if !defined(__DWC_CIL_H__)
> +#define __DWC_CIL_H__
> +#include <linux/io.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/interrupt.h>
> +#include <linux/dmapool.h>
> +#include <linux/spinlock.h>
> +#include <linux/usb/otg.h>
> +
> +#include "regs.h"
> +
> +#ifdef CONFIG_DWC_DEBUG
> +#define DEBUG
> +#endif
> +
> +/**
> + * Reads the content of a register.
> + */
> +static inline u32 dwc_read32(ulong reg)
> +{
> +#ifdef CONFIG_DWC_OTG_REG_LE
> + return in_le32((unsigned __iomem *)reg);
> +#else
> + return in_be32((unsigned __iomem *)reg);
> +#endif
> +};
> +/**
> + * Writes a register with a 32 bit value.
> + */
> +static inline void dwc_write32(ulong reg, const u32 value)
> +{
> +#ifdef CONFIG_DWC_OTG_REG_LE
> + out_le32((unsigned __iomem *)reg, value);
> +#else
> + out_be32((unsigned __iomem *)reg, value);
> +#endif
> +};
> +
> +/**
> + * This function modifies bit values in a register. Using the
> + * algorithm: (reg_contents & ~clear_mask) | set_mask.
> + */
> +static inline
> + void dwc_modify32(ulong reg, const u32 _clear_mask, const u32
_set_mask)
> +{
> +#ifdef CONFIG_DWC_OTG_REG_LE
> + out_le32((unsigned __iomem *)reg,
> + (in_le32((unsigned __iomem *)reg) & ~_clear_mask)
|
> + _set_mask);
> +#else
> + out_be32((unsigned __iomem *)reg,
> + (in_be32(((unsigned __iomem *))reg) &
~_clear_mask) |
> + _set_mask);
> +#endif
> +};
> +
> +static inline void dwc_write_fifo32(ulong reg, const u32 _value)
> +{
> +#ifdef CONFIG_DWC_OTG_FIFO_LE
> + out_le32((unsigned __iomem *)reg, _value);
> +#else
> + out_be32((unsigned __iomem *)reg, _value);
> +#endif
> +};
> +
> +static inline u32 dwc_read_fifo32(ulong _reg)
> +{
> +#ifdef CONFIG_DWC_OTG_FIFO_LE
> + return in_le32((unsigned __iomem *) _reg);
> +#else
> + return in_be32((unsigned __iomem *) _reg);
> +#endif
> +};
> +
> +/*
> + * Debugging support vanishes in non-debug builds.
> + */
> +/* Display CIL Debug messages */
> +#define dwc_dbg_cil (0x2)
> +
> +/* Display CIL Verbose debug messages */
> +#define dwc_dbg_cilv (0x20)
> +
> +/* Display PCD (Device) debug messages */
> +#define dwc_dbg_pcd (0x4)
> +
> +/* Display PCD (Device) Verbose debug messages */
> +#define dwc_dbg_pcdv (0x40)
> +
> +/* Display Host debug messages */
> +#define dwc_dbg_hcd (0x8)
> +
> +/* Display Verbose Host debug messages */
> +#define dwc_dbg_hcdv (0x80)
> +
> +/* Display enqueued URBs in host mode. */
> +#define dwc_dbg_hcd_urb (0x800)
> +
> +/* Display "special purpose" debug messages */
> +#define dwc_dbg_sp (0x400)
> +
> +/* Display all debug messages */
> +#define dwc_dbg_any (0xFF)
> +
> +/* All debug messages off */
> +#define dwc_dbg_off 0
> +
> +/* Prefix string for DWC_DEBUG print macros. */
> +#define usb_dwc "dwc_otg: "
> +
> +/*
> + * This file contains the interface to the Core Interface Layer.
> + */
> +
> +/*
> + * Added-sr: 2007-07-26
> + *
> + * Since the 405EZ (Ultra) only support 2047 bytes as
> + * max transfer size, we have to split up bigger transfers
> + * into multiple transfers of 1024 bytes sized messages.
> + * I happens often, that transfers of 4096 bytes are
> + * required (zero-gadget, file_storage-gadget).
> + *
> + * MAX_XFER_LEN is set to 1024 right now, but could be 2047,
> + * since the xfer-size field in the 405EZ USB device controller
> + * implementation has 11 bits. Using 1024 seems to work for now.
> + */
> +#define MAX_XFER_LEN 1024
> +
> +/*
> + * The dwc_ep structure represents the state of a single endpoint when
acting in
> + * device mode. It contains the data items needed for an endpoint to be
> + * activated and transfer packets.
> + */
> +struct dwc_ep {
> + /* EP number used for register address lookup */
> + u8 num;
> + /* EP direction 0 = OUT */
> + unsigned is_in:1;
> + /* EP active. */
> + unsigned active:1;
> +
> + /*
> + * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use
> + * non-periodic Tx FIFO If dedicated Tx FIFOs are enabled for all
> + * IN Eps - Tx FIFO # FOR IN EPs
> + */
> + unsigned tx_fifo_num:4;
> + /* EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR
*/
> + unsigned type:2;
> +#define DWC_OTG_EP_TYPE_CONTROL 0
> +#define DWC_OTG_EP_TYPE_ISOC 1
> +#define DWC_OTG_EP_TYPE_BULK 2
> +#define DWC_OTG_EP_TYPE_INTR 3
> +
> + /* DATA start PID for INTR and BULK EP */
> + unsigned data_pid_start:1;
> + /* Frame (even/odd) for ISOC EP */
> + unsigned even_odd_frame:1;
> + /* Max Packet bytes */
> + unsigned maxpacket:11;
> +
> + ulong dma_addr;
> +
> + /*
> + * Pointer to the beginning of the transfer buffer -- do not
modify
> + * during transfer.
> + */
> + u8 *start_xfer_buff;
> + /* pointer to the transfer buffer */
> + u8 *xfer_buff;
> + /* Number of bytes to transfer */
> + unsigned xfer_len:19;
> + /* Number of bytes transferred. */
> + unsigned xfer_count:19;
> + /* Sent ZLP */
> + unsigned sent_zlp:1;
> + /* Total len for control transfer */
> + unsigned total_len:19;
> +
> + /* stall clear flag */
> + unsigned stall_clear_flag:1;
> +
> + /*
> + * Added-sr: 2007-07-26
> + *
> + * Since the 405EZ (Ultra) only support 2047 bytes as
> + * max transfer size, we have to split up bigger transfers
> + * into multiple transfers of 1024 bytes sized messages.
> + * I happens often, that transfers of 4096 bytes are
> + * required (zero-gadget, file_storage-gadget).
> + *
> + * "bytes_pending" will hold the amount of bytes that are
> + * still pending to be send in further messages to complete
> + * the bigger transfer.
> + */
> + u32 bytes_pending;
> +};
> +
> +/*
> + * States of EP0.
> + */
> +enum ep0_state {
> + EP0_DISCONNECT = 0, /* no host */
> + EP0_IDLE = 1,
> + EP0_IN_DATA_PHASE = 2,
> + EP0_OUT_DATA_PHASE = 3,
> + EP0_STATUS = 4,
> + EP0_STALL = 5,
> +};
> +
> +/* Fordward declaration.*/
> +struct dwc_pcd;
> +
> +/*
> + * This structure describes an EP, there is an array of EPs in the PCD
> + * structure.
> + */
> +struct pcd_ep {
> + /* USB EP data */
> + struct usb_ep ep;
> + /* USB EP Descriptor */
> + const struct usb_endpoint_descriptor *desc;
> +
> + /* queue of dwc_otg_pcd_requests. */
> + struct list_head queue;
> + unsigned stopped:1;
> + unsigned disabling:1;
> + unsigned dma:1;
> + unsigned queue_sof:1;
> + unsigned wedged:1;
> +
> + /* DWC_otg ep data. */
> + struct dwc_ep dwc_ep;
> +
> + /* Pointer to PCD */
> + struct dwc_pcd *pcd;
> +};
> +
> +/*
> + * DWC_otg PCD Structure.
> + * This structure encapsulates the data for the dwc_otg PCD.
> + */
> +struct dwc_pcd {
> + /* USB gadget */
> + struct usb_gadget gadget;
> + /* USB gadget driver pointer */
> + struct usb_gadget_driver *driver;
> + /* The DWC otg device pointer. */
> + struct dwc_otg_device *otg_dev;
> +
> + /* State of EP0 */
> + enum ep0_state ep0state;
> + /* EP0 Request is pending */
> + unsigned ep0_pending:1;
> + /* Indicates when SET CONFIGURATION Request is in process */
> + unsigned request_config:1;
> + /* The state of the Remote Wakeup Enable. */
> + unsigned remote_wakeup_enable:1;
> + /* The state of the B-Device HNP Enable. */
> + unsigned b_hnp_enable:1;
> + /* The state of A-Device HNP Support. */
> + unsigned a_hnp_support:1;
> + /* The state of the A-Device Alt HNP support. */
> + unsigned a_alt_hnp_support:1;
> + /* Count of pending Requests */
> + unsigned request_pending;
> +
> + /*
> + * SETUP packet for EP0. This structure is allocated as a DMA
buffer on
> + * PCD initialization with enough space for up to 3 setup packets.
> + */
> + union {
> + struct usb_ctrlrequest req;
> + u32 d32[2];
> + } *setup_pkt;
> +
> + struct dma_pool *dwc_pool;
> + dma_addr_t setup_pkt_dma_handle;
> +
> + /* 2-byte dma buffer used to return status from GET_STATUS */
> + u16 *status_buf;
> + dma_addr_t status_buf_dma_handle;
> +
> + /* Array of EPs. */
> + struct pcd_ep ep0;
> + /* Array of IN EPs. */
> + struct pcd_ep in_ep[MAX_EPS_CHANNELS - 1];
> + /* Array of OUT EPs. */
> + struct pcd_ep out_ep[MAX_EPS_CHANNELS - 1];
> + spinlock_t lock;
> + /*
> + * Timer for SRP. If it expires before SRP is successful clear
the
> + * SRP.
> + */
> + struct timer_list srp_timer;
> +
> + /*
> + * Tasklet to defer starting of TEST mode transmissions until
Status
> + * Phase has been completed.
> + */
> + struct tasklet_struct test_mode_tasklet;
> +
> + /* Tasklet to delay starting of xfer in DMA mode */
> + struct tasklet_struct *start_xfer_tasklet;
> +
> + /* The test mode to enter when the tasklet is executed. */
> + unsigned test_mode;
> +};
> +
> +/*
> + * This structure holds the state of the HCD, including the
non-periodic and
> + * periodic schedules.
> + */
> +struct dwc_hcd {
> + spinlock_t lock;
> +
> + /* DWC OTG Core Interface Layer */
> + struct core_if *core_if;
> +
> + /* Internal DWC HCD Flags */
> + union dwc_otg_hcd_internal_flags {
> + u32 d32;
> + struct {
> + unsigned port_connect_status_change:1;
> + unsigned port_connect_status:1;
> + unsigned port_reset_change:1;
> + unsigned port_enable_change:1;
> + unsigned port_suspend_change:1;
> + unsigned port_over_current_change:1;
> + unsigned reserved:27;
> + } b;
> + } flags;
> +
> + /*
> + * Inactive items in the non-periodic schedule. This is a list of
> + * Queue Heads. Transfers associated with these Queue Heads are
not
> + * currently assigned to a host channel.
> + */
> + struct list_head non_periodic_sched_inactive;
> +
> + /*
> + * Deferred items in the non-periodic schedule. This is a list of
> + * Queue Heads. Transfers associated with these Queue Heads are
not
> + * currently assigned to a host channel.
> + * When we get an NAK, the QH goes here.
> + */
> + struct list_head non_periodic_sched_deferred;
> +
> + /*
> + * Active items in the non-periodic schedule. This is a list of
> + * Queue Heads. Transfers associated with these Queue Heads are
> + * currently assigned to a host channel.
> + */
> + struct list_head non_periodic_sched_active;
> +
> + /*
> + * Pointer to the next Queue Head to process in the active
> + * non-periodic schedule.
> + */
> + struct list_head *non_periodic_qh_ptr;
> +
> + /*
> + * Inactive items in the periodic schedule. This is a list of QHs
for
> + * periodic transfers that are _not_ scheduled for the next frame.
> + * Each QH in the list has an interval counter that determines
when it
> + * needs to be scheduled for execution. This scheduling mechanism
> + * allows only a simple calculation for periodic bandwidth used
(i.e.
> + * must assume that all periodic transfers may need to execute in
the
> + * same frame). However, it greatly simplifies scheduling and
should
> + * be sufficient for the vast majority of OTG hosts, which need to
> + * connect to a small number of peripherals at one time.
> + *
> + * Items move from this list to periodic_sched_ready when the QH
> + * interval counter is 0 at SOF.
> + */
> + struct list_head periodic_sched_inactive;
> +
> + /*
> + * List of periodic QHs that are ready for execution in the next
> + * frame, but have not yet been assigned to host channels.
> + *
> + * Items move from this list to periodic_sched_assigned as host
> + * channels become available during the current frame.
> + */
> + struct list_head periodic_sched_ready;
> +
> + /*
> + * List of periodic QHs to be executed in the next frame that are
> + * assigned to host channels.
> + *
> + * Items move from this list to periodic_sched_queued as the
> + * transactions for the QH are queued to the DWC_otg controller.
> + */
> + struct list_head periodic_sched_assigned;
> +
> + /*
> + * List of periodic QHs that have been queued for execution.
> + *
> + * Items move from this list to either periodic_sched_inactive or
> + * periodic_sched_ready when the channel associated with the
transfer
> + * is released. If the interval for the QH is 1, the item moves to
> + * periodic_sched_ready because it must be rescheduled for the
next
> + * frame. Otherwise, the item moves to periodic_sched_inactive.
> + */
> + struct list_head periodic_sched_queued;
> +
> + /*
> + * Total bandwidth claimed so far for periodic transfers. This
value
> + * is in microseconds per (micro)frame. The assumption is that all
> + * periodic transfers may occur in the same (micro)frame.
> + */
> + u16 periodic_usecs;
> +
> + /*
> + * Total bandwidth claimed so far for all periodic transfers
> + * in a frame.
> + * This will include a mixture of HS and FS transfers.
> + * Units are microseconds per (micro)frame.
> + * We have a budget per frame and have to schedule
> + * transactions accordingly.
> + * Watch out for the fact that things are actually scheduled for
the
> + * "next frame".
> + */
> + u16 frame_usecs[8];
> +
> + /*
> + * Frame number read from the core at SOF. The value ranges from 0
to
> + * DWC_HFNUM_MAX_FRNUM.
> + */
> + u16 frame_number;
> +
> + /*
> + * Free host channels in the controller. This is a list of
> + * struct dwc_hc items.
> + */
> + struct list_head free_hc_list;
> +
> + /*
> + * Number of available host channels.
> + */
> + u32 available_host_channels;
> +
> + /*
> + * Array of pointers to the host channel descriptors. Allows
accessing
> + * a host channel descriptor given the host channel number. This
is
> + * useful in interrupt handlers.
> + */
> + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
> +
> + /*
> + * Buffer to use for any data received during the status phase of
a
> + * control transfer. Normally no data is transferred during the
status
> + * phase. This buffer is used as a bit bucket.
> + */
> + u8 *status_buf;
> +
> + /*
> + * DMA address for status_buf.
> + */
> + dma_addr_t status_buf_dma;
> +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
> +
> + /*
> + * Structure to allow starting the HCD in a non-interrupt context
> + * during an OTG role change.
> + */
> + struct work_struct start_work;
> + struct usb_hcd *_p;
> +
> + /*
> + * Connection timer. An OTG host must display a message if the
device
> + * does not connect. Started when the VBus power is turned on via
> + * sysfs attribute "buspower".
> + */
> + struct timer_list conn_timer;
> +
> + /* workqueue for port wakeup */
> + struct work_struct usb_port_reset;
> +
> + /* Addition HCD interrupt */
> + int cp_irq; /* charge pump interrupt */
> + int cp_irq_installed;
> +};
> +
> +/*
> + * Reasons for halting a host channel.
> + */
> +enum dwc_halt_status {
> + DWC_OTG_HC_XFER_NO_HALT_STATUS,
> + DWC_OTG_HC_XFER_COMPLETE,
> + DWC_OTG_HC_XFER_URB_COMPLETE,
> + DWC_OTG_HC_XFER_ACK,
> + DWC_OTG_HC_XFER_NAK,
> + DWC_OTG_HC_XFER_NYET,
> + DWC_OTG_HC_XFER_STALL,
> + DWC_OTG_HC_XFER_XACT_ERR,
> + DWC_OTG_HC_XFER_FRAME_OVERRUN,
> + DWC_OTG_HC_XFER_BABBLE_ERR,
> + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
> + DWC_OTG_HC_XFER_AHB_ERR,
> + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
> + DWC_OTG_HC_XFER_URB_DEQUEUE
> +};
> +
> +/*
> + * Host channel descriptor. This structure represents the state of a
single
> + * host channel when acting in host mode. It contains the data items
needed to
> + * transfer packets to an endpoint via a host channel.
> + */
> +struct dwc_hc {
> + /* Host channel number used for register address lookup */
> + u8 hc_num;
> +
> + /* Device to access */
> + unsigned dev_addr:7;
> +
> + /* EP to access */
> + unsigned ep_num:4;
> +
> + /* EP direction. 0: OUT, 1: IN */
> + unsigned ep_is_in:1;
> +
> + /*
> + * EP speed.
> + * One of the following values:
> + * - DWC_OTG_EP_SPEED_LOW
> + * - DWC_OTG_EP_SPEED_FULL
> + * - DWC_OTG_EP_SPEED_HIGH
> + */
> + unsigned speed:2;
> +#define DWC_OTG_EP_SPEED_LOW 0
> +#define DWC_OTG_EP_SPEED_FULL 1
> +#define DWC_OTG_EP_SPEED_HIGH 2
> +
> + /*
> + * Endpoint type.
> + * One of the following values:
> + * - DWC_OTG_EP_TYPE_CONTROL: 0
> + * - DWC_OTG_EP_TYPE_ISOC: 1
> + * - DWC_OTG_EP_TYPE_BULK: 2
> + * - DWC_OTG_EP_TYPE_INTR: 3
> + */
> + unsigned ep_type:2;
> +
> + /* Max packet size in bytes */
> + unsigned max_packet:11;
> +
> + /*
> + * PID for initial transaction.
> + * 0: DATA0,
> + * 1: DATA2,
> + * 2: DATA1,
> + * 3: MDATA (non-Control EP),
> + * SETUP (Control EP)
> + */
> + unsigned data_pid_start:2;
> +#define DWC_OTG_HC_PID_DATA0 0
> +#define DWC_OTG_HC_PID_DATA2 1
> +#define DWC_OTG_HC_PID_DATA1 2
> +#define DWC_OTG_HC_PID_MDATA 3
> +#define DWC_OTG_HC_PID_SETUP 3
> +
> + /* Number of periodic transactions per (micro)frame */
> + unsigned multi_count:2;
> +
> + /* Pointer to the current transfer buffer position. */
> + u8 *xfer_buff;
> + /* Total number of bytes to transfer. */
> + u32 xfer_len;
> + /* Number of bytes transferred so far. */
> + u32 xfer_count;
> + /* Packet count at start of transfer. */
> + u16 start_pkt_count;
> +
> + /*
> + * Flag to indicate whether the transfer has been started. Set to
1 if
> + * it has been started, 0 otherwise.
> + */
> + u8 xfer_started;
> +
> + /*
> + * Set to 1 to indicate that a PING request should be issued on
this
> + * channel. If 0, process normally.
> + */
> + u8 do_ping;
> +
> + /*
> + * Set to 1 to indicate that the error count for this transaction
is
> + * non-zero. Set to 0 if the error count is 0.
> + */
> + u8 error_state;
> +
> + /*
> + * Set to 1 to indicate that this channel should be halted the
next
> + * time a request is queued for the channel. This is necessary in
> + * slave mode if no request queue space is available when an
attempt
> + * is made to halt the channel.
> + */
> + u8 halt_on_queue;
> +
> + /*
> + * Set to 1 if the host channel has been halted, but the core is
not
> + * finished flushing queued requests. Otherwise 0.
> + */
> + u8 halt_pending;
> +
> + /* Reason for halting the host channel. */
> + enum dwc_halt_status halt_status;
> +
> + /* Split settings for the host channel */
> + u8 do_split; /* Enable split for the channel */
> + u8 complete_split; /* Enable complete split */
> + u8 hub_addr; /* Address of high speed hub */
> + u8 port_addr; /* Port of the low/full speed device */
> +
> + /*
> + * Split transaction position. One of the following values:
> + * - DWC_HCSPLIT_XACTPOS_MID
> + * - DWC_HCSPLIT_XACTPOS_BEGIN
> + * - DWC_HCSPLIT_XACTPOS_END
> + * - DWC_HCSPLIT_XACTPOS_ALL */
> + u8 xact_pos;
> +
> + /* Set when the host channel does a short read. */
> + u8 short_read;
> +
> + /*
> + * Number of requests issued for this channel since it was
assigned to
> + * the current transfer (not counting PINGs).
> + */
> + u8 requests;
> +
> + /* Queue Head for the transfer being processed by this channel. */
> + struct dwc_qh *qh;
> +
> + /* Entry in list of host channels. */
> + struct list_head hc_list_entry;
> +};
> +
> +/*
> + * The following parameters may be specified when starting the module.
These
> + * parameters define how the DWC_otg controller should be configured.
Parameter
> + * values are passed to the CIL initialization function
dwc_otg_cil_init.
> + */
> +struct core_params {
> + /*
> + * Specifies the OTG capabilities. The driver will automatically
> + * detect the value for this parameter if none is specified.
> + * 0 - HNP and SRP capable (default)
> + * 1 - SRP Only capable
> + * 2 - No HNP/SRP capable
> + */
> + int otg_cap;
> +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
> +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
> +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
> +
> +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
> +
> + /*
> + * Specifies whether to use slave or DMA mode for accessing the
data
> + * FIFOs. The driver will automatically detect the value for this
> + * parameter if none is specified.
> + * 0 - Slave
> + * 1 - DMA (default, if available)
> + */
> + int dma_enable;
> +#ifdef CONFIG_DWC_SLAVE
> +#define dwc_param_dma_enable_default 0
> +#else
> +#define dwc_param_dma_enable_default 1
> +#endif
> +
> + /*
> + * The DMA Burst size (applicable only for External DMA Mode).
> + * 1, 4, 8 16, 32, 64, 128, 256 (default 32)
> + */
> + int dma_burst_size; /* Translate this to GAHBCFG values */
> +#define dwc_param_dma_burst_size_default 32
> +
> + /*
> + * Specifies the maximum speed of operation in host and device
mode.
> + * The actual speed depends on the speed of the attached device
and
> + * the value of phy_type. The actual speed depends on the speed of
the
> + * attached device.
> + * 0 - High Speed (default)
> + * 1 - Full Speed
> + */
> + int speed;
> +#define dwc_param_speed_default 0
> +#define DWC_SPEED_PARAM_HIGH 0
> +#define DWC_SPEED_PARAM_FULL 1
> +
> + /*
> + * Specifies whether low power mode is supported when attached to
a Full
> + * Speed or Low Speed device in host mode.
> + * 0 - Don't support low power mode (default)
> + * 1 - Support low power mode
> + */
> + int host_support_fs_ls_low_power;
> +#define dwc_param_host_support_fs_ls_low_power_default 0
> +
> + /*
> + * Specifies the PHY clock rate in low power mode when connected
to a
> + * Low Speed device in host mode. This parameter is applicable
only if
> + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to
FS
> + * then defaults to 6 MHZ otherwise 48 MHZ.
> + *
> + * 0 - 48 MHz
> + * 1 - 6 MHz
> + */
> + int host_ls_low_power_phy_clk;
> +#define dwc_param_host_ls_low_power_phy_clk_default 0
> +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
> +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
> +
> + /*
> + * 0 - Use cC FIFO size parameters
> + * 1 - Allow dynamic FIFO sizing (default)
> + */
> + int enable_dynamic_fifo;
> +#define dwc_param_enable_dynamic_fifo_default 1
> +
> + /*
> + * Number of 4-byte words in the Rx FIFO in device mode when
dynamic
> + * FIFO sizing is enabled. 16 to 32768 (default 1064)
> + */
> + int dev_rx_fifo_size;
> +#define dwc_param_dev_rx_fifo_size_default 1064
> +
> + /*
> + * Number of 4-byte words in the non-periodic Tx FIFO in device
mode
> + * when dynamic FIFO sizing is enabled. 16 to 32768 (default
1024)
> + */
> + int dev_nperio_tx_fifo_size;
> +#define dwc_param_dev_nperio_tx_fifo_size_default 1024
> +
> + /*
> + * Number of 4-byte words in each of the periodic Tx FIFOs in
device
> + * mode when dynamic FIFO sizing is enabled. 4 to 768 (default
256)
> + */
> + u32 dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
> +#define dwc_param_dev_perio_tx_fifo_size_default 256
> +
> + /*
> + * Number of 4-byte words in the Rx FIFO in host mode when dynamic
> + * FIFO sizing is enabled. 16 to 32768 (default 1024)
> + */
> + int host_rx_fifo_size;
> +#define dwc_param_host_rx_fifo_size_default 1024
> +
> + /*
> + * Number of 4-byte words in the non-periodic Tx FIFO in host mode
> + * when Dynamic FIFO sizing is enabled in the core. 16 to 32768
> + * (default 1024)
> + */
> + int host_nperio_tx_fifo_size;
> +#define dwc_param_host_nperio_tx_fifo_size_default 1024
> +
> + /*
> + Number of 4-byte words in the host periodic Tx FIFO when
dynamic
> + * FIFO sizing is enabled. 16 to 32768 (default 1024)
> + */
> + int host_perio_tx_fifo_size;
> +#define dwc_param_host_perio_tx_fifo_size_default 1024
> +
> + /*
> + * The maximum transfer size supported in bytes. 2047 to 65,535
> + * (default 65,535)
> + */
> + int max_transfer_size;
> +#define dwc_param_max_transfer_size_default 65535
> +
> + /*
> + * The maximum number of packets in a transfer. 15 to 511
(default 511)
> + */
> + int max_packet_count;
> +#define dwc_param_max_packet_count_default 511
> +
> + /*
> + * The number of host channel registers to use.
> + * 1 to 16 (default 12)
> + * Note: The FPGA configuration supports a maximum of 12 host
channels.
> + */
> + int host_channels;
> +#define dwc_param_host_channels_default 12
> +
> + /*
> + * The number of endpoints in addition to EP0 available for device
> + * mode operations.
> + * 1 to 15 (default 6 IN and OUT)
> + * Note: The FPGA configuration supports a maximum of 6 IN and OUT
> + * endpoints in addition to EP0.
> + */
> + int dev_endpoints;
> +#define dwc_param_dev_endpoints_default 6
> +
> + /*
> + * Specifies the type of PHY interface to use. By default, the
driver
> + * will automatically detect the phy_type.
> + *
> + * 0 - Full Speed PHY
> + * 1 - UTMI+ (default)
> + * 2 - ULPI
> + */
> + int phy_type;
> +#define DWC_PHY_TYPE_PARAM_FS 0
> +#define DWC_PHY_TYPE_PARAM_UTMI 1
> +#define DWC_PHY_TYPE_PARAM_ULPI 2
> +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
> +
> + /*
> + * Specifies the UTMI+ Data Width. This parameter is applicable
for a
> + * PHY_TYPE of UTMI+ or ULPI. (For a ULPI PHY_TYPE, this parameter
> + * indicates the data width between the MAC and the ULPI Wrapper.)
Also,
> + * this parameter is applicable only if the OTG_HSPHY_WIDTH cC
parameter
> + * was set to "8 and 16 bits", meaning that the core has been
configured
> + * to work at either data path width.
> + *
> + * 8 or 16 bits (default 16)
> + */
> + int phy_utmi_width;
> +#define dwc_param_phy_utmi_width_default 16
> +
> + /*
> + * Specifies whether the ULPI operates at double or single
> + * data rate. This parameter is only applicable if PHY_TYPE is
> + * ULPI.
> + *
> + * 0 - single data rate ULPI interface with 8 bit wide data
> + * bus (default)
> + * 1 - double data rate ULPI interface with 4 bit wide data
> + * bus
> + */
> + int phy_ulpi_ddr;
> +#define dwc_param_phy_ulpi_ddr_default 0
> +
> + /*
> + * Specifies whether to use the internal or external supply to
> + * drive the vbus with a ULPI phy.
> + */
> + int phy_ulpi_ext_vbus;
> +#define DWC_PHY_ULPI_INTERNAL_VBUS 0
> +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
> +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
> +
> + /*
> + * Specifies whether to use the I2Cinterface for full speed PHY.
This
> + * parameter is only applicable if PHY_TYPE is FS.
> + * 0 - No (default)
> + * 1 - Yes
> + */
> + int i2c_enable;
> +#define dwc_param_i2c_enable_default 0
> +
> + int ulpi_fs_ls;
> +#define dwc_param_ulpi_fs_ls_default 0
> +
> + int ts_dline;
> +#define dwc_param_ts_dline_default 0
> +
> + /*
> + * Specifies whether dedicated transmit FIFOs are enabled for non
> + * periodic IN endpoints in device mode
> + * 0 - No
> + * 1 - Yes
> + */
> + int en_multiple_tx_fifo;
> +#define dwc_param_en_multiple_tx_fifo_default 1
> +
> + /*
> + * Number of 4-byte words in each of the Tx FIFOs in device
> + * mode when dynamic FIFO sizing is enabled. 4 to 768 (default
256)
> + */
> + u32 dev_tx_fifo_size[MAX_TX_FIFOS];
> +#define dwc_param_dev_tx_fifo_size_default 256
> +
> + /*
> + * Thresholding enable flag
> + * bit 0 - enable non-ISO Tx thresholding
> + * bit 1 - enable ISO Tx thresholding
> + * bit 2 - enable Rx thresholding
> + */
> + u32 thr_ctl;
> +#define dwc_param_thr_ctl_default 0
> +
> + /* Thresholding length for Tx FIFOs in 32 bit DWORDs */
> + u32 tx_thr_length;
> +#define dwc_param_tx_thr_length_default 64
> +
> + /* Thresholding length for Rx FIFOs in 32 bit DWORDs */
> + u32 rx_thr_length;
> +#define dwc_param_rx_thr_length_default 64
> +
> +};
> +
> +/*
> + * The core_if structure contains information needed to manage the
> + * DWC_otg controller acting in either host or device mode. It
represents the
> + * programming view of the controller as a whole.
> + */
> +struct core_if {
> + /* Parameters that define how the core should be configured. */
> + struct core_params *core_params;
> +
> + /* Core Global registers starting at offset 000h. */
> + ulong core_global_regs;
> +
> + /* Device-specific information */
> + struct device_if *dev_if;
> + /* Host-specific information */
> + struct dwc_host_if *host_if;
> +
> + /*
> + * Set to 1 if the core PHY interface bits in USBCFG have been
> + * initialized.
> + */
> + u8 phy_init_done;
> +
> + /*
> + * SRP Success flag, set by srp success interrupt in FS I2C mode
> + */
> + u8 srp_success;
> + u8 srp_timer_started;
> +
> + /* Common configuration information */
> + /* Power and Clock Gating Control Register */
> + ulong pcgcctl;
> +#define DWC_OTG_PCGCCTL_OFFSET 0xE00
> +
> + /* Push/pop addresses for endpoints or host channels. */
> + ulong data_fifo[MAX_EPS_CHANNELS];
> +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
> +#define DWC_OTG_DATA_FIFO_SIZE 0x1000
> +
> + /* Total RAM for FIFOs (Bytes) */
> + u16 total_fifo_size;
> + /* Size of Rx FIFO (Bytes) */
> + u16 rx_fifo_size;
> + /* Size of Non-periodic Tx FIFO (Bytes) */
> + u16 nperio_tx_fifo_size;
> +
> + /* 1 if DMA is enabled, 0 otherwise. */
> + u8 dma_enable;
> +
> + /* 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
> + u8 en_multiple_tx_fifo;
> +
> + /*
> + * Set to 1 if multiple packets of a high-bandwidth transfer is
in
> + * process of being queued
> + */
> + u8 queuing_high_bandwidth;
> +
> + /* Hardware Configuration -- stored here for convenience. */
> + ulong hwcfg1;
> + ulong hwcfg2;
> + ulong hwcfg3;
> + ulong hwcfg4;
> +
> + /* HCD callbacks */
> + /* include/linux/usb/otg.h */
> +
> + /* HCD callbacks */
> + struct cil_callbacks *hcd_cb;
> + /* PCD callbacks */
> + struct cil_callbacks *pcd_cb;
> +
> + /* Device mode Periodic Tx FIFO Mask */
> + u32 p_tx_msk;
> + /* Device mode Periodic Tx FIFO Mask */
> + u32 tx_msk;
> +
> + /* Features of various DWC implementation */
> + u32 features;
> +
> + /* Added to support PLB DMA : phys-virt mapping */
> + resource_size_t phys_addr;
> +
> + struct delayed_work usb_port_wakeup;
> + struct work_struct usb_port_otg;
> + struct otg_transceiver *xceiv;
> +};
> +
> +/*
> + * The following functions support initialization of the CIL driver
component
> + * and the DWC_otg controller.
> + */
> +extern void dwc_otg_core_init(struct core_if *core_if);
> +extern void init_fslspclksel(struct core_if *core_if);
> +extern void dwc_otg_core_dev_init(struct core_if *core_if);
> +extern const char *op_state_str(enum usb_otg_state state);
> +extern void dwc_otg_enable_global_interrupts(struct core_if *core_if);
> +extern void dwc_otg_disable_global_interrupts(struct core_if *core_if);
> +extern void dwc_otg_enable_common_interrupts(struct core_if *core_if);
> +
> +/**
> + * This function Reads HPRT0 in preparation to modify. It keeps the WC
bits 0
> + * so that if they are read as 1, they won't clear when you write it
back
> + */
> +static inline u32 dwc_otg_read_hprt0(struct core_if *core_if)
> +{
> + u32 hprt0 = 0;
> + hprt0 = dwc_read32(core_if->host_if->hprt0);
> + hprt0 = DWC_HPRT0_PRT_ENA_RW(hprt0, 0);
> + hprt0 = DWC_HPRT0_PRT_CONN_DET_RW(hprt0, 0);
> + hprt0 = DWC_HPRT0_PRT_ENA_DIS_CHG_RW(hprt0, 0);
> + hprt0 = DWC_HPRT0_PRT_OVRCURR_ACT_RW(hprt0, 0);
> + return hprt0;
> +}
> +
> +/*
> + * The following functions support managing the DWC_otg controller in
either
> + * device or host mode.
> + */
> +extern void dwc_otg_read_packet(struct core_if *core_if, u8 * dest, u16
bytes);
> +extern void dwc_otg_flush_tx_fifo(struct core_if *core_if, const int
_num);
> +extern void dwc_otg_flush_rx_fifo(struct core_if *core_if);
> +
> +#define NP_TXFIFO_EMPTY -1
> +#define MAX_NP_TXREQUEST_Q_SLOTS 8
> +
> +/**
> + * This function returns the Core Interrupt register.
> + */
> +static inline u32 dwc_otg_read_core_intr(struct core_if *core_if)
> +{
> + u32 global_regs = (u32) core_if->core_global_regs;
> + return dwc_read32(global_regs + DWC_GINTSTS) &
> + dwc_read32(global_regs + DWC_GINTMSK);
> +}
> +
> +/**
> + * This function returns the mode of the operation, host or device.
> + */
> +static inline u32 dwc_otg_mode(struct core_if *core_if)
> +{
> + u32 global_regs = (u32) core_if->core_global_regs;
> + return dwc_read32(global_regs + DWC_GINTSTS) & 0x1;
> +}
> +
> +static inline u8 dwc_otg_is_device_mode(struct core_if *core_if)
> +{
> + return dwc_otg_mode(core_if) != DWC_HOST_MODE;
> +}
> +static inline u8 dwc_otg_is_host_mode(struct core_if *core_if)
> +{
> + return dwc_otg_mode(core_if) == DWC_HOST_MODE;
> +}
> +
> +extern int dwc_otg_handle_common_intr(struct core_if *core_if);
> +
> +/*
> + * DWC_otg CIL callback structure. This structure allows the HCD and
PCD to
> + * register functions used for starting and stopping the PCD and HCD
for role
> + * change on for a DRD.
> + */
> +struct cil_callbacks {
> + /* Start function for role change */
> + int (*start) (void *_p);
> + /* Stop Function for role change */
> + int (*stop) (void *_p);
> + /* Disconnect Function for role change */
> + int (*disconnect) (void *_p);
> + /* Resume/Remote wakeup Function */
> + int (*resume_wakeup) (void *_p);
> + /* Suspend function */
> + int (*suspend) (void *_p);
> + /* Session Start (SRP) */
> + int (*session_start) (void *_p);
> + /* Pointer passed to start() and stop() */
> + void *p;
> +};
> +
> +extern void dwc_otg_cil_register_pcd_callbacks(struct core_if *core_if,
> + struct cil_callbacks *cb,
> + void *p);
> +extern void dwc_otg_cil_register_hcd_callbacks(struct core_if *core_if,
> + struct cil_callbacks *cb,
> + void *p);
> +
> +#define DWC_LIMITED_XFER 0x00000000
> +#define DWC_DEVICE_ONLY 0x00000000
> +#define DWC_HOST_ONLY 0x00000000
> +
> +#ifdef DWC_LIMITED_XFER_SIZE
> +#undef DWC_LIMITED_XFER
> +#define DWC_LIMITED_XFER 0x00000001
> +#endif
> +
> +#ifdef CONFIG_DWC_DEVICE_ONLY
> +#undef DWC_DEVICE_ONLY
> +#define DWC_DEVICE_ONLY 0x00000002
> +static inline void dwc_otg_hcd_remove(struct device *dev)
> +{
> +}
> +static inline int dwc_otg_hcd_init(struct device *_dev,
> + struct dwc_otg_device *dwc_dev)
> +{
> + return 0;
> +}
> +#else
> +extern int __init dwc_otg_hcd_init(struct device *_dev,
> + struct dwc_otg_device *dwc_dev);
> +extern void dwc_otg_hcd_remove(struct device *_dev);
> +#endif
> +
> +#ifdef CONFIG_DWC_HOST_ONLY
> +#undef DWC_HOST_ONLY
> +#define DWC_HOST_ONLY 0x00000004
> +static inline void dwc_otg_pcd_remove(struct device *dev)
> +{
> +}
> +static inline int dwc_otg_pcd_init(struct device *dev)
> +{
> + return 0;
> +}
> +#else
> +extern void dwc_otg_pcd_remove(struct device *dev);
> +extern int __init dwc_otg_pcd_init(struct device *dev);
> +#endif
> +
> +extern void dwc_otg_cil_remove(struct core_if *core_if);
> +extern struct core_if __devinit *dwc_otg_cil_init(const __iomem u32 *
base,
> + struct core_params
*params);
> +
> +static inline void dwc_set_feature(struct core_if *core_if)
> +{
> + core_if->features = DWC_LIMITED_XFER | DWC_DEVICE_ONLY |
DWC_HOST_ONLY;
> +}
> +
> +static inline int dwc_has_feature(struct core_if *core_if,
> + unsigned long feature)
> +{
> + return core_if->features & feature;
> +}
> +extern struct core_params dwc_otg_module_params;
> +extern int __devinit check_parameters(struct core_if *core_if);
> +#endif
> diff --git a/drivers/usb/otg/dwc/cil_intr.c
b/drivers/usb/otg/dwc/cil_intr.c
> new file mode 100644
> index 0000000..9111795
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/cil_intr.c
> @@ -0,0 +1,616 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * 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 program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld at apm.com>
> + * Modified by Stefan Roese <sr at denx.de>, DENX Software Engineering
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 SYNOPSYS, 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.
> + *
> + */
> +
> +/*
> + * The Core Interface Layer provides basic services for accessing and
> + * managing the DWC_otg hardware. These services are used by both the
> + * Host Controller Driver and the Peripheral Controller Driver.
> + *
> + * This file contains the Common Interrupt handlers.
> + */
> +#include <linux/delay.h>
> +
> +#include "cil.h"
> +
> +/**
> + * This function will log a debug message
> + */
> +static int dwc_otg_handle_mode_mismatch_intr(struct core_if *core_if)
> +{
> + u32 gintsts = 0;
> + ulong global_regs = core_if->core_global_regs;
> +
> + pr_warning("Mode Mismatch Interrupt: currently in %s mode\n",
> + dwc_otg_mode(core_if) ? "Host" : "Device");
> +
> + /* Clear interrupt */
> + gintsts |= DWC_INTSTS_MODE_MISMTC;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> +
> + return 1;
> +}
> +
> +/**
> + * Start the HCD. Helper function for using the HCD callbacks.
> + */
> +static inline void hcd_start(struct core_if *core_if)
> +{
> + if (core_if->hcd_cb && core_if->hcd_cb->start)
> + core_if->hcd_cb->start(core_if->hcd_cb->p);
> +}
> +
> +/**
> + * Stop the HCD. Helper function for using the HCD callbacks.
> + */
> +static inline void hcd_stop(struct core_if *core_if)
> +{
> + if (core_if->hcd_cb && core_if->hcd_cb->stop)
> + core_if->hcd_cb->stop(core_if->hcd_cb->p);
> +}
> +
> +/**
> + * Disconnect the HCD. Helper function for using the HCD callbacks.
> + */
> +static inline void hcd_disconnect(struct core_if *core_if)
> +{
> + if (core_if->hcd_cb && core_if->hcd_cb->disconnect)
> + core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
> +}
> +
> +/**
> + * Inform the HCD the a New Session has begun. Helper function for
using the
> + * HCD callbacks.
> + */
> +static inline void hcd_session_start(struct core_if *core_if)
> +{
> + if (core_if->hcd_cb && core_if->hcd_cb->session_start)
> + core_if->hcd_cb->session_start(core_if->hcd_cb->p);
> +}
> +
> +/**
> + * Start the PCD. Helper function for using the PCD callbacks.
> + */
> +static inline void pcd_start(struct core_if *core_if)
> +{
> + if (core_if->pcd_cb && core_if->pcd_cb->start) {
> + struct dwc_pcd *pcd;
> +
> + pcd = (struct dwc_pcd *)core_if->pcd_cb->p;
> + spin_lock(&pcd->lock);
> + core_if->pcd_cb->start(core_if->pcd_cb->p);
> + spin_unlock(&pcd->lock);
> + }
> +}
> +
> +/**
> + * Stop the PCD. Helper function for using the PCD callbacks.
> + */
> +static inline void pcd_stop(struct core_if *core_if)
> +{
> + if (core_if->pcd_cb && core_if->pcd_cb->stop) {
> + struct dwc_pcd *pcd;
> +
> + pcd = (struct dwc_pcd *)core_if->pcd_cb->p;
> + spin_lock(&pcd->lock);
> + core_if->pcd_cb->stop(core_if->pcd_cb->p);
> + spin_unlock(&pcd->lock);
> + }
> +}
> +
> +/**
> + * Suspend the PCD. Helper function for using the PCD callbacks.
> + */
> +static inline void pcd_suspend(struct core_if *core_if)
> +{
> + if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
> + struct dwc_pcd *pcd;
> +
> + pcd = (struct dwc_pcd *)core_if->pcd_cb->p;
> + spin_lock(&pcd->lock);
> + core_if->pcd_cb->suspend(core_if->pcd_cb->p);
> + spin_unlock(&pcd->lock);
> + }
> +}
> +
> +/**
> + * Resume the PCD. Helper function for using the PCD callbacks.
> + */
> +static inline void pcd_resume(struct core_if *core_if)
> +{
> + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
> + struct dwc_pcd *pcd;
> +
> + pcd = (struct dwc_pcd *)core_if->pcd_cb->p;
> + spin_lock(&pcd->lock);
> + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
> + spin_unlock(&pcd->lock);
> + }
> +}
> +
> +/**
> + * This function handles the OTG Interrupts. It reads the OTG
> + * Interrupt Register (GOTGINT) to determine what interrupt has
> + * occurred.
> + */
> +static int dwc_otg_handle_otg_intr(struct core_if *core_if)
> +{
> + ulong global_regs = core_if->core_global_regs;
> + u32 gotgint;
> + u32 gotgctl;
> + u32 gintmsk;
> +
> + gotgint = dwc_read32(global_regs + DWC_GOTGINT);
> + if (gotgint & DWC_GINT_SES_ENDDET) {
> + gotgctl = dwc_read32(global_regs + DWC_GOTGCTL);
> + if (core_if->xceiv->state == OTG_STATE_B_HOST) {
> + pcd_start(core_if);
> + core_if->xceiv->state = OTG_STATE_B_PERIPHERAL;
> + } else {
> + /*
> + * If not B_HOST and Device HNP still set. HNP did
not
> + * succeed
> + */
> + if (gotgctl & DWC_GCTL_DEV_HNP_ENA)
> + pr_err("Device Not Connected / "
> + "Responding\n");
> + /*
> + * If Session End Detected the B-Cable has been
> + * disconnected. Reset PCD and Gadget driver to a
> + * clean state.
> + */
> + pcd_stop(core_if);
> + }
> + gotgctl = 0;
> + gotgctl |= DWC_GCTL_DEV_HNP_ENA;
> + dwc_modify32(global_regs + DWC_GOTGCTL, gotgctl, 0);
> + }
> + if (gotgint & DWC_GINT_SES_REQSUC) {
> + gotgctl = dwc_read32(global_regs + DWC_GOTGCTL);
> + if (gotgctl & DWC_GCTL_SES_REQ_SUCCESS) {
> + if (core_if->core_params->phy_type ==
> + DWC_PHY_TYPE_PARAM_FS &&
> + core_if->core_params->i2c_enable) {
> + core_if->srp_success = 1;
> + } else {
> + pcd_resume(core_if);
> +
> + /* Clear Session Request */
> + gotgctl = 0;
> + gotgctl |= DWC_GCTL_SES_REQ;
> + dwc_modify32(global_regs + DWC_GOTGCTL,
> + gotgctl, 0);
> + }
> + }
> + }
> + if (gotgint & DWC_GINT_HST_NEGSUC) {
> + /*
> + * Print statements during the HNP interrupt handling can
cause
> + * it to fail.
> + */
> + gotgctl = dwc_read32(global_regs + DWC_GOTGCTL);
> + if (gotgctl & DWC_GCTL_HOST_NEG_SUCCES) {
> + if (dwc_otg_is_host_mode(core_if)) {
> + core_if->xceiv->state = OTG_STATE_B_HOST;
> + /*
> + * Need to disable SOF interrupt
immediately.
> + * When switching from device to host, the
PCD
> + * interrupt handler won't handle the
> + * interrupt if host mode is already set.
The
> + * HCD interrupt handler won't get called
if
> + * the HCD state is HALT. This means that
the
> + * interrupt does not get handled and
Linux
> + * complains loudly.
> + */
> + gintmsk = 0;
> + gintmsk |= DWC_INTMSK_STRT_OF_FRM;
> + dwc_modify32(global_regs + DWC_GINTMSK,
> + gintmsk, 0);
> + pcd_stop(core_if);
> + /* Initialize the Core for Host mode. */
> + hcd_start(core_if);
> + core_if->xceiv->state = OTG_STATE_B_HOST;
> + }
> + } else {
> + gotgctl = 0;
> + gotgctl |= DWC_GCTL_HNP_REQ;
> + gotgctl |= DWC_GCTL_DEV_HNP_ENA;
> + dwc_modify32(global_regs + DWC_GOTGCTL, gotgctl,
0);
> +
> + pr_err("Device Not Connected / Responding\n");
> + }
> + }
> + if (gotgint & DWC_GINT_HST_NEGDET) {
> + /*
> + * The disconnect interrupt is set at the same time as
> + * Host Negotiation Detected. During the mode
> + * switch all interrupts are cleared so the disconnect
> + * interrupt handler will not get executed.
> + */
> + if (dwc_otg_is_device_mode(core_if)) {
> + hcd_disconnect(core_if);
> + pcd_start(core_if);
> + core_if->xceiv->state = OTG_STATE_A_PERIPHERAL;
> + } else {
> + /*
> + * Need to disable SOF interrupt immediately. When
> + * switching from device to host, the PCD
interrupt
> + * handler won't handle the interrupt if host mode
is
> + * already set. The HCD interrupt handler won't
get
> + * called if the HCD state is HALT. This means
that
> + * the interrupt does not get handled and Linux
> + * complains loudly.
> + */
> + gintmsk = 0;
> + gintmsk |= DWC_INTMSK_STRT_OF_FRM;
> + dwc_modify32(global_regs + DWC_GINTMSK, gintmsk,
0);
> + pcd_stop(core_if);
> + hcd_start(core_if);
> + core_if->xceiv->state = OTG_STATE_A_HOST;
> + }
> + }
> + if (gotgint & DWC_GINT_DEVTOUT)
> + pr_info(" ++OTG Interrupt: A-Device Timeout "
"Change++\n");
> + if (gotgint & DWC_GINT_DEBDONE)
> + pr_info(" ++OTG Interrupt: Debounce Done++\n");
> +
> + /* Clear GOTGINT */
> + dwc_write32(global_regs + DWC_GOTGINT, gotgint);
> + return 1;
> +}
> +
> +/*
> + * Wakeup Workqueue implementation
> + */
> +static void port_otg_wqfunc(struct work_struct *work)
> +{
> + struct core_if *core_if = container_of(work, struct core_if,
> + usb_port_otg);
> + ulong global_regs = core_if->core_global_regs;
> + u32 count = 0;
> + u32 gotgctl;
> +
> + pr_info("%s\n", __func__);
> +
> + gotgctl = dwc_read32(global_regs + DWC_GOTGCTL);
> + if (gotgctl & DWC_GCTL_CONN_ID_STATUS) {
> + /*
> + * B-Device connector (device mode) wait for switch to
device
> + * mode.
> + */
> + while (!dwc_otg_is_device_mode(core_if) && ++count <=
10000) {
> + pr_info("Waiting for Peripheral Mode, "
> + "Mode=%s\n", dwc_otg_is_host_mode(core_if)
?
> + "Host" : "Peripheral");
> + msleep(100);
> + }
> + BUG_ON(count > 10000);
> + core_if->xceiv->state = OTG_STATE_B_PERIPHERAL;
> + dwc_otg_core_init(core_if);
> + dwc_otg_enable_global_interrupts(core_if);
> + pcd_start(core_if);
> + } else {
> + /*
> + * A-Device connector (host mode) wait for switch to host
> + * mode.
> + */
> + while (!dwc_otg_is_host_mode(core_if) && ++count <= 10000)
{
> + pr_info("Waiting for Host Mode, Mode=%s\n",
> + dwc_otg_is_host_mode(core_if) ?
> + "Host" : "Peripheral");
> + msleep(100);
> + }
> + BUG_ON(count > 10000);
> + core_if->xceiv->state = OTG_STATE_A_HOST;
> + dwc_otg_core_init(core_if);
> + dwc_otg_enable_global_interrupts(core_if);
> + hcd_start(core_if);
> + }
> +}
> +
> +/**
> + * This function handles the Connector ID Status Change Interrupt. It
> + * reads the OTG Interrupt Register (GOTCTL) to determine whether this
> + * is a Device to Host Mode transition or a Host Mode to Device
> + * Transition.
> + *
> + * This only occurs when the cable is connected/removed from the PHY
> + * connector.
> + */
> +static int dwc_otg_handle_conn_id_status_change_intr(struct core_if
*core_if)
> +{
> + u32 gintsts = 0;
> + u32 gintmsk = 0;
> + ulong global_regs = core_if->core_global_regs;
> +
> + /*
> + * Need to disable SOF interrupt immediately. If switching from
device
> + * to host, the PCD interrupt handler won't handle the interrupt
if
> + * host mode is already set. The HCD interrupt handler won't get
> + * called if the HCD state is HALT. This means that the interrupt
does
> + * not get handled and Linux complains loudly.
> + */
> + gintmsk |= DWC_INTSTS_STRT_OF_FRM;
> + dwc_modify32(global_regs + DWC_GINTMSK, gintmsk, 0);
> +
> + INIT_WORK(&core_if->usb_port_otg, port_otg_wqfunc);
> + schedule_work(&core_if->usb_port_otg);
> +
> + /* Set flag and clear interrupt */
> + gintsts |= DWC_INTSTS_CON_ID_STS_CHG;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> + return 1;
> +}
> +
> +/**
> + * This interrupt indicates that a device is initiating the Session
> + * Request Protocol to request the host to turn on bus power so a new
> + * session can begin. The handler responds by turning on bus power. If
> + * the DWC_otg controller is in low power mode, the handler brings the
> + * controller out of low power mode before turning on bus power.
> + */
> +static int dwc_otg_handle_session_req_intr(struct core_if *core_if)
> +{
> + u32 gintsts = 0;
> + ulong global_regs = core_if->core_global_regs;
> +
> + if (!dwc_has_feature(core_if, DWC_HOST_ONLY)) {
> + u32 hprt0;
> +
> + if (dwc_otg_is_device_mode(core_if)) {
> + pr_info("SRP: Device mode\n");
> + } else {
> + pr_info("SRP: Host mode\n");
> +
> + /* Turn on the port power bit. */
> + hprt0 = dwc_otg_read_hprt0(core_if);
> + hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 1);
> + dwc_write32(core_if->host_if->hprt0, hprt0);
> +
> + /*
> + * Start the Connection timer.
> + * A message can be displayed,
> + * if connect does not occur within 10 seconds.
> + */
> + hcd_session_start(core_if);
> + }
> + }
> + /* Clear interrupt */
> + gintsts |= DWC_INTSTS_NEW_SES_DET;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> + return 1;
> +}
> +
> +/**
> + * This interrupt indicates that the DWC_otg controller has detected a
> + * resume or remote wakeup sequence. If the DWC_otg controller is in
> + * low power mode, the handler must brings the controller out of low
> + * power mode. The controller automatically begins resume
> + * signaling. The handler schedules a time to stop resume signaling.
> + */
> +static int dwc_otg_handle_wakeup_detected_intr(struct core_if *core_if)
> +{
> + u32 gintsts = 0;
> + struct device_if *dev_if = core_if->dev_if;
> + ulong global_regs = core_if->core_global_regs;
Tabify the declarations ;
> +
> + if (dwc_otg_is_device_mode(core_if)) {
> + u32 dctl = 0;
> +
> + /* Clear the Remote Wakeup Signalling */
> + dctl = DEC_DCTL_REMOTE_WAKEUP_SIG(dctl, 1);
> + dwc_modify32(dev_if->dev_global_regs + DWC_DCTL, dctl, 0);
> +
> + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup)
> +
core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
> + } else {
> + u32 pcgcctl = 0;
> +
> + /* Restart the Phy Clock */
> + pcgcctl = DWC_PCGCCTL_STOP_CLK_SET(pcgcctl);
> + dwc_modify32(core_if->pcgcctl, pcgcctl, 0);
> + schedule_delayed_work(&core_if->usb_port_wakeup, 10);
> + }
> +
> + /* Clear interrupt */
> + gintsts |= DWC_INTSTS_WKP;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> + return 1;
> +}
> +
> +/**
> + * This interrupt indicates that a device has been disconnected from
> + * the root port.
> + */
> +static int dwc_otg_handle_disconnect_intr(struct core_if *core_if)
> +{
> + u32 gintsts = 0;
> + ulong global_regs = core_if->core_global_regs;
> +
> + if (!dwc_has_feature(core_if, DWC_HOST_ONLY)) {
> + if (core_if->xceiv->state == OTG_STATE_B_HOST) {
> + hcd_disconnect(core_if);
> + pcd_start(core_if);
> + core_if->xceiv->state = OTG_STATE_B_PERIPHERAL;
> + } else if (dwc_otg_is_device_mode(core_if)) {
> + u32 gotgctl;
> +
> + gotgctl = dwc_read32(global_regs + DWC_GOTGCTL);
> +
> + /*
> + * If HNP is in process, do nothing.
> + * The OTG "Host Negotiation Detected"
> + * interrupt will do the mode switch.
> + * Otherwise, since we are in device mode,
> + * disconnect and stop the HCD,
> + * then start the PCD.
> + */
> + if ((gotgctl) & DWC_GCTL_DEV_HNP_ENA) {
> + hcd_disconnect(core_if);
> + pcd_start(core_if);
> + core_if->xceiv->state =
OTG_STATE_B_PERIPHERAL;
> + }
> + } else if (core_if->xceiv->state == OTG_STATE_A_HOST) {
> + /* A-Cable still connected but device
disconnected. */
> + hcd_disconnect(core_if);
> + }
> + }
> + gintsts |= DWC_INTSTS_SES_DISCON_DET;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> + return 1;
> +}
> +
> +/**
> + * This interrupt indicates that SUSPEND state has been detected on
> + * the USB.
> + *
> + * For HNP the USB Suspend interrupt signals the change from
> + * "a_peripheral" to "a_host".
> + *
> + * When power management is enabled the core will be put in low power
> + * mode.
> + */
> +static int dwc_otg_handle_usb_suspend_intr(struct core_if *core_if)
> +{
> + u32 dsts = 0;
> + u32 gintsts = 0;
> + ulong global_regs = core_if->core_global_regs;
> + struct device_if *dev_if = core_if->dev_if;
Tabify the declarations ;
> +
> + if (dwc_otg_is_device_mode(core_if)) {
> + /*
> + * Check the Device status register to determine if the
Suspend
> + * state is active.
> + */
> + dsts = dwc_read32(dev_if->dev_global_regs + DWC_DSTS);
> + /* PCD callback for suspend. */
> + pcd_suspend(core_if);
> + } else {
> + if (core_if->xceiv->state == OTG_STATE_A_PERIPHERAL) {
> + /* Clear the a_peripheral flag, back to a_host. */
> + pcd_stop(core_if);
> + hcd_start(core_if);
> + core_if->xceiv->state = OTG_STATE_A_HOST;
> + }
> + }
> +
> + /* Clear interrupt */
> + gintsts |= DWC_INTMSK_USB_SUSP;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> + return 1;
> +}
> +
> +/**
> + * This function returns the Core Interrupt register.
> + *
> + * Although the Host Port interrupt (portintr) is documented as host
mode
> + * only, it appears to occur in device mode when Port Enable / Disable
Changed
> + * bit in HPRT0 is set. The code in dwc_otg_handle_common_intr checks
if in
> + * device mode and just clears the interrupt.
> + */
> +static inline u32 dwc_otg_read_common_intr(struct core_if *core_if)
> +{
> + u32 gintsts;
> + u32 gintmsk;
> + u32 gintmsk_common = 0;
> + ulong global_regs = core_if->core_global_regs;
> +
> + gintmsk_common |= DWC_INTMSK_WKP;
> + gintmsk_common |= DWC_INTMSK_NEW_SES_DET;
> + gintmsk_common |= DWC_INTMSK_CON_ID_STS_CHG;
> + gintmsk_common |= DWC_INTMSK_OTG;
> + gintmsk_common |= DWC_INTMSK_MODE_MISMTC;
> + gintmsk_common |= DWC_INTMSK_SES_DISCON_DET;
> + gintmsk_common |= DWC_INTMSK_USB_SUSP;
> + gintmsk_common |= DWC_INTMSK_HST_PORT;
> +
> + gintsts = dwc_read32(global_regs + DWC_GINTSTS);
> + gintmsk = dwc_read32(global_regs + DWC_GINTMSK);
> +
> + return (gintsts & gintmsk) & gintmsk_common;
> +}
> +
> +/**
> + * Common interrupt handler.
> + *
> + * The common interrupts are those that occur in both Host and Device
mode.
> + * This handler handles the following interrupts:
> + * - Mode Mismatch Interrupt
> + * - Disconnect Interrupt
> + * - OTG Interrupt
> + * - Connector ID Status Change Interrupt
> + * - Session Request Interrupt.
> + * - Resume / Remote Wakeup Detected Interrupt.
> + *
> + * - Host Port Interrupt. Although this interrupt is documented as
only
> + * occurring in Host mode, it also occurs in Device mode when Port
Enable /
> + * Disable Changed bit in HPRT0 is set. If it is seen here, while in
Device
> + * mode, the interrupt is just cleared.
> + *
> + */
> +int dwc_otg_handle_common_intr(struct core_if *core_if)
> +{
> + int retval = 0;
> + u32 gintsts;
> + ulong global_regs = core_if->core_global_regs;
> +
> + gintsts = dwc_otg_read_common_intr(core_if);
> +
> + if (gintsts & DWC_INTSTS_MODE_MISMTC)
> + retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
> + if (gintsts & DWC_INTSTS_OTG)
> + retval |= dwc_otg_handle_otg_intr(core_if);
> + if (gintsts & DWC_INTSTS_CON_ID_STS_CHG)
> + retval |=
dwc_otg_handle_conn_id_status_change_intr(core_if);
> + if (gintsts & DWC_INTSTS_SES_DISCON_DET)
> + retval |= dwc_otg_handle_disconnect_intr(core_if);
> + if (gintsts & DWC_INTSTS_NEW_SES_DET)
> + retval |= dwc_otg_handle_session_req_intr(core_if);
> + if (gintsts & DWC_INTSTS_WKP)
> + retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
> + if (gintsts & DWC_INTMSK_USB_SUSP)
> + retval |= dwc_otg_handle_usb_suspend_intr(core_if);
> +
> + if ((gintsts & DWC_INTSTS_HST_PORT) &&
> + dwc_otg_is_device_mode(core_if)) {
> + gintsts = 0;
> + gintsts |= DWC_INTSTS_HST_PORT;
> + dwc_write32(global_regs + DWC_GINTSTS, gintsts);
> + retval |= 1;
> + pr_info("RECEIVED PORTINT while in Device mode\n");
> + }
> +
> + return retval;
> +}
> --
> 1.6.1.rc3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the Linuxppc-dev
mailing list