aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/pch_udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/pch_udc.c')
-rw-r--r--drivers/usb/gadget/pch_udc.c2947
1 files changed, 2947 insertions, 0 deletions
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
new file mode 100644
index 00000000000..0c8dd81dddc
--- /dev/null
+++ b/drivers/usb/gadget/pch_udc.c
@@ -0,0 +1,2947 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Address offset of Registers */
+#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */
+
+#define UDC_EPCTL_ADDR 0x00 /* Endpoint control */
+#define UDC_EPSTS_ADDR 0x04 /* Endpoint status */
+#define UDC_BUFIN_FRAMENUM_ADDR 0x08 /* buffer size in / frame number out */
+#define UDC_BUFOUT_MAXPKT_ADDR 0x0C /* buffer size out / maxpkt in */
+#define UDC_SUBPTR_ADDR 0x10 /* setup buffer pointer */
+#define UDC_DESPTR_ADDR 0x14 /* Data descriptor pointer */
+#define UDC_CONFIRM_ADDR 0x18 /* Write/Read confirmation */
+
+#define UDC_DEVCFG_ADDR 0x400 /* Device configuration */
+#define UDC_DEVCTL_ADDR 0x404 /* Device control */
+#define UDC_DEVSTS_ADDR 0x408 /* Device status */
+#define UDC_DEVIRQSTS_ADDR 0x40C /* Device irq status */
+#define UDC_DEVIRQMSK_ADDR 0x410 /* Device irq mask */
+#define UDC_EPIRQSTS_ADDR 0x414 /* Endpoint irq status */
+#define UDC_EPIRQMSK_ADDR 0x418 /* Endpoint irq mask */
+#define UDC_DEVLPM_ADDR 0x41C /* LPM control / status */
+#define UDC_CSR_BUSY_ADDR 0x4f0 /* UDC_CSR_BUSY Status register */
+#define UDC_SRST_ADDR 0x4fc /* SOFT RESET register */
+#define UDC_CSR_ADDR 0x500 /* USB_DEVICE endpoint register */
+
+/* Endpoint control register */
+/* Bit position */
+#define UDC_EPCTL_MRXFLUSH (1 << 12)
+#define UDC_EPCTL_RRDY (1 << 9)
+#define UDC_EPCTL_CNAK (1 << 8)
+#define UDC_EPCTL_SNAK (1 << 7)
+#define UDC_EPCTL_NAK (1 << 6)
+#define UDC_EPCTL_P (1 << 3)
+#define UDC_EPCTL_F (1 << 1)
+#define UDC_EPCTL_S (1 << 0)
+#define UDC_EPCTL_ET_SHIFT 4
+/* Mask patern */
+#define UDC_EPCTL_ET_MASK 0x00000030
+/* Value for ET field */
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+/* Endpoint status register */
+/* Bit position */
+#define UDC_EPSTS_XFERDONE (1 << 27)
+#define UDC_EPSTS_RSS (1 << 26)
+#define UDC_EPSTS_RCS (1 << 25)
+#define UDC_EPSTS_TXEMPTY (1 << 24)
+#define UDC_EPSTS_TDC (1 << 10)
+#define UDC_EPSTS_HE (1 << 9)
+#define UDC_EPSTS_MRXFIFO_EMP (1 << 8)
+#define UDC_EPSTS_BNA (1 << 7)
+#define UDC_EPSTS_IN (1 << 6)
+#define UDC_EPSTS_OUT_SHIFT 4
+/* Mask patern */
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_ALL_CLR_MASK 0x1F0006F0
+/* Value for OUT field */
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_DATA 1
+
+/* Device configuration register */
+/* Bit position */
+#define UDC_DEVCFG_CSR_PRG (1 << 17)
+#define UDC_DEVCFG_SP (1 << 3)
+/* SPD Valee */
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+
+/* Device control register */
+/* Bit position */
+#define UDC_DEVCTL_THLEN_SHIFT 24
+#define UDC_DEVCTL_BRLEN_SHIFT 16
+#define UDC_DEVCTL_CSR_DONE (1 << 13)
+#define UDC_DEVCTL_SD (1 << 10)
+#define UDC_DEVCTL_MODE (1 << 9)
+#define UDC_DEVCTL_BREN (1 << 8)
+#define UDC_DEVCTL_THE (1 << 7)
+#define UDC_DEVCTL_DU (1 << 4)
+#define UDC_DEVCTL_TDE (1 << 3)
+#define UDC_DEVCTL_RDE (1 << 2)
+#define UDC_DEVCTL_RES (1 << 0)
+
+/* Device status register */
+/* Bit position */
+#define UDC_DEVSTS_TS_SHIFT 18
+#define UDC_DEVSTS_ENUM_SPEED_SHIFT 13
+#define UDC_DEVSTS_ALT_SHIFT 8
+#define UDC_DEVSTS_INTF_SHIFT 4
+#define UDC_DEVSTS_CFG_SHIFT 0
+/* Mask patern */
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+/* value for maximum speed for SPEED field */
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+#define UDC_DEVSTS_ENUM_SPEED_LOW 2
+#define UDC_DEVSTS_ENUM_SPEED_FULLX 3
+
+/* Device irq register */
+/* Bit position */
+#define UDC_DEVINT_RWKP (1 << 7)
+#define UDC_DEVINT_ENUM (1 << 6)
+#define UDC_DEVINT_SOF (1 << 5)
+#define UDC_DEVINT_US (1 << 4)
+#define UDC_DEVINT_UR (1 << 3)
+#define UDC_DEVINT_ES (1 << 2)
+#define UDC_DEVINT_SI (1 << 1)
+#define UDC_DEVINT_SC (1 << 0)
+/* Mask patern */
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint irq register */
+/* Bit position */
+#define UDC_EPINT_IN_SHIFT 0
+#define UDC_EPINT_OUT_SHIFT 16
+#define UDC_EPINT_IN_EP0 (1 << 0)
+#define UDC_EPINT_OUT_EP0 (1 << 16)
+/* Mask patern */
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+
+/* UDC_CSR_BUSY Status register */
+/* Bit position */
+#define UDC_CSR_BUSY (1 << 0)
+
+/* SOFT RESET register */
+/* Bit position */
+#define UDC_PSRST (1 << 1)
+#define UDC_SRST (1 << 0)
+
+/* USB_DEVICE endpoint register */
+/* Bit position */
+#define UDC_CSR_NE_NUM_SHIFT 0
+#define UDC_CSR_NE_DIR_SHIFT 4
+#define UDC_CSR_NE_TYPE_SHIFT 5
+#define UDC_CSR_NE_CFG_SHIFT 7
+#define UDC_CSR_NE_INTF_SHIFT 11
+#define UDC_CSR_NE_ALT_SHIFT 15
+#define UDC_CSR_NE_MAX_PKT_SHIFT 19
+/* Mask patern */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+
+#define PCH_UDC_CSR(ep) (UDC_CSR_ADDR + ep*4)
+#define PCH_UDC_EPINT(in, num)\
+ (1 << (num + (in ? UDC_EPINT_IN_SHIFT : UDC_EPINT_OUT_SHIFT)))
+
+/* Index of endpoint */
+#define UDC_EP0IN_IDX 0
+#define UDC_EP0OUT_IDX 1
+#define UDC_EPIN_IDX(ep) (ep * 2)
+#define UDC_EPOUT_IDX(ep) (ep * 2 + 1)
+#define PCH_UDC_EP0 0
+#define PCH_UDC_EP1 1
+#define PCH_UDC_EP2 2
+#define PCH_UDC_EP3 3
+
+/* Number of endpoint */
+#define PCH_UDC_EP_NUM 32 /* Total number of EPs (16 IN,16 OUT) */
+#define PCH_UDC_USED_EP_NUM 4 /* EP number of EP's really used */
+/* Length Value */
+#define PCH_UDC_BRLEN 0x0F /* Burst length */
+#define PCH_UDC_THLEN 0x1F /* Threshold length */
+/* Value of EP Buffer Size */
+#define UDC_EP0IN_BUFF_SIZE 64
+#define UDC_EPIN_BUFF_SIZE 512
+#define UDC_EP0OUT_BUFF_SIZE 64
+#define UDC_EPOUT_BUFF_SIZE 512
+/* Value of EP maximum packet size */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+#define UDC_BULK_MAX_PKT_SIZE 512
+
+/* DMA */
+#define DMA_DIR_RX 1 /* DMA for data receive */
+#define DMA_DIR_TX 2 /* DMA for data transmit */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define UDC_DMA_MAXPACKET 65536 /* maximum packet size for DMA */
+
+/**
+ * struct pch_udc_data_dma_desc - Structure to hold DMA descriptor information
+ * for data
+ * @status: Status quadlet
+ * @reserved: Reserved
+ * @dataptr: Buffer descriptor
+ * @next: Next descriptor
+ */
+struct pch_udc_data_dma_desc {
+ u32 status;
+ u32 reserved;
+ u32 dataptr;
+ u32 next;
+};
+
+/**
+ * struct pch_udc_stp_dma_desc - Structure to hold DMA descriptor information
+ * for control data
+ * @status: Status
+ * @reserved: Reserved
+ * @data12: First setup word
+ * @data34: Second setup word
+ */
+struct pch_udc_stp_dma_desc {
+ u32 status;
+ u32 reserved;
+ struct usb_ctrlrequest request;
+} __attribute((packed));
+
+/* DMA status definitions */
+/* Buffer status */
+#define PCH_UDC_BUFF_STS 0xC0000000
+#define PCH_UDC_BS_HST_RDY 0x00000000
+#define PCH_UDC_BS_DMA_BSY 0x40000000
+#define PCH_UDC_BS_DMA_DONE 0x80000000
+#define PCH_UDC_BS_HST_BSY 0xC0000000
+/* Rx/Tx Status */
+#define PCH_UDC_RXTX_STS 0x30000000
+#define PCH_UDC_RTS_SUCC 0x00000000
+#define PCH_UDC_RTS_DESERR 0x10000000
+#define PCH_UDC_RTS_BUFERR 0x30000000
+/* Last Descriptor Indication */
+#define PCH_UDC_DMA_LAST 0x08000000
+/* Number of Rx/Tx Bytes Mask */
+#define PCH_UDC_RXTX_BYTES 0x0000ffff
+
+/**
+ * struct pch_udc_cfg_data - Structure to hold current configuration
+ * and interface information
+ * @cur_cfg: current configuration in use
+ * @cur_intf: current interface in use
+ * @cur_alt: current alt interface in use
+ */
+struct pch_udc_cfg_data {
+ u16 cur_cfg;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/**
+ * struct pch_udc_ep - Structure holding a PCH USB device Endpoint information
+ * @ep: embedded ep request
+ * @td_stp_phys: for setup request
+ * @td_data_phys: for data request
+ * @td_stp: for setup request
+ * @td_data: for data request
+ * @dev: reference to device struct
+ * @offset_addr: offset address of ep register
+ * @desc: for this ep
+ * @queue: queue for requests
+ * @num: endpoint number
+ * @in: endpoint is IN
+ * @halted: endpoint halted?
+ * @epsts: Endpoint status
+ */
+struct pch_udc_ep {
+ struct usb_ep ep;
+ dma_addr_t td_stp_phys;
+ dma_addr_t td_data_phys;
+ struct pch_udc_stp_dma_desc *td_stp;
+ struct pch_udc_data_dma_desc *td_data;
+ struct pch_udc_dev *dev;
+ unsigned long offset_addr;
+ const struct usb_endpoint_descriptor *desc;
+ struct list_head queue;
+ unsigned num:5,
+ in:1,
+ halted:1;
+ unsigned long epsts;
+};
+
+/**
+ * struct pch_udc_dev - Structure holding complete information
+ * of the PCH USB device
+ * @gadget: gadget driver data
+ * @driver: reference to gadget driver bound
+ * @pdev: reference to the PCI device
+ * @ep: array of endpoints
+ * @lock: protects all state
+ * @active: enabled the PCI device
+ * @stall: stall requested
+ * @prot_stall: protcol stall requested
+ * @irq_registered: irq registered with system
+ * @mem_region: device memory mapped
+ * @registered: driver regsitered with system
+ * @suspended: driver in suspended state
+ * @connected: gadget driver associated
+ * @set_cfg_not_acked: pending acknowledgement 4 setup
+ * @waiting_zlp_ack: pending acknowledgement 4 ZLP
+ * @data_requests: DMA pool for data requests
+ * @stp_requests: DMA pool for setup requests
+ * @dma_addr: DMA pool for received
+ * @ep0out_buf: Buffer for DMA
+ * @setup_data: Received setup data
+ * @phys_addr: of device memory
+ * @base_addr: for mapped device memory
+ * @irq: IRQ line for the device
+ * @cfg_data: current cfg, intf, and alt in use
+ */
+struct pch_udc_dev {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct pci_dev *pdev;
+ struct pch_udc_ep ep[PCH_UDC_EP_NUM];
+ spinlock_t lock; /* protects all state */
+ unsigned active:1,
+ stall:1,
+ prot_stall:1,
+ irq_registered:1,
+ mem_region:1,
+ registered:1,
+ suspended:1,
+ connected:1,
+ set_cfg_not_acked:1,
+ waiting_zlp_ack:1;
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+ dma_addr_t dma_addr;
+ unsigned long ep0out_buf[64];
+ struct usb_ctrlrequest setup_data;
+ unsigned long phys_addr;
+ void __iomem *base_addr;
+ unsigned irq;
+ struct pch_udc_cfg_data cfg_data;
+};
+
+#define PCH_UDC_PCI_BAR 1
+#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
+
+static const char ep0_string[] = "ep0in";
+static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */
+struct pch_udc_dev *pch_udc; /* pointer to device object */
+
+static int speed_fs;
+module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
+MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
+
+/**
+ * struct pch_udc_request - Structure holding a PCH USB device request packet
+ * @req: embedded ep request
+ * @td_data_phys: phys. address
+ * @td_data: first dma desc. of chain
+ * @td_data_last: last dma desc. of chain
+ * @queue: associated queue
+ * @dma_going: DMA in progress for request
+ * @dma_mapped: DMA memory mapped for request
+ * @dma_done: DMA completed for request
+ * @chain_len: chain length
+ */
+struct pch_udc_request {
+ struct usb_request req;
+ dma_addr_t td_data_phys;
+ struct pch_udc_data_dma_desc *td_data;
+ struct pch_udc_data_dma_desc *td_data_last;
+ struct list_head queue;
+ unsigned dma_going:1,
+ dma_mapped:1,
+ dma_done:1;
+ unsigned chain_len;
+};
+
+static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg)
+{
+ return ioread32(dev->base_addr + reg);
+}
+
+static inline void pch_udc_writel(struct pch_udc_dev *dev,
+ unsigned long val, unsigned long reg)
+{
+ iowrite32(val, dev->base_addr + reg);
+}
+
+static inline void pch_udc_bit_set(struct pch_udc_dev *dev,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_writel(dev, pch_udc_readl(dev, reg) | bitmask, reg);
+}
+
+static inline void pch_udc_bit_clr(struct pch_udc_dev *dev,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_writel(dev, pch_udc_readl(dev, reg) & ~(bitmask), reg);
+}
+
+static inline u32 pch_udc_ep_readl(struct pch_udc_ep *ep, unsigned long reg)
+{
+ return ioread32(ep->dev->base_addr + ep->offset_addr + reg);
+}
+
+static inline void pch_udc_ep_writel(struct pch_udc_ep *ep,
+ unsigned long val, unsigned long reg)
+{
+ iowrite32(val, ep->dev->base_addr + ep->offset_addr + reg);
+}
+
+static inline void pch_udc_ep_bit_set(struct pch_udc_ep *ep,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_ep_writel(ep, pch_udc_ep_readl(ep, reg) | bitmask, reg);
+}
+
+static inline void pch_udc_ep_bit_clr(struct pch_udc_ep *ep,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_ep_writel(ep, pch_udc_ep_readl(ep, reg) & ~(bitmask), reg);
+}
+
+/**
+ * pch_udc_csr_busy() - Wait till idle.
+ * @dev: Reference to pch_udc_dev structure
+ */
+static void pch_udc_csr_busy(struct pch_udc_dev *dev)
+{
+ unsigned int count = 200;
+
+ /* Wait till idle */
+ while ((pch_udc_readl(dev, UDC_CSR_BUSY_ADDR) & UDC_CSR_BUSY)
+ && --count)
+ cpu_relax();
+ if (!count)
+ dev_err(&dev->pdev->dev, "%s: wait error\n", __func__);
+}
+
+/**
+ * pch_udc_write_csr() - Write the command and status registers.
+ * @dev: Reference to pch_udc_dev structure
+ * @val: value to be written to CSR register
+ * @addr: address of CSR register
+ */
+static void pch_udc_write_csr(struct pch_udc_dev *dev, unsigned long val,
+ unsigned int ep)
+{
+ unsigned long reg = PCH_UDC_CSR(ep);
+
+ pch_udc_csr_busy(dev); /* Wait till idle */
+ pch_udc_writel(dev, val, reg);
+ pch_udc_csr_busy(dev); /* Wait till idle */
+}
+
+/**
+ * pch_udc_read_csr() - Read the command and status registers.
+ * @dev: Reference to pch_udc_dev structure
+ * @addr: address of CSR register
+ *
+ * Return codes: content of CSR register
+ */
+static u32 pch_udc_read_csr(struct pch_udc_dev *dev, unsigned int ep)
+{
+ unsigned long reg = PCH_UDC_CSR(ep);
+
+ pch_udc_csr_busy(dev); /* Wait till idle */
+ pch_udc_readl(dev, reg); /* Dummy read */
+ pch_udc_csr_busy(dev); /* Wait till idle */
+ return pch_udc_readl(dev, reg);
+}
+
+/**
+ * pch_udc_rmt_wakeup() - Initiate for remote wakeup
+ * @dev: Reference to pch_udc_dev structure
+ */
+static inline void pch_udc_rmt_wakeup(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+ mdelay(1);
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
+ * pch_udc_get_frame() - Get the current frame from device status register
+ * @dev: Reference to pch_udc_dev structure
+ * Retern current frame
+ */
+static inline int pch_udc_get_frame(struct pch_udc_dev *dev)
+{
+ u32 frame = pch_udc_readl(dev, UDC_DEVSTS_ADDR);
+ return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_SHIFT;
+}
+
+/**
+ * pch_udc_clear_selfpowered() - Clear the self power control
+ * @dev: Reference to pch_udc_regs structure
+ */
+static inline void pch_udc_clear_selfpowered(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_clr(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_SP);
+}
+
+/**
+ * pch_udc_set_selfpowered() - Set the self power control
+ * @dev: Reference to pch_udc_regs structure
+ */
+static inline void pch_udc_set_selfpowered(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_SP);
+}
+
+/**
+ * pch_udc_set_disconnect() - Set the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ */
+static inline void pch_udc_set_disconnect(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+}
+
+/**
+ * pch_udc_clear_disconnect() - Clear the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ */
+static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
+{
+ /* Clear the disconnect */
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+ mdelay(1);
+ /* Resume USB signalling */
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
+ * pch_udc_vbus_session() - set or clearr the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ * @is_active: Parameter specifying the action
+ * 0: indicating VBUS power is ending
+ * !0: indicating VBUS power is starting
+ */
+static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
+ int is_active)
+{
+ if (is_active)
+ pch_udc_clear_disconnect(dev);
+ else
+ pch_udc_set_disconnect(dev);
+}
+
+/**
+ * pch_udc_ep_set_stall() - Set the stall of endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static void pch_udc_ep_set_stall(struct pch_udc_ep *ep)
+{
+ if (ep->in) {
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F);
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S);
+ } else {
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S);
+ }
+}
+
+/**
+ * pch_udc_ep_clear_stall() - Clear the stall of endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_clear_stall(struct pch_udc_ep *ep)
+{
+ /* Clear the stall */
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S);
+ /* Clear NAK by writing CNAK */
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK);
+}
+
+/**
+ * pch_udc_ep_set_trfr_type() - Set the transfer type of endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @type: Type of endpoint
+ */
+static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep,
+ u8 type)
+{
+ pch_udc_ep_writel(ep, ((type << UDC_EPCTL_ET_SHIFT) &
+ UDC_EPCTL_ET_MASK), UDC_EPCTL_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @buf_size: The buffer size
+ */
+static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,
+ u32 buf_size, u32 ep_in)
+{
+ u32 data;
+ if (ep_in) {
+ data = pch_udc_ep_readl(ep, UDC_BUFIN_FRAMENUM_ADDR);
+ data = (data & 0xffff0000) | (buf_size & 0xffff);
+ pch_udc_ep_writel(ep, data, UDC_BUFIN_FRAMENUM_ADDR);
+ } else {
+ data = pch_udc_ep_readl(ep, UDC_BUFOUT_MAXPKT_ADDR);
+ data = (buf_size << 16) | (data & 0xffff);
+ pch_udc_ep_writel(ep, data, UDC_BUFOUT_MAXPKT_ADDR);
+ }
+}
+
+/**
+ * pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @pkt_size: The packet size
+ */
+static void pch_udc_ep_set_maxpkt(struct pch_udc_ep *ep, u32 pkt_size)
+{
+ u32 data = pch_udc_ep_readl(ep, UDC_BUFOUT_MAXPKT_ADDR);
+ data = (data & 0xffff0000) | (pkt_size & 0xffff);
+ pch_udc_ep_writel(ep, data, UDC_BUFOUT_MAXPKT_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_subptr() - Set the Setup buffer pointer for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @addr: Address of the register
+ */
+static inline void pch_udc_ep_set_subptr(struct pch_udc_ep *ep, u32 addr)
+{
+ pch_udc_ep_writel(ep, addr, UDC_SUBPTR_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_ddptr() - Set the Data descriptor pointer for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @addr: Address of the register
+ */
+static inline void pch_udc_ep_set_ddptr(struct pch_udc_ep *ep, u32 addr)
+{
+ pch_udc_ep_writel(ep, addr, UDC_DESPTR_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_pd() - Set the poll demand bit for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_set_pd(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_P);
+}
+
+/**
+ * pch_udc_ep_set_rrdy() - Set the receive ready bit for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_set_rrdy(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_RRDY);
+}
+
+/**
+ * pch_udc_ep_clear_rrdy() - Clear the receive ready bit for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_clear_rrdy(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_RRDY);
+}
+
+/**
+ * pch_udc_set_dma() - Set the 'TDE' or RDE bit of device control
+ * register depending on the direction specified
+ * @dev: Reference to structure of type pch_udc_regs
+ * @dir: whether Tx or Rx
+ * DMA_DIR_RX: Receive
+ * DMA_DIR_TX: Transmit
+ */
+static inline void pch_udc_set_dma(struct pch_udc_dev *dev, int dir)
+{
+ if (dir == DMA_DIR_RX)
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RDE);
+ else if (dir == DMA_DIR_TX)
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_TDE);
+}
+
+/**
+ * pch_udc_clear_dma() - Clear the 'TDE' or RDE bit of device control
+ * register depending on the direction specified
+ * @dev: Reference to structure of type pch_udc_regs
+ * @dir: Whether Tx or Rx
+ * DMA_DIR_RX: Receive
+ * DMA_DIR_TX: Transmit
+ */
+static inline void pch_udc_clear_dma(struct pch_udc_dev *dev, int dir)
+{
+ if (dir == DMA_DIR_RX)
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RDE);
+ else if (dir == DMA_DIR_TX)
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_TDE);
+}
+
+/**
+ * pch_udc_set_csr_done() - Set the device control register
+ * CSR done field (bit 13)
+ * @dev: reference to structure of type pch_udc_regs
+ */
+static inline void pch_udc_set_csr_done(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_CSR_DONE);
+}
+
+/**
+ * pch_udc_disable_interrupts() - Disables the specified interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to disable interrupts
+ */
+static inline void pch_udc_disable_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_enable_interrupts() - Enable the specified interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to enable interrupts
+ */
+static inline void pch_udc_enable_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_disable_ep_interrupts() - Disable endpoint interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to disable interrupts
+ */
+static inline void pch_udc_disable_ep_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_enable_ep_interrupts() - Enable endpoint interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to enable interrupts
+ */
+static inline void pch_udc_enable_ep_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_clr(dev, UDC_EPIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_read_device_interrupts() - Read the device interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * Retern The device interrupts
+ */
+static inline u32 pch_udc_read_device_interrupts(struct pch_udc_dev *dev)
+{
+ return pch_udc_readl(dev, UDC_DEVIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_write_device_interrupts() - Write device interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @val: The value to be written to interrupt register
+ */
+static inline void pch_udc_write_device_interrupts(struct pch_udc_dev *dev,
+ u32 val)
+{
+ pch_udc_writel(dev, val, UDC_DEVIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_read_ep_interrupts() - Read the endpoint interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * Retern The endpoint interrupt
+ */
+static inline u32 pch_udc_read_ep_interrupts(struct pch_udc_dev *dev)
+{
+ return pch_udc_readl(dev, UDC_EPIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_write_ep_interrupts() - Clear endpoint interupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @val: The value to be written to interrupt register
+ */
+static inline void pch_udc_write_ep_interrupts(struct pch_udc_dev *dev,
+ u32 val)
+{
+ pch_udc_writel(dev, val, UDC_EPIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_read_device_status() - Read the device status
+ * @dev: Reference to structure of type pch_udc_regs
+ * Retern The device status
+ */
+static inline u32 pch_udc_read_device_status(struct pch_udc_dev *dev)
+{
+ return pch_udc_readl(dev, UDC_DEVSTS_ADDR);
+}
+
+/**
+ * pch_udc_read_ep_control() - Read the endpoint control
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * Retern The endpoint control register value
+ */
+static inline u32 pch_udc_read_ep_control(struct pch_udc_ep *ep)
+{
+ return pch_udc_ep_readl(ep, UDC_EPCTL_ADDR);
+}
+
+/**
+ * pch_udc_clear_ep_control() - Clear the endpoint control register
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * Retern The endpoint control register value
+ */
+static inline void pch_udc_clear_ep_control(struct pch_udc_ep *ep)
+{
+ return pch_udc_ep_writel(ep, 0, UDC_EPCTL_ADDR);
+}
+
+/**
+ * pch_udc_read_ep_status() - Read the endpoint status
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * Retern The endpoint status
+ */
+static inline u32 pch_udc_read_ep_status(struct pch_udc_ep *ep)
+{
+ return pch_udc_ep_readl(ep, UDC_EPSTS_ADDR);
+}
+
+/**
+ * pch_udc_clear_ep_status() - Clear the endpoint status
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @stat: Endpoint status
+ */
+static inline void pch_udc_clear_ep_status(struct pch_udc_ep *ep,
+ u32 stat)
+{
+ return pch_udc_ep_writel(ep, stat, UDC_EPSTS_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_nak() - Set the bit 7 (SNAK field)
+ * of the endpoint control register
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_set_nak(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_SNAK);
+}
+
+/**
+ * pch_udc_ep_clear_nak() - Set the bit 8 (CNAK field)
+ * of the endpoint control register
+ * @ep: reference to structure of type pch_udc_ep_regs
+ */
+static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep)
+{
+ unsigned int loopcnt = 0;
+ struct pch_udc_dev *dev = ep->dev;
+
+ if (!(pch_udc_ep_readl(ep, UDC_EPCTL_ADDR) & UDC_EPCTL_NAK))
+ return;
+ if (!ep->in) {
+ loopcnt = 10000;
+ while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) &&
+ --loopcnt)
+ udelay(5);
+ if (!loopcnt)
+ dev_err(&dev->pdev->dev, "%s: RxFIFO not Empty\n",
+ __func__);
+ }
+ loopcnt = 10000;
+ while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_NAK) && --loopcnt) {
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK);
+ udelay(5);
+ }
+ if (!loopcnt)
+ dev_err(&dev->pdev->dev, "%s: Clear NAK not set for ep%d%s\n",
+ __func__, ep->num, (ep->in ? "in" : "out"));
+}
+
+/**
+ * pch_udc_ep_fifo_flush() - Flush the endpoint fifo
+ * @ep: reference to structure of type pch_udc_ep_regs
+ * @dir: direction of endpoint
+ * 0: endpoint is OUT
+ * !0: endpoint is IN
+ */
+static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir)
+{
+ unsigned int loopcnt = 0;
+ struct pch_udc_dev *dev = ep->dev;
+
+ if (dir) { /* IN ep */
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F);
+ return;
+ }
+
+ if (pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP)
+ return;
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
+ /* Wait for RxFIFO Empty */
+ loopcnt = 10000;
+ while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) &&
+ --loopcnt)
+ udelay(5);
+ if (!loopcnt)
+ dev_err(&dev->pdev->dev, "RxFIFO not Empty\n");
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
+}
+
+/**
+ * pch_udc_ep_enable() - This api enables endpoint
+ * @regs: Reference to structure pch_udc_ep_regs
+ * @desc: endpoint descriptor
+ */
+static void pch_udc_ep_enable(struct pch_udc_ep *ep,
+ struct pch_udc_cfg_data *cfg,
+ const struct usb_endpoint_descriptor *desc)
+{
+ u32 val = 0;
+ u32 buff_size = 0;
+
+ pch_udc_ep_set_trfr_type(ep, desc->bmAttributes);
+ if (ep->in)
+ buff_size = UDC_EPIN_BUFF_SIZE;
+ else
+ buff_size = UDC_EPOUT_BUFF_SIZE;
+ pch_udc_ep_set_bufsz(ep, buff_size, ep->in);
+ pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize));
+ pch_udc_ep_set_nak(ep);
+ pch_udc_ep_fifo_flush(ep, ep->in);
+ /* Configure the endpoint */
+ val = ep->num << UDC_CSR_NE_NUM_SHIFT | ep->in << UDC_CSR_NE_DIR_SHIFT |
+ ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) <<
+ UDC_CSR_NE_TYPE_SHIFT) |
+ (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) |
+ (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) |
+ (cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) |
+ le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT;
+
+ if (ep->in)
+ pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num));
+ else
+ pch_udc_write_csr(ep->dev, val, UDC_EPOUT_IDX(ep->num));
+}
+
+/**
+ * pch_udc_ep_disable() - This api disables endpoint
+ * @regs: Reference to structure pch_udc_ep_regs
+ */
+static void pch_udc_ep_disable(struct pch_udc_ep *ep)
+{
+ if (ep->in) {
+ /* flush the fifo */
+ pch_udc_ep_writel(ep, UDC_EPCTL_F, UDC_EPCTL_ADDR);
+ /* set NAK */
+ pch_udc_ep_writel(ep, UDC_EPCTL_SNAK, UDC_EPCTL_ADDR);
+ pch_udc_ep_bit_set(ep, UDC_EPSTS_ADDR, UDC_EPSTS_IN);
+ } else {
+ /* set NAK */
+ pch_udc_ep_writel(ep, UDC_EPCTL_SNAK, UDC_EPCTL_ADDR);
+ }
+ /* reset desc pointer */
+ pch_udc_ep_writel(ep, 0, UDC_DESPTR_ADDR);
+}
+
+/**
+ * pch_udc_wait_ep_stall() - Wait EP stall.
+ * @dev: Reference to pch_udc_dev structure
+ */
+static void pch_udc_wait_ep_stall(struct pch_udc_ep *ep)
+{
+ unsigned int count = 10000;
+
+ /* Wait till idle */
+ while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_S) && --count)
+ udelay(5);
+ if (!count)
+ dev_err(&ep->dev->pdev->dev, "%s: wait error\n", __func__);
+}
+
+/**
+ * pch_udc_init() - This API initializes usb device controller
+ * @dev: Rreference to pch_udc_regs structure
+ */
+static void pch_udc_init(struct pch_udc_dev *dev)
+{
+ if (NULL == dev) {
+ pr_err("%s: Invalid address\n", __func__);
+ return;
+ }
+ /* Soft Reset and Reset PHY */
+ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+ pch_udc_writel(dev, UDC_SRST | UDC_PSRST, UDC_SRST_ADDR);
+ mdelay(1);
+ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+ pch_udc_writel(dev, 0x00, UDC_SRST_ADDR);
+ mdelay(1);
+ /* mask and clear all device interrupts */
+ pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, UDC_DEVINT_MSK);
+ pch_udc_bit_set(dev, UDC_DEVIRQSTS_ADDR, UDC_DEVINT_MSK);
+
+ /* mask and clear all ep interrupts */
+ pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, UDC_EPINT_MSK_DISABLE_ALL);
+ pch_udc_bit_set(dev, UDC_EPIRQSTS_ADDR, UDC_EPINT_MSK_DISABLE_ALL);
+
+ /* enable dynamic CSR programmingi, self powered and device speed */
+ if (speed_fs)
+ pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_CSR_PRG |
+ UDC_DEVCFG_SP | UDC_DEVCFG_SPD_FS);
+ else /* defaul high speed */
+ pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_CSR_PRG |
+ UDC_DEVCFG_SP | UDC_DEVCFG_SPD_HS);
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR,
+ (PCH_UDC_THLEN << UDC_DEVCTL_THLEN_SHIFT) |
+ (PCH_UDC_BRLEN << UDC_DEVCTL_BRLEN_SHIFT) |
+ UDC_DEVCTL_MODE | UDC_DEVCTL_BREN |
+ UDC_DEVCTL_THE);
+}
+
+/**
+ * pch_udc_exit() - This API exit usb device controller
+ * @dev: Reference to pch_udc_regs structure
+ */
+static void pch_udc_exit(struct pch_udc_dev *dev)
+{
+ /* mask all device interrupts */
+ pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, UDC_DEVINT_MSK);
+ /* mask all ep interrupts */
+ pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, UDC_EPINT_MSK_DISABLE_ALL);
+ /* put device in disconnected state */
+ pch_udc_set_disconnect(dev);
+}
+
+/**
+ * pch_udc_pcd_get_frame() - This API is invoked to get the current frame number
+ * @gadget: Reference to the gadget driver
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_get_frame(struct usb_gadget *gadget)
+{
+ struct pch_udc_dev *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ return pch_udc_get_frame(dev);
+}
+
+/**
+ * pch_udc_pcd_wakeup() - This API is invoked to initiate a remote wakeup
+ * @gadget: Reference to the gadget driver
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_wakeup(struct usb_gadget *gadget)
+{
+ struct pch_udc_dev *dev;
+ unsigned long flags;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ spin_lock_irqsave(&dev->lock, flags);
+ pch_udc_rmt_wakeup(dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_selfpowered() - This API is invoked to specify whether the device
+ * is self powered or not
+ * @gadget: Reference to the gadget driver
+ * @value: Specifies self powered or not
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
+{
+ struct pch_udc_dev *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ if (value)
+ pch_udc_set_selfpowered(dev);
+ else
+ pch_udc_clear_selfpowered(dev);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_pullup() - This API is invoked to make the device
+ * visib