aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h50
-rw-r--r--arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h377
-rw-r--r--drivers/usb/gadget/Kconfig14
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c3269
5 files changed, 3711 insertions, 0 deletions
diff --git a/arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h b/arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h
new file mode 100644
index 00000000000..36a85f5000c
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h
@@ -0,0 +1,50 @@
+/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - USB2.0 Highspeed/OtG device PHY registers
+ *
+ * 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.
+*/
+
+/* Note, this is a seperate header file as some of the clock framework
+ * needs to touch this if the clk_48m is used as the USB OHCI or other
+ * peripheral source.
+*/
+
+#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H
+#define __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H __FILE__
+
+/* S3C64XX_PA_USB_HSPHY */
+
+#define S3C_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY)
+
+#define S3C_PHYPWR S3C_HSOTG_PHYREG(0x00)
+#define SRC_PHYPWR_OTG_DISABLE (1 << 4)
+#define SRC_PHYPWR_ANALOG_POWERDOWN (1 << 3)
+#define SRC_PHYPWR_FORCE_SUSPEND (1 << 1)
+
+#define S3C_PHYCLK S3C_HSOTG_PHYREG(0x04)
+#define S3C_PHYCLK_MODE_USB11 (1 << 6)
+#define S3C_PHYCLK_EXT_OSC (1 << 5)
+#define S3C_PHYCLK_CLK_FORCE (1 << 4)
+#define S3C_PHYCLK_ID_PULL (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT (0)
+#define S3C_PHYCLK_CLKSEL_48M (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M (0x3 << 0)
+
+#define S3C_RSTCON S3C_HSOTG_PHYREG(0x08)
+#define S3C_RSTCON_PHYCLK (1 << 2)
+#define S3C_RSTCON_HCLK (1 << 2)
+#define S3C_RSTCON_PHY (1 << 0)
+
+#define S3C_PHYTUNE S3C_HSOTG_PHYREG(0x20)
+
+#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H */
diff --git a/arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h b/arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
new file mode 100644
index 00000000000..8d18d9d4d14
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
@@ -0,0 +1,377 @@
+/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - USB2.0 Highspeed/OtG device block registers
+ *
+ * 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.
+*/
+
+#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_H
+#define __PLAT_S3C64XX_REGS_USB_HSOTG_H __FILE__
+
+#define S3C_HSOTG_REG(x) (x)
+
+#define S3C_GOTGCTL S3C_HSOTG_REG(0x000)
+#define S3C_GOTGCTL_BSESVLD (1 << 19)
+#define S3C_GOTGCTL_ASESVLD (1 << 18)
+#define S3C_GOTGCTL_DBNC_SHORT (1 << 17)
+#define S3C_GOTGCTL_CONID_B (1 << 16)
+#define S3C_GOTGCTL_DEVHNPEN (1 << 11)
+#define S3C_GOTGCTL_HSSETHNPEN (1 << 10)
+#define S3C_GOTGCTL_HNPREQ (1 << 9)
+#define S3C_GOTGCTL_HSTNEGSCS (1 << 8)
+#define S3C_GOTGCTL_SESREQ (1 << 1)
+#define S3C_GOTGCTL_SESREQSCS (1 << 0)
+
+#define S3C_GOTGINT S3C_HSOTG_REG(0x004)
+#define S3C_GOTGINT_DbnceDone (1 << 19)
+#define S3C_GOTGINT_ADevTOUTChg (1 << 18)
+#define S3C_GOTGINT_HstNegDet (1 << 17)
+#define S3C_GOTGINT_HstnegSucStsChng (1 << 9)
+#define S3C_GOTGINT_SesReqSucStsChng (1 << 8)
+#define S3C_GOTGINT_SesEndDet (1 << 2)
+
+#define S3C_GAHBCFG S3C_HSOTG_REG(0x008)
+#define S3C_GAHBCFG_PTxFEmpLvl (1 << 8)
+#define S3C_GAHBCFG_NPTxFEmpLvl (1 << 7)
+#define S3C_GAHBCFG_DMAEn (1 << 5)
+#define S3C_GAHBCFG_HBstLen_MASK (0xf << 1)
+#define S3C_GAHBCFG_HBstLen_SHIFT (1)
+#define S3C_GAHBCFG_HBstLen_Single (0x0 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr (0x1 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr4 (0x3 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr8 (0x5 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr16 (0x7 << 1)
+#define S3C_GAHBCFG_GlblIntrEn (1 << 0)
+
+#define S3C_GUSBCFG S3C_HSOTG_REG(0x00C)
+#define S3C_GUSBCFG_PHYLPClkSel (1 << 15)
+#define S3C_GUSBCFG_HNPCap (1 << 9)
+#define S3C_GUSBCFG_SRPCap (1 << 8)
+#define S3C_GUSBCFG_PHYIf16 (1 << 3)
+#define S3C_GUSBCFG_TOutCal_MASK (0x7 << 0)
+#define S3C_GUSBCFG_TOutCal_SHIFT (0)
+#define S3C_GUSBCFG_TOutCal_LIMIT (0x7)
+#define S3C_GUSBCFG_TOutCal(_x) ((_x) << 0)
+
+#define S3C_GRSTCTL S3C_HSOTG_REG(0x010)
+
+#define S3C_GRSTCTL_AHBIdle (1 << 31)
+#define S3C_GRSTCTL_DMAReq (1 << 30)
+#define S3C_GRSTCTL_TxFNum_MASK (0x1f << 6)
+#define S3C_GRSTCTL_TxFNum_SHIFT (6)
+#define S3C_GRSTCTL_TxFNum_LIMIT (0x1f)
+#define S3C_GRSTCTL_TxFNum(_x) ((_x) << 6)
+#define S3C_GRSTCTL_TxFFlsh (1 << 5)
+#define S3C_GRSTCTL_RxFFlsh (1 << 4)
+#define S3C_GRSTCTL_INTknQFlsh (1 << 3)
+#define S3C_GRSTCTL_FrmCntrRst (1 << 2)
+#define S3C_GRSTCTL_HSftRst (1 << 1)
+#define S3C_GRSTCTL_CSftRst (1 << 0)
+
+#define S3C_GINTSTS S3C_HSOTG_REG(0x014)
+#define S3C_GINTMSK S3C_HSOTG_REG(0x018)
+
+#define S3C_GINTSTS_WkUpInt (1 << 31)
+#define S3C_GINTSTS_SessReqInt (1 << 30)
+#define S3C_GINTSTS_DisconnInt (1 << 29)
+#define S3C_GINTSTS_ConIDStsChng (1 << 28)
+#define S3C_GINTSTS_PTxFEmp (1 << 26)
+#define S3C_GINTSTS_HChInt (1 << 25)
+#define S3C_GINTSTS_PrtInt (1 << 24)
+#define S3C_GINTSTS_FetSusp (1 << 22)
+#define S3C_GINTSTS_incompIP (1 << 21)
+#define S3C_GINTSTS_IncomplSOIN (1 << 20)
+#define S3C_GINTSTS_OEPInt (1 << 19)
+#define S3C_GINTSTS_IEPInt (1 << 18)
+#define S3C_GINTSTS_EPMis (1 << 17)
+#define S3C_GINTSTS_EOPF (1 << 15)
+#define S3C_GINTSTS_ISOutDrop (1 << 14)
+#define S3C_GINTSTS_EnumDone (1 << 13)
+#define S3C_GINTSTS_USBRst (1 << 12)
+#define S3C_GINTSTS_USBSusp (1 << 11)
+#define S3C_GINTSTS_ErlySusp (1 << 10)
+#define S3C_GINTSTS_GOUTNakEff (1 << 7)
+#define S3C_GINTSTS_GINNakEff (1 << 6)
+#define S3C_GINTSTS_NPTxFEmp (1 << 5)
+#define S3C_GINTSTS_RxFLvl (1 << 4)
+#define S3C_GINTSTS_SOF (1 << 3)
+#define S3C_GINTSTS_OTGInt (1 << 2)
+#define S3C_GINTSTS_ModeMis (1 << 1)
+#define S3C_GINTSTS_CurMod_Host (1 << 0)
+
+#define S3C_GRXSTSR S3C_HSOTG_REG(0x01C)
+#define S3C_GRXSTSP S3C_HSOTG_REG(0x020)
+
+#define S3C_GRXSTS_FN_MASK (0x7f << 25)
+#define S3C_GRXSTS_FN_SHIFT (25)
+
+#define S3C_GRXSTS_PktSts_MASK (0xf << 17)
+#define S3C_GRXSTS_PktSts_SHIFT (17)
+#define S3C_GRXSTS_PktSts_GlobalOutNAK (0x1 << 17)
+#define S3C_GRXSTS_PktSts_OutRX (0x2 << 17)
+#define S3C_GRXSTS_PktSts_OutDone (0x3 << 17)
+#define S3C_GRXSTS_PktSts_SetupDone (0x4 << 17)
+#define S3C_GRXSTS_PktSts_SetupRX (0x6 << 17)
+
+#define S3C_GRXSTS_DPID_MASK (0x3 << 15)
+#define S3C_GRXSTS_DPID_SHIFT (15)
+#define S3C_GRXSTS_ByteCnt_MASK (0x7ff << 4)
+#define S3C_GRXSTS_ByteCnt_SHIFT (4)
+#define S3C_GRXSTS_EPNum_MASK (0xf << 0)
+#define S3C_GRXSTS_EPNum_SHIFT (0)
+
+#define S3C_GRXFSIZ S3C_HSOTG_REG(0x024)
+
+#define S3C_GNPTXFSIZ S3C_HSOTG_REG(0x028)
+
+#define S3C_GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16)
+#define S3C_GNPTXFSIZ_NPTxFDep_SHIFT (16)
+#define S3C_GNPTXFSIZ_NPTxFDep_LIMIT (0xffff)
+#define S3C_GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16)
+#define S3C_GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0)
+#define S3C_GNPTXFSIZ_NPTxFStAddr_SHIFT (0)
+#define S3C_GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff)
+#define S3C_GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0)
+
+#define S3C_GNPTXSTS S3C_HSOTG_REG(0x02C)
+
+#define S3C_GNPTXSTS_NPtxQTop_MASK (0x7f << 24)
+#define S3C_GNPTXSTS_NPtxQTop_SHIFT (24)
+
+#define S3C_GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16)
+#define S3C_GNPTXSTS_NPTxQSpcAvail_SHIFT (16)
+#define S3C_GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff)
+
+#define S3C_GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0)
+#define S3C_GNPTXSTS_NPTxFSpcAvail_SHIFT (0)
+#define S3C_GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff)
+
+
+#define S3C_HPTXFSIZ S3C_HSOTG_REG(0x100)
+
+#define S3C_DPTXFSIZn(_a) S3C_HSOTG_REG(0x104 + (((_a) - 1) * 4))
+
+#define S3C_DPTXFSIZn_DPTxFSize_MASK (0xffff << 16)
+#define S3C_DPTXFSIZn_DPTxFSize_SHIFT (16)
+#define S3C_DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff)
+#define S3C_DPTXFSIZn_DPTxFSize_LIMIT (0xffff)
+#define S3C_DPTXFSIZn_DPTxFSize(_x) ((_x) << 16)
+
+#define S3C_DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0)
+#define S3C_DPTXFSIZn_DPTxFStAddr_SHIFT (0)
+
+/* Device mode registers */
+#define S3C_DCFG S3C_HSOTG_REG(0x800)
+
+#define S3C_DCFG_EPMisCnt_MASK (0x1f << 18)
+#define S3C_DCFG_EPMisCnt_SHIFT (18)
+#define S3C_DCFG_EPMisCnt_LIMIT (0x1f)
+#define S3C_DCFG_EPMisCnt(_x) ((_x) << 18)
+
+#define S3C_DCFG_PerFrInt_MASK (0x3 << 11)
+#define S3C_DCFG_PerFrInt_SHIFT (11)
+#define S3C_DCFG_PerFrInt_LIMIT (0x3)
+#define S3C_DCFG_PerFrInt(_x) ((_x) << 11)
+
+#define S3C_DCFG_DevAddr_MASK (0x7f << 4)
+#define S3C_DCFG_DevAddr_SHIFT (4)
+#define S3C_DCFG_DevAddr_LIMIT (0x7f)
+#define S3C_DCFG_DevAddr(_x) ((_x) << 4)
+
+#define S3C_DCFG_NZStsOUTHShk (1 << 2)
+
+#define S3C_DCFG_DevSpd_MASK (0x3 << 0)
+#define S3C_DCFG_DevSpd_SHIFT (0)
+#define S3C_DCFG_DevSpd_HS (0x0 << 0)
+#define S3C_DCFG_DevSpd_FS (0x1 << 0)
+#define S3C_DCFG_DevSpd_LS (0x2 << 0)
+#define S3C_DCFG_DevSpd_FS48 (0x3 << 0)
+
+#define S3C_DCTL S3C_HSOTG_REG(0x804)
+
+#define S3C_DCTL_PWROnPrgDone (1 << 11)
+#define S3C_DCTL_CGOUTNak (1 << 10)
+#define S3C_DCTL_SGOUTNak (1 << 9)
+#define S3C_DCTL_CGNPInNAK (1 << 8)
+#define S3C_DCTL_SGNPInNAK (1 << 7)
+#define S3C_DCTL_TstCtl_MASK (0x7 << 4)
+#define S3C_DCTL_TstCtl_SHIFT (4)
+#define S3C_DCTL_GOUTNakSts (1 << 3)
+#define S3C_DCTL_GNPINNakSts (1 << 2)
+#define S3C_DCTL_SftDiscon (1 << 1)
+#define S3C_DCTL_RmtWkUpSig (1 << 0)
+
+#define S3C_DSTS S3C_HSOTG_REG(0x808)
+
+#define S3C_DSTS_SOFFN_MASK (0x3fff << 8)
+#define S3C_DSTS_SOFFN_SHIFT (8)
+#define S3C_DSTS_SOFFN_LIMIT (0x3fff)
+#define S3C_DSTS_SOFFN(_x) ((_x) << 8)
+#define S3C_DSTS_ErraticErr (1 << 3)
+#define S3C_DSTS_EnumSpd_MASK (0x3 << 1)
+#define S3C_DSTS_EnumSpd_SHIFT (1)
+#define S3C_DSTS_EnumSpd_HS (0x0 << 1)
+#define S3C_DSTS_EnumSpd_FS (0x1 << 1)
+#define S3C_DSTS_EnumSpd_LS (0x2 << 1)
+#define S3C_DSTS_EnumSpd_FS48 (0x3 << 1)
+
+#define S3C_DSTS_SuspSts (1 << 0)
+
+#define S3C_DIEPMSK S3C_HSOTG_REG(0x810)
+
+#define S3C_DIEPMSK_INEPNakEffMsk (1 << 6)
+#define S3C_DIEPMSK_INTknEPMisMsk (1 << 5)
+#define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4)
+#define S3C_DIEPMSK_TimeOUTMsk (1 << 3)
+#define S3C_DIEPMSK_AHBErrMsk (1 << 2)
+#define S3C_DIEPMSK_EPDisbldMsk (1 << 1)
+#define S3C_DIEPMSK_XferComplMsk (1 << 0)
+
+#define S3C_DOEPMSK S3C_HSOTG_REG(0x814)
+
+#define S3C_DOEPMSK_Back2BackSetup (1 << 6)
+#define S3C_DOEPMSK_OUTTknEPdisMsk (1 << 4)
+#define S3C_DOEPMSK_SetupMsk (1 << 3)
+#define S3C_DOEPMSK_AHBErrMsk (1 << 2)
+#define S3C_DOEPMSK_EPDisbldMsk (1 << 1)
+#define S3C_DOEPMSK_XferComplMsk (1 << 0)
+
+#define S3C_DAINT S3C_HSOTG_REG(0x818)
+#define S3C_DAINTMSK S3C_HSOTG_REG(0x81C)
+
+#define S3C_DAINT_OutEP_SHIFT (16)
+#define S3C_DAINT_OutEP(x) (1 << ((x) + 16))
+#define S3C_DAINT_InEP(x) (1 << (x))
+
+#define S3C_DTKNQR1 S3C_HSOTG_REG(0x820)
+#define S3C_DTKNQR2 S3C_HSOTG_REG(0x824)
+#define S3C_DTKNQR3 S3C_HSOTG_REG(0x830)
+#define S3C_DTKNQR4 S3C_HSOTG_REG(0x834)
+
+#define S3C_DVBUSDIS S3C_HSOTG_REG(0x828)
+#define S3C_DVBUSPULSE S3C_HSOTG_REG(0x82C)
+
+#define S3C_DIEPCTL0 S3C_HSOTG_REG(0x900)
+#define S3C_DOEPCTL0 S3C_HSOTG_REG(0xB00)
+#define S3C_DIEPCTL(_a) S3C_HSOTG_REG(0x900 + ((_a) * 0x20))
+#define S3C_DOEPCTL(_a) S3C_HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting differenct for EP0
+*/
+#define S3C_D0EPCTL_MPS_MASK (0x3 << 0)
+#define S3C_D0EPCTL_MPS_SHIFT (0)
+#define S3C_D0EPCTL_MPS_64 (0x0 << 0)
+#define S3C_D0EPCTL_MPS_32 (0x1 << 0)
+#define S3C_D0EPCTL_MPS_16 (0x2 << 0)
+#define S3C_D0EPCTL_MPS_8 (0x3 << 0)
+
+#define S3C_DxEPCTL_EPEna (1 << 31)
+#define S3C_DxEPCTL_EPDis (1 << 30)
+#define S3C_DxEPCTL_SetD1PID (1 << 29)
+#define S3C_DxEPCTL_SetOddFr (1 << 29)
+#define S3C_DxEPCTL_SetD0PID (1 << 28)
+#define S3C_DxEPCTL_SetEvenFr (1 << 28)
+#define S3C_DxEPCTL_SNAK (1 << 27)
+#define S3C_DxEPCTL_CNAK (1 << 26)
+#define S3C_DxEPCTL_TxFNum_MASK (0xf << 22)
+#define S3C_DxEPCTL_TxFNum_SHIFT (22)
+#define S3C_DxEPCTL_TxFNum_LIMIT (0xf)
+#define S3C_DxEPCTL_TxFNum(_x) ((_x) << 22)
+
+#define S3C_DxEPCTL_Stall (1 << 21)
+#define S3C_DxEPCTL_Snp (1 << 20)
+#define S3C_DxEPCTL_EPType_MASK (0x3 << 18)
+#define S3C_DxEPCTL_EPType_SHIFT (18)
+#define S3C_DxEPCTL_EPType_Control (0x0 << 18)
+#define S3C_DxEPCTL_EPType_Iso (0x1 << 18)
+#define S3C_DxEPCTL_EPType_Bulk (0x2 << 18)
+#define S3C_DxEPCTL_EPType_Intterupt (0x3 << 18)
+
+#define S3C_DxEPCTL_NAKsts (1 << 17)
+#define S3C_DxEPCTL_DPID (1 << 16)
+#define S3C_DxEPCTL_EOFrNum (1 << 16)
+#define S3C_DxEPCTL_USBActEp (1 << 15)
+#define S3C_DxEPCTL_NextEp_MASK (0xf << 11)
+#define S3C_DxEPCTL_NextEp_SHIFT (11)
+#define S3C_DxEPCTL_NextEp_LIMIT (0xf)
+#define S3C_DxEPCTL_NextEp(_x) ((_x) << 11)
+
+#define S3C_DxEPCTL_MPS_MASK (0x7ff << 0)
+#define S3C_DxEPCTL_MPS_SHIFT (0)
+#define S3C_DxEPCTL_MPS_LIMIT (0x7ff)
+#define S3C_DxEPCTL_MPS(_x) ((_x) << 0)
+
+#define S3C_DIEPINT(_a) S3C_HSOTG_REG(0x908 + ((_a) * 0x20))
+#define S3C_DOEPINT(_a) S3C_HSOTG_REG(0xB08 + ((_a) * 0x20))
+
+#define S3C_DxEPINT_INEPNakEff (1 << 6)
+#define S3C_DxEPINT_Back2BackSetup (1 << 6)
+#define S3C_DxEPINT_INTknEPMis (1 << 5)
+#define S3C_DxEPINT_INTknTXFEmp (1 << 4)
+#define S3C_DxEPINT_OUTTknEPdis (1 << 4)
+#define S3C_DxEPINT_Timeout (1 << 3)
+#define S3C_DxEPINT_Setup (1 << 3)
+#define S3C_DxEPINT_AHBErr (1 << 2)
+#define S3C_DxEPINT_EPDisbld (1 << 1)
+#define S3C_DxEPINT_XferCompl (1 << 0)
+
+#define S3C_DIEPTSIZ0 S3C_HSOTG_REG(0x910)
+
+#define S3C_DIEPTSIZ0_PktCnt_MASK (0x3 << 19)
+#define S3C_DIEPTSIZ0_PktCnt_SHIFT (19)
+#define S3C_DIEPTSIZ0_PktCnt_LIMIT (0x3)
+#define S3C_DIEPTSIZ0_PktCnt(_x) ((_x) << 19)
+
+#define S3C_DIEPTSIZ0_XferSize_MASK (0x7f << 0)
+#define S3C_DIEPTSIZ0_XferSize_SHIFT (0)
+#define S3C_DIEPTSIZ0_XferSize_LIMIT (0x7f)
+#define S3C_DIEPTSIZ0_XferSize(_x) ((_x) << 0)
+
+
+#define DOEPTSIZ0 S3C_HSOTG_REG(0xB10)
+#define S3C_DOEPTSIZ0_SUPCnt_MASK (0x3 << 29)
+#define S3C_DOEPTSIZ0_SUPCnt_SHIFT (29)
+#define S3C_DOEPTSIZ0_SUPCnt_LIMIT (0x3)
+#define S3C_DOEPTSIZ0_SUPCnt(_x) ((_x) << 29)
+
+#define S3C_DOEPTSIZ0_PktCnt (1 << 19)
+#define S3C_DOEPTSIZ0_XferSize_MASK (0x7f << 0)
+#define S3C_DOEPTSIZ0_XferSize_SHIFT (0)
+
+#define S3C_DIEPTSIZ(_a) S3C_HSOTG_REG(0x910 + ((_a) * 0x20))
+#define S3C_DOEPTSIZ(_a) S3C_HSOTG_REG(0xB10 + ((_a) * 0x20))
+
+#define S3C_DxEPTSIZ_MC_MASK (0x3 << 29)
+#define S3C_DxEPTSIZ_MC_SHIFT (29)
+#define S3C_DxEPTSIZ_MC_LIMIT (0x3)
+#define S3C_DxEPTSIZ_MC(_x) ((_x) << 29)
+
+#define S3C_DxEPTSIZ_PktCnt_MASK (0x3ff << 19)
+#define S3C_DxEPTSIZ_PktCnt_SHIFT (19)
+#define S3C_DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff)
+#define S3C_DxEPTSIZ_PktCnt_LIMIT (0x3ff)
+#define S3C_DxEPTSIZ_PktCnt(_x) ((_x) << 19)
+
+#define S3C_DxEPTSIZ_XferSize_MASK (0x7ffff << 0)
+#define S3C_DxEPTSIZ_XferSize_SHIFT (0)
+#define S3C_DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff)
+#define S3C_DxEPTSIZ_XferSize_LIMIT (0x7ffff)
+#define S3C_DxEPTSIZ_XferSize(_x) ((_x) << 0)
+
+
+#define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
+#define S3C_DOEPDMA(_a) S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
+
+#define S3C_EPFIFO(_a) S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5de9b4f2171..924bb7a1cec 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -272,6 +272,20 @@ config USB_PXA27X
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_S3C_HSOTG
+ boolean "S3C HS/OtG USB Device controller"
+ depends on S3C_DEV_USB_HSOTG
+ select USB_GADGET_S3C_HSOTG_PIO
+ help
+ The Samsung S3C64XX USB2.0 high-speed gadget controller
+ integrated into the S3C64XX series SoC.
+
+config USB_S3C_HSOTG
+ tristate
+ depends on USB_GADGET_S3C_HSOTG
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_S3C2410
boolean "S3C2410 USB Device Controller"
depends on ARCH_S3C2410
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c3fe06396b7..9be2fbd6f5c 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -25,6 +25,7 @@ endif
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
+obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
new file mode 100644
index 00000000000..50c71aae2cc
--- /dev/null
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -0,0 +1,3269 @@
+/* linux/drivers/usb/gadget/s3c-hsotg.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * S3C USB2.0 High-speed / OtG driver
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/regs-usb-hsotg.h>
+#include <plat/regs-sys.h>
+#include <plat/udc-hs.h>
+
+#define DMA_ADDR_INVALID (~((dma_addr_t)0))
+
+/* EP0_MPS_LIMIT
+ *
+ * Unfortunately there seems to be a limit of the amount of data that can
+ * be transfered by IN transactions on EP0. This is either 127 bytes or 3
+ * packets (which practially means 1 packet and 63 bytes of data) when the
+ * MPS is set to 64.
+ *
+ * This means if we are wanting to move >127 bytes of data, we need to
+ * split the transactions up, but just doing one packet at a time does
+ * not work (this may be an implicit DATA0 PID on first packet of the
+ * transaction) and doing 2 packets is outside the controller's limits.
+ *
+ * If we try to lower the MPS size for EP0, then no transfers work properly
+ * for EP0, and the system will fail basic enumeration. As no cause for this
+ * has currently been found, we cannot support any large IN transfers for
+ * EP0.
+ */
+#define EP0_MPS_LIMIT 64
+
+struct s3c_hsotg;
+struct s3c_hsotg_req;
+
+/**
+ * struct s3c_hsotg_ep - driver endpoint definition.
+ * @ep: The gadget layer representation of the endpoint.
+ * @name: The driver generated name for the endpoint.
+ * @queue: Queue of requests for this endpoint.
+ * @parent: Reference back to the parent device structure.
+ * @req: The current request that the endpoint is processing. This is
+ * used to indicate an request has been loaded onto the endpoint
+ * and has yet to be completed (maybe due to data move, or simply
+ * awaiting an ack from the core all the data has been completed).
+ * @debugfs: File entry for debugfs file for this endpoint.
+ * @lock: State lock to protect contents of endpoint.
+ * @dir_in: Set to true if this endpoint is of the IN direction, which
+ * means that it is sending data to the Host.
+ * @index: The index for the endpoint registers.
+ * @name: The name array passed to the USB core.
+ * @halted: Set if the endpoint has been halted.
+ * @periodic: Set if this is a periodic ep, such as Interrupt
+ * @sent_zlp: Set if we've sent a zero-length packet.
+ * @total_data: The total number of data bytes done.
+ * @fifo_size: The size of the FIFO (for periodic IN endpoints)
+ * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
+ * @last_load: The offset of data for the last start of request.
+ * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN
+ *
+ * This is the driver's state for each registered enpoint, allowing it
+ * to keep track of transactions that need doing. Each endpoint has a
+ * lock to protect the state, to try and avoid using an overall lock
+ * for the host controller as much as possible.
+ *
+ * For periodic IN endpoints, we have fifo_size and fifo_load to try
+ * and keep track of the amount of data in the periodic FIFO for each
+ * of these as we don't have a status register that tells us how much
+ * is in each of them.
+ */
+struct s3c_hsotg_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct s3c_hsotg *parent;
+ struct s3c_hsotg_req *req;
+ struct dentry *debugfs;
+
+ spinlock_t lock;
+
+ unsigned long total_data;
+ unsigned int size_loaded;
+ unsigned int last_load;
+ unsigned int fifo_load;
+ unsigned short fifo_size;
+
+ unsigned char dir_in;
+ unsigned char index;
+
+ unsigned int halted:1;
+ unsigned int periodic:1;
+ unsigned int sent_zlp:1;
+
+ char name[10];
+};
+
+#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */
+
+/**
+ * struct s3c_hsotg - driver state.
+ * @dev: The parent device supplied to the probe function
+ * @driver: USB gadget driver
+ * @plat: The platform specific configuration data.
+ * @regs: The memory area mapped for accessing registers.
+ * @regs_res: The resource that was allocated when claiming register space.
+ * @irq: The IRQ number we are using
+ * @debug_root: root directrory for debugfs.
+ * @debug_file: main status file for debugfs.
+ * @debug_fifo: FIFO status file for debugfs.
+ * @ep0_reply: Request used for ep0 reply.
+ * @ep0_buff: Buffer for EP0 reply data, if needed.
+ * @ctrl_buff: Buffer for EP0 control requests.
+ * @ctrl_req: Request for EP0 control packets.
+ * @eps: The endpoints being supplied to the gadget framework
+ */
+struct s3c_hsotg {
+ struct device *dev;
+ struct usb_gadget_driver *driver;
+ struct s3c_hsotg_plat *plat;
+
+ void __iomem *regs;
+ struct resource *regs_res;
+ int irq;
+
+ struct dentry *debug_root;
+ struct dentry *debug_file;
+ struct dentry *debug_fifo;
+
+ struct usb_request *ep0_reply;
+ struct usb_request *ctrl_req;
+ u8 ep0_buff[8];
+ u8 ctrl_buff[8];
+
+ struct usb_gadget gadget;
+ struct s3c_hsotg_ep eps[];
+};
+
+/**
+ * struct s3c_hsotg_req - data transfer request
+ * @req: The USB gadget request
+ * @queue: The list of requests for the endpoint this is queued for.
+ * @in_progress: Has already had size/packets written to core
+ * @mapped: DMA buffer for this request has been mapped via dma_map_single().
+ */
+struct s3c_hsotg_req {
+ struct usb_request req;
+ struct list_head queue;
+ unsigned char in_progress;
+ unsigned char mapped;
+};
+
+/* conversion functions */
+static inline struct s3c_hsotg_req *our_req(struct usb_request *req)
+{
+ return container_of(req, struct s3c_hsotg_req, req);
+}
+
+static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct s3c_hsotg_ep, ep);
+}
+
+static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct s3c_hsotg, gadget);
+}
+
+static inline void __orr32(void __iomem *ptr, u32 val)
+{
+ writel(readl(ptr) | val, ptr);
+}
+
+static inline void __bic32(void __iomem *ptr, u32 val)
+{
+ writel(readl(ptr) & ~val, ptr);
+}
+
+/* forward decleration of functions */
+static void s3c_hsotg_dump(struct s3c_hsotg *hsotg);
+
+/**
+ * using_dma - return the DMA status of the driver.
+ * @hsotg: The driver state.
+ *
+ * Return true if we're using DMA.
+ *
+ * Currently, we have the DMA support code worked into everywhere
+ * that needs it, but the AMBA DMA implementation in the hardware can
+ * only DMA from 32bit aligned addresses. This means that gadgets such
+ * as the CDC Ethernet cannot work as they often pass packets which are
+ * not 32bit aligned.
+ *
+ * Unfortunately the choice to use DMA or not is global to the controller
+ * and seems to be only settable when the controller is being put through
+ * a core reset. This means we either need to fix the gadgets to take
+ * account of DMA alignment, or add bounce buffers (yuerk).
+ *
+ * Until this issue is sorted out, we always return 'false'.
+ */
+static inline bool using_dma(struct s3c_hsotg *hsotg)
+{
+ return false; /* support is not complete */
+}
+
+/**
+ * s3c_hsotg_en_gsint - enable one or more of the general interrupt
+ * @hsotg: The device state
+ * @ints: A bitmask of the interrupts to enable
+ */
+static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
+{
+ u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ u32 new_gsintmsk;
+
+ new_gsintmsk = gsintmsk | ints;
+
+ if (new_gsintmsk != gsintmsk) {
+ dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
+ writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+ }
+}
+
+/**
+ * s3c_hsotg_disable_gsint - disable one or more of the general interrupt
+ * @hsotg: The device state
+ * @ints: A bitmask of the interrupts to enable
+ */
+static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
+{
+ u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ u32 new_gsintmsk;
+
+ new_gsintmsk = gsintmsk & ~ints;
+
+ if (new_gsintmsk != gsintmsk)
+ writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+}
+
+/**
+ * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq
+ * @hsotg: The device state
+ * @ep: The endpoint index
+ * @dir_in: True if direction is in.
+ * @en: The enable value, true to enable
+ *
+ * Set or clear the mask for an individual endpoint's interrupt
+ * request.
+ */
+static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
+ unsigned int ep, unsigned int dir_in,
+ unsigned int en)
+{
+ unsigned long flags;
+ u32 bit = 1 << ep;
+ u32 daint;
+
+ if (!dir_in)
+ bit <<= 16;
+
+ local_irq_save(flags);
+ daint = readl(hsotg->regs + S3C_DAINTMSK);
+ if (en)
+ daint |= bit;
+ else
+ daint &= ~bit;
+ writel(daint, hsotg->regs + S3C_DAINTMSK);
+ local_irq_restore(flags);
+}
+
+/**
+ * s3c_hsotg_init_fifo - initialise non-periodic FIFOs
+ * @hsotg: The device instance.
+ */
+static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
+{
+ /* the ryu 2.6.24 release ahs
+ writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
+ writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
+ S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
+ hsotg->regs + S3C_GNPTXFSIZ);
+ */
+
+ /* set FIFO sizes to 2048/0x1C0 */
+
+ writel(2048, hsotg->regs + S3C_GRXFSIZ);
+ writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
+ S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
+ hsotg->regs + S3C_GNPTXFSIZ);
+}
+
+/**
+ * @ep: USB endpoint to allocate request for.
+ * @flags: Allocation flags
+ *
+ * Allocate a new USB request structure appropriate for the specified endpoint
+ */
+struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags)
+{
+ struct s3c_hsotg_req *req;
+
+ req = kzalloc(sizeof(struct s3c_hsotg_req), flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ req->req.dma = DMA_ADDR_INVALID;
+ return &req->req;
+}
+
+/**
+ * is_ep_periodic - return true if the endpoint is in periodic mode.
+ * @hs_ep: The endpoint to query.
+ *
+ * Returns true if the endpoint is in periodic mode, meaning it is being
+ * used for an Interrupt or ISO transfer.
+ */
+static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep)
+{
+ return hs_ep->periodic;
+}
+
+/**
+ * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint for the request
+ * @hs_req: The request being processed.
+ *
+ * This is the reverse of s3c_hsotg_map_dma(), called for the completion
+ * of a request to ensure the buffer is ready for access by the caller.
+*/
+static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
+ struct s3c_hsotg_ep *hs_ep,
+ struct s3c_hsotg_req *hs_req)
+{
+ struct usb_request *req = &hs_req->req;
+ enum dma_data_direction dir;
+
+ dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ /* ignore this if we're not moving any data */
+ if (hs_req->req.length == 0)
+ return;
+
+ if (hs_req->mapped) {
+ /* we mapped this, so unmap and remove the dma */
+
+ dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
+
+ req->dma = DMA_ADDR_INVALID;
+ hs_req->mapped = 0;
+ } else {
+ dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+ }
+}
+
+/**
+ * s3c_hsotg_write_fifo - write packet Data to the TxFIFO
+ * @hsotg: The controller state.
+ * @hs_ep: The endpoint we're going to write for.
+ * @hs_req: The request to write data for.
+ *
+ * This is called when the TxFIFO has some space in it to hold a new
+ * transmission and we have something to give it. The actual setup of
+ * the data size is done elsewhere, so all we have to do is to actually
+ * write the data.
+ *
+ * The return value is zero if there is more space (or nothing was done)
+ * otherwise -ENOSPC is returned if the FIFO space was used up.
+ *
+ * This routine is only needed for PIO
+*/
+static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
+ struct s3c_hsotg_ep *hs_ep,
+ struct s3c_hsotg_req *hs_req)
+{
+ bool periodic = is_ep_periodic(hs_ep);
+ u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS);
+ int buf_pos = hs_req->req.actual;
+ int to_write = hs_ep->size_loaded;
+ void *data;
+ int can_write;
+ int pkt_round;
+
+ to_write -= (buf_pos - hs_ep->last_load);
+
+ /* if there's nothing to write, get out early */
+ if (to_write == 0)
+ return 0;
+
+ if (periodic) {
+ u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+ int size_left;
+ int size_done;
+
+ /* work out how much data was loaded so we can calculate
+ * how much data is left in the fifo. */
+
+ size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+
+ dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n",
+ __func__, size_left,
+ hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size);
+
+ /* how much of the data has moved */
+ size_done = hs_ep->size_loaded - size_left;
+
+ /* how much data is left in the fifo */
+ can_write = hs_ep->fifo_load - size_done;
+ dev_dbg(hsotg->dev, "%s: => can_write1=%d\n",
+ __func__, can_write);
+
+ can_write = hs_ep->fifo_size - can_write;
+ dev_dbg(hsotg->dev, "%s: => can_write2=%d\n",
+ __func__, can_write);
+
+ if (can_write <= 0) {
+ s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ return -ENOSPC;
+ }
+ } else {
+ if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
+ dev_dbg(hsotg->dev,
+ "%s: no queue slots available (0x%08x)\n",
+ __func__, gnptxsts);
+
+ s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+ return -ENOSPC;
+ }
+
+ can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
+ }
+
+ dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n",
+ __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket);
+
+ /* limit to 512 bytes of data, it seems at least on the non-periodic
+ * FIFO, requests of >512 cause the endpoint to get stuck with a
+ * fragment of the end of the transfer in it.
+ */
+ if (can_write > 512)
+ can_write = 512;
+
+ /* see if we can write data */
+
+ if (to_write > can_write) {
+ to_write = can_write;
+ pkt_round = to_write % hs_ep->ep.maxpacket;
+
+ /* Not sure, but we probably shouldn't be writing partial
+ * packets into the FIFO, so round the write down to an
+ * exact number of packets.
+ *
+ * Note, we do not currently check to see if we can ever
+ * write a full packet or not to the FIFO.
+ */
+
+ if (pkt_round)
+ to_write -= pkt_round;
+
+ /* enable correct FIFO interrupt to alert us when there
+ * is more room left. */
+
+ s3c_hsotg_en_gsint(hsotg,
+ periodic ? S3C_GINTSTS_PTxFEmp :
+ S3C_GINTSTS_NPTxFEmp);
+ }
+
+ dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n",
+ to_write, hs_req->req.length, can_write, buf_pos);
+
+ if (to_write <= 0)
+ return -ENOSPC;
+
+ hs_req->req.actual = buf_pos + to_write;
+ hs_ep->total_data += to_write;
+
+ if (periodic)
+ hs_ep->fifo_load += to_write;
+
+ to_write = DIV_ROUND_UP(to_write, 4);
+ data = hs_req->req.buf + buf_pos;
+
+ writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write);
+
+ return (to_write >= can_write) ? -ENOSPC : 0;
+}
+
+/**
+ * get_ep_limit - get the maximum data legnth for this endpoint
+ * @hs_ep: The endpoint
+ *
+ * Return the maximum data that can be queued in one go on a given endpoint
+ * so that transfers that are too long can be split.
+ */
+static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
+{
+ int index = hs_ep->index;
+ unsigned maxsize;
+ unsigned maxpkt;
+
+ if (index != 0) {
+ maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
+ maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
+ } else {
+ if (hs_ep->dir_in) {
+ /* maxsize = S3C_DIEPTSIZ0_XferSize_LIMIT + 1; */
+ maxsize = 64+64+1;
+ maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
+ } else {
+ maxsize = 0x3f;
+ maxpkt = 2;
+ }
+ }
+
+ /* we made the constant loading easier above by using +1 */
+ maxpkt--;
+ maxsize--;
+
+ /* constrain by packet count if maxpkts*pktsize is greater
+ * than the length register size. */
+
+ if ((maxpkt * hs_ep->ep.maxpacket) < maxsize)
+ maxsize = maxpkt * hs_ep->ep.maxpacket;
+
+ return maxsize;
+}
+
+/**
+ * s3c_hsotg_start_req - start a USB request from an endpoint's queue
+ * @hsotg: The controller state.
+ * @hs_ep: The endpoint to process a request for
+ * @hs_req: The request to start.
+ * @continuing: True if we are doing more for the current request.
+ *
+ * Start the given request running by setting the endpoint registers
+ * appr