[PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine

Vladimir Moravcevic posted 3 patches 6 days, 13 hours ago
[PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
Posted by Vladimir Moravcevic 6 days, 13 hours ago
Add Corigine USB IP Driver for Axiado AX3000 SoC's
USB peripheral (USB 2.0/3.0).
The driver is based on the Corigine USB IP core with
Axiado-specific enhancements including VBUS detection and USB link
stability fixes.

The driver supports both USB 2.0 High-Speed and USB 3.0 SuperSpeed
modes with control, bulk, interrupt, and isochronous transfer types.

Co-developed-by: Krutik Shah <krutikshah@axiado.com>
Signed-off-by: Krutik Shah <krutikshah@axiado.com>
Co-developed-by: Prasad Bolisetty <pbolisetty@axiado.com>
Signed-off-by: Prasad Bolisetty <pbolisetty@axiado.com>
Signed-off-by: Vladimir Moravcevic <vmoravcevic@axiado.com>
---
 drivers/usb/gadget/udc/Kconfig   |   15 +
 drivers/usb/gadget/udc/Makefile  |    1 +
 drivers/usb/gadget/udc/crg_udc.c | 4522 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/udc/crg_udc.h |  364 +++
 4 files changed, 4902 insertions(+)

diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 26460340fbc9..b94d113aad99 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -417,6 +417,21 @@ config USB_ASPEED_UDC
 	  dynamically linked module called "aspeed_udc" and force all
 	  gadget drivers to also be dynamically linked.
 
+config USB_CRG_UDC
+	tristate "AXIADO CORIGINE-based AX3000 Device Controller"
+	depends on ARCH_AXIADO || COMPILE_TEST
+	depends on USB_GADGET
+	help
+	  Enables AX3000 USB device controller driver for Axiado
+	  SoCs and evaluation boards.
+
+	  Based on the Corigine USB IP core driver with Axiado specific
+	  enhancements. Supports USB 2.0 (High-Speed) and USB 3.0
+	  (SuperSpeed), including control, bulk, interrupt, and
+	  isochronous transfers.
+
+	  Say "y" to build statically, or "m" to build as a module.
+
 source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig"
 
 source "drivers/usb/gadget/udc/cdns2/Kconfig"
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index 1b9b1a4f9c57..b17b9c4665a1 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_USB_ASPEED_UDC)	+= aspeed_udc.o
 obj-$(CONFIG_USB_BDC_UDC)	+= bdc/
 obj-$(CONFIG_USB_MAX3420_UDC)	+= max3420_udc.o
 obj-$(CONFIG_USB_CDNS2_UDC)	+= cdns2/
+obj-$(CONFIG_USB_CRG_UDC)     += crg_udc.o
diff --git a/drivers/usb/gadget/udc/crg_udc.c b/drivers/usb/gadget/udc/crg_udc.c
new file mode 100644
index 000000000000..701123dc35bc
--- /dev/null
+++ b/drivers/usb/gadget/udc/crg_udc.c
@@ -0,0 +1,4522 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+//
+// Copyright (c) 2019 Corigine Inc.
+// Copyright (c) 2022-2026 Axiado Corporation.
+//
+
+#include <linux/net.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/unaligned.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/wait.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/scatterlist.h>
+#include "crg_udc.h"
+
+#define INIT_ZERO					-1
+#define UDC_FALSE					false
+
+#define MAX_PACKET_SIZE 1024
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+#define CRG_ERST_SIZE 1
+#define CRG_EVENT_RING_SIZE 256
+#define CRG_NUM_EP_CX	32
+
+#define TRB_MAX_BUFFER_SIZE		65536
+#define CRGUDC_CONTROL_EP_TD_RING_SIZE	16
+#define CRGUDC_BULK_EP_TD_RING_SIZE	1024
+#define CRGUDC_ISOC_EP_TD_RING_SIZE	32
+#define CRGUDC_INT_EP_TD_RING_SIZE	8
+#define CRGUDC_ROLE_DEVICE		0x1
+
+#define	U1_TIMEOUT_VAL	0x70
+#define	U2_TIMEOUT_VAL	0x70
+
+#define STATE_USB_LINK_STABLE 4
+
+/*********Feature switches********************/
+#define U12_FORBIDDEN	1
+#define U12_INITIATE_FORBIDDEN 1
+#define CRG_UDC_INT_EN
+#define REINIT_EP0_ON_BUS_RESET
+/*********************************************/
+
+enum EP_STATE_E {
+	EP_STATE_DISABLED = 0,
+	EP_STATE_RUNNING = 1,
+	EP_STATE_HALTED	= 2,
+	EP_STATE_STOPPED = 3
+};
+
+enum EP_TYPE_E {
+	EP_TYPE_INVALID = 0,
+	EP_TYPE_ISOCH_OUTBOUND,
+	EP_TYPE_BULK_OUTBOUND,
+	EP_TYPE_INTR_OUTBOUND,
+	EP_TYPE_INVALID2,
+	EP_TYPE_ISOCH_INBOUND,
+	EP_TYPE_BULK_INBOUND,
+	EP_TYPE_INTR_INBOUND
+};
+
+enum TRB_TYPE_E {
+	TRB_TYPE_RSVD = 0,
+	TRB_TYPE_XFER_NORMAL,
+	TRB_TYPE_RSVD2,
+	TRB_TYPE_XFER_DATA_STAGE,
+	TRB_TYPE_XFER_STATUS_STAGE,
+	TRB_TYPE_XFER_DATA_ISOCH,   /* 5*/
+	TRB_TYPE_LINK,
+	TRB_TYPE_RSVD7,
+	TRB_TYPE_NO_OP,
+
+	TRB_TYPE_EVT_TRANSFER = 32,
+	TRB_TYPE_EVT_CMD_COMPLETION = 33,
+	TRB_TYPE_EVT_PORT_STATUS_CHANGE = 34,
+	TRB_TYPE_EVT_MFINDEX_WRAP = 39,
+	TRB_TYPE_EVT_SETUP_PKT = 40,
+};
+
+/*Table 127*/
+enum TRB_CMPL_CODES_E {
+	CMPL_CODE_INVALID       = 0,
+	CMPL_CODE_SUCCESS,
+	CMPL_CODE_DATA_BUFFER_ERR,
+	CMPL_CODE_BABBLE_DETECTED_ERR,
+	CMPL_CODE_USB_TRANS_ERR,
+	CMPL_CODE_TRB_ERR,  /*5*/
+	CMPL_CODE_TRB_STALL,
+	CMPL_CODE_INVALID_STREAM_TYPE_ERR = 10,
+	CMPL_CODE_SHORT_PKT = 13,
+	CMPL_CODE_RING_UNDERRUN,
+	CMPL_CODE_RING_OVERRUN, /*15*/
+	CMPL_CODE_EVENT_RING_FULL_ERR = 21,
+	CMPL_CODE_STOPPED = 26,
+	CMPL_CODE_STOPPED_LENGTH_INVALID = 27,
+	CMPL_CODE_ISOCH_BUFFER_OVERRUN = 31,
+	/*192-224 vendor defined error*/
+	CMPL_CODE_PROTOCOL_STALL = 192,
+	CMPL_CODE_SETUP_TAG_MISMATCH = 193,
+	CMPL_CODE_HALTED = 194,
+	CMPL_CODE_HALTED_LENGTH_INVALID = 195,
+	CMPL_CODE_DISABLED = 196,
+	CMPL_CODE_DISABLED_LENGTH_INVALID = 197,
+};
+
+static const char driver_name[] = "crg_udc";
+
+struct buffer_info {
+	void *vaddr;
+	dma_addr_t dma;
+	u32 len;
+};
+
+struct transfer_trb_s {
+	__le32   dw0;
+	__le32   dw1;
+
+#define TRB_TRANSFER_LEN_MASK       0x0001FFFF
+#define TRB_TRANSFER_LEN_SHIFT               0
+#define TRB_TD_SIZE_MASK            0x003E0000
+#define TRB_TD_SIZE_SHIFT                   17
+#define TRB_INTR_TARGET_MASK        0xFFC00000
+#define TRB_INTR_TARGET_SHIFT               22
+	__le32   dw2;
+
+#define TRB_CYCLE_BIT_MASK          0x00000001
+#define TRB_CYCLE_BIT_SHIFT                  0
+#define TRB_LINK_TOGGLE_CYCLE_MASK  0x00000002
+#define TRB_LINK_TOGGLE_CYCLE_SHIFT          1
+#define TRB_INTR_ON_SHORT_PKT_MASK  0x00000004
+#define TRB_INTR_ON_SHORT_PKT_SHIFT          2
+#define TRB_NO_SNOOP_MASK           0x00000008
+#define TRB_NO_SNOOP_SHIFT                   3
+#define TRB_CHAIN_BIT_MASK          0x00000010
+#define TRB_CHAIN_BIT_SHIFT                  4
+#define TRB_INTR_ON_COMPLETION_MASK 0x00000020
+#define TRB_INTR_ON_COMPLETION_SHIFT         5
+
+#define TRB_APPEND_ZLP_MASK	    0x00000080
+#define TRB_APPEND_ZLP_SHIFT		     7
+
+#define TRB_BLOCK_EVENT_INT_MASK    0x00000200
+#define TRB_BLOCK_EVENT_INT_SHIFT            9
+#define TRB_TYPE_MASK               0x0000FC00
+#define TRB_TYPE_SHIFT                      10
+#define DATA_STAGE_TRB_DIR_MASK     0x00010000
+#define DATA_STAGE_TRB_DIR_SHIFT            16
+#define TRB_SETUP_TAG_MASK          0x00060000
+#define TRB_SETUP_TAG_SHIFT                 17
+#define STATUS_STAGE_TRB_STALL_MASK 0x00080000
+#define STATUS_STAGE_TRB_STALL_SHIFT        19
+#define STATUS_STAGE_TRB_SET_ADDR_MASK 0x00100000
+#define STATUS_STAGE_TRB_SET_ADDR_SHIFT        20
+
+#define ISOC_TRB_FRAME_ID_MASK      0x7FF00000
+#define ISOC_TRB_FRAME_ID_SHIFT             20
+#define ISOC_TRB_SIA_MASK           0x80000000
+#define ISOC_TRB_SIA_SHIFT                  31
+	__le32   dw3;
+};
+
+struct event_trb_s {
+	__le32 dw0;
+	__le32 dw1;
+
+#define EVE_TRB_TRAN_LEN_MASK       0x0001FFFF
+#define EVE_TRB_TRAN_LEN_SHIFT               0
+#define EVE_TRB_COMPL_CODE_MASK     0xFF000000
+#define EVE_TRB_COMPL_CODE_SHIFT            24
+	__le32 dw2;
+
+#define EVE_TRB_CYCLE_BIT_MASK		0x00000001
+#define EVE_TRB_CYCLE_BIT_SHIFT		0
+#define EVE_TRB_TYPE_MASK		0x0000FC00
+#define EVE_TRB_TYPE_SHIFT		10
+#define EVE_TRB_ENDPOINT_ID_MASK	0x001F0000
+#define EVE_TRB_ENDPOINT_ID_SHIFT	16
+#define EVE_TRB_SETUP_TAG_MASK		0x00600000
+#define EVE_TRB_SETUP_TAG_SHIFT		21
+	__le32 dw3;
+};
+
+struct ep_cx_s {
+
+#define EP_CX_LOGICAL_EP_NUM_MASK	0x00000078
+#define EP_CX_LOGICAL_EP_NUM_SHIFT	3
+
+
+#define EP_CX_INTERVAL_MASK		0x00FF0000
+#define EP_CX_INTERVAL_SHIFT            16
+	__le32 dw0;
+
+#define EP_CX_EP_TYPE_MASK		0x00000038
+#define EP_CX_EP_TYPE_SHIFT		3
+#define EP_CX_MAX_BURST_SIZE_MASK	0x0000FF00
+#define EP_CX_MAX_BURST_SIZE_SHIFT	8
+#define EP_CX_MAX_PACKET_SIZE_MASK	0xFFFF0000
+#define EP_CX_MAX_PACKET_SIZE_SHIFT	16
+	__le32 dw1;
+
+#define EP_CX_DEQ_CYC_STATE_MASK	0x00000001
+#define EP_CX_DEQ_CYC_STATE_SHIFT	0
+#define EP_CX_TR_DQPT_LO_MASK		0xFFFFFFF0
+#define EP_CX_TR_DQPT_LO_SHIFT		4
+	__le32 dw2;
+	__le32 dw3;
+};
+
+struct erst_s {
+	/* 64-bit event ring segment address */
+	__le32	seg_addr_lo;
+	__le32	seg_addr_hi;
+	__le32	seg_size;
+	/* Set to zero */
+	__le32	rsvd;
+};
+
+struct sel_value_s {
+	u16 u2_pel_value;
+	u16 u2_sel_value;
+	u8 u1_pel_value;
+	u8 u1_sel_value;
+};
+
+struct crg_udc_request {
+	struct usb_request usb_req;
+	struct list_head queue;
+	bool mapped;
+	u64 buff_len_left;
+	u32 trbs_needed;
+	struct transfer_trb_s *first_trb;
+	struct transfer_trb_s *last_trb;
+	bool all_trbs_queued;
+	bool short_pkt;
+};
+
+struct crg_udc_ep {
+	struct usb_ep usb_ep;
+
+	struct buffer_info tran_ring_info;
+	struct transfer_trb_s *first_trb;
+	struct transfer_trb_s *last_trb;
+
+	struct transfer_trb_s *enq_pt;
+	struct transfer_trb_s *deq_pt;
+	u8 pcs;
+
+	char name[10];
+	u8 DCI;
+	struct list_head queue;
+	const struct usb_endpoint_descriptor *desc;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	bool tran_ring_full;
+	struct crg_gadget_dev *crg_udc;
+
+	int ep_state;
+
+	unsigned wedge:1;
+};
+
+#define CRG_RING_NUM	1
+
+struct crg_udc_event {
+	struct buffer_info erst;
+	struct erst_s *p_erst;
+	struct buffer_info event_ring;
+	struct event_trb_s *evt_dq_pt;
+	u8 CCS;
+	struct event_trb_s *evt_seg0_last_trb;
+};
+
+struct crg_setup_packet {
+	struct usb_ctrlrequest usbctrlreq;
+	u16 setup_tag;
+};
+
+struct crg_udc_priv {
+	bool plat_setup_gen3;
+};
+
+struct crg_gadget_dev {
+	void __iomem *mmio_virt_base;
+	struct resource	*udc_res;
+	resource_size_t udc_res_len;
+	struct crg_uccr *uccr;
+	struct crg_uicr *uicr[CRG_RING_NUM];
+
+	const struct crg_udc_priv *priv;
+
+	/* udc_lock device lock */
+	spinlock_t udc_lock;
+
+	struct device *dev;
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *gadget_driver;
+
+	int irq;
+	struct task_struct *vbus_task;
+
+	struct crg_udc_ep udc_ep[32];
+	struct buffer_info ep_cx;
+	struct ep_cx_s *p_epcx;
+
+	struct crg_udc_event udc_event[CRG_RING_NUM];
+
+	struct crg_udc_request *status_req;
+	u16 *statusbuf;
+	struct sel_value_s sel_value;
+	void (*setup_fn_call_back)(struct crg_gadget_dev *a);
+
+#define WAIT_FOR_SETUP      0
+#define SETUP_PKT_PROCESS_IN_PROGRESS 1
+#define DATA_STAGE_XFER     2
+#define DATA_STAGE_RECV     3
+#define STATUS_STAGE_XFER   4
+#define STATUS_STAGE_RECV   5
+	u8 setup_status;
+#define CTRL_REQ_QUEUE_DEPTH  5
+	struct crg_setup_packet ctrl_req_queue[CTRL_REQ_QUEUE_DEPTH];
+	u8    ctrl_req_enq_idx;
+
+	u8 device_state;
+	u8 resume_state;
+	u16 dev_addr;
+	u8 setup_tag;
+	u8 set_tm;
+
+	u32 num_enabled_eps;
+
+	int connected;
+
+	unsigned u2_RWE:1;
+	unsigned feature_u1_enable:1;
+	unsigned feature_u2_enable:1;
+
+	int setup_tag_mismatch_found;
+	int portsc_on_reconnecting;
+};
+
+/*An array should be implemented if we want to support multi
+ * usb device controller
+ */
+static DECLARE_WAIT_QUEUE_HEAD(vbus_wait);
+
+static struct usb_endpoint_descriptor crg_udc_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = cpu_to_le16(64),
+};
+
+static int get_ep_state(struct crg_gadget_dev *crg_udc, int DCI)
+{
+	struct crg_udc_ep *udc_ep_ptr;
+
+	if (DCI < 0 || DCI == 1)
+		return -EINVAL;
+
+	udc_ep_ptr = &crg_udc->udc_ep[DCI];
+
+	return udc_ep_ptr->ep_state;
+}
+
+/************command related ops**************************/
+static int crg_issue_command(struct crg_gadget_dev *crg_udc,
+			enum crg_cmd_type type, u32 param0, u32 param1)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 status;
+	bool check_complete = false;
+	u32 tmp;
+
+	tmp = readl(&uccr->control);
+	if (tmp & CRG_U3DC_CTRL_RUN)
+		check_complete = true;
+
+	if (check_complete) {
+		tmp = readl(&uccr->cmd_control);
+		if (tmp & CRG_U3DC_CMD_CTRL_ACTIVE) {
+			dev_err(crg_udc->dev, "%s prev command is not complete!\n", __func__);
+			return -1;
+		}
+	}
+	/* Ensure that everything is written before issuing new command */
+	wmb();
+
+	writel(param0, &uccr->cmd_param0);
+	writel(param1, &uccr->cmd_param1);
+
+	/*ignore CMD IOC, in uboot no irq is*/
+	tmp = CRG_U3DC_CMD_CTRL_ACTIVE |
+		CRG_U3DC_CMD_CTRL_TYPE(type);
+	writel(tmp, &uccr->cmd_control);
+
+	dev_dbg(crg_udc->dev, "%s start, type=%d, par0=0x%x, par1=0x%x\n",
+		__func__, type, param0, param1);
+
+	if (check_complete) {
+		do {
+			tmp = readl(&uccr->cmd_control);
+		} while (tmp & CRG_U3DC_CMD_CTRL_ACTIVE);
+
+		dev_dbg(crg_udc->dev, "%s successful\n", __func__);
+
+		status = CRG_U3DC_CMD_CTRL_STATUS_GET(tmp);
+		if (status != 0) {
+			dev_dbg(crg_udc->dev, "%s fail\n", __func__);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void setup_link_trb(struct transfer_trb_s *link_trb,
+					bool toggle, ulong next_trb)
+{
+	u32 dw = 0;
+
+	link_trb->dw0 = cpu_to_le32(lower_32_bits(next_trb));
+	link_trb->dw1 = cpu_to_le32(upper_32_bits(next_trb));
+	link_trb->dw2 = 0;
+
+	dw = SETF_VAR(TRB_TYPE, dw, TRB_TYPE_LINK);
+	if (toggle)
+		dw = SETF_VAR(TRB_LINK_TOGGLE_CYCLE, dw, 1);
+	else
+		dw = SETF_VAR(TRB_LINK_TOGGLE_CYCLE, dw, 0);
+
+	link_trb->dw3 = cpu_to_le32(dw);
+
+	/* Ensure that lint trb is updated */
+	wmb();
+}
+
+static dma_addr_t tran_trb_virt_to_dma(struct crg_udc_ep *udc_ep,
+	struct transfer_trb_s *trb)
+{
+	unsigned long offset;
+	int trb_idx;
+	dma_addr_t dma_addr = 0;
+
+	trb_idx = trb - udc_ep->first_trb;
+	if (unlikely(trb_idx < 0))
+		return 0;
+
+	offset = trb_idx * sizeof(*trb);
+	if (unlikely(offset > udc_ep->tran_ring_info.len))
+		return 0;
+	dma_addr = udc_ep->tran_ring_info.dma + offset;
+	return dma_addr;
+}
+
+static struct transfer_trb_s *tran_trb_dma_to_virt
+	(struct crg_udc_ep *udc_ep, dma_addr_t address)
+{
+	unsigned long offset;
+	struct transfer_trb_s *trb_virt;
+
+	if (lower_32_bits(address) & 0xf)
+		return NULL;
+
+	offset = address - udc_ep->tran_ring_info.dma;
+	if (unlikely(offset > udc_ep->tran_ring_info.len))
+		return NULL;
+	offset = offset / sizeof(struct transfer_trb_s);
+	trb_virt = udc_ep->first_trb + offset;
+	return trb_virt;
+}
+
+static dma_addr_t event_trb_virt_to_dma
+	(struct crg_udc_event *udc_event, struct event_trb_s *event)
+{
+	dma_addr_t dma_addr = 0;
+	unsigned long seg_offset;
+
+	if (!udc_event || !event)
+		return 0;
+
+	/* update dequeue pointer */
+	seg_offset = (void *)event - udc_event->event_ring.vaddr;
+	dma_addr = udc_event->event_ring.dma + seg_offset;
+
+	return dma_addr;
+}
+
+/* Completes request.  Calls gadget completion handler
+ * caller must have acquired spin lock.
+ */
+static void req_done(struct crg_udc_ep *udc_ep,
+			struct crg_udc_request *udc_req, int status)
+{
+	unsigned long flags = 0;
+	struct crg_gadget_dev *crg_udc = udc_ep->crg_udc;
+
+	if (likely(udc_req->usb_req.status == -EINPROGRESS))
+		udc_req->usb_req.status = status;
+
+	list_del_init(&udc_req->queue);
+
+
+	if (udc_req->usb_req.num_mapped_sgs) {
+		dma_unmap_sg(crg_udc->dev, udc_req->usb_req.sg,
+				udc_req->usb_req.num_sgs,
+				(usb_endpoint_dir_in(udc_ep->desc)
+				 ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+
+		udc_req->usb_req.num_mapped_sgs = 0;
+		dev_dbg(crg_udc->dev, "dma_unmap_sg done\n");
+	}
+
+	if (udc_req->mapped) {
+		if (udc_req->usb_req.length) {
+			dma_unmap_single(crg_udc->dev, udc_req->usb_req.dma,
+				udc_req->usb_req.length, usb_endpoint_dir_in(udc_ep->desc)
+				? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		}
+		udc_req->usb_req.dma = DMA_ADDR_INVALID;
+		udc_req->mapped = 0;
+	}
+
+	if (udc_req->usb_req.complete) {
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		udc_req->usb_req.complete(&udc_ep->usb_ep, &udc_req->usb_req);
+		spin_lock_irqsave(&crg_udc->udc_lock, flags);
+	}
+}
+
+static void nuke(struct crg_udc_ep *udc_ep, int status)
+{
+	struct crg_udc_request *req = NULL;
+
+	while (!list_empty(&udc_ep->queue)) {
+		req = list_entry(udc_ep->queue.next,
+				struct crg_udc_request,
+				queue);
+
+		req_done(udc_ep, req, status);
+	}
+}
+
+static void clear_req_container(struct crg_udc_request *udc_req_ptr)
+{
+	udc_req_ptr->buff_len_left = 0;
+	udc_req_ptr->trbs_needed = 0;
+	udc_req_ptr->all_trbs_queued = 0;
+	udc_req_ptr->first_trb = NULL;
+	udc_req_ptr->last_trb = NULL;
+	udc_req_ptr->short_pkt = 0;
+}
+
+static bool is_pointer_less_than(struct transfer_trb_s *a,
+	struct transfer_trb_s *b, struct crg_udc_ep *udc_ep)
+{
+	if (b > a && (udc_ep->enq_pt >= b || udc_ep->enq_pt < a))
+		return true;
+	if (b < a && (udc_ep->enq_pt >= b && udc_ep->enq_pt < a))
+		return true;
+	return false;
+}
+
+/* num_trbs here is the size of the ring. */
+static u32 room_on_ring(struct crg_gadget_dev *crg_udc, u32 num_trbs,
+		struct transfer_trb_s *p_ring, struct transfer_trb_s *enq_pt,
+		struct transfer_trb_s *dq_pt)
+{
+	u32 i = 0;
+
+	if (enq_pt == dq_pt) {
+		/* ring is empty */
+		return num_trbs - 1;
+	}
+
+	while (enq_pt != dq_pt) {
+		i++;
+
+		enq_pt++;
+
+		if (GETF(TRB_TYPE, enq_pt->dw3) == TRB_TYPE_LINK)
+			enq_pt = p_ring;
+
+		if (i > num_trbs)
+			break;
+	}
+
+	return i - 1;
+}
+
+static void crg_udc_epcx_setup(struct crg_udc_ep *udc_ep)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep->crg_udc;
+	const struct usb_endpoint_descriptor *desc = udc_ep->desc;
+	const struct usb_ss_ep_comp_descriptor *comp_desc = udc_ep->comp_desc;
+	u8 DCI = udc_ep->DCI;
+	struct ep_cx_s *epcx = (struct ep_cx_s *)(crg_udc->p_epcx + DCI - 2);
+	enum EP_TYPE_E ep_type;
+	u16 maxburst = 0;
+	u8 maxstreams = 0;
+	u16 maxsize;
+	u32 dw;
+
+	dev_dbg(crg_udc->dev, "crgudc->p_epcx %p, epcx %p\n", crg_udc->p_epcx, epcx);
+	dev_dbg(crg_udc->dev, "DCI %d, sizeof ep_cx %ld\n", DCI, sizeof(struct ep_cx_s));
+	dev_dbg(crg_udc->dev, "desc epaddr = 0x%x\n", desc->bEndpointAddress);
+
+	/*corigine gadget dir should be opposite to host dir*/
+	if (usb_endpoint_dir_out(desc))
+		ep_type = usb_endpoint_type(desc) + EP_TYPE_INVALID2;
+	else
+		ep_type = usb_endpoint_type(desc);
+
+	maxsize = usb_endpoint_maxp(desc) & 0x07ff; /* D[0:10] */
+
+	if (crg_udc->gadget.speed >= USB_SPEED_SUPER) {
+		maxburst = comp_desc->bMaxBurst;
+
+		if (usb_endpoint_xfer_bulk(udc_ep->desc))
+			maxstreams = comp_desc->bmAttributes & 0x1f;
+
+	} else if ((crg_udc->gadget.speed == USB_SPEED_HIGH ||
+		crg_udc->gadget.speed == USB_SPEED_FULL) &&
+			(usb_endpoint_xfer_int(udc_ep->desc) ||
+				usb_endpoint_xfer_isoc(udc_ep->desc))) {
+		if (crg_udc->gadget.speed == USB_SPEED_HIGH)
+			maxburst = (usb_endpoint_maxp(desc) >> 11) & 0x3;
+		if (maxburst == 0x3) {
+			dev_err(crg_udc->dev, "invalid maxburst\n");
+			maxburst = 0x2;
+		}
+	}
+
+	/* fill ep_dw0 */
+	dw = 0;
+	dw = SETF_VAR(EP_CX_LOGICAL_EP_NUM, dw, udc_ep->DCI / 2);
+	dw = SETF_VAR(EP_CX_INTERVAL, dw, desc->bInterval);
+	if (maxstreams) {
+		dev_err(crg_udc->dev, "%s maxstream=%d is not expected\n",
+			__func__, maxstreams);
+	}
+	epcx->dw0 = cpu_to_le32(dw);
+
+	/* fill ep_dw1 */
+	dw = 0;
+	dw = SETF_VAR(EP_CX_EP_TYPE, dw, ep_type);
+	dw = SETF_VAR(EP_CX_MAX_PACKET_SIZE, dw, maxsize);
+	dw = SETF_VAR(EP_CX_MAX_BURST_SIZE, dw, maxburst);
+	epcx->dw1 = cpu_to_le32(dw);
+
+	/* fill ep_dw2 */
+	dw = lower_32_bits(udc_ep->tran_ring_info.dma) & EP_CX_TR_DQPT_LO_MASK;
+	dw = SETF_VAR(EP_CX_DEQ_CYC_STATE, dw, udc_ep->pcs);
+	epcx->dw2 = cpu_to_le32(dw);
+
+	/* fill ep_dw3 */
+	dw = upper_32_bits(udc_ep->tran_ring_info.dma);
+	epcx->dw3 = cpu_to_le32(dw);
+	/* Ensure that epcx is updated */
+	wmb();
+}
+
+static void crg_udc_epcx_update_dqptr(struct crg_udc_ep *udc_ep)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep->crg_udc;
+	u8 DCI = udc_ep->DCI;
+	struct ep_cx_s *epcx = (struct ep_cx_s *)(crg_udc->p_epcx + DCI - 2);
+	u32 dw;
+	dma_addr_t dqptaddr;
+	u32 cmd_param0;
+
+	if (DCI == 0) {
+		dev_err(crg_udc->dev, "%s Cannot update dqptr for ep0\n", __func__);
+		return;
+	}
+
+	dqptaddr = tran_trb_virt_to_dma(udc_ep, udc_ep->deq_pt);
+
+	/* fill ep_dw2 */
+	dw = lower_32_bits(dqptaddr) & EP_CX_TR_DQPT_LO_MASK;
+	dw = SETF_VAR(EP_CX_DEQ_CYC_STATE, dw, udc_ep->pcs);
+	epcx->dw2 = cpu_to_le32(dw);
+
+	/* fill ep_dw3 */
+	dw = upper_32_bits(dqptaddr);
+	epcx->dw3 = cpu_to_le32(dw);
+
+	cmd_param0 = (0x1 << udc_ep->DCI);
+	/* Ensure that dqptr is updated */
+	wmb();
+
+	crg_issue_command(crg_udc, CRG_CMD_SET_TR_DQPTR, cmd_param0, 0);
+}
+
+static void setup_status_trb(struct crg_gadget_dev *crg_udc,
+		struct transfer_trb_s *p_trb,
+		struct usb_request *usb_req, u8 pcs, u8 set_addr, u8 stall)
+{
+	u32 tmp, dir = 0;
+
+	/* There are some cases where seutp_status_trb() is called with
+	 * usb_req set to NULL.
+	 */
+
+	p_trb->dw0 = 0;
+	p_trb->dw1 = 0;
+
+	dev_dbg(crg_udc->dev, "data_buf_ptr_lo = 0x%x, data_buf_ptr_hi = 0x%x\n",
+		p_trb->dw0, p_trb->dw1);
+
+	tmp = 0;
+	tmp = SETF_VAR(TRB_INTR_TARGET, tmp, 0);
+	p_trb->dw2 = tmp;
+
+	tmp = 0;
+	tmp = SETF_VAR(TRB_CYCLE_BIT, tmp, pcs);
+	tmp = SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, 1);/*IOC:1*/
+	tmp = SETF_VAR(TRB_TYPE, tmp, TRB_TYPE_XFER_STATUS_STAGE);
+
+	dir = (crg_udc->setup_status == STATUS_STAGE_XFER) ? 0 : 1;
+	tmp = SETF_VAR(DATA_STAGE_TRB_DIR, tmp, dir);
+
+	tmp = SETF_VAR(TRB_SETUP_TAG, tmp, crg_udc->setup_tag);
+	tmp = SETF_VAR(STATUS_STAGE_TRB_STALL, tmp, stall);
+	tmp = SETF_VAR(STATUS_STAGE_TRB_SET_ADDR, tmp, set_addr);
+
+	p_trb->dw3 = tmp;
+	dev_dbg(crg_udc->dev, "trb_dword2 = 0x%x, trb_dword3 = 0x%x\n",
+			p_trb->dw2, p_trb->dw3);
+	/* Ensure that status trb is updated */
+	wmb();
+}
+
+static void knock_doorbell(struct crg_gadget_dev *crg_udc, int DCI)
+{
+	u32 tmp;
+	struct crg_uccr *uccr;
+
+	uccr = crg_udc->uccr;
+	/* Ensure evreything is written before notifying the HW */
+	wmb();
+
+	tmp = CRG_U3DC_DB_TARGET(DCI);
+	dev_dbg(crg_udc->dev, "DOORBELL = 0x%x\n", tmp);
+	writel(tmp, &uccr->doorbell);
+}
+
+static void setup_datastage_trb(struct crg_gadget_dev *crg_udc,
+		struct transfer_trb_s *p_trb, struct usb_request *usb_req,
+		u8 pcs, u32 num_trb, u32 transfer_length, u32 td_size,
+		u8 IOC, u8 AZP, u8 dir, u8 setup_tag)
+{
+	u32 tmp;
+
+	dev_dbg(crg_udc->dev, "dma = 0x%llx, ", usb_req->dma);
+	dev_dbg(crg_udc->dev, "buf = 0x%lx, ", (unsigned long)usb_req->buf);
+
+	p_trb->dw0 = lower_32_bits(usb_req->dma);
+	p_trb->dw1 = upper_32_bits(usb_req->dma);
+
+	dev_dbg(crg_udc->dev, "data_buf_ptr_lo = 0x%x, data_buf_ptr_hi = 0x%x\n",
+		p_trb->dw0, p_trb->dw1);
+
+
+	/* TRB_Transfer_Length
+	 *For USB_DIR_OUT, this field is the number of data bytes expected from
+	 *xhc. For USB_DIR_IN, this field is the number of data bytes the device
+	 *will send.
+	 */
+	tmp = 0;
+	tmp = SETF_VAR(TRB_TRANSFER_LEN, tmp, transfer_length);
+	tmp = SETF_VAR(TRB_TD_SIZE, tmp, td_size);
+	tmp = SETF_VAR(TRB_INTR_TARGET, tmp, 0);
+	p_trb->dw2 = tmp;
+
+	tmp = 0;
+	tmp = SETF_VAR(TRB_CYCLE_BIT, tmp, pcs);
+	tmp = SETF_VAR(TRB_INTR_ON_SHORT_PKT, tmp, 1);
+	tmp = SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, IOC);
+	tmp = SETF_VAR(TRB_TYPE, tmp, TRB_TYPE_XFER_DATA_STAGE);
+	tmp = SETF_VAR(TRB_APPEND_ZLP, tmp, AZP);
+	tmp = SETF_VAR(DATA_STAGE_TRB_DIR, tmp, dir);
+	tmp = SETF_VAR(TRB_SETUP_TAG, tmp, setup_tag);
+
+	p_trb->dw3 = tmp;
+	/* Ensure that datastage trb is updated */
+	wmb();
+
+	dev_dbg(crg_udc->dev, "trb_dword0 = 0x%x, trb_dword1 = 0x%x trb_dword2 = 0x%x, trb_dword3 = 0x%x\n",
+			p_trb->dw0, p_trb->dw1, p_trb->dw2, p_trb->dw3);
+}
+
+static void setup_trb(struct crg_gadget_dev *crg_udc,
+		struct transfer_trb_s *p_trb,
+		struct usb_request *usb_req, u32 xfer_len,
+		dma_addr_t xfer_buf_addr, u8 td_size, u8 pcs,
+		u8 trb_type, u8 short_pkt, u8 chain_bit,
+		u8 intr_on_compl, bool b_setup_stage, u8 usb_dir,
+		bool b_isoc, u8 tlb_pc, u16 frame_i_d, u8 SIA, u8 AZP)
+{
+	u32 tmp;
+
+	p_trb->dw0 = lower_32_bits(xfer_buf_addr);
+	p_trb->dw1 = upper_32_bits(xfer_buf_addr);
+
+	dev_dbg(crg_udc->dev, "data_buf_ptr_lo = 0x%x, data_buf_ptr_hi = 0x%x\n",
+		p_trb->dw0, p_trb->dw1);
+
+	tmp = 0;
+	tmp = SETF_VAR(TRB_TRANSFER_LEN, tmp, xfer_len);
+	tmp = SETF_VAR(TRB_TD_SIZE, tmp, td_size);
+	tmp = SETF_VAR(TRB_INTR_TARGET, tmp, 0);
+
+	p_trb->dw2 = tmp;
+
+	tmp = 0;
+	tmp = SETF_VAR(TRB_CYCLE_BIT, tmp, pcs);
+	tmp = SETF_VAR(TRB_INTR_ON_SHORT_PKT, tmp, short_pkt);
+	tmp = SETF_VAR(TRB_CHAIN_BIT, tmp, chain_bit);
+	tmp = SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, intr_on_compl);
+	tmp = SETF_VAR(TRB_APPEND_ZLP, tmp, AZP);
+	tmp = SETF_VAR(TRB_TYPE, tmp, trb_type);
+
+	if (b_setup_stage)
+		tmp = SETF_VAR(DATA_STAGE_TRB_DIR, tmp, usb_dir);
+
+	if (b_isoc) {
+		tmp = SETF_VAR(ISOC_TRB_FRAME_ID, tmp, frame_i_d);
+		tmp = SETF_VAR(ISOC_TRB_SIA, tmp, SIA);
+	}
+
+	p_trb->dw3 = tmp;
+	/* Ensure that trb is updated */
+	wmb();
+	dev_dbg(crg_udc->dev, "trb_dword2 = 0x%.8x, trb_dword3 = 0x%.8x\n",
+		p_trb->dw2, p_trb->dw3);
+
+}
+
+static int crg_udc_queue_trbs(struct crg_udc_ep *udc_ep_ptr,
+		struct crg_udc_request *udc_req_ptr,  bool b_isoc,
+		u32 xfer_ring_size,
+		u32 num_trbs_needed, u64 buffer_length)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
+	struct transfer_trb_s *p_xfer_ring = udc_ep_ptr->first_trb;
+	u32 num_trbs_ava = 0;
+	struct usb_request *usb_req = &udc_req_ptr->usb_req;
+	u64 buff_len_temp = 0;
+	u32 i, j = 1;
+	struct transfer_trb_s *enq_pt = udc_ep_ptr->enq_pt;
+	u8 td_size;
+	u8 chain_bit = 1;
+	u8 short_pkt = 0;
+	u8 intr_on_compl = 0;
+	u32 count;
+	bool full_td = true;
+	u32 intr_rate;
+	dma_addr_t trb_buf_addr;
+	bool need_zlp = false;
+	struct scatterlist *sg = NULL;
+	u32 num_sgs = 0;
+	u64 sg_addr = 0;
+
+	dev_dbg(crg_udc->dev, "%s %s\n", __func__, udc_ep_ptr->usb_ep.name);
+	if (udc_req_ptr->usb_req.num_sgs) {
+		num_sgs = udc_req_ptr->usb_req.num_sgs;
+		sg = udc_req_ptr->usb_req.sg;
+		sg_addr = (u64) sg_dma_address(sg);
+		buffer_length = sg_dma_len(sg);
+
+		dev_dbg(crg_udc->dev, "num_sgs = %d, num_mapped_sgs = %d\n",
+			udc_req_ptr->usb_req.num_sgs,
+			udc_req_ptr->usb_req.num_mapped_sgs);
+		dev_dbg(crg_udc->dev,
+			"sg_addr = %p, buffer_length = %llu, num_trbs = %d\n",
+			(void *)sg_addr, buffer_length, num_trbs_needed);
+	}
+
+	if (!b_isoc) {
+		if (udc_req_ptr->usb_req.zero == 1 &&
+			udc_req_ptr->usb_req.length != 0 &&
+			((udc_req_ptr->usb_req.length %
+			  udc_ep_ptr->usb_ep.maxpacket) == 0)) {
+			need_zlp = true;
+		}
+	}
+
+	td_size = num_trbs_needed;
+
+	num_trbs_ava = room_on_ring(crg_udc, xfer_ring_size,
+		p_xfer_ring, udc_ep_ptr->enq_pt, udc_ep_ptr->deq_pt);
+
+	/* trb_buf_addr points to the addr of the buffer that we write in
+	 * each TRB. If this function is called to complete the pending TRB
+	 * transfers of a previous request, point it to the buffer that is
+	 * not transferred, or else point it to the starting address of the
+	 * buffer received in usb_request
+	 */
+	if (udc_req_ptr->trbs_needed) {
+		/* Here udc_req_ptr->trbs_needed is used to indicate if we
+		 * are completing a previous req
+		 */
+		trb_buf_addr = usb_req->dma +
+			(usb_req->length - udc_req_ptr->buff_len_left);
+	} else {
+		if (sg_addr)
+			trb_buf_addr = sg_addr;
+		else
+			trb_buf_addr = usb_req->dma;
+	}
+
+	if (num_trbs_ava >= num_trbs_needed) {
+		count = num_trbs_needed;
+	} else {
+		if (b_isoc) {
+			struct crg_udc_request *udc_req_ptr_temp;
+			u8 temp = 0;
+
+			list_for_each_entry(udc_req_ptr_temp,
+					&udc_ep_ptr->queue, queue) {
+				temp++;
+			}
+
+			if (temp >= 2) {
+				dev_err(crg_udc->dev, "%s don't do isoc discard\n", __func__);
+				/*  we already scheduled two mfi in advance. */
+				return 0;
+			}
+		}
+
+		/* always keep one trb for zlp. */
+		count = num_trbs_ava;
+		full_td = false;
+		dev_dbg(crg_udc->dev, "TRB Ring Full. Avail: 0x%x Req: 0x%x\n",
+				num_trbs_ava, num_trbs_needed);
+		udc_ep_ptr->tran_ring_full = true;
+
+		/*if there is still some trb not queued,
+		 *it means last queued
+		 *trb is not the last trb of TD, so no need zlp
+		 */
+		need_zlp = false;
+	}
+
+	for (i = 0; i < count; i++) {
+		if ((udc_req_ptr->usb_req.num_sgs) && (buffer_length == 0)) {
+			sg = sg_next(sg);
+			if (sg) {
+				trb_buf_addr = (u64) sg_dma_address(sg);
+				buffer_length = sg_dma_len(sg);
+				dev_dbg(crg_udc->dev,
+					"trb_buf_addr = %p, num_trbs = %d\n",
+					(void *)trb_buf_addr, num_trbs_needed);
+				dev_dbg(crg_udc->dev, "buffer_length = %llu\n",
+					buffer_length);
+			} else {
+				dev_err(crg_udc->dev,
+					"scatterlist ended unexpectedly (i=%d, count=%d)\n",
+					i, count);
+				return -EINVAL;
+			}
+		}
+
+		if (buffer_length > TRB_MAX_BUFFER_SIZE)
+			buff_len_temp = TRB_MAX_BUFFER_SIZE;
+		else
+			buff_len_temp = buffer_length;
+
+		buffer_length -= buff_len_temp;
+
+		if (usb_endpoint_dir_out(udc_ep_ptr->desc))
+			short_pkt = 1;
+
+		if ((buffer_length == 0) && (i == (count - 1))) {
+			chain_bit = 0;
+			intr_on_compl = 1;
+			udc_req_ptr->all_trbs_queued = 1;
+		}
+
+
+#define BULK_EP_INTERRUPT_RATE      5
+#define ISOC_EP_INTERRUPT_RATE      1
+		if  (b_isoc)
+			intr_rate = ISOC_EP_INTERRUPT_RATE;
+		else
+			intr_rate = BULK_EP_INTERRUPT_RATE;
+
+		if  (!full_td && j == intr_rate) {
+			intr_on_compl = 1;
+			j = 0;
+		}
+
+		if (b_isoc) {
+			setup_trb(crg_udc, enq_pt, usb_req, buff_len_temp,
+				trb_buf_addr, td_size - 1, udc_ep_ptr->pcs,
+				TRB_TYPE_XFER_DATA_ISOCH, short_pkt, chain_bit,
+				intr_on_compl, 0, 0, 1, 0, 0, 1, 0);
+		} else {
+			u8 pcs = udc_ep_ptr->pcs;
+
+			if (udc_ep_ptr->comp_desc &&
+				(usb_ss_max_streams(udc_ep_ptr->comp_desc))) {
+				dev_err(crg_udc->dev, "%s don't do bulk stream\n", __func__);
+			} else {
+				if (udc_req_ptr->all_trbs_queued) {
+					/*it is the last trb of TD,
+					 * so consider zlp
+					 */
+					u8 AZP = 0;
+
+					AZP = (need_zlp ? 1 : 0);
+
+					setup_trb(crg_udc, enq_pt, usb_req,
+						buff_len_temp, trb_buf_addr,
+						td_size - 1, pcs,
+						TRB_TYPE_XFER_NORMAL, short_pkt,
+						chain_bit, intr_on_compl,
+						0, 0, 0, 0, 0, 0, AZP);
+
+				} else {
+					setup_trb(crg_udc, enq_pt, usb_req,
+						buff_len_temp, trb_buf_addr,
+						td_size - 1, pcs,
+						TRB_TYPE_XFER_NORMAL, short_pkt,
+						chain_bit, intr_on_compl,
+						0, 0, 0, 0, 0, 0, 0);
+				}
+			}
+		}
+		trb_buf_addr += buff_len_temp;
+		td_size--;
+		enq_pt++;
+		j++;
+		if (GETF(TRB_TYPE, enq_pt->dw3) == TRB_TYPE_LINK) {
+			if (GETF(TRB_LINK_TOGGLE_CYCLE,
+					enq_pt->dw3)) {
+				enq_pt->dw3 = SETF_VAR(TRB_CYCLE_BIT,
+					enq_pt->dw3, udc_ep_ptr->pcs);
+				udc_ep_ptr->pcs ^= 0x1;
+				/* Ensure that trb cycle bit is updated */
+				wmb();
+				enq_pt = udc_ep_ptr->first_trb;
+			}
+		}
+	}
+
+	if (!udc_req_ptr->trbs_needed)
+		udc_req_ptr->first_trb = udc_ep_ptr->enq_pt;
+	udc_ep_ptr->enq_pt = enq_pt;
+	udc_req_ptr->buff_len_left = buffer_length;
+	udc_req_ptr->trbs_needed = td_size;
+
+	if (udc_req_ptr->buff_len_left == 0) {
+		/* It is actually last trb of a request plus 1 */
+		if (udc_ep_ptr->enq_pt == udc_ep_ptr->first_trb)
+			udc_req_ptr->last_trb = udc_ep_ptr->last_trb - 1;
+		else
+			udc_req_ptr->last_trb = udc_ep_ptr->enq_pt - 1;
+	}
+
+	return 0;
+}
+
+static int crg_udc_queue_ctrl(struct crg_udc_ep *udc_ep_ptr,
+		struct crg_udc_request *udc_req_ptr, u32 num_of_trbs_needed)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
+	u8 ep_state;
+	struct transfer_trb_s *enq_pt = udc_ep_ptr->enq_pt;
+	struct transfer_trb_s *dq_pt = udc_ep_ptr->deq_pt;
+	struct usb_request *usb_req = &udc_req_ptr->usb_req;
+	struct transfer_trb_s *p_trb;
+	u32 transfer_length;
+	u32 td_size = 0;
+	u8 IOC;
+	u8 AZP;
+	u8 dir = 0;
+	u8 setup_tag = crg_udc->setup_tag;
+
+	ep_state = get_ep_state(crg_udc, 0);
+
+
+	/* Need to queue the request even ep is paused or halted */
+	if (ep_state != EP_STATE_RUNNING) {
+		dev_dbg(crg_udc->dev, "EP State = 0x%x\n", ep_state);
+		return -EINVAL;
+	}
+
+	if (list_empty(&udc_ep_ptr->queue)) {
+		/* For control endpoint, we can handle one setup request at a
+		 * time. so if there are TD pending in the transfer ring.
+		 * wait for the sequence number error event. Then put the new
+		 * request to transfer ring
+		 */
+		if (enq_pt == dq_pt) {
+			u32 tmp = 0, i;
+			bool need_zlp = false;
+
+			dev_dbg(crg_udc->dev, "Setup Data Stage TRBs\n");
+			/* Transfer ring is empty
+			 * setup data stage TRBs
+			 */
+			udc_req_ptr->first_trb = udc_ep_ptr->enq_pt;
+
+			if (crg_udc->setup_status ==  DATA_STAGE_XFER)
+				dir = 0;
+			else if (crg_udc->setup_status == DATA_STAGE_RECV)
+				dir = 1;
+			else
+				dev_dbg(crg_udc->dev, "unexpected setup_status!%d\n",
+					crg_udc->setup_status);
+
+			if (udc_req_ptr->usb_req.zero == 1 &&
+				udc_req_ptr->usb_req.length != 0 &&
+				((udc_req_ptr->usb_req.length %
+				  udc_ep_ptr->usb_ep.maxpacket) == 0))
+				need_zlp = true;/*zlp = zero length packet*/
+
+
+			for (i = 0; i < num_of_trbs_needed; i++) {
+				p_trb = enq_pt;
+				if (i < (num_of_trbs_needed - 1)) {
+					transfer_length = TRB_MAX_BUFFER_SIZE;
+					IOC = 0;
+					AZP = 0;
+				} else {
+					tmp = TRB_MAX_BUFFER_SIZE * i;
+					transfer_length = (u32)usb_req->length
+						- tmp;
+
+					IOC = 1;
+					AZP = (need_zlp ? 1 : 0);
+				}
+
+				dev_dbg(crg_udc->dev,
+					"tx_len = 0x%x, tmp = 0x%x\n",
+					transfer_length, tmp);
+
+				setup_datastage_trb(crg_udc, p_trb, usb_req,
+					udc_ep_ptr->pcs, i, transfer_length,
+					td_size, IOC, AZP, dir, setup_tag);
+				udc_req_ptr->all_trbs_queued = 1;
+				enq_pt++;
+
+				if (GETF(TRB_TYPE, enq_pt->dw3) ==
+						TRB_TYPE_LINK) {
+					if (GETF(TRB_LINK_TOGGLE_CYCLE,
+							enq_pt->dw3)) {
+						enq_pt->dw3 = SETF_VAR(TRB_CYCLE_BIT,
+							enq_pt->dw3,
+							udc_ep_ptr->pcs);
+						udc_ep_ptr->pcs ^= 0x1;
+					}
+					/* Ensure that trb cycle bit is updated */
+					wmb();
+					enq_pt = udc_ep_ptr->first_trb;
+				}
+			}
+
+			udc_ep_ptr->enq_pt = enq_pt;
+
+			tmp = 0;
+
+			knock_doorbell(crg_udc, 0);
+
+			if (udc_ep_ptr->enq_pt == udc_ep_ptr->first_trb)
+				udc_req_ptr->last_trb =
+					udc_ep_ptr->last_trb - 1;
+			else
+				udc_req_ptr->last_trb = udc_ep_ptr->enq_pt - 1;
+		} else {
+			/* we process one setup request at a time, so ring
+			 * should already be empty.
+			 */
+			dev_err(crg_udc->dev, "Eq = 0x%p != Dq = 0x%p\n",
+				enq_pt, dq_pt);
+		}
+	} else {
+		dev_err(crg_udc->dev, "udc_ep_ptr->queue not empty\n");
+		/* New setup packet came
+		 * Drop the this req..
+		 */
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void build_ep0_status(struct crg_udc_ep *udc_ep_ptr,
+		 bool default_value, u32 status,
+		 struct crg_udc_request *udc_req_ptr, u8 set_addr, u8 stall)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
+	struct transfer_trb_s *enq_pt = udc_ep_ptr->enq_pt;
+
+	if (default_value) {
+		udc_req_ptr = crg_udc->status_req;
+		udc_req_ptr->usb_req.length = 0;
+		udc_req_ptr->usb_req.status = status;
+		udc_req_ptr->usb_req.actual = 0;
+		udc_req_ptr->usb_req.complete = NULL;
+	} else {
+		udc_req_ptr->usb_req.status = status;
+		udc_req_ptr->usb_req.actual = 0;
+	}
+
+	setup_status_trb(crg_udc, enq_pt, &udc_req_ptr->usb_req,
+			udc_ep_ptr->pcs, set_addr, stall);
+
+	enq_pt++;
+
+	/* check if we are at end of trb segment.  If so, update
+	 * pcs and enq for next segment
+	 */
+	if (GETF(TRB_TYPE, enq_pt->dw3) == TRB_TYPE_LINK) {
+		if (GETF(TRB_LINK_TOGGLE_CYCLE, enq_pt->dw3)) {
+			enq_pt->dw3 = SETF_VAR
+				(TRB_CYCLE_BIT, enq_pt->dw3, udc_ep_ptr->pcs);
+			udc_ep_ptr->pcs ^= 0x1;
+		}
+		enq_pt = udc_ep_ptr->first_trb;
+	}
+	udc_ep_ptr->enq_pt = enq_pt;
+
+	knock_doorbell(crg_udc, 0);
+
+	list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue);
+}
+
+static void ep0_req_complete(struct crg_udc_ep *udc_ep_ptr)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
+
+	switch (crg_udc->setup_status) {
+	case DATA_STAGE_XFER:
+		crg_udc->setup_status = STATUS_STAGE_RECV;
+		build_ep0_status(udc_ep_ptr, true, -EINPROGRESS, NULL, 0, 0);
+		break;
+	case DATA_STAGE_RECV:
+		crg_udc->setup_status = STATUS_STAGE_XFER;
+		build_ep0_status(udc_ep_ptr, true, -EINPROGRESS, NULL, 0, 0);
+		break;
+	default:
+		if (crg_udc->setup_fn_call_back)
+			crg_udc->setup_fn_call_back(crg_udc);
+
+		crg_udc->setup_status = WAIT_FOR_SETUP;
+		break;
+	}
+}
+
+static void handle_cmpl_code_success(struct crg_gadget_dev *crg_udc,
+		struct event_trb_s *event, struct crg_udc_ep *udc_ep_ptr)
+{
+	u64 trb_pt;
+	struct transfer_trb_s *p_trb;
+	struct crg_udc_request *udc_req_ptr;
+	u32 trb_transfer_length;
+
+	trb_pt = (u64)event->dw0 + ((u64)(event->dw1) << 32);
+	p_trb = tran_trb_dma_to_virt(udc_ep_ptr, trb_pt);
+
+	dev_dbg(crg_udc->dev, "trb_pt = 0x%lx, p_trb = 0x%p\n", (unsigned long)trb_pt, p_trb);
+	dev_dbg(crg_udc->dev, "trb dw0 = 0x%x\n", p_trb->dw0);
+	dev_dbg(crg_udc->dev, "trb dw1 = 0x%x\n", p_trb->dw1);
+	dev_dbg(crg_udc->dev, "trb dw2 = 0x%x\n", p_trb->dw2);
+	dev_dbg(crg_udc->dev, "trb dw3 = 0x%x\n", p_trb->dw3);
+
+	if (!GETF(TRB_CHAIN_BIT, p_trb->dw3)) {
+		/* chain bit is not set, which means it
+		 * is the end of a TD
+		 */
+		udc_req_ptr = list_entry(udc_ep_ptr->queue.next,
+					struct crg_udc_request, queue);
+
+		dev_dbg(crg_udc->dev, "udc_req_ptr = 0x%p\n", udc_req_ptr);
+
+		trb_transfer_length = GETF(EVE_TRB_TRAN_LEN,
+					event->dw2);
+		udc_req_ptr->usb_req.actual = udc_req_ptr->usb_req.length -
+					trb_transfer_length;
+		dev_dbg(crg_udc->dev, "Actual data xfer = 0x%x, tx_len = 0x%x\n",
+			udc_req_ptr->usb_req.actual, trb_transfer_length);
+
+		dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.buf = 0x%p\n",
+			udc_req_ptr->usb_req.buf);
+		/* Ensure that req_ptr is updated */
+		wmb();
+		req_done(udc_ep_ptr, udc_req_ptr, 0);
+		if (!udc_ep_ptr->desc) {
+			dev_dbg(crg_udc->dev, "udc_ep_ptr->desc is NULL\n");
+		} else {
+			if (usb_endpoint_xfer_control(udc_ep_ptr->desc))
+				ep0_req_complete(udc_ep_ptr);
+		}
+	}
+}
+
+static void update_dequeue_pt(struct event_trb_s *event,
+	struct crg_udc_ep *udc_ep)
+{
+	u32 deq_pt_lo = event->dw0;
+	u32 deq_pt_hi = event->dw1;
+	u64 dq_pt_addr = (u64)deq_pt_lo + ((u64)deq_pt_hi << 32);
+	struct transfer_trb_s *deq_pt;
+
+	deq_pt = tran_trb_dma_to_virt(udc_ep, dq_pt_addr);
+	deq_pt++;
+
+	if (GETF(TRB_TYPE, deq_pt->dw3) == TRB_TYPE_LINK)
+		deq_pt = udc_ep->first_trb;
+
+	udc_ep->deq_pt = deq_pt;
+}
+
+static void advance_dequeue_pt(struct crg_udc_ep *udc_ep)
+{
+	struct crg_udc_request *udc_req;
+
+	if (!list_empty(&udc_ep->queue)) {
+		udc_req = list_entry(udc_ep->queue.next,
+				struct crg_udc_request,
+				queue);
+
+		if (udc_req->first_trb)
+			udc_ep->deq_pt = udc_req->first_trb;
+		else
+			udc_ep->deq_pt = udc_ep->enq_pt;
+	} else
+		udc_ep->deq_pt = udc_ep->enq_pt;
+}
+
+static bool is_request_dequeued(struct crg_gadget_dev *crg_udc,
+		struct crg_udc_ep *udc_ep, struct event_trb_s *event)
+{
+	struct crg_udc_request *udc_req;
+	u32 trb_pt_lo = event->dw0;
+	u32 trb_pt_hi = event->dw1;
+	u64 trb_addr = (u64)trb_pt_lo + ((u64)trb_pt_hi << 32);
+	struct transfer_trb_s *trb_pt;
+	bool status = true;
+
+	if (udc_ep->DCI == 0)
+		return false;
+
+	trb_pt = tran_trb_dma_to_virt(udc_ep, trb_addr);
+	list_for_each_entry(udc_req, &udc_ep->queue, queue) {
+		if (trb_pt == udc_req->last_trb ||
+			trb_pt == udc_req->first_trb) {
+			status = false;
+			break;
+		}
+
+		if (is_pointer_less_than(trb_pt, udc_req->last_trb, udc_ep) &&
+			is_pointer_less_than(udc_req->first_trb, trb_pt,
+				udc_ep)) {
+			status = false;
+			break;
+		}
+	}
+
+	return status;
+}
+
+static unsigned int count_trbs(u64 addr, u64 len)
+{
+	unsigned int num_trbs;
+
+	num_trbs = DIV_ROUND_UP(len + (addr & (TRB_MAX_BUFFER_SIZE - 1)),
+			TRB_MAX_BUFFER_SIZE);
+	if (num_trbs == 0)
+		num_trbs++;
+
+	return num_trbs;
+}
+
+static unsigned int count_sg_trbs_needed(struct usb_request *usb_req)
+{
+	struct scatterlist *sg;
+	unsigned int i, len, full_len, num_trbs = 0;
+
+	full_len = usb_req->length;
+
+	for_each_sg(usb_req->sg, sg, usb_req->num_mapped_sgs, i) {
+		len = sg_dma_len(sg);
+		num_trbs += count_trbs(sg_dma_address(sg), len);
+		len = min_t(unsigned int, len, full_len);
+		full_len -= len;
+		if (full_len == 0)
+			break;
+	}
+
+	return num_trbs;
+}
+
+
+static int crg_udc_build_td(struct crg_udc_ep *udc_ep_ptr,
+		struct crg_udc_request *udc_req_ptr)
+{
+	int status = 0;
+	struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
+	u32 num_trbs_needed;
+	u64 buffer_length;
+	u32 tmp;
+
+	dev_dbg(crg_udc->dev, "udc_req buf = 0x%p\n", udc_req_ptr->usb_req.buf);
+
+	if (udc_req_ptr->trbs_needed) {
+		/* If this is called to complete pending TRB transfers
+		 * of previous Request
+		 */
+		buffer_length = udc_req_ptr->buff_len_left;
+		num_trbs_needed = udc_req_ptr->trbs_needed;
+	} else {
+		buffer_length = (u64)udc_req_ptr->usb_req.length;
+
+		if (udc_req_ptr->usb_req.num_sgs)
+			num_trbs_needed = count_sg_trbs_needed(&udc_req_ptr->usb_req);
+		else {
+			num_trbs_needed = (u32)(buffer_length / TRB_MAX_BUFFER_SIZE);
+
+			if (buffer_length == 0 ||
+				(buffer_length % TRB_MAX_BUFFER_SIZE))
+				num_trbs_needed += 1;
+		}
+	}
+
+	dev_dbg(crg_udc->dev, "buf_len = %ld, num_trb_needed = %d\n",
+		(unsigned long)buffer_length, num_trbs_needed);
+
+	if (usb_endpoint_xfer_control(udc_ep_ptr->desc)) {
+		dev_dbg(crg_udc->dev, "crg_udc_queue_ctrl control\n");
+		status = crg_udc_queue_ctrl(udc_ep_ptr,
+				 udc_req_ptr, num_trbs_needed);
+	} else if (usb_endpoint_xfer_isoc(udc_ep_ptr->desc)) {
+		dev_dbg(crg_udc->dev, "crg_udc_queue_trbs isoc\n");
+		status = crg_udc_queue_trbs(udc_ep_ptr, udc_req_ptr, 1,
+				CRGUDC_ISOC_EP_TD_RING_SIZE,
+				num_trbs_needed, buffer_length);
+
+		tmp = udc_ep_ptr->DCI;
+		tmp = CRG_U3DC_DB_TARGET(tmp);
+		dev_dbg(crg_udc->dev, "DOORBELL = 0x%x\n", tmp);
+
+		knock_doorbell(crg_udc, udc_ep_ptr->DCI);
+	} else if (usb_endpoint_xfer_bulk(udc_ep_ptr->desc)) {
+		dev_dbg(crg_udc->dev, "crg_udc_queue_trbs bulk\n");
+		status = crg_udc_queue_trbs(udc_ep_ptr, udc_req_ptr, 0,
+				CRGUDC_BULK_EP_TD_RING_SIZE,
+				num_trbs_needed, buffer_length);
+		tmp = udc_ep_ptr->DCI;
+		tmp = CRG_U3DC_DB_TARGET(tmp);
+		if (udc_ep_ptr->comp_desc &&
+				usb_ss_max_streams(udc_ep_ptr->comp_desc)) {
+			/* hold the doorbell if stream_rejected is set */
+			dev_err(crg_udc->dev, "%s, WANT TO have bulk stream\n", __func__);
+		}
+
+		knock_doorbell(crg_udc, udc_ep_ptr->DCI);
+	} else {
+		/* interrupt endpoint */
+		status = crg_udc_queue_trbs(udc_ep_ptr, udc_req_ptr, 0,
+				CRGUDC_INT_EP_TD_RING_SIZE,
+				num_trbs_needed, buffer_length);
+		tmp = udc_ep_ptr->DCI;
+		tmp = CRG_U3DC_DB_TARGET(tmp);
+
+		knock_doorbell(crg_udc, udc_ep_ptr->DCI);
+	}
+
+	return status;
+}
+
+/* This function will go through the list of the USB requests for the
+ * given endpoint and schedule any unscheduled trb's to the xfer ring
+ */
+static void queue_pending_trbs(struct crg_udc_ep *udc_ep_ptr)
+{
+	struct crg_udc_request *udc_req_ptr;
+	/* schedule  trbs till there arent any pending unscheduled ones
+	 * or the ring is full again
+	 */
+
+	list_for_each_entry(udc_req_ptr, &udc_ep_ptr->queue, queue) {
+		if (udc_req_ptr->all_trbs_queued == 0)
+			crg_udc_build_td(udc_ep_ptr, udc_req_ptr);
+
+		if (udc_ep_ptr->tran_ring_full)
+			break;
+	}
+}
+
+static void squeeze_xfer_ring(struct crg_udc_ep *udc_ep_ptr,
+		struct crg_udc_request *udc_req_ptr)
+{
+	struct transfer_trb_s *temp = udc_req_ptr->first_trb;
+	struct crg_udc_request *next_req;
+
+	/* All the incompleted Requests are recorded in crg_udc_ep.queue by SW*/
+	/* 1. Clear all the queued-in-ring trbs from the deleted point */
+	/* 2. Re-queue in ring the Requests that are after the deleted Request*/
+	while (temp != udc_ep_ptr->enq_pt) {
+		temp->dw0 = 0;
+		temp->dw1 = 0;
+		temp->dw2 = 0;
+		temp->dw3 = 0;
+
+		temp++;
+
+		if (GETF(TRB_TYPE, temp->dw3) == TRB_TYPE_LINK)
+			temp = udc_ep_ptr->first_trb;
+	}
+
+	/* Update the new enq_ptr starting from the deleted req */
+	udc_ep_ptr->enq_pt = udc_req_ptr->first_trb;
+
+	if (udc_ep_ptr->tran_ring_full)
+		udc_ep_ptr->tran_ring_full = false;
+
+	next_req = list_entry(udc_req_ptr->queue.next,
+				struct crg_udc_request, queue);
+
+	list_for_each_entry_from(next_req, &udc_ep_ptr->queue, queue) {
+		next_req->usb_req.status = -EINPROGRESS;
+		next_req->usb_req.actual = 0;
+
+		/* clear the values of the nv_udc_request container **/
+		clear_req_container(next_req);
+
+		if (udc_ep_ptr->tran_ring_full)
+			break;
+
+		/* push the request to the transfer ring */
+		crg_udc_build_td(udc_ep_ptr, next_req);
+	}
+}
+
+static int set_ep0_halt(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_udc_ep *udc_ep_ptr = &crg_udc->udc_ep[0];
+	int ep_state;
+
+	ep_state = get_ep_state(crg_udc, udc_ep_ptr->DCI);
+	if (ep_state == EP_STATE_HALTED ||
+		ep_state == EP_STATE_DISABLED) {
+		return 0;
+	}
+
+	build_ep0_status(udc_ep_ptr, true, -EINVAL, NULL, 0, 1);
+
+	udc_ep_ptr->ep_state = EP_STATE_HALTED;
+
+	return 0;
+}
+
+static int set_ep_halt(struct crg_gadget_dev *crg_udc, int DCI)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	struct crg_udc_ep *udc_ep_ptr = &crg_udc->udc_ep[DCI];
+	u32 param0;
+	u32 tmp;
+
+	dev_dbg(crg_udc->dev, "%s DCI=%d  !!\n", __func__, DCI);
+
+	if (DCI == 0)
+		return 0;
+
+	if (udc_ep_ptr->ep_state == EP_STATE_DISABLED ||
+		udc_ep_ptr->ep_state == EP_STATE_HALTED)
+		return 0;
+
+	param0 = (0x1 << DCI);
+	crg_issue_command(crg_udc, CRG_CMD_SET_HALT, param0, 0);
+	do {
+		tmp = readl(&uccr->ep_running);
+	} while ((tmp & param0) != 0);
+
+	/* clean up the request queue */
+	nuke(udc_ep_ptr, -ECONNRESET);
+
+	udc_ep_ptr->deq_pt = udc_ep_ptr->enq_pt;
+	udc_ep_ptr->tran_ring_full = false;
+	udc_ep_ptr->ep_state = EP_STATE_HALTED;
+
+	return 0;
+}
+
+static int ep_halt(struct crg_udc_ep *udc_ep_ptr,
+					int halt, int ignore_wedge)
+{
+	struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
+	struct crg_uccr *uccr = crg_udc->uccr;
+	int ep_state;
+	bool reset_seq_only = false;
+	int do_halt;
+	u32 param0;
+	u32 tmp;
+	struct crg_udc_request *udc_req_ptr;
+
+	if (!udc_ep_ptr->desc) {
+		dev_err(crg_udc->dev, "NULL desc\n");
+		return -EINVAL;
+	}
+
+	if (udc_ep_ptr->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+		dev_err(crg_udc->dev, "Isoc ep, halt not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (udc_ep_ptr->DCI == 0)
+		return 0;
+
+	ep_state = get_ep_state(crg_udc, udc_ep_ptr->DCI);
+
+	if (ep_state == EP_STATE_DISABLED)
+		return 0;
+
+	if (ep_state == EP_STATE_HALTED) {
+		if (halt != 0)
+			return 0;
+
+		/* want unhalt an halted ep */
+		if (udc_ep_ptr->wedge && !ignore_wedge)	{
+			do_halt = -1;
+			reset_seq_only = true;
+		} else {
+			do_halt = 0;
+		}
+
+	} else {
+		/* ep state == running or stopped */
+		if (halt != 0) {
+			/* want halt a running ep */
+			do_halt = 1;
+		} else {
+			/* reset a running ep */
+			do_halt = 0;
+			reset_seq_only = true;
+		}
+	}
+
+	param0 = (0x1 << udc_ep_ptr->DCI);
+	if (do_halt == 1) {
+		/* setting ep to halt */
+		dev_dbg(crg_udc->dev, "HALT EP DCI = %d\n", udc_ep_ptr->DCI);
+		crg_issue_command(crg_udc, CRG_CMD_SET_HALT, param0, 0);
+		do {
+			tmp = readl(&uccr->ep_running);
+		} while ((tmp & param0) != 0);
+
+		if (crg_udc->gadget.speed >= USB_SPEED_SUPER) {
+			/* clean up the request queue */
+			nuke(udc_ep_ptr, -ECONNRESET);
+
+			udc_ep_ptr->deq_pt = udc_ep_ptr->enq_pt;
+			udc_ep_ptr->tran_ring_full = false;
+
+			dev_dbg(crg_udc->dev, "update deq_pt tp enq_pt 0x%p\n",
+				udc_ep_ptr->deq_pt);
+		}
+		/* clean up the request queue */
+		udc_ep_ptr->ep_state = EP_STATE_HALTED;
+	} else if (do_halt == 0) {
+		/* clearing ep halt state */
+		dev_dbg(crg_udc->dev, "Clear EP HALT DCI = %d\n", udc_ep_ptr->DCI);
+		/* reset sequence number */
+		crg_issue_command(crg_udc, CRG_CMD_RESET_SEQNUM, param0, 0);
+
+		if (!reset_seq_only) {
+			/* Clear halt for a halted EP.*/
+			/* NOTE: we must CLEAR_HALT first, then SET_TR_DQPTR*/
+			crg_issue_command(crg_udc,
+				CRG_CMD_CLEAR_HALT, param0, 0);
+			crg_udc_epcx_update_dqptr(udc_ep_ptr);
+
+			dev_dbg(crg_udc->dev,
+				"crg_udc_epcx_update_dqptr , PCS = %d\n",
+				udc_ep_ptr->pcs);
+		}
+
+		udc_ep_ptr->wedge = 0;
+		udc_ep_ptr->ep_state = EP_STATE_RUNNING;
+		/* set endpoint to running state */
+		/* clear pause for the endpoint */
+		if (!list_empty(&udc_ep_ptr->queue)) {
+			tmp = udc_ep_ptr->DCI;
+			tmp = CRG_U3DC_DB_TARGET(tmp);
+
+			list_for_each_entry(udc_req_ptr, &udc_ep_ptr->queue,
+					    queue) {
+				struct transfer_trb_s *tmp_ptr =
+					udc_ep_ptr->deq_pt;
+
+				tmp_ptr--;
+				tmp_ptr = udc_ep_ptr->deq_pt + 1;
+				if (GETF(TRB_TYPE, tmp_ptr->dw3) == TRB_TYPE_LINK) {
+					udc_ep_ptr->pcs ^= 0x1;
+					crg_udc_epcx_update_dqptr(udc_ep_ptr);
+					udc_ep_ptr->pcs ^= 0x1;
+				}
+			}
+			knock_doorbell(crg_udc, udc_ep_ptr->DCI);
+		}
+	} else {
+		/* wedged EP deny CLEAR HALT */
+		dev_dbg(crg_udc->dev, "wedged EP deny CLEAR HALT DCI = %d\n", udc_ep_ptr->DCI);
+		/* reset sequence number */
+		if (reset_seq_only)
+			crg_issue_command(crg_udc,
+				CRG_CMD_RESET_SEQNUM, param0, 0);
+	}
+
+	return 0;
+}
+
+/************ep related ops*******************************/
+static int crg_udc_ep_disable(struct usb_ep *ep)
+{
+	struct crg_udc_ep *udc_ep;
+	struct crg_gadget_dev *crg_udc;
+	struct ep_cx_s *p_ep_cx;
+	int ep_state;
+	struct crg_uccr *uccr;
+	unsigned long flags = 0;
+
+	if (!ep)
+		return -EINVAL;
+
+	udc_ep = container_of(ep, struct crg_udc_ep, usb_ep);
+	crg_udc = udc_ep->crg_udc;
+
+	if (udc_ep->DCI == 0)
+		return 0;
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	uccr = crg_udc->uccr;
+	p_ep_cx = (struct ep_cx_s *)crg_udc->p_epcx + udc_ep->DCI - 2;
+
+	ep_state = get_ep_state(crg_udc, udc_ep->DCI);
+	if (ep_state == EP_STATE_DISABLED) {
+		/* get here if ep is already disabled */
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+	}
+
+	dev_dbg(crg_udc->dev, "EPDCI = 0x%x\n", udc_ep->DCI);
+
+	/*Maybe we need to halt ep before ep disable*/
+
+	writel(0x1 << udc_ep->DCI, &uccr->ep_enable);
+
+	/* clean up the request queue */
+	nuke(udc_ep, -ESHUTDOWN);
+
+	/* decrement ep counters */
+	crg_udc->num_enabled_eps--;
+
+	udc_ep->desc = NULL;
+
+	/* clean up the endpoint context */
+	memset(p_ep_cx, 0, sizeof(struct ep_cx_s));
+
+	dev_dbg(crg_udc->dev, "num_enabled_eps = %d\n", crg_udc->num_enabled_eps);
+
+	/* If device state was changed to default by port
+	 * reset, should not overwrite it again
+	 */
+	if (crg_udc->num_enabled_eps == 0 &&
+		crg_udc->device_state == USB_STATE_CONFIGURED) {
+		dev_dbg(crg_udc->dev, "Device State USB_STATE_CONFIGURED\n");
+		dev_dbg(crg_udc->dev, "Set Device State to addressed\n");
+		crg_udc->device_state = USB_STATE_ADDRESS;
+
+	}
+
+	udc_ep->ep_state = EP_STATE_DISABLED;
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return 0;
+}
+
+static int crg_udc_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct crg_udc_ep *udc_ep;
+	struct crg_gadget_dev *crg_udc;
+	u32 param0;
+	unsigned long flags = 0;
+	struct ep_cx_s *epcx;
+	struct crg_uccr *uccr;
+
+	if  (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	udc_ep = container_of(ep, struct crg_udc_ep, usb_ep);
+
+	/*ep0 is always running*/
+	if (udc_ep->DCI == 0)
+		return 0;
+
+	crg_udc = udc_ep->crg_udc;
+	uccr = crg_udc->uccr;
+
+	if (!crg_udc->gadget_driver)
+		return -ESHUTDOWN;
+
+	dev_dbg(crg_udc->dev, "%s DCI = %d\n", __func__, udc_ep->DCI);
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	/*crg ep context start from ep1*/
+	if (get_ep_state(crg_udc, udc_ep->DCI) != EP_STATE_DISABLED) {
+		dev_dbg(crg_udc->dev, "%s disable first\n", __func__);
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		crg_udc_ep_disable(ep);
+		spin_lock_irqsave(&crg_udc->udc_lock, flags);
+	}
+
+	udc_ep->desc = desc;
+	udc_ep->comp_desc = ep->comp_desc;
+
+	/* setup endpoint context for regular endpoint
+	 * the endpoint context for control endpoint has been
+	 * setted up in probe function
+	 */
+	if (udc_ep->DCI) {
+		dev_dbg(crg_udc->dev, "ep_enable udc_ep->DCI = %d\n", udc_ep->DCI);
+
+		/* setup transfer ring */
+		if (!udc_ep->tran_ring_info.vaddr) {
+			dma_addr_t dma;
+			u32 ring_size = 0;
+			void *vaddr;
+			size_t len;
+
+			if (usb_endpoint_xfer_bulk(desc))
+				ring_size =  CRGUDC_BULK_EP_TD_RING_SIZE;
+			else if (usb_endpoint_xfer_isoc(desc))
+				ring_size = CRGUDC_ISOC_EP_TD_RING_SIZE;
+			else if (usb_endpoint_xfer_int(desc))
+				ring_size = CRGUDC_INT_EP_TD_RING_SIZE;
+			len = ring_size * sizeof(struct transfer_trb_s);
+			spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+			vaddr = dma_alloc_coherent(crg_udc->dev, len,
+					&dma, GFP_ATOMIC);
+			if (!vaddr)
+				return -ENOMEM;
+			spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+			udc_ep->tran_ring_info.vaddr = vaddr;
+			udc_ep->tran_ring_info.dma = dma;
+			udc_ep->tran_ring_info.len = len;
+			udc_ep->first_trb = vaddr;
+			udc_ep->last_trb = udc_ep->first_trb + ring_size - 1;
+		}
+		memset(udc_ep->first_trb, 0, udc_ep->tran_ring_info.len);
+		/* Ensure that transfer ring is updated */
+		wmb();
+		setup_link_trb(udc_ep->last_trb, true,
+					udc_ep->tran_ring_info.dma);
+
+		udc_ep->enq_pt = udc_ep->first_trb;
+		udc_ep->deq_pt = udc_ep->first_trb;
+		udc_ep->pcs = 1;
+		udc_ep->tran_ring_full = false;
+		crg_udc->num_enabled_eps++;
+		crg_udc_epcx_setup(udc_ep);
+	}
+
+	dev_dbg(crg_udc->dev, "num_enabled_eps = %d\n", crg_udc->num_enabled_eps);
+
+	epcx = (struct ep_cx_s *)(crg_udc->p_epcx + udc_ep->DCI - 2);
+
+	param0 = (0x1 << udc_ep->DCI);
+	crg_issue_command(crg_udc, CRG_CMD_CONFIG_EP, param0, 0);
+
+	dev_dbg(crg_udc->dev, "config ep and start, DCI=%d\n", udc_ep->DCI);
+	if (crg_udc->device_state == USB_STATE_ADDRESS)
+		crg_udc->device_state = USB_STATE_CONFIGURED;
+
+	udc_ep->wedge = 0;
+	udc_ep->ep_state = EP_STATE_RUNNING;
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return 0;
+}
+
+static struct usb_request *
+crg_udc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct crg_udc_request *udc_req_ptr = NULL;
+
+	udc_req_ptr = kzalloc(sizeof(*udc_req_ptr), gfp_flags);
+
+
+	if (!udc_req_ptr)
+		return NULL;
+
+	udc_req_ptr->usb_req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&udc_req_ptr->queue);
+
+	return &udc_req_ptr->usb_req;
+}
+
+static void crg_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct crg_udc_request *udc_req_ptr = NULL;
+
+	if (!_ep || !_req)
+		return;
+
+	udc_req_ptr = container_of(_req, struct crg_udc_request, usb_req);
+	kfree(udc_req_ptr);
+}
+
+static int
+crg_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+				gfp_t gfp_flags)
+{
+	struct crg_udc_request *udc_req_ptr;
+	struct crg_udc_ep *udc_ep_ptr;
+	struct crg_gadget_dev *crg_udc;
+	int status;
+	unsigned long flags = 0;
+	int dma_data_dir = 0;
+
+
+	if (!_req || !_ep)
+		return -EINVAL;
+
+	udc_req_ptr = container_of(_req, struct crg_udc_request, usb_req);
+	if (!udc_req_ptr)
+		return -EINVAL;
+
+	udc_ep_ptr = container_of(_ep, struct crg_udc_ep, usb_ep);
+	if (!udc_ep_ptr)
+		return -EINVAL;
+
+	crg_udc = udc_ep_ptr->crg_udc;
+	if (!crg_udc)
+		return -EINVAL;
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	if (!udc_ep_ptr->first_trb ||
+		!udc_req_ptr->usb_req.complete ||
+		(!udc_req_ptr->usb_req.buf && !udc_req_ptr->usb_req.num_sgs) ||
+		!list_empty(&udc_req_ptr->queue)) {
+		dev_dbg(crg_udc->dev, "%s, invalid usbrequest\n", __func__);
+		if (!udc_ep_ptr->first_trb)
+			dev_err(crg_udc->dev, "%s, no first_trb\n", __func__);
+
+		if (!udc_req_ptr->usb_req.complete)
+			dev_err(crg_udc->dev, "%s, no complete\n", __func__);
+
+		if (!udc_req_ptr->usb_req.buf)
+			dev_err(crg_udc->dev, "%s, no req buf\n", __func__);
+
+		if (!list_empty(&udc_req_ptr->queue))
+			dev_err(crg_udc->dev, "%s, list not empty\n", __func__);
+
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+	}
+	dev_dbg(crg_udc->dev, "enqueue EPDCI = 0x%x\n", udc_ep_ptr->DCI);
+	dev_dbg(crg_udc->dev, "udc_req buf = 0x%p\n", udc_req_ptr->usb_req.buf);
+
+	if (!udc_ep_ptr->desc) {
+		dev_dbg(crg_udc->dev, "udc_ep_ptr->Desc is null\n");
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+	}
+	/* Ensure that req_ptr is updated */
+	wmb();
+	/* Clearing the Values of the UDC_REQUEST container */
+	clear_req_container(udc_req_ptr);
+	udc_req_ptr->mapped = 0;
+
+	if (usb_endpoint_xfer_control(udc_ep_ptr->desc) &&
+				_req->length == 0) {
+		crg_udc->setup_status = STATUS_STAGE_XFER;
+		status = -EINPROGRESS;
+		dev_dbg(crg_udc->dev, "udc_req_ptr = 0x%p\n", udc_req_ptr);
+
+		build_ep0_status(&crg_udc->udc_ep[0], false, status,
+			udc_req_ptr, 0, 0);
+		dev_dbg(crg_udc->dev, "act status request for control endpoint\n");
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return 0;
+	}
+
+	/* request length is possible to be 0. Like SCSI blank command */
+	dev_dbg(crg_udc->dev, "request length=%d\n", _req->length);
+
+	if (udc_req_ptr->usb_req.num_sgs) {
+		int n;
+
+		dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.num_sgs = %d\n",
+			udc_req_ptr->usb_req.num_sgs);
+		dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.sg->length = %d\n",
+			udc_req_ptr->usb_req.sg->length);
+		dma_data_dir = (usb_endpoint_dir_in(udc_ep_ptr->desc)
+				? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		n = dma_map_sg(crg_udc->dev, udc_req_ptr->usb_req.sg,
+			udc_req_ptr->usb_req.num_sgs, dma_data_dir);
+		if (n <= 0) {
+			dev_err(crg_udc->dev, "dma_map_sg fail, ret is %d\n", n);
+			dump_stack();
+			spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+			return -EINVAL;
+		}
+		if (n != udc_req_ptr->usb_req.num_sgs) {
+			dev_err(crg_udc->dev, "URB_DMA_SG_COMBINED we not support\n");
+			spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+			return -EAGAIN;
+		}
+		udc_req_ptr->usb_req.num_mapped_sgs = n;
+		dev_dbg(crg_udc->dev, "dma_map_sg done , usb_req.num_mapped_sgs = %d\n", n);
+
+
+	} else if (udc_req_ptr->usb_req.sg) {
+		dev_err(crg_udc->dev, "num_sgs = 0, but udc_req_ptr->usb_req.sg is not NULL\n");
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+
+	} else {
+		if (udc_req_ptr->usb_req.dma == DMA_ADDR_INVALID && _req->length != 0) {
+			if (usb_endpoint_xfer_control(udc_ep_ptr->desc)) {
+				if (crg_udc->setup_status == DATA_STAGE_XFER ||
+					crg_udc->setup_status == STATUS_STAGE_XFER)
+					dma_data_dir = DMA_TO_DEVICE;
+
+				if (crg_udc->setup_status == DATA_STAGE_RECV ||
+					crg_udc->setup_status == STATUS_STAGE_RECV)
+					dma_data_dir = DMA_FROM_DEVICE;
+			} else {
+				dma_data_dir = (usb_endpoint_dir_in(udc_ep_ptr->desc)
+						? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+			}
+			udc_req_ptr->usb_req.dma =
+				dma_map_single(crg_udc->dev, udc_req_ptr->usb_req.buf,
+						udc_req_ptr->usb_req.length,
+						dma_data_dir);
+
+
+			udc_req_ptr->mapped = 1;
+
+			dev_dbg(crg_udc->dev, "dma_map_single and mapped is 1\n");
+		}
+	}
+
+	udc_req_ptr->usb_req.status = -EINPROGRESS;
+	udc_req_ptr->usb_req.actual = 0;
+
+	/* If the transfer ring for this particular end point is full,
+	 * then simply queue the request and return
+	 */
+	if (udc_ep_ptr->tran_ring_full) {
+		status = 0;
+	} else {
+		/* push the request to the transfer ring if possible. */
+		status = crg_udc_build_td(udc_ep_ptr, udc_req_ptr);
+	}
+	if (!status)
+		list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue);
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return status;
+}
+
+static int
+crg_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct crg_udc_ep *udc_ep_ptr;
+	struct crg_gadget_dev *crg_udc;
+	struct crg_uccr *uccr;
+	u32 tmp = 0;
+	struct crg_udc_request *udc_req;
+	struct ep_cx_s *p_ep_cx;
+	int old_ep_state;
+	struct transfer_trb_s *pause_pt;
+	u32 deq_pt_lo, deq_pt_hi;
+	u64 dq_pt_addr;
+	u8 DCI;
+	unsigned long flags = 0;
+
+	if (!_ep || !_req)
+		return -EINVAL;
+
+	udc_ep_ptr = container_of(_ep, struct crg_udc_ep, usb_ep);
+	crg_udc = udc_ep_ptr->crg_udc;
+	uccr = crg_udc->uccr;
+	DCI = udc_ep_ptr->DCI;
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	dev_dbg(crg_udc->dev, "%s EPDCI = 0x%x\n", __func__, DCI);
+	old_ep_state = get_ep_state(crg_udc, DCI);
+	if (DCI != 0 && old_ep_state == EP_STATE_RUNNING) {
+		u32 param0;
+
+		dev_dbg(crg_udc->dev, "%s, EP_STATE_RUNNING\n", __func__);
+		param0 = (0x1 << DCI);
+		/* stop the DMA from HW first */
+		crg_issue_command(crg_udc, CRG_CMD_STOP_EP, param0, 0);
+		do {
+			tmp = readl(&uccr->ep_running);
+		} while ((tmp & param0) != 0);
+		udc_ep_ptr->ep_state = EP_STATE_STOPPED;
+	}
+
+	list_for_each_entry(udc_req, &udc_ep_ptr->queue, queue) {
+		if (&udc_req->usb_req == _req)
+			break;
+	}
+
+	if (&udc_req->usb_req != _req) {
+		dev_dbg(crg_udc->dev, "did not find the request in request queue\n");
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+	}
+	/* Request hasn't been queued to transfer ring yet
+	 * dequeue it from sw queue only
+	 */
+	if (!udc_req->first_trb) {
+		req_done(udc_ep_ptr, udc_req, -ECONNRESET);
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return 0;
+	}
+
+	/* ep0 cannot be stopped. So if request has already been queued to
+	 * transfer ring, it cannot be dequeued
+	 */
+	if (DCI == 0) {
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+	}
+
+	p_ep_cx = crg_udc->p_epcx + DCI - 2;
+	deq_pt_lo = p_ep_cx->dw2 & EP_CX_TR_DQPT_LO_MASK;
+	deq_pt_hi = p_ep_cx->dw3;
+	dq_pt_addr = (u64)deq_pt_lo + ((u64)deq_pt_hi << 32);
+	pause_pt = tran_trb_dma_to_virt(udc_ep_ptr, dq_pt_addr);
+
+	dev_dbg(crg_udc->dev, "dequeue pause_pt = 0x%p, first_trb = 0x%p\n",
+		pause_pt, udc_req->first_trb);
+	dev_dbg(crg_udc->dev, "dequeue deq_pt = 0x%p, enq_pt = 0x%p\n",
+		udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt);
+
+	if (is_pointer_less_than(pause_pt, udc_req->first_trb, udc_ep_ptr)) {
+		dev_dbg(crg_udc->dev, "squeeze_xfer_ring\n");
+		/* HW hasn't process the request yet */
+		squeeze_xfer_ring(udc_ep_ptr, udc_req);
+		req_done(udc_ep_ptr, udc_req, -ECONNRESET);
+	} else if (udc_req->last_trb &&
+		is_pointer_less_than(udc_req->last_trb, pause_pt, udc_ep_ptr)) {
+		/* Request has been completed by HW
+		 * There must be transfer events pending in event ring, and
+		 * it will be processed later once interrupt context gets spin
+		 * lock.
+		 * Gadget driver free the request without checking the return
+		 * value of usb_ep_dequeue, so we have to complete the request
+		 * here and drop the transfer event later.
+		 */
+		dev_dbg(crg_udc->dev, " Request has been complete by HW, reject request\n");
+		req_done(udc_ep_ptr, udc_req, -ECONNRESET);
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EINVAL;
+
+	} else {
+		/* Request has been partially completed by HW */
+
+		dev_dbg(crg_udc->dev, " Request has been partially completed by HW\n");
+		/*udc_req->usb_req.actual = actual_data_xfered(udc_ep, udc_req);*/
+
+		dev_dbg(crg_udc->dev, "%s, complete requests\n", __func__);
+		req_done(udc_ep_ptr, udc_req, -ECONNRESET);
+
+		advance_dequeue_pt(udc_ep_ptr);
+		crg_udc_epcx_update_dqptr(udc_ep_ptr);
+
+		/* For big TD, we generated completion event every 5 TRBS.
+		 * So, we do not need to update sw dequeue pointer here.
+		 * Wait for interrupt context to update it.
+		 * Do not need to queue more trbs also.
+		 */
+	}
+
+	dev_dbg(crg_udc->dev, "End dequeue deq_pt = 0x%p, enq_pt = 0x%p\n",
+			udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt);
+
+	/* knock doorbell and resume data transfer */
+	if (old_ep_state == EP_STATE_RUNNING) {
+		tmp = DCI;
+		tmp = CRG_U3DC_DB_TARGET(tmp);
+
+		knock_doorbell(crg_udc, udc_ep_ptr->DCI);
+
+		udc_ep_ptr->ep_state = EP_STATE_RUNNING;
+	}
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return 0;
+}
+
+static int crg_udc_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct crg_udc_ep *udc_ep_ptr;
+	int status;
+	unsigned long flags = 0;
+	struct crg_gadget_dev *crg_udc;
+
+	if (!_ep)
+		return -EINVAL;
+
+	udc_ep_ptr = container_of(_ep, struct crg_udc_ep, usb_ep);
+	crg_udc = udc_ep_ptr->crg_udc;
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	if (value && usb_endpoint_dir_in(udc_ep_ptr->desc) &&
+			!list_empty(&udc_ep_ptr->queue)) {
+		dev_err(crg_udc->dev, "set_halt: list not empty\n");
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		return -EAGAIN;
+	}
+
+	status = ep_halt(udc_ep_ptr, value, 1);
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return status;
+}
+
+static int crg_udc_ep_set_wedge(struct usb_ep *_ep)
+{
+	struct crg_udc_ep *udc_ep_ptr;
+	int status;
+	unsigned long flags = 0;
+	struct crg_gadget_dev *crg_udc;
+
+	if (!_ep)
+		return -EINVAL;
+
+	udc_ep_ptr = container_of(_ep, struct crg_udc_ep, usb_ep);
+	crg_udc = udc_ep_ptr->crg_udc;
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	udc_ep_ptr->wedge = 1;
+
+	status = ep_halt(udc_ep_ptr, 1, 1);
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return status;
+}
+
+static struct usb_ep_ops crg_udc_ep_ops = {
+	.enable = crg_udc_ep_enable,
+	.disable = crg_udc_ep_disable,
+	.alloc_request = crg_udc_alloc_request,
+	.free_request = crg_udc_free_request,
+	.queue = crg_udc_ep_queue,
+	.dequeue = crg_udc_ep_dequeue,
+	.set_halt = crg_udc_ep_set_halt,
+	.set_wedge = crg_udc_ep_set_wedge,
+};
+
+static void crg_ep_struct_setup(struct crg_gadget_dev *crg_udc,
+			u32 DCI, const char *name)
+{
+	struct crg_udc_ep *ep = &crg_udc->udc_ep[DCI];
+
+	ep->DCI = DCI;
+
+	if (ep->DCI > 1) {
+		strscpy_pad(ep->name, name, sizeof(ep->name) - 1);
+		ep->usb_ep.name = ep->name;
+		ep->usb_ep.maxpacket = 1024;
+		ep->usb_ep.max_streams = 16;
+
+		ep->usb_ep.caps.type_iso = 1;
+		ep->usb_ep.caps.type_bulk = 1;
+		ep->usb_ep.caps.type_int = 1;
+		ep->usb_ep.caps.dir_in = 1;
+		ep->usb_ep.caps.type_control = 1;
+
+		ep->usb_ep.caps.type_iso = 1;
+		ep->usb_ep.caps.type_bulk = 1;
+		ep->usb_ep.caps.type_int = 1;
+		ep->usb_ep.caps.type_control = 1;
+		if (ep->DCI % 2)
+			ep->usb_ep.caps.dir_out = 1;
+		else
+			ep->usb_ep.caps.dir_in = 1;
+		usb_ep_set_maxpacket_limit(&ep->usb_ep, MAX_PACKET_SIZE);
+	} else {
+		strscpy(ep->name, "ep0", sizeof(ep->name) - 1);
+		ep->usb_ep.name = ep->name;
+		ep->usb_ep.maxpacket = 512;
+		ep->usb_ep.caps.type_control = 1;
+		ep->usb_ep.caps.dir_in = 1;
+		ep->usb_ep.caps.dir_out = 1;
+	}
+
+	dev_dbg(crg_udc->dev, "ep = 0x%p, ep name = %s maxpacket = %d DCI=%d\n",
+			ep, ep->name, ep->usb_ep.maxpacket, ep->DCI);
+	ep->usb_ep.ops = &crg_udc_ep_ops;
+	ep->crg_udc = crg_udc;
+
+	INIT_LIST_HEAD(&ep->queue);
+	if (ep->DCI > 1)
+		list_add_tail(&ep->usb_ep.ep_list, &crg_udc->gadget.ep_list);
+}
+
+
+static void enable_setup_event(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 val;
+
+	dev_dbg(crg_udc->dev, "before setup en config1[0x%p]=0x%x\n",
+		&uccr->config1, readl(&uccr->config1));
+
+	val = readl(&uccr->config1);
+	val |= CRG_U3DC_CFG1_SETUP_EVENT_EN;
+	writel(val, &uccr->config1);
+	dev_dbg(crg_udc->dev, "update config1[0x%p]=0x%x\n",
+		&uccr->config1, readl(&uccr->config1));
+}
+
+static int is_event_ring_x_empty(struct crg_gadget_dev *crg_udc, int index)
+{
+	struct event_trb_s *event;
+	struct crg_udc_event *udc_event;
+
+	udc_event = &crg_udc->udc_event[index];
+	if (udc_event->evt_dq_pt) {
+		event = (struct event_trb_s *)udc_event->evt_dq_pt;
+
+		if (GETF(EVE_TRB_CYCLE_BIT, event->dw3) !=
+				udc_event->CCS)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int is_event_rings_empty(struct crg_gadget_dev *crg_udc)
+{
+	int i;
+
+	for (i = 0; i < CRG_RING_NUM; i++) {
+		if (!is_event_ring_x_empty(crg_udc, i)) {
+			dev_err(crg_udc->dev, "%s evt ring not empty\n", __func__);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int enable_setup(struct crg_gadget_dev *crg_udc)
+{
+	enable_setup_event(crg_udc);
+	crg_udc->device_state = USB_STATE_DEFAULT;
+	crg_udc->setup_status = WAIT_FOR_SETUP;
+	dev_dbg(crg_udc->dev, "%s ready to receive setup events\n", __func__);
+
+	return 0;
+}
+
+static int prepare_for_setup(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_udc_ep *udc_ep0_ptr;
+
+#ifdef REINIT_EP0_ON_BUS_RESET
+	dma_addr_t dqptaddr;
+	u32 cmd_param0;
+	u32 cmd_param1;
+#endif
+
+	if (!is_event_rings_empty(crg_udc) ||
+		crg_udc->portsc_on_reconnecting == 1)
+		return -EBUSY;
+
+	udc_ep0_ptr = &crg_udc->udc_ep[0];
+/* If we reinit ep0 on bus reset, we just make ep0 dequeue pointer align
+ * with enqueue pointer, all remaining xfer trbs became dumb ones which
+ * will not produce xfer event anymore.
+ *
+ * If we considering the opposite solution, we should wait all ep0 xfer
+ * trbs be completed(with some err complete code)
+ */
+#ifdef REINIT_EP0_ON_BUS_RESET
+	/* Complete any reqs on EP0 queue */
+	nuke(udc_ep0_ptr, -ESHUTDOWN);
+
+	crg_udc->ctrl_req_enq_idx = 0;
+	memset(crg_udc->ctrl_req_queue, 0,
+			sizeof(struct crg_setup_packet) * CTRL_REQ_QUEUE_DEPTH);
+
+	/*context related ops*/
+	dqptaddr = tran_trb_virt_to_dma(udc_ep0_ptr, udc_ep0_ptr->enq_pt);
+	cmd_param0 = (lower_32_bits(dqptaddr) &
+			CRG_CMD0_0_DQPTRLO_MASK) |
+			CRG_CMD0_0_DCS(udc_ep0_ptr->pcs);
+	cmd_param1 = upper_32_bits(dqptaddr);
+	crg_issue_command(crg_udc,
+		CRG_CMD_INIT_EP0, cmd_param0, cmd_param1);
+
+	/* TRY this solution*/
+	udc_ep0_ptr->deq_pt = udc_ep0_ptr->enq_pt;
+	udc_ep0_ptr->tran_ring_full = false;
+#else
+	if (!list_empty(&udc_ep0_ptr->queue)) {
+		dev_err(crg_udc->dev, "%s remaining ep0 xfer trbs on reset!\n", __func__);
+		return -EBUSY;
+	}
+#endif
+
+	enable_setup(crg_udc);
+
+	return 0;
+}
+
+static void update_ep0_maxpacketsize(struct crg_gadget_dev *crg_udc)
+{
+	u16 maxpacketsize = 0;
+	struct crg_udc_ep *udc_ep0 = &crg_udc->udc_ep[0];
+	u32 param0;
+
+	if (crg_udc->gadget.speed >= USB_SPEED_SUPER)
+		maxpacketsize = 512;
+	else
+		maxpacketsize = 64;
+
+	param0 = CRG_CMD1_0_MPS(maxpacketsize);
+	crg_issue_command(crg_udc, CRG_CMD_UPDATE_EP0_CFG, param0, 0);
+
+	crg_udc_ep0_desc.wMaxPacketSize = cpu_to_le16(maxpacketsize);
+	udc_ep0->usb_ep.maxpacket = maxpacketsize;
+}
+
+static int init_event_ring(struct crg_gadget_dev *crg_udc, int index)
+{
+	struct crg_uicr *uicr = crg_udc->uicr[index];
+	struct crg_udc_event *udc_event = &crg_udc->udc_event[index];
+
+	int ret;
+	u32 buff_length;
+	dma_addr_t mapping;
+
+	buff_length = CRG_ERST_SIZE * sizeof(struct erst_s);
+	if (!udc_event->erst.vaddr) {
+		udc_event->erst.vaddr =
+			dma_alloc_coherent(crg_udc->dev, buff_length,
+				&mapping, GFP_KERNEL);
+
+		if (!udc_event->erst.vaddr) {
+			ret = -ENOMEM;
+			return ret;
+		}
+	} else {
+		mapping = udc_event->erst.dma;
+	}
+
+	udc_event->erst.len = buff_length;
+	udc_event->erst.dma = mapping;
+	udc_event->p_erst = udc_event->erst.vaddr;
+
+	buff_length = CRG_EVENT_RING_SIZE * sizeof(struct event_trb_s);
+	if (!udc_event->event_ring.vaddr) {
+		udc_event->event_ring.vaddr =
+			dma_alloc_coherent(crg_udc->dev, buff_length,
+				&mapping, GFP_KERNEL);
+
+		if (!udc_event->event_ring.vaddr) {
+			ret = -ENOMEM;
+			return ret;
+		}
+	} else {
+		mapping = udc_event->event_ring.dma;
+	}
+
+	udc_event->event_ring.len = buff_length;
+	udc_event->event_ring.dma = mapping;
+	udc_event->evt_dq_pt = udc_event->event_ring.vaddr;
+
+	udc_event->evt_seg0_last_trb =
+		(struct event_trb_s *)(udc_event->event_ring.vaddr)
+		+ (CRG_EVENT_RING_SIZE - 1);
+
+	udc_event->CCS = 1;
+
+	udc_event->p_erst->seg_addr_lo =
+		lower_32_bits(udc_event->event_ring.dma);
+	udc_event->p_erst->seg_addr_hi =
+		upper_32_bits(udc_event->event_ring.dma);
+	udc_event->p_erst->seg_size = cpu_to_le32(CRG_EVENT_RING_SIZE);
+	udc_event->p_erst->rsvd = 0;
+	/* Ensure that event ring is updated */
+	wmb();
+	/*clear the event ring, to avoid hw unexpected ops
+	 *because of dirty data
+	 */
+	memset(udc_event->event_ring.vaddr, 0, buff_length);
+
+	/*hw related ops ERSTBA && ERSTSZ && ERDP*/
+	/* Ensure that event ring is clear */
+	wmb();
+
+	/**************************/
+	writel(CRG_ERST_SIZE, &uicr->erstsz);
+	writel(lower_32_bits(udc_event->erst.dma), &uicr->erstbalo);
+	writel(upper_32_bits(udc_event->erst.dma), &uicr->erstbahi);
+	writel(lower_32_bits(udc_event->event_ring.dma) | CRG_U3DC_ERDPLO_EHB,
+		&uicr->erdplo);
+	writel(upper_32_bits(udc_event->event_ring.dma), &uicr->erdphi);
+
+	writel((CRG_U3DC_IMAN_INT_EN | CRG_U3DC_IMAN_INT_PEND), &uicr->iman);
+	writel((0L << 0) | (4000L << 0), &uicr->imod);
+
+	return 0;
+}
+
+static int init_device_context(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	int ret;
+	u32 buff_length;
+	dma_addr_t mapping;
+
+	/*ep0 is not included in ep contexts in crg udc*/
+	buff_length = (CRG_NUM_EP_CX - 2) * sizeof(struct ep_cx_s);
+
+	if (!crg_udc->ep_cx.vaddr) {
+		crg_udc->ep_cx.vaddr =
+			dma_alloc_coherent(crg_udc->dev, buff_length,
+				&mapping, GFP_KERNEL);
+			/* Ensure that ep_cx.vaddr is updated */
+			wmb();
+		if  (!crg_udc->ep_cx.vaddr) {
+			ret = -ENOMEM;
+			return ret;
+		}
+	} else {
+		mapping = crg_udc->ep_cx.dma;
+	}
+
+	crg_udc->p_epcx = crg_udc->ep_cx.vaddr;
+	crg_udc->ep_cx.len = buff_length;
+	crg_udc->ep_cx.dma = mapping;
+
+	/*hw ops DCBAPLO DCBAPHI*/
+	writel(lower_32_bits(crg_udc->ep_cx.dma), &uccr->dcbaplo);
+	writel(upper_32_bits(crg_udc->ep_cx.dma), &uccr->dcbaphi);
+
+	dev_dbg(crg_udc->dev, "dcbaplo[0x%p]=0x%x\n", &uccr->dcbaplo, readl(&uccr->dcbaplo));
+	dev_dbg(crg_udc->dev, "dcbaphi[0x%p]=0x%x\n", &uccr->dcbaphi, readl(&uccr->dcbaphi));
+
+	return 0;
+}
+
+static int reset_data_struct(struct crg_gadget_dev *crg_udc)
+{
+	u32 tmp;
+	int i;
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 val;
+
+	val = readl(&uccr->control);
+	val &= (~(CRG_U3DC_CTRL_INT_EN | CRG_U3DC_CTRL_RUN));
+	writel(val, &uccr->control);
+
+	dev_dbg(crg_udc->dev, "capability[0x%p]=0x%x\n", &uccr->capability,
+			readl(&uccr->capability));
+
+	switch (crg_udc->gadget.max_speed) {
+	case USB_SPEED_FULL:
+		tmp = CRG_U3DC_CFG0_MAXSPEED_FS;
+		break;
+	case USB_SPEED_HIGH:
+		tmp = CRG_U3DC_CFG0_MAXSPEED_HS;
+		break;
+	case USB_SPEED_SUPER:
+		tmp = CRG_U3DC_CFG0_MAXSPEED_SS;
+		break;
+	case USB_SPEED_SUPER_PLUS:
+		tmp = CRG_U3DC_CFG0_MAXSPEED_SSP;
+		break;
+	case USB_SPEED_UNKNOWN:
+	default:
+		return -EINVAL;
+	}
+	writel(tmp, &uccr->config0);
+
+	for (i = 0; i < CRG_RING_NUM; i++)
+		init_event_ring(crg_udc, i);
+
+	init_device_context(crg_udc);
+
+	if (!crg_udc->status_req) {
+		crg_udc->status_req =
+		container_of(crg_udc_alloc_request(&crg_udc->udc_ep[0].usb_ep,
+			GFP_ATOMIC), struct crg_udc_request,
+			usb_req);
+	}
+
+	/*other hw ops*/
+	return 0;
+}
+
+static int init_ep0(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_udc_ep *udc_ep_ptr = &crg_udc->udc_ep[0];
+	u32 cmd_param0;
+	u32 cmd_param1;
+
+	/* setup transfer ring */
+	if (!udc_ep_ptr->tran_ring_info.vaddr) {
+		dma_addr_t dma;
+		u32 ring_size = CRGUDC_CONTROL_EP_TD_RING_SIZE;
+		void *vaddr;
+		size_t len;
+
+		len = ring_size * sizeof(struct transfer_trb_s);
+		vaddr = dma_alloc_coherent(crg_udc->dev, len,
+					&dma, GFP_KERNEL);
+		if (!vaddr)
+			return -ENOMEM;
+
+		udc_ep_ptr->tran_ring_info.vaddr = vaddr;
+		udc_ep_ptr->tran_ring_info.dma = dma;
+		udc_ep_ptr->tran_ring_info.len = len;
+		udc_ep_ptr->first_trb = vaddr;
+		udc_ep_ptr->last_trb = udc_ep_ptr->first_trb + ring_size - 1;
+	}
+
+	memset(udc_ep_ptr->first_trb, 0, udc_ep_ptr->tran_ring_info.len);
+	/* Ensure that transfer ring is updated */
+	wmb();
+	udc_ep_ptr->enq_pt = udc_ep_ptr->first_trb;
+	udc_ep_ptr->deq_pt = udc_ep_ptr->first_trb;
+	udc_ep_ptr->pcs = 1;
+	udc_ep_ptr->tran_ring_full = false;
+
+	setup_link_trb(udc_ep_ptr->last_trb,
+		true, udc_ep_ptr->tran_ring_info.dma);
+
+	/*context related ops*/
+	cmd_param0 = (lower_32_bits(udc_ep_ptr->tran_ring_info.dma) &
+			CRG_CMD0_0_DQPTRLO_MASK) |
+			CRG_CMD0_0_DCS(udc_ep_ptr->pcs);
+	cmd_param1 = upper_32_bits(udc_ep_ptr->tran_ring_info.dma);
+
+	dev_dbg(crg_udc->dev, "ep0 ring dma addr = 0x%llx\n", udc_ep_ptr->tran_ring_info.dma);
+
+	dev_dbg(crg_udc->dev, "ep0 ring vaddr = 0x%p\n", udc_ep_ptr->tran_ring_info.vaddr);
+
+	dev_dbg(crg_udc->dev, "INIT EP0 CMD, par0=0x%x, par1=0x%x\n", cmd_param0, cmd_param1);
+
+	crg_issue_command(crg_udc, CRG_CMD_INIT_EP0, cmd_param0, cmd_param1);
+
+	udc_ep_ptr->ep_state = EP_STATE_RUNNING;
+
+	return 0;
+}
+
+static int EP0_Start(struct crg_gadget_dev *crg_udc)
+{
+	crg_udc->udc_ep[0].desc = &crg_udc_ep0_desc;
+
+	return 0;
+}
+
+static void crg_udc_start(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr;
+	u32 val;
+
+	uccr = crg_udc->uccr;
+
+	/*****interrupt related*****/
+	val = readl(&uccr->config1);
+	val |= (CRG_U3DC_CFG1_CSC_EVENT_EN |
+			CRG_U3DC_CFG1_PEC_EVENT_EN |
+			CRG_U3DC_CFG1_PPC_EVENT_EN |
+			CRG_U3DC_CFG1_PRC_EVENT_EN |
+			CRG_U3DC_CFG1_PLC_EVENT_EN |
+			CRG_U3DC_CFG1_CEC_EVENT_EN);
+	writel(val, &uccr->config1);
+	dev_dbg(crg_udc->dev, "config1[0x%p]=0x%x\n", &uccr->config1, readl(&uccr->config1));
+	dev_dbg(crg_udc->dev, "config0[0x%p]=0x%x\n", &uccr->config0, readl(&uccr->config0));
+
+	val = readl(&uccr->control);
+	val |= (CRG_U3DC_CTRL_SYSERR_EN |
+			CRG_U3DC_CTRL_INT_EN);
+	writel(val, &uccr->control);
+	/*****interrupt related end*****/
+
+	val = readl(&uccr->control);
+	val |= CRG_U3DC_CTRL_RUN;
+	writel(val, &uccr->control);
+	dev_dbg(crg_udc->dev, "%s, control=0x%x\n", __func__, readl(&uccr->control));
+}
+
+static void crg_udc_clear_portpm(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 tmp;
+
+	tmp = readl(&uccr->u3portpmsc);
+
+	tmp &= (~CRG_U3DC_U3PORTPM_U1IEN);
+	tmp = SETF_VAR(CRG_U3DC_U3PORTPM_U1TMOUT, tmp, 0);
+	tmp &= (~CRG_U3DC_U3PORTPM_U2IEN);
+	tmp = SETF_VAR(CRG_U3DC_U3PORTPM_U2TMOUT, tmp, 0);
+
+	writel(tmp, &uccr->u3portpmsc);
+
+	crg_udc->feature_u1_enable = 0;
+	crg_udc->feature_u2_enable = 0;
+}
+
+static void crg_udc_reinit(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 i, tmp;
+	unsigned long flags = 0;
+	struct crg_udc_ep *udc_ep_ptr;
+
+	crg_udc->setup_status = WAIT_FOR_SETUP;
+	/* Base on Figure 9-1, default USB_STATE is attached */
+	crg_udc->device_state = USB_STATE_RECONNECTING;
+
+	/* halt all the endpoints */
+
+	dev_dbg(crg_udc->dev, "ep_enable=0x%x\n", readl(&uccr->ep_enable));
+	dev_dbg(crg_udc->dev, "ep_running=0x%x\n", readl(&uccr->ep_running));
+
+	/* disable all the endpoints */
+	tmp = readl(&uccr->ep_enable);
+	writel(tmp, &uccr->ep_enable);
+	for (i = 0; i < 50; i++) {
+		tmp = readl(&uccr->ep_enable);
+		if (tmp == 0)
+			break;
+	}
+
+	dev_dbg(crg_udc->dev, "i=%d\n", i);
+	dev_dbg(crg_udc->dev, "after ep_enable=0x%x\n", readl(&uccr->ep_enable));
+
+	for (i = 2; i < 32; i++) {
+		udc_ep_ptr = &crg_udc->udc_ep[i];
+		udc_ep_ptr->usb_ep.enabled = 0;
+		if (udc_ep_ptr->desc)
+			nuke(udc_ep_ptr, -ESHUTDOWN);
+		udc_ep_ptr->tran_ring_full = false;
+		udc_ep_ptr->ep_state = EP_STATE_DISABLED;
+	}
+	crg_udc->num_enabled_eps = 0;
+
+/* we don't handle ep0 here, we init_ep0 when event ring is empty*/
+
+	if (crg_udc->dev_addr != 0) {
+		u32 param0;
+
+		param0 = CRG_CMD2_0_DEV_ADDR(0);
+		crg_issue_command(crg_udc, CRG_CMD_SET_ADDR, param0, 0);
+		crg_udc->dev_addr = 0;
+	}
+
+	crg_udc_clear_portpm(crg_udc);
+
+	if (crg_udc->gadget_driver) {
+		dev_dbg(crg_udc->dev, "calling disconnect\n");
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+		crg_udc->gadget_driver->disconnect(&crg_udc->gadget);
+		spin_lock_irqsave(&crg_udc->udc_lock, flags);
+	}
+}
+
+static int crg_udc_reset(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 i, tmp, count;
+	struct crg_udc_ep *udc_ep_ptr;
+	u32 val;
+
+	dev_dbg(crg_udc->dev, "capability = %x\n",  readl(&uccr->capability));
+
+	count = 0;
+	val = readl(&uccr->control);
+	val |= CRG_U3DC_CTRL_SWRST;
+	writel(val, &uccr->control);
+	do {
+		mdelay(10);
+		tmp = readl(&uccr->control);
+		count++;
+
+		if (count == 50) {
+			dev_err(crg_udc->dev, "reset error\n");
+			return -1;
+		}
+	} while ((tmp & CRG_U3DC_CTRL_SWRST) != 0);
+
+	crg_udc_clear_portpm(crg_udc);
+
+	crg_udc->setup_status = WAIT_FOR_SETUP;
+	/* Base on Figure 9-1, default USB_STATE is attached */
+	crg_udc->device_state = USB_STATE_ATTACHED;
+	crg_udc->dev_addr = 0;
+
+	/* Complete any reqs on EP1-EP15 queue */
+	for (i = 2; i < 32; i++) {
+		udc_ep_ptr = &crg_udc->udc_ep[i];
+
+		if (udc_ep_ptr->desc)
+			nuke(udc_ep_ptr, -ESHUTDOWN);
+		udc_ep_ptr->tran_ring_full = false;
+		udc_ep_ptr->ep_state = EP_STATE_DISABLED;
+	}
+	crg_udc->num_enabled_eps = 0;
+
+	/* Complete any reqs on EP0 queue */
+	udc_ep_ptr = &crg_udc->udc_ep[0];
+	if (udc_ep_ptr->desc)
+		nuke(udc_ep_ptr, -ESHUTDOWN);
+
+	crg_udc->ctrl_req_enq_idx = 0;
+	memset(crg_udc->ctrl_req_queue, 0,
+			sizeof(struct crg_setup_packet) * CTRL_REQ_QUEUE_DEPTH);
+
+	return 0;
+}
+
+/************controller related ops*******************************/
+#define gadget_to_udc(g)	(container_of(g, struct crg_gadget_dev, gadget))
+int g_dnl_board_usb_cable_connected(struct crg_gadget_dev *crg_udc);
+
+static int crg_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+	struct crg_gadget_dev *crg_udc;
+
+	/* No need to call g_dnl_board_usb_cable_connected upon stop
+	 * controller or pull down D- event.
+	 */
+	if (is_on) {
+		crg_udc = gadget_to_udc(g);
+		g_dnl_board_usb_cable_connected(crg_udc);
+	}
+	return 0;
+}
+
+static int crg_vbus_detect_thread(void *data);
+
+static void crg_vbus_detect(struct crg_gadget_dev *crg_udc, int enable)
+{
+	if (enable) {
+		if (crg_udc->vbus_task) {
+			dev_err(crg_udc->dev,
+				"vbus task already run, wake up vbus_wait\n");
+			wake_up_interruptible(&vbus_wait);
+			return;
+		}
+		/* Enable the VBUS */
+		writel((readl(crg_udc->mmio_virt_base +
+					CRG_UDC_VENDOR_REG) |
+					CRG_UDC_VBUS_DETECT),
+					crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG);
+		crg_udc->vbus_task = kthread_run(crg_vbus_detect_thread,
+							(void *)crg_udc,
+							"corigine_vbus_thread");
+		if (IS_ERR(crg_udc->vbus_task)) {
+			dev_err(crg_udc->dev,
+				"Unable to create corigine_vbus_thread.\n");
+			crg_udc->vbus_task = NULL;
+			return;
+		}
+	} else {
+		if (crg_udc->vbus_task) {
+			/* Disable VBUS to stop controller */
+			writel((readl(crg_udc->mmio_virt_base +
+					    CRG_UDC_VENDOR_REG) &
+				   ~(CRG_UDC_VBUS_DETECT)),
+				   crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG);
+			wake_up_interruptible(&vbus_wait);
+			kthread_stop(crg_udc->vbus_task);
+			crg_udc->vbus_task = NULL;
+			return;
+		}
+	}
+}
+
+static int crg_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct crg_gadget_dev *crg_udc;
+
+	crg_udc = gadget_to_udc(g);
+	crg_udc->gadget_driver = driver;
+
+	dev_dbg(crg_udc->dev, "%s %d gadget speed=%d, max speed=%d\n",
+		__func__, __LINE__, g->speed, g->max_speed);
+	dev_dbg(crg_udc->dev, "%s %d driver speed=%d\n",
+		__func__, __LINE__, driver->max_speed);
+	crg_vbus_detect(crg_udc, 1);
+	return 0;
+}
+
+static int crg_gadget_stop(struct usb_gadget *g)
+{
+	struct crg_gadget_dev *crg_udc;
+	unsigned long flags = 0;
+
+	crg_udc = gadget_to_udc(g);
+
+	crg_udc->device_state = USB_STATE_ATTACHED;
+	crg_vbus_detect(crg_udc, 0);
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	crg_udc_reset(crg_udc);
+
+	reset_data_struct(crg_udc);
+	crg_udc->connected = 0;
+	crg_udc->gadget_driver = NULL;
+	crg_udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+	init_ep0(crg_udc);
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops crg_gadget_ops = {
+	.pullup			= crg_gadget_pullup,
+	.udc_start		= crg_gadget_start,
+	.udc_stop		= crg_gadget_stop,
+};
+
+static int init_ep_info(struct crg_gadget_dev *crg_udc)
+{
+	int i;
+
+	/*udc_ep[0] is reserved, */
+	crg_ep_struct_setup(crg_udc, 0, NULL);
+
+	for (i = 1; i < CRG_NUM_EP_CX / 2; i++) {
+		char name[14];
+
+		sprintf(name, "ep%din", i);
+		crg_ep_struct_setup(crg_udc, i * 2, name);
+		sprintf(name, "ep%dout", i);
+		crg_ep_struct_setup(crg_udc, i * 2 + 1, name);
+	}
+
+	return 0;
+}
+
+static void queue_setup_pkt(struct crg_gadget_dev *crg_udc,
+		struct usb_ctrlrequest *setup_pkt,
+		u16 setup_tag)
+{
+	if (crg_udc->ctrl_req_enq_idx == CTRL_REQ_QUEUE_DEPTH) {
+		dev_err(crg_udc->dev, "ctrl request queque is full\n");
+		return;
+	}
+
+	memcpy(&crg_udc->ctrl_req_queue[crg_udc->ctrl_req_enq_idx].usbctrlreq,
+			setup_pkt, sizeof(struct usb_ctrlrequest));
+	crg_udc->ctrl_req_queue[crg_udc->ctrl_req_enq_idx].setup_tag =
+		setup_tag;
+
+	crg_udc->ctrl_req_enq_idx++;
+}
+
+static inline u32 index2DCI(u16 index)
+{
+	if (index == 0)
+		return 0;
+
+	return (index & USB_ENDPOINT_NUMBER_MASK) * 2 + ((index &
+				USB_DIR_IN) ? 0 : 1);
+}
+
+static void get_status_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	kfree(req->buf);
+}
+
+static void getstatusrequest(struct crg_gadget_dev *crg_udc,
+		u8 RequestType, u16 value, u16 index, u16 length)
+{
+	u32 status_val = 0;
+	u32 status = -EINPROGRESS;
+	struct crg_udc_ep *udc_ep_ptr;
+	struct crg_udc_request *udc_req_ptr = crg_udc->status_req;
+
+	if (!udc_req_ptr)
+		return;
+	udc_req_ptr->usb_req.buf = kzalloc(sizeof(u16), GFP_ATOMIC);
+	dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.buf = 0x%p\n", udc_req_ptr->usb_req.buf);
+	if (!udc_req_ptr->usb_req.buf)
+		return;
+
+	if (value || length > 2 || !length) {
+		status = -EINVAL;
+		goto get_status_error;
+	}
+
+	dev_dbg(crg_udc->dev, "Get status request RequestType = 0x%x Index=%x\n",
+			RequestType, index);
+	if ((RequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		dev_dbg(crg_udc->dev, "Get status request Device request\n");
+		if (index) {
+			status = -EINVAL;
+			goto get_status_error;
+		}
+
+		if (crg_udc->gadget.speed == USB_SPEED_HIGH ||
+			crg_udc->gadget.speed == USB_SPEED_FULL) {
+			if (crg_udc->u2_RWE)
+				status_val |= BIT(USB_DEVICE_REMOTE_WAKEUP);
+		}
+
+		if (crg_udc->gadget.speed >= USB_SPEED_SUPER) {
+			if (crg_udc->feature_u1_enable)
+				status_val |= BIT(USB_DEV_STAT_U1_ENABLED);
+			if (crg_udc->feature_u2_enable)
+				status_val |= BIT(USB_DEV_STAT_U2_ENABLED);
+		}
+
+		status_val |= USB_DEVICE_SELF_POWERED;
+		dev_dbg(crg_udc->dev, "Status = 0x%x\n", status_val);
+
+	} else if ((RequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+		dev_dbg(crg_udc->dev, "Get status request Interface request\n");
+		status_val = 0;
+	} else if ((RequestType & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+		u32 DCI;
+
+		DCI = index2DCI(index);
+
+		dev_dbg(crg_udc->dev, "Get status request endpoint request DCI = %d\n", DCI);
+
+		if (DCI == 1) {
+			status_val = 0;
+			dev_dbg(crg_udc->dev, "Get status request INVALID! DCI = %d\n", DCI);
+			goto get_status_error;
+		}
+		/* if device state is address state, index should be 0
+		 * if device state is configured state, index should be an
+		 * endpoint configured.
+		 */
+
+		dev_dbg(crg_udc->dev, "crg_udc->device_state = %d\n", crg_udc->device_state);
+		if (crg_udc->device_state == USB_STATE_ADDRESS && DCI != 0) {
+			status = -EINVAL;
+			goto get_status_error;
+		}
+
+		if (crg_udc->device_state == USB_STATE_CONFIGURED) {
+			if (get_ep_state(crg_udc, DCI) == EP_STATE_DISABLED) {
+				status = -EINVAL;
+				goto get_status_error;
+			}
+
+			if (get_ep_state(crg_udc, DCI) == EP_STATE_HALTED) {
+				status_val = BIT(USB_ENDPOINT_HALT);
+				dev_dbg(crg_udc->dev, "endpoint was halted = 0x%lx\n",
+					(unsigned long)status_val);
+			}
+		}
+	}
+
+get_status_error:
+	if (status != -EINPROGRESS) {
+		udc_req_ptr->usb_req.length = 0;
+	} else {
+		*(u16 *)udc_req_ptr->usb_req.buf = cpu_to_le16(status_val);
+		dev_dbg(crg_udc->dev, "usb_req.buf = 0x%x\n",
+				*((u16 *)udc_req_ptr->usb_req.buf));
+
+		dev_dbg(crg_udc->dev, "usb_req.buf addr = 0x%p\n",
+				(udc_req_ptr->usb_req.buf));
+
+		udc_req_ptr->usb_req.length = 2;
+	}
+	udc_req_ptr->usb_req.status = status;
+	udc_req_ptr->usb_req.actual = 0;
+	udc_req_ptr->usb_req.complete = get_status_cmpl;
+
+	if (udc_req_ptr->usb_req.dma == DMA_ADDR_INVALID) {
+		udc_req_ptr->usb_req.dma =
+			dma_map_single(crg_udc->dev, udc_req_ptr->usb_req.buf,
+					udc_req_ptr->usb_req.length,
+					DMA_FROM_DEVICE);
+		udc_req_ptr->mapped = 1;
+	}
+	dev_dbg(crg_udc->dev, "status_val = 0x%x, cpu_to_le16(status_val) = 0x%x\n",
+		status_val, cpu_to_le16(status_val));
+	dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.buf = 0x%p, value = 0x%x\n",
+		udc_req_ptr->usb_req.buf, *(u16 *)(udc_req_ptr->usb_req.buf));
+	dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.dma = 0x%llx\n",
+		udc_req_ptr->usb_req.dma);
+
+	udc_ep_ptr = &crg_udc->udc_ep[0];
+
+	crg_udc->setup_status = DATA_STAGE_XFER;
+	status = crg_udc_build_td(udc_ep_ptr, udc_req_ptr);
+
+	dev_dbg(crg_udc->dev, "getstatus databuf eqpt = 0x%p\n", udc_ep_ptr->enq_pt);
+
+	if (!status)
+		list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue);
+}
+
+static void set_address_cmpl(struct crg_gadget_dev *crg_udc)
+{
+	if (crg_udc->device_state == USB_STATE_DEFAULT &&
+				crg_udc->dev_addr != 0) {
+		crg_udc->device_state = USB_STATE_ADDRESS;
+		dev_dbg(crg_udc->dev, "USB State Addressed\n");
+
+	} else if (crg_udc->device_state == USB_STATE_ADDRESS) {
+		if (crg_udc->dev_addr == 0)
+			crg_udc->device_state = USB_STATE_DEFAULT;
+	}
+}
+
+static void setaddressrequest(struct crg_gadget_dev *crg_udc,
+		u16 value, u16 index, u16 length)
+{
+	int status = -EINPROGRESS;
+	u8 status_set_addr = 0;
+
+	if (value > 127 || index != 0 || length != 0) {
+		status = -EINVAL;
+		goto set_address_error;
+	}
+
+	if ((crg_udc->device_state == USB_STATE_DEFAULT && value != 0) ||
+			crg_udc->device_state == USB_STATE_ADDRESS) {
+		u32 param0;
+
+		crg_udc->dev_addr = value;
+
+		param0 = CRG_CMD2_0_DEV_ADDR(value);
+		crg_issue_command(crg_udc, CRG_CMD_SET_ADDR, param0, 0);
+		status_set_addr = 1;
+	} else {
+		status = -EINVAL;
+	}
+
+set_address_error:
+	dev_dbg(crg_udc->dev, "build_ep0_status for Address Device\n");
+
+	crg_udc->setup_status = STATUS_STAGE_XFER;
+	crg_udc->setup_fn_call_back = &set_address_cmpl;
+	build_ep0_status(&crg_udc->udc_ep[0],
+		true, status, NULL, status_set_addr, 0);
+}
+
+static void set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct crg_udc_ep *udc_ep;
+	struct crg_gadget_dev *crg_udc;
+	struct sel_value_s *sel_value;
+
+	udc_ep = container_of(ep, struct crg_udc_ep, usb_ep);
+	crg_udc = udc_ep->crg_udc;
+
+	if (req->buf) {
+		sel_value = req->buf;
+		crg_udc->sel_value.u2_pel_value = sel_value->u2_pel_value;
+		crg_udc->sel_value.u2_sel_value = sel_value->u2_sel_value;
+		crg_udc->sel_value.u1_pel_value = sel_value->u1_pel_value;
+		crg_udc->sel_value.u1_sel_value = sel_value->u1_sel_value;
+
+		kfree(req->buf);
+	}
+
+	dev_dbg(crg_udc->dev, "u1_sel_value = 0x%x, u2_sel_value = 0x%x\n",
+			crg_udc->sel_value.u1_sel_value,
+			crg_udc->sel_value.u2_sel_value);
+}
+
+static void setselrequest(struct crg_gadget_dev *crg_udc,
+		u16 value, u16 index, u16 length, u64 data)
+{
+	int status = -EINPROGRESS;
+	struct crg_udc_request *udc_req_ptr = crg_udc->status_req;
+	struct crg_udc_ep *udc_ep_ptr = &crg_udc->udc_ep[0];
+
+	if (!udc_req_ptr)
+		return;
+
+	if (crg_udc->device_state == USB_STATE_DEFAULT)
+		status = -EINVAL;
+
+	if (index != 0 || value != 0 || length != 6)
+		status = -EINVAL;
+
+	if (status != -EINPROGRESS) {
+	} else {
+		udc_req_ptr->usb_req.length = length;
+		udc_req_ptr->usb_req.buf =
+			kzalloc(sizeof(*udc_req_ptr->usb_req.buf), GFP_ATOMIC);
+	}
+
+	udc_req_ptr->usb_req.status = -EINPROGRESS;
+	udc_req_ptr->usb_req.actual = 0;
+	udc_req_ptr->usb_req.complete = set_sel_cmpl;
+
+	if (udc_req_ptr->usb_req.dma == DMA_ADDR_INVALID) {
+		udc_req_ptr->usb_req.dma =
+			dma_map_single(crg_udc->dev, udc_req_ptr->usb_req.buf,
+					udc_req_ptr->usb_req.length,
+					DMA_TO_DEVICE);
+		udc_req_ptr->mapped = 1;
+	}
+
+	status = crg_udc_build_td(udc_ep_ptr, udc_req_ptr);
+
+	if (!status)
+		list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue);
+}
+
+static void set_test_mode_cmpl(struct crg_gadget_dev *crg_udc)
+{
+	if (crg_udc->set_tm != 0) {
+		u32 tmp;
+		struct crg_uccr *uccr = crg_udc->uccr;
+
+		tmp = readl(&uccr->u2portpmsc);
+		tmp = SETF_VAR(CRG_U3DC_U2PORTPM_TM, tmp, crg_udc->set_tm);
+		writel(tmp, &uccr->u2portpmsc);
+
+		crg_udc->set_tm = 0;
+	}
+}
+
+static bool setfeaturesrequest(struct crg_gadget_dev *crg_udc,
+	u8 RequestType, u8 bRequest, u16 value, u16 index, u16 length)
+{
+	int status = -EINPROGRESS;
+	u8  DCI;
+	struct crg_udc_ep *udc_ep_ptr;
+	u32 tmp;
+	bool set_feat = 0;
+	struct crg_uccr *uccr = crg_udc->uccr;
+
+	if (length != 0) {
+		status = -EINVAL;
+		goto set_feature_error;
+	}
+
+	if (crg_udc->device_state == USB_STATE_DEFAULT) {
+		status = -EINVAL;
+		goto set_feature_error;
+	}
+
+	set_feat = (bRequest == USB_REQ_SET_FEATURE) ? 1 : 0;
+	if ((RequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+			(USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
+		dev_dbg(crg_udc->dev, "Halt/Unhalt EP\n");
+		if (crg_udc->device_state == USB_STATE_ADDRESS) {
+			if (index != 0) {
+				status = -EINVAL;
+				goto set_feature_error;
+			}
+		}
+
+		DCI = index2DCI(index);
+
+		if (DCI == 1) {
+			dev_dbg(crg_udc->dev, "setfeat INVALID DCI = 0x%x !!\n", DCI);
+			goto set_feature_error;
+		}
+
+		udc_ep_ptr = &crg_udc->udc_ep[DCI];
+		dev_dbg(crg_udc->dev, "halt/Unhalt endpoint DCI = 0x%x\n", DCI);
+
+		status = ep_halt(udc_ep_ptr,
+				(bRequest == USB_REQ_SET_FEATURE) ? 1 : 0,
+				0);
+
+		if (status < 0)
+			goto set_feature_error;
+	} else if ((RequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+			(USB_RECIP_DEVICE | USB_TYPE_STANDARD)) {
+		switch (value) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			dev_dbg(crg_udc->dev, "USB_DEVICE_REMOTE_WAKEUP called\n");
+			/* REMOTE_WAKEUP selector is not used by USB3.0 */
+			if (crg_udc->device_state < USB_STATE_DEFAULT ||
+				crg_udc->gadget.speed >= USB_SPEED_SUPER) {
+				status = -EINVAL;
+				goto set_feature_error;
+			}
+			dev_dbg(crg_udc->dev, "%s_Feature RemoteWake\n",
+				set_feat ? "Set" : "Clear");
+
+			/*TODO corigine hardware ops needed*/
+			crg_udc->u2_RWE = set_feat;
+
+			break;
+		case USB_DEVICE_U1_ENABLE:
+		case USB_DEVICE_U2_ENABLE:
+		{
+			u32 timeout_val;
+
+			dev_dbg(crg_udc->dev, "USB_DEVICE_U12_ENABLE called\n");
+			if (crg_udc->device_state != USB_STATE_CONFIGURED) {
+				dev_err(crg_udc->dev, "%s u12 enable fail, usb state=%d\n",
+					__func__, crg_udc->device_state);
+				status = -EINVAL;
+				goto set_feature_error;
+			}
+
+			if (index & 0xff) {
+				status = -EINVAL;
+				goto set_feature_error;
+			}
+
+			if (set_feat == 1 && U12_FORBIDDEN > 0) {
+				status = -EINVAL;
+				goto set_feature_error;
+			}
+
+			tmp = readl(&uccr->u3portpmsc);
+			/*TODO corigine hardware ops needed*/
+			if (value == USB_DEVICE_U1_ENABLE) {
+#if (U12_INITIATE_FORBIDDEN == 0)
+				tmp &= (~CRG_U3DC_U3PORTPM_U1IEN);
+				tmp |= (set_feat <<
+					CRG_U3DC_U3PORTPM_U1IEN_SHIFT);
+#endif
+				if (U12_FORBIDDEN == 0)
+					timeout_val = set_feat ?
+						U1_TIMEOUT_VAL : 0;
+				else
+					timeout_val = 0;
+
+				tmp = SETF_VAR(CRG_U3DC_U3PORTPM_U1TMOUT,
+					tmp, timeout_val);
+
+				crg_udc->feature_u1_enable = set_feat;
+			}
+
+			if (value == USB_DEVICE_U2_ENABLE) {
+#if (U12_INITIATE_FORBIDDEN == 0)
+				tmp &= (~CRG_U3DC_U3PORTPM_U2IEN);
+				tmp |= (set_feat <<
+					CRG_U3DC_U3PORTPM_U2IEN_SHIFT);
+#endif
+				if (U12_FORBIDDEN == 0)
+					timeout_val = set_feat ? U1_TIMEOUT_VAL : 0;
+				else
+					timeout_val = 0;
+
+				tmp = SETF_VAR(CRG_U3DC_U3PORTPM_U2TMOUT,
+					tmp, timeout_val);
+
+				crg_udc->feature_u2_enable = set_feat;
+			}
+			writel(tmp, &uccr->u3portpmsc);
+
+			break;
+		}
+		case USB_DEVICE_TEST_MODE:
+		{
+			u32 u_pattern;
+
+			dev_dbg(crg_udc->dev, "USB_DEVICE_TEST_MODE called\n");
+			if (crg_udc->gadget.speed > USB_SPEED_HIGH)
+				goto set_feature_error;
+
+			if (crg_udc->device_state < USB_STATE_DEFAULT)
+				goto set_feature_error;
+
+			u_pattern = index >> 8;
+			/* TESTMODE is only defined for high speed device */
+			if (crg_udc->gadget.speed == USB_SPEED_HIGH) {
+				dev_dbg(crg_udc->dev, "high speed test mode enter\n");
+				crg_udc->set_tm = u_pattern;
+				crg_udc->setup_fn_call_back =
+					&set_test_mode_cmpl;
+			}
+			break;
+		}
+
+		default:
+			goto set_feature_error;
+		}
+
+	} else if ((RequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+			(USB_RECIP_INTERFACE | USB_TYPE_STANDARD)) {
+		if (crg_udc->device_state != USB_STATE_CONFIGURED) {
+			dev_err(crg_udc->dev, "%s interface u12 enable fail, usb state=%d\n",
+					__func__, crg_udc->device_state);
+			status = -EINVAL;
+			goto set_feature_error;
+		}
+
+		/* Suspend Option */
+		if (value == USB_INTRF_FUNC_SUSPEND) {
+			if (index & USB_INTR_FUNC_SUSPEND_OPT_MASK &
+				USB_INTRF_FUNC_SUSPEND_LP) {
+				if (index & USB_INTRF_FUNC_SUSPEND_RW)
+					dev_dbg(crg_udc->dev, "Interface En Remote Wakeup\n");
+				else
+					dev_dbg(crg_udc->dev, "Interface Dis RemoteWakeup\n");
+
+				/* Do not need to return status stage here
+				 * Pass to composite gadget driver to process
+				 * the request
+				 */
+				return false;
+			}
+		}
+	}
+
+	crg_udc->setup_status = STATUS_STAGE_XFER;
+	build_ep0_status(&crg_udc->udc_ep[0], true, status, NULL, 0, 0);
+	return true;
+
+set_feature_error:
+	set_ep0_halt(crg_udc);
+	return true;
+}
+
+static bool setconfigurationrequest(struct crg_gadget_dev *crg_udc, u16 value)
+{
+	if (crg_udc->device_state <= USB_STATE_DEFAULT)
+		goto set_config_error;
+
+	/*return false means need further process by composite gadget driver*/
+	return false;
+
+set_config_error:
+	set_ep0_halt(crg_udc);
+	return true;
+}
+
+static void set_isoch_delay(struct crg_gadget_dev *crg_udc,
+		 u16 value, u16 index, u16 length)
+{
+	int status = -EINPROGRESS;
+
+	if (value > 65535 || index != 0 || length != 0)
+		status = -EINVAL;
+
+	/*need further ops for isoch delay*/
+
+	crg_udc->setup_status = STATUS_STAGE_XFER;
+	build_ep0_status(&crg_udc->udc_ep[0], true, status, NULL, 0, 0);
+}
+
+static void crg_handle_setup_pkt(struct crg_gadget_dev *crg_udc,
+		struct usb_ctrlrequest *setup_pkt, u8 setup_tag)
+{
+	u16 wValue = setup_pkt->wValue;
+	u16 wIndex = setup_pkt->wIndex;
+	u16 wLength = setup_pkt->wLength;
+	u64 wData = 0;
+	unsigned long flags = 0;
+
+	dev_dbg(crg_udc->dev, "bRequest=0x%x, wValue=0x%.4x, wIndex=0x%x, wLength=%d\n",
+			setup_pkt->bRequest, wValue, wIndex, wLength);
+
+	/* EP0 come backs to running when new setup packet comes*/
+	crg_udc->udc_ep[0].ep_state = EP_STATE_RUNNING;
+
+	crg_udc->setup_tag = setup_tag;
+	crg_udc->setup_status = SETUP_PKT_PROCESS_IN_PROGRESS;
+	crg_udc->setup_fn_call_back = NULL;
+
+	if ((setup_pkt->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (setup_pkt->bRequest) {
+		case USB_REQ_GET_STATUS:
+			dev_dbg(crg_udc->dev, "USB_REQ_GET_STATUS\n");
+			if ((setup_pkt->bRequestType & (USB_DIR_IN |
+							USB_TYPE_MASK))
+				!= (USB_DIR_IN | USB_TYPE_STANDARD)) {
+				crg_udc->setup_status = WAIT_FOR_SETUP;
+				return;
+			}
+
+			getstatusrequest(crg_udc, setup_pkt->bRequestType,
+						wValue, wIndex, wLength);
+			return;
+		case USB_REQ_SET_ADDRESS:
+			dev_dbg(crg_udc->dev, "USB_REQ_SET_ADDRESS\n");
+			if (setup_pkt->bRequestType != (USB_DIR_OUT |
+						USB_RECIP_DEVICE |
+						USB_TYPE_STANDARD)) {
+				crg_udc->setup_status = WAIT_FOR_SETUP;
+				return;
+			}
+
+			setaddressrequest(crg_udc, wValue, wIndex, wLength);
+			return;
+		case USB_REQ_SET_SEL:
+			dev_dbg(crg_udc->dev, "USB_REQ_SET_SEL\n");
+
+			if (setup_pkt->bRequestType != (USB_DIR_OUT |
+						USB_RECIP_DEVICE |
+						USB_TYPE_STANDARD)) {
+				crg_udc->setup_status = WAIT_FOR_SETUP;
+				return;
+			}
+
+			crg_udc->setup_status = DATA_STAGE_RECV;
+			setselrequest(crg_udc, wValue, wIndex, wLength, wData);
+			return;
+		case USB_REQ_SET_ISOCH_DELAY:
+			if (setup_pkt->bRequestType != (USB_DIR_OUT |
+						USB_RECIP_DEVICE |
+						USB_TYPE_STANDARD))
+				break;
+
+			dev_dbg(crg_udc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
+			set_isoch_delay(crg_udc, wValue, wIndex, wLength);
+			return;
+
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+			dev_dbg(crg_udc->dev, "USB_REQ_CLEAR/SET_FEATURE\n");
+
+			/* Need composite gadget driver
+			 * to process the function remote wakeup request
+			 */
+			if (setfeaturesrequest(crg_udc, setup_pkt->bRequestType,
+						setup_pkt->bRequest,
+					wValue, wIndex, wLength)) {
+				/* Get here if request has been processed.*/
+				return;
+			}
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+				/*In theory we need to clear RUN bit before
+				 *status stage of deconfig request sent.
+				 *But seeing problem if we do it before all the
+				 *endpoints belonging to the configuration
+				 *disabled.
+				 */
+			dev_dbg(crg_udc->dev, "USB_REQ_SET_CONFIGURATION\n");
+			dev_dbg(crg_udc->dev, "CONFIGURATION wValue=%d\n", wValue);
+
+			if (setconfigurationrequest(crg_udc, wValue)) {
+				/* Get here if request has been processed.
+				 * Or error happens
+				 */
+				return;
+			}
+
+			if (crg_udc->device_state == USB_STATE_ADDRESS)
+				crg_udc->device_state = USB_STATE_CONFIGURED;
+			dev_dbg(crg_udc->dev, "USB_REQ_SET_CONFIGURATION: device_state is %d\n",
+				crg_udc->device_state);
+			break;
+		default:
+			dev_dbg(crg_udc->dev, "USB_REQ default bRequest=%d, bRequestType=%d\n",
+			 setup_pkt->bRequest, setup_pkt->bRequestType);
+		}
+	}
+
+	if (wLength) {
+		/* data phase from gadget like GET_CONFIGURATION
+		 * call the setup routine of gadget driver.
+		 * remember the request direction.
+		 */
+		crg_udc->setup_status =
+			(setup_pkt->bRequestType & USB_DIR_IN) ?
+			DATA_STAGE_XFER :  DATA_STAGE_RECV;
+	}
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+	if (crg_udc->gadget_driver->setup(&crg_udc->gadget, setup_pkt) < 0) {
+		spin_lock_irqsave(&crg_udc->udc_lock, flags);
+		set_ep0_halt(crg_udc);
+		return;
+	}
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+}
+
+static int crg_handle_xfer_event(struct crg_gadget_dev *crg_udc,
+			struct event_trb_s *event)
+{
+	u8 DCI = GETF(EVE_TRB_ENDPOINT_ID, event->dw3);
+	struct crg_udc_ep *udc_ep_ptr = &crg_udc->udc_ep[DCI];
+	/*Corigine ep contexts start from ep1*/
+	u16 comp_code;
+	struct crg_udc_request *udc_req_ptr;
+	bool trbs_dequeued = false;
+
+	if (!udc_ep_ptr->first_trb ||
+		get_ep_state(crg_udc, DCI) == EP_STATE_DISABLED)
+		return -ENODEV;
+
+	comp_code = GETF(EVE_TRB_COMPL_CODE, event->dw2);
+	if (comp_code == CMPL_CODE_STOPPED ||
+		comp_code == CMPL_CODE_STOPPED_LENGTH_INVALID ||
+		comp_code == CMPL_CODE_DISABLED ||
+		comp_code == CMPL_CODE_DISABLED_LENGTH_INVALID ||
+		comp_code == CMPL_CODE_HALTED ||
+		comp_code == CMPL_CODE_HALTED_LENGTH_INVALID) {
+		dev_dbg(crg_udc->dev, "comp_code = %d(STOPPED/HALTED/DISABLED)\n", comp_code);
+	} else {
+		update_dequeue_pt(event, udc_ep_ptr);
+	}
+
+	dev_dbg(crg_udc->dev, "%s ep%d dqpt=0x%p, eqpt=0x%p\n", __func__,
+		DCI, udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt);
+	dev_dbg(crg_udc->dev, "comp_code = %d\n", comp_code);
+
+	if (is_request_dequeued(crg_udc, udc_ep_ptr, event)) {
+		trbs_dequeued = true;
+		dev_dbg(crg_udc->dev, "WARNING: Drop the transfer event\n");
+		goto queue_more_trbs;
+	}
+
+	comp_code = GETF(EVE_TRB_COMPL_CODE, event->dw2);
+
+	switch (comp_code) {
+	case CMPL_CODE_SUCCESS:
+	{
+		dev_dbg(crg_udc->dev, "%s Complete SUCCESS\n", __func__);
+		handle_cmpl_code_success(crg_udc, event, udc_ep_ptr);
+
+		trbs_dequeued = true;
+		break;
+	}
+	case CMPL_CODE_SHORT_PKT:
+	{
+		u32 trb_transfer_length;
+
+		dev_dbg(crg_udc->dev, "handle_exfer_event CMPL_CODE_SHORT_PKT\n");
+		if (usb_endpoint_dir_out(udc_ep_ptr->desc)) {
+
+			trb_transfer_length = GETF(EVE_TRB_TRAN_LEN,
+						event->dw2);
+			udc_req_ptr = list_entry(udc_ep_ptr->queue.next,
+						struct crg_udc_request, queue);
+
+			udc_req_ptr->usb_req.actual =
+				udc_req_ptr->usb_req.length -
+				trb_transfer_length;
+			/* Ensure that req_ptr is updated */
+			wmb();
+			if (udc_req_ptr->usb_req.actual != 512 &&
+				udc_req_ptr->usb_req.actual != 31) {
+				u64 trb_pt;
+				struct transfer_trb_s *p_trb;
+
+				dev_dbg(crg_udc->dev, "Actual Data transferred = %d\n",
+					udc_req_ptr->usb_req.actual);
+
+				trb_pt = (u64)event->dw0 +
+					((u64)(event->dw1) << 32);
+
+				p_trb = tran_trb_dma_to_virt(udc_ep_ptr, trb_pt);
+
+				dev_dbg(crg_udc->dev, "event dw0 = 0x%x\n", event->dw0);
+				dev_dbg(crg_udc->dev, "event dw1 = 0x%x\n", event->dw1);
+				dev_dbg(crg_udc->dev, "event dw2 = 0x%x\n", event->dw2);
+				dev_dbg(crg_udc->dev, "event dw3 = 0x%x\n", event->dw3);
+
+				dev_dbg(crg_udc->dev, "trb_pt = 0x%lx, p_trb = 0x%p\n",
+					(unsigned long)trb_pt, p_trb);
+
+				dev_dbg(crg_udc->dev, "trb dw0 = 0x%x\n", p_trb->dw0);
+				dev_dbg(crg_udc->dev, "trb dw1 = 0x%x\n", p_trb->dw1);
+				dev_dbg(crg_udc->dev, "trb dw2 = 0x%x\n", p_trb->dw2);
+				dev_dbg(crg_udc->dev, "trb dw3 = 0x%x\n", p_trb->dw3);
+			}
+			req_done(udc_ep_ptr, udc_req_ptr, 0);
+		} else {
+			dev_dbg(crg_udc->dev, "ep dir in\n");
+		}
+
+		trbs_dequeued = true;
+
+		/* Advance the dequeue pointer to next TD */
+		advance_dequeue_pt(udc_ep_ptr);
+
+		break;
+	}
+
+	case CMPL_CODE_PROTOCOL_STALL:
+	{
+		dev_dbg(crg_udc->dev, "%s CMPL_CODE_PROTOCOL_STALL\n", __func__);
+
+		udc_req_ptr = list_entry(udc_ep_ptr->queue.next,
+					struct crg_udc_request, queue);
+		req_done(udc_ep_ptr, udc_req_ptr, -EINVAL);
+		trbs_dequeued = true;
+		crg_udc->setup_status = WAIT_FOR_SETUP;
+		advance_dequeue_pt(udc_ep_ptr);
+		break;
+	}
+
+	case CMPL_CODE_SETUP_TAG_MISMATCH:
+	{
+		u32 enq_idx = crg_udc->ctrl_req_enq_idx;
+		struct usb_ctrlrequest *setup_pkt;
+		struct crg_setup_packet *crg_setup_pkt;
+		u16 setup_tag;
+
+		dev_err(crg_udc->dev, "%s SETUP TAG MISMATCH\n", __func__);
+		dev_dbg(crg_udc->dev, "NOW setup tag = 0x%x\n", crg_udc->setup_tag);
+
+		/* skip seqnum err event until last one arrives. */
+		if (udc_ep_ptr->deq_pt == udc_ep_ptr->enq_pt) {
+			udc_req_ptr = list_entry(udc_ep_ptr->queue.next,
+					struct crg_udc_request,
+					queue);
+
+			if (udc_req_ptr)
+				req_done(udc_ep_ptr, udc_req_ptr, -EINVAL);
+
+			/* drop all the queued setup packet, only
+			 * process the latest one.
+			 */
+			crg_udc->setup_status = WAIT_FOR_SETUP;
+			if (enq_idx) {
+				crg_setup_pkt =
+					&crg_udc->ctrl_req_queue[enq_idx - 1];
+				setup_pkt = &crg_setup_pkt->usbctrlreq;
+				setup_tag = crg_setup_pkt->setup_tag;
+				crg_handle_setup_pkt(crg_udc, setup_pkt,
+							setup_tag);
+				/* flash the queue after the latest
+				 * setup pkt got handled..
+				 */
+				memset(crg_udc->ctrl_req_queue, 0,
+					sizeof(struct crg_setup_packet)
+					* CTRL_REQ_QUEUE_DEPTH);
+				crg_udc->ctrl_req_enq_idx = 0;
+			}
+		} else {
+			dev_dbg(crg_udc->dev, "setuptag mismatch skp dpt!=ept: 0x%p, 0x%p\n",
+				udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt);
+		}
+
+		crg_udc->setup_tag_mismatch_found = 1;
+		dev_dbg(crg_udc->dev, "%s SETUP TAG MISMATCH END\n", __func__);
+		break;
+	}
+
+	case CMPL_CODE_BABBLE_DETECTED_ERR:
+	case CMPL_CODE_INVALID_STREAM_TYPE_ERR:
+	case CMPL_CODE_RING_UNDERRUN:
+	case CMPL_CODE_RING_OVERRUN:
+	case CMPL_CODE_ISOCH_BUFFER_OVERRUN:
+	case CMPL_CODE_USB_TRANS_ERR:
+	case CMPL_CODE_TRB_ERR:
+	{
+		dev_err(crg_udc->dev, "XFER event err, comp_code = 0x%x\n", comp_code);
+		set_ep_halt(crg_udc, DCI);
+		break;
+	}
+
+	case CMPL_CODE_STOPPED:
+	case CMPL_CODE_STOPPED_LENGTH_INVALID:
+		/* Any ep stop ops should deal with stopped trbs itselves
+		 * Event handler didn't know whether the stopped trb should
+		 * be discarded or continued. So we do nothing here
+		 */
+		dev_err(crg_udc->dev, "STOP, comp_code = 0x%x\n", comp_code);
+		break;
+	default:
+		dev_dbg(crg_udc->dev, "CRG UNKNOWN comp_code = 0x%x\n", comp_code);
+		dev_dbg(crg_udc->dev, "EPDCI = 0x%x\n", udc_ep_ptr->DCI);
+		break;
+	}
+
+	dev_dbg(crg_udc->dev, "%s 2 ep%d dqpt=0x%p, eqpt=0x%p\n", __func__,
+		DCI, udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt);
+
+queue_more_trbs:
+	/* If there are some trbs dequeued by HW and the ring
+	 * was full before, then schedule any pending TRB's
+	 */
+	if (trbs_dequeued && udc_ep_ptr->tran_ring_full) {
+		udc_ep_ptr->tran_ring_full = false;
+		queue_pending_trbs(udc_ep_ptr);
+	}
+	return 0;
+}
+
+int g_dnl_board_usb_cable_connected(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr;
+	u32 tmp, tmp_cfg0;
+	static bool pp = UDC_FALSE;
+	static int cnt = INIT_ZERO;
+
+	uccr = crg_udc->uccr;
+	crg_udc_start(crg_udc);
+
+	if (cnt < STATE_USB_LINK_STABLE) {
+		tmp = readl(crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG);
+		writel(tmp | 1 << 26,
+			  crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG);
+
+		tmp = readl(&uccr->control);
+		tmp |= CRG_U3DC_CTRL_RUN;
+		dev_dbg(crg_udc->dev, "tmp1 = 0x%x\n", tmp);
+		writel(tmp, &uccr->control);
+		tmp = readl(&uccr->control);
+		dev_dbg(crg_udc->dev, "control = 0x%x\n", tmp);
+		mdelay(10);
+		pp = (readl(crg_udc->mmio_virt_base +
+			       CRG_UDC_VENDOR_REG) >> 26) & 1;
+		tmp = readl(&uccr->control);
+		tmp &= ~CRG_U3DC_CTRL_RUN;
+		writel(tmp, &uccr->control);
+		tmp = readl(&uccr->control);
+		dev_dbg(crg_udc->dev, "control2 = 0x%x\n", tmp);
+		cnt++;
+	} else {
+		pp = (readl(crg_udc->mmio_virt_base +
+			       CRG_UDC_VENDOR_REG) >> 26) & 1;
+		dev_dbg(crg_udc->dev, "pp = %d\n", pp);
+		if (pp) {
+			if (crg_udc->device_state < USB_STATE_POWERED) {
+				tmp_cfg0 = readl(&uccr->config0);
+				tmp_cfg0 &= (~0xf0);
+				tmp_cfg0 |= 0xf0;
+				writel(tmp_cfg0, &uccr->config0);
+
+				mdelay(3);
+				crg_udc_start(crg_udc);
+				crg_udc->device_state = USB_STATE_POWERED;
+				return 1;
+			} else
+				return 1;
+
+		} else {
+			cnt = 0;
+			return 0;
+		}
+	}
+	tmp = readl(&uccr->portsc);
+	if (tmp & CRG_U3DC_PORTSC_PP) {
+		mdelay(100);
+		tmp = readl(&uccr->portsc);
+		if (tmp & CRG_U3DC_PORTSC_PP) {
+			if (crg_udc->device_state < USB_STATE_POWERED) {
+				u32 tmp_cfg0;
+
+				dev_dbg(crg_udc->dev, "%s powered, portsc[0x%p]=0x%x\n", __func__,
+					&uccr->portsc, tmp);
+
+				/*set usb 3 disable count to 15*/
+				tmp_cfg0 = readl(&uccr->config0);
+				tmp_cfg0 &= (~0xf0);
+				tmp_cfg0 |= 0xf0;
+				writel(tmp_cfg0, &uccr->config0);
+
+				mdelay(3);
+				crg_udc_start(crg_udc);
+
+				dev_dbg(crg_udc->dev, "%s device state powered\n", __func__);
+				crg_udc->device_state = USB_STATE_POWERED;
+			}
+		}
+		return 1;
+	}
+
+	dev_dbg(crg_udc->dev, "%s no power, portsc[0x%p]=0x%x\n", __func__,
+		&uccr->portsc, tmp);
+
+	return 0;
+}
+
+static int crg_handle_port_status(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 portsc_val;
+	u32 tmp;
+	u32 speed;
+	unsigned long flags = 0;
+
+	/* handle Port Reset */
+	portsc_val = readl(&uccr->portsc);
+	writel(portsc_val, &uccr->portsc);
+
+	tmp = readl(&uccr->portsc);
+	dev_dbg(crg_udc->dev, "%s RAW,portsc[0x%p]=0x%x\n", __func__,
+		&uccr->portsc, portsc_val);
+
+	if (portsc_val & CRG_U3DC_PORTSC_PRC) {
+		mdelay(3);
+
+		tmp = readl(&uccr->portsc);
+		if (tmp & CRG_U3DC_PORTSC_PRC) {
+			dev_dbg(crg_udc->dev, "PRC is still set\n");
+		} else if (tmp & CRG_U3DC_PORTSC_PR) {
+			/* first port status change event for port reset*/
+			dev_dbg(crg_udc->dev, "PRC is not set, but PR is set!!!!!!!!\n");
+		} else {
+			if (CRG_U3DC_PORTSC_PLS_GET(tmp) != 0 ||
+				(!(tmp & CRG_U3DC_PORTSC_PED))) {
+				dev_dbg(crg_udc->dev,
+					"portsc[0x%p]=0x%x no PED\n",
+					&uccr->portsc, tmp);
+				return 0;
+			}
+
+			switch (CRG_U3DC_PORTSC_SPEED_GET(tmp)) {
+			case CRG_U3DC_PORTSC_SPEED_SSP:
+				speed = USB_SPEED_SUPER_PLUS;
+				break;
+			case CRG_U3DC_PORTSC_SPEED_SS:
+				speed = USB_SPEED_SUPER;
+				break;
+			case CRG_U3DC_PORTSC_SPEED_HS:
+				speed = USB_SPEED_HIGH;
+				break;
+
+			case CRG_U3DC_PORTSC_SPEED_FS:
+				speed = USB_SPEED_FULL;
+				break;
+
+			case CRG_U3DC_PORTSC_SPEED_LS:
+				speed = USB_SPEED_LOW;
+				break;
+			default:
+				speed = USB_SPEED_UNKNOWN;
+				return 0;
+			}
+
+			if (crg_udc->device_state >= USB_STATE_DEFAULT)
+				crg_udc_reinit(crg_udc);
+
+			crg_udc->gadget.speed = speed;
+			dev_dbg(crg_udc->dev, "gadget speed = 0x%x\n", crg_udc->gadget.speed);
+
+			update_ep0_maxpacketsize(crg_udc);
+
+			crg_udc->connected = 1;
+
+			if (crg_udc->device_state < USB_STATE_RECONNECTING)
+				enable_setup(crg_udc);
+
+			dev_dbg(crg_udc->dev, "PORTSC = 0x%x\n", readl(&uccr->portsc));
+		}
+	}
+	/* handle Port Reset end */
+
+	/* handle Port Connection Change*/
+		tmp = readl(&uccr->portsc);
+		if ((tmp & (CRG_U3DC_PORTSC_CCS | CRG_U3DC_PORTSC_PP)) ==
+			(CRG_U3DC_PORTSC_CCS | CRG_U3DC_PORTSC_PP)) {
+			dev_dbg(crg_udc->dev, "connect int checked\n");
+			dev_dbg(crg_udc->dev, "portsc[0x%p]=0x%x\n", &uccr->portsc, tmp);
+
+			if (CRG_U3DC_PORTSC_PLS_GET(tmp) != 0 ||
+				(!(tmp & CRG_U3DC_PORTSC_PED)))
+				return 0;
+
+			switch (CRG_U3DC_PORTSC_SPEED_GET(tmp)) {
+			case CRG_U3DC_PORTSC_SPEED_SSP:
+				speed = USB_SPEED_SUPER_PLUS;
+				break;
+			case CRG_U3DC_PORTSC_SPEED_SS:
+				speed = USB_SPEED_SUPER;
+				break;
+			case CRG_U3DC_PORTSC_SPEED_HS:
+				speed = USB_SPEED_HIGH;
+				break;
+
+			case CRG_U3DC_PORTSC_SPEED_FS:
+				speed = USB_SPEED_FULL;
+				break;
+
+			case CRG_U3DC_PORTSC_SPEED_LS:
+			default:
+				speed = USB_SPEED_UNKNOWN;
+				return 0;
+			}
+			crg_udc->gadget.speed = speed;
+
+			update_ep0_maxpacketsize(crg_udc);
+
+			crg_udc->connected = 1;
+
+			if (crg_udc->device_state < USB_STATE_RECONNECTING)
+				enable_setup(crg_udc);
+
+			dev_dbg(crg_udc->dev, "connect speed = %d\n", speed);
+
+		} else if (!(tmp & CRG_U3DC_PORTSC_CCS)) {
+			int cable_connected;
+
+			int ccs_drop_ignore = 0;
+
+			if ((CRG_U3DC_PORTSC_PLS_GET(tmp) == 0x0) &&
+				(CRG_U3DC_PORTSC_SPEED_GET(tmp) <
+					 CRG_U3DC_PORTSC_SPEED_SS)) {
+				ccs_drop_ignore = 1;
+				dev_err(crg_udc->dev, "ccs glitch detect on HS/FS!\n");
+			}
+
+			if (!ccs_drop_ignore)
+				crg_udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+			mdelay(150);
+			cable_connected =
+				g_dnl_board_usb_cable_connected(crg_udc);
+			if (cable_connected && !ccs_drop_ignore) {
+				crg_udc->device_state = USB_STATE_POWERED;
+				dev_dbg(crg_udc->dev, "do warm reset\n");
+				crg_udc_reinit(crg_udc);
+				crg_udc->connected = 0;
+			} else if (!cable_connected) {
+				dev_dbg(crg_udc->dev, "cable disconnected, rst controller\n");
+
+				crg_udc_reset(crg_udc);
+				if (crg_udc->gadget_driver->disconnect) {
+					spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+					crg_udc->gadget_driver->disconnect(&crg_udc->gadget);
+					spin_lock_irqsave(&crg_udc->udc_lock, flags);
+				}
+
+				reset_data_struct(crg_udc);
+				crg_udc->connected = 0;
+				init_ep0(crg_udc);
+
+				crg_udc->device_state = USB_STATE_ATTACHED;
+
+				wake_up_interruptible(&vbus_wait);
+				return -ECONNRESET;
+			}
+		}
+	/* handle Port Connection Change end*/
+
+	if (portsc_val & CRG_U3DC_PORTSC_PLC) {
+		tmp = readl(&uccr->portsc);
+		if (CRG_U3DC_PORTSC_PLS_GET(tmp) == 0xf) {
+			tmp = SETF_VAR(CRG_U3DC_PORTSC_PLS, tmp, 0x0);
+			writel(tmp, &uccr->portsc);
+			dev_dbg(crg_udc->dev, "pls to 0, write portsc 0x%x\n", tmp);
+		}  else if (CRG_U3DC_PORTSC_PLS_GET(tmp) == 0x3) {
+			if (crg_udc->gadget_driver->disconnect) {
+				spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+				crg_udc->gadget_driver->disconnect(&crg_udc->gadget);
+				spin_lock_irqsave(&crg_udc->udc_lock, flags);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int crg_udc_handle_event(struct crg_gadget_dev *crg_udc,
+			struct event_trb_s *event)
+{
+	int ret;
+
+	switch (GETF(EVE_TRB_TYPE, event->dw3)) {
+	case TRB_TYPE_EVT_PORT_STATUS_CHANGE:
+		if (crg_udc->device_state == USB_STATE_RECONNECTING) {
+			crg_udc->portsc_on_reconnecting = 1;
+			break;
+		}
+		/* 1.Port Reset  2.Port Connection Change 3.Port Link Change */
+		ret = crg_handle_port_status(crg_udc);
+		if (ret)
+			return ret;
+
+		break;
+	case TRB_TYPE_EVT_TRANSFER:
+		if (crg_udc->device_state < USB_STATE_RECONNECTING) {
+			dev_err(crg_udc->dev,
+				"Xfer compl event rcved when dev state=%d !\n",
+				crg_udc->device_state);
+			break;
+		}
+
+		crg_handle_xfer_event(crg_udc, event);
+		break;
+	case TRB_TYPE_EVT_SETUP_PKT:
+		{
+			struct usb_ctrlrequest *setup_pkt;
+			u8 setup_tag;
+
+			dev_dbg(crg_udc->dev, "handle_setup_pkt(%d)\n",
+				crg_udc->device_state);
+
+			setup_pkt = (struct usb_ctrlrequest *)&event->dw0;
+
+			setup_tag = GETF(EVE_TRB_SETUP_TAG, event->dw3);
+			dev_dbg(crg_udc->dev, "setup_pkt = 0x%p, setup_tag = 0x%x\n",
+				setup_pkt, setup_tag);
+			if (crg_udc->setup_status != WAIT_FOR_SETUP) {
+				/*previous setup packet hasn't
+				 * completed yet. Just ignore the prev setup
+				 */
+				dev_err(crg_udc->dev, "consecutive setup\n");
+				queue_setup_pkt(crg_udc, setup_pkt, setup_tag);
+				break;
+			}
+
+			crg_handle_setup_pkt(crg_udc, setup_pkt, setup_tag);
+
+			break;
+		}
+	default:
+		dev_dbg(crg_udc->dev, "unexpect TRB_TYPE = 0x%x",
+			GETF(EVE_TRB_TYPE, event->dw3));
+		break;
+	}
+
+	return 0;
+}
+
+static int process_event_ring(struct crg_gadget_dev *crg_udc, int index)
+{
+	struct event_trb_s *event;
+	struct crg_udc_event *udc_event;
+	struct crg_uicr *uicr = crg_udc->uicr[index];
+	dma_addr_t tmp;
+	u32 val;
+	dma_addr_t erdp;
+	int ret;
+
+	if (!uicr)
+		return IRQ_NONE;
+
+	tmp = readl(&uicr->iman);
+	if ((tmp & (CRG_U3DC_IMAN_INT_EN | CRG_U3DC_IMAN_INT_PEND)) !=
+		(CRG_U3DC_IMAN_INT_EN | CRG_U3DC_IMAN_INT_PEND)) {
+	}
+
+	val = readl(&uicr->iman);
+	val |= CRG_U3DC_IMAN_INT_PEND;
+	writel(val, &uicr->iman);
+
+	udc_event = &crg_udc->udc_event[index];
+	while (udc_event->evt_dq_pt) {
+		/* rmb */
+		rmb();
+		event = (struct event_trb_s *)udc_event->evt_dq_pt;
+
+		if (GETF(EVE_TRB_CYCLE_BIT, event->dw3) !=
+				udc_event->CCS)
+			break;
+
+		ret = crg_udc_handle_event(crg_udc, event);
+		if (ret == -ECONNRESET)
+			return ret;
+
+		if (event == udc_event->evt_seg0_last_trb) {
+			udc_event->CCS = udc_event->CCS ? 0 : 1;
+			udc_event->evt_dq_pt = udc_event->event_ring.vaddr;
+		} else {
+			udc_event->evt_dq_pt++;
+		}
+	}
+
+	/* update dequeue pointer */
+	erdp = event_trb_virt_to_dma(udc_event, udc_event->evt_dq_pt);
+	tmp =  upper_32_bits(erdp);
+	writel(upper_32_bits(erdp), &uicr->erdphi);
+	tmp = lower_32_bits(erdp);
+	tmp |= CRG_U3DC_ERDPLO_EHB;
+	writel(lower_32_bits(erdp | CRG_U3DC_ERDPLO_EHB), &uicr->erdplo);
+
+	return 0;
+}
+
+static int crg_gadget_handle_interrupt(struct crg_gadget_dev *crg_udc)
+{
+	struct crg_uccr *uccr = crg_udc->uccr;
+	u32 tmp_status;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+	/******************************/
+
+	tmp_status = readl(&uccr->status);
+
+	if (tmp_status & CRG_U3DC_STATUS_SYS_ERR) {
+		dev_err(crg_udc->dev, "%s System error happens!!!\n", __func__);
+		/*Handle system error*/
+		writel(CRG_U3DC_STATUS_SYS_ERR, &uccr->status);
+	}
+
+	if (tmp_status & CRG_U3DC_STATUS_EINT) {
+		int i;
+
+		writel(CRG_U3DC_STATUS_EINT, &uccr->status);
+
+		/*process event rings*/
+		for (i = 0; i < CRG_RING_NUM; i++)
+			process_event_ring(crg_udc, i);
+	}
+
+	if (crg_udc->device_state == USB_STATE_RECONNECTING &&
+		crg_udc->portsc_on_reconnecting == 1 &&
+		is_event_rings_empty(crg_udc)) {
+		crg_udc->portsc_on_reconnecting = 0;
+		crg_handle_port_status(crg_udc);
+	}
+
+	if (crg_udc->device_state == USB_STATE_RECONNECTING &&
+		crg_udc->connected == 1) {
+		dev_dbg(crg_udc->dev, "check if ready for setup\n");
+		prepare_for_setup(crg_udc);
+	}
+
+	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+	return 0;
+}
+
+static irqreturn_t crg_udc_common_irq(int irq, void *dev)
+{
+	int retval = 0;
+
+	retval = crg_gadget_handle_interrupt(dev);
+
+	return IRQ_HANDLED;
+}
+
+static int crg_gadget_irq_init(struct platform_device *pdev, struct crg_gadget_dev *crg_udc)
+{
+	int	irq = 0;
+	int retval = 0;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENODEV;
+
+	crg_udc->irq = irq;
+
+	retval = request_irq(irq, crg_udc_common_irq,
+			     IRQF_SHARED, "crg_udc",
+			     crg_udc);
+	if (retval) {
+		dev_err(crg_udc->dev, "request of irq%d failed\n", irq);
+		retval = -EBUSY;
+	}
+
+	return 0;
+}
+
+static int crg_vbus_detect_thread(void *data)
+{
+	struct crg_gadget_dev *crg_udc = (struct crg_gadget_dev *)data;
+	unsigned long flags = 0;
+	int cable_connected = 0;
+
+	while (1) {
+		if (kthread_should_stop())
+			break;
+
+		dev_dbg(crg_udc->dev, "crg_udc->device_state is %d\n",
+					crg_udc->device_state);
+
+		spin_lock_irqsave(&crg_udc->udc_lock, flags);
+
+		cable_connected = g_dnl_board_usb_cable_connected(crg_udc);
+
+		spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
+
+		if (cable_connected) {
+			wait_event_interruptible
+				(vbus_wait, crg_udc->device_state < USB_STATE_POWERED);
+		} else {
+			dev_dbg(crg_udc->dev, "wait for vbus\n");
+			msleep(1000);
+		}
+	}
+
+	return 0;
+}
+
+
+static const struct crg_udc_priv ax3000_plat_setup_gen2 = {
+	.plat_setup_gen3 = false,
+};
+
+static const struct crg_udc_priv ax3000_plat_setup_gen3 = {
+	.plat_setup_gen3 = true,
+};
+
+/**
+ * crg_gadget_probe - Initializes gadget driver
+ *
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+
+static const struct of_device_id of_crg_udc_match[] = {
+	{
+		.compatible = "axiado,ax3000-udc",
+		.data = &ax3000_plat_setup_gen2
+	},
+	{
+		.compatible = "axiado,ax3000-udc-gen3",
+		.data = &ax3000_plat_setup_gen3
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_crg_udc_match);
+
+static int crg_udc_probe(struct platform_device *pdev)
+{
+	int ret;
+	int i;
+	struct crg_gadget_dev *crg_udc;
+	static int udc_gcnt = INIT_ZERO;
+	char udc_gname[10] = {""};
+	const struct crg_udc_priv *priv;
+
+	priv = of_device_get_match_data(&pdev->dev);
+	sprintf(udc_gname, "gadget-%d", udc_gcnt);
+	crg_udc = devm_kzalloc(&pdev->dev, sizeof(*crg_udc), GFP_KERNEL);
+	if (!crg_udc)
+		return -ENOMEM;
+	crg_udc->dev = &pdev->dev;
+
+	spin_lock_init(&crg_udc->udc_lock);
+	platform_set_drvdata(pdev, crg_udc);
+
+	dev_set_name(&crg_udc->gadget.dev, udc_gname);
+	crg_udc->gadget.ops = &crg_gadget_ops;
+	crg_udc->gadget.ep0 = &crg_udc->udc_ep[0].usb_ep;
+	crg_udc->gadget.dev.parent = &pdev->dev;
+	INIT_LIST_HEAD(&crg_udc->gadget.ep_list);
+	if (priv->plat_setup_gen3) {
+		crg_udc->gadget.max_speed = USB_SPEED_SUPER;
+		crg_udc->gadget.speed = USB_SPEED_SUPER;
+	} else {
+		crg_udc->gadget.max_speed = USB_SPEED_HIGH;
+		crg_udc->gadget.speed = USB_SPEED_HIGH;
+	}
+	crg_udc->gadget.name = udc_gname;
+	crg_udc->gadget.sg_supported = true;
+	dev_dbg(crg_udc->dev, "%s sg support\n", __func__);
+	crg_udc->connected = 0;
+	crg_udc->dev_addr = 0;
+
+	crg_udc->udc_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!crg_udc->udc_res) {
+		dev_err(&pdev->dev, "missing memory resource\n");
+		return -ENODEV;
+	}
+
+	crg_udc->mmio_virt_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(crg_udc->mmio_virt_base)) {
+		dev_err(&pdev->dev, "mmio ioremap failed\n");
+		return PTR_ERR(crg_udc->mmio_virt_base);
+	}
+
+	/* set controller device role*/
+	writel((readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) |
+		 CRGUDC_ROLE_DEVICE),
+		 crg_udc->mmio_virt_base + CRG_UDC_MODE_REG);
+	for (i = 0; i < CRG_RING_NUM; i++) {
+		crg_udc->uicr[i] = crg_udc->mmio_virt_base +
+				CRG_UICR_OFFSET + i * CRG_UICR_STRIDE;
+
+		dev_dbg(crg_udc->dev, "crg_udc->uicr[%d] = %p\n", i,
+			crg_udc->uicr[i]);
+	}
+	crg_udc->uccr = crg_udc->mmio_virt_base + CRG_UCCR_OFFSET;
+
+	crg_udc_reset(crg_udc);
+
+	crg_udc_clear_portpm(crg_udc);
+
+	ret = reset_data_struct(crg_udc);
+	if (ret) {
+		dev_err(crg_udc->dev, "reset_data_struct error\n");
+		goto err0;
+	}
+
+	init_ep_info(crg_udc);
+	init_ep0(crg_udc);
+
+	EP0_Start(crg_udc);
+
+	crg_gadget_irq_init(pdev, crg_udc);
+
+	ret = usb_add_gadget_udc(&pdev->dev, &crg_udc->gadget);
+	if (ret)
+		goto err0;
+
+	udc_gcnt++;
+
+	return 0;
+
+err0:
+	return -1;
+}
+
+static void crg_udc_remove(struct platform_device *pdev)
+{
+	struct crg_gadget_dev *crg_udc = platform_get_drvdata(pdev);
+	u32 tmp = 0;
+
+	dev_dbg(crg_udc->dev, "%s %d called\n", __func__, __LINE__);
+
+	crg_udc->device_state = USB_STATE_ATTACHED;
+	crg_vbus_detect(crg_udc, 0);
+
+	usb_del_gadget_udc(&crg_udc->gadget);
+
+	/* set controller host role*/
+	tmp = readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) & ~0x1;
+	writel(tmp, crg_udc->mmio_virt_base + CRG_UDC_MODE_REG);
+
+	if (crg_udc->irq)
+		free_irq(crg_udc->irq, crg_udc);
+
+	platform_set_drvdata(pdev, 0);
+
+	dev_dbg(crg_udc->dev, "%s %d gadget remove\n", __func__, __LINE__);
+
+}
+
+static void crg_udc_shutdown(struct platform_device *pdev)
+{
+	struct crg_gadget_dev *crg_udc = platform_get_drvdata(pdev);
+
+	dev_dbg(crg_udc->dev, "%s %d called\n", __func__, __LINE__);
+
+	crg_udc->device_state = USB_STATE_ATTACHED;
+	crg_vbus_detect(crg_udc, 0);
+	usb_del_gadget_udc(&crg_udc->gadget);
+
+	if (crg_udc->irq)
+		free_irq(crg_udc->irq, crg_udc);
+	/*
+	 * Clear the drvdata pointer.
+	 */
+	platform_set_drvdata(pdev, 0);
+}
+
+#ifdef CONFIG_PM
+static int crg_udc_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int crg_udc_resume(struct device *dev)
+{
+
+
+	return 0;
+}
+#else
+#define crg_udc_suspend	NULL
+#define crg_udc_resume	NULL
+#endif
+
+static const struct dev_pm_ops crg_udc_pm_ops = {
+	.suspend = crg_udc_suspend,
+	.resume = crg_udc_resume,
+};
+
+static struct platform_driver crg_udc_driver = {
+	.probe = crg_udc_probe,
+	.remove = crg_udc_remove,
+	.shutdown = crg_udc_shutdown,
+	.driver			= {
+		.name		= "crg_udc",
+		.owner		= THIS_MODULE,
+		.pm			= &crg_udc_pm_ops,
+		.of_match_table	= of_match_ptr(of_crg_udc_match),
+	},
+};
+
+static void crg_gadget_exit(void)
+{
+	platform_driver_unregister(&crg_udc_driver);
+}
+
+static int crg_gadget_init(void)
+{
+
+	return platform_driver_register(&crg_udc_driver);
+}
+
+module_init(crg_gadget_init);
+module_exit(crg_gadget_exit);
+
+MODULE_DESCRIPTION("Corigine USB Device Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/crg_udc.h b/drivers/usb/gadget/udc/crg_udc.h
new file mode 100644
index 000000000000..bb0cd724582c
--- /dev/null
+++ b/drivers/usb/gadget/udc/crg_udc.h
@@ -0,0 +1,364 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Corigine, Inc.
+ * Copyright (c) 2022-2026 Axiado Corporation.
+ */
+
+#ifndef __CRG_UDC_H__
+#define __CRG_UDC_H__
+
+#define CRG_UCCR_OFFSET (0x2400)
+#define CRG_UICR_OFFSET (0x2500)
+#define CRG_UICR_STRIDE (0x20)
+
+/* corigine usb 3.1 device core register macros */
+struct crg_uccr {
+	u32 capability;	/*0x00*/
+	u32 resv0[3];
+
+	u32 config0;	/*0x10*/
+	u32 config1;
+	u32 resv1[2];
+
+	u32 control;	/*0x20*/
+	u32 status;
+	u32 dcbaplo;
+	u32 dcbaphi;
+	u32 portsc;
+	u32 u3portpmsc;
+	u32 u2portpmsc;
+	u32 u3portli;
+
+	u32 doorbell;	/*0x40*/
+	u32 mfindex;
+	u32 speed_select;
+	u32 resv3[5];
+
+	u32 ep_enable;	/*0x60*/
+	u32 ep_running;
+	u32 resv4[2];
+
+	u32 cmd_param0;	/*0x70*/
+	u32 cmd_param1;
+	u32 cmd_control;
+	u32 resv5[1];
+
+	u32 odb_capability;	/*0x80*/
+	u32 resv6[3];
+	u32 odb_config[8];
+
+	u32 debug0;	/*0xB0*/
+};
+
+struct crg_uicr {
+	u32 iman;
+	u32 imod;
+	u32 erstsz;
+	u32 resv0;
+
+	u32 erstbalo; /*0x10*/
+	u32 erstbahi;
+	u32 erdplo;
+	u32 erdphi;
+};
+
+#define SETF_VAR(field, var, fieldval) \
+	(((var) & ~(field ## _MASK)) | \
+			(((fieldval) << field ## _SHIFT) & (field ## _MASK)))
+
+#define GETF(field, val) \
+		(((val) & (field ## _MASK)) >> (field ## _SHIFT))
+
+#define MAKEF_VAR(field, fieldval) \
+		(((fieldval) << field ## _SHIFT) & (field ## _MASK))
+
+/* interrupt registers array */
+#define	CRG_U3DC_IRS_BASE			(0x100L)
+#define	CRG_U3DC_IRS_IMAN(x)		\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x00L)
+#define	CRG_U3DC_IRS_IMOD(x)		\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x04L)
+#define	CRG_U3DC_IRS_ERSTSZ(x)		\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x08L)
+#define	CRG_U3DC_IRS_ERSTBALO(x)	\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x10L)
+#define	CRG_U3DC_IRS_ERSTBAHI(x)	\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x14L)
+#define	CRG_U3DC_IRS_ERDPLO(x)		\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x18L)
+#define	CRG_U3DC_IRS_ERDPHI(x)		\
+	(CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x20L)
+
+/* reg config 0 & 1*/
+#define	CRG_U3DC_CFG0_MAXSPEED_MASK		(0xfL << 0)
+#define	CRG_U3DC_CFG0_MAXSPEED_FS		(0x1L << 0)
+#define	CRG_U3DC_CFG0_MAXSPEED_HS		(0x3L << 0)
+#define	CRG_U3DC_CFG0_MAXSPEED_SS		(0x4L << 0)
+#define	CRG_U3DC_CFG0_MAXSPEED_SSP		(0x5L << 0)
+
+#define	CRG_U3DC_CFG1_CSC_EVENT_EN		BIT(0)
+#define	CRG_U3DC_CFG1_PEC_EVENT_EN		BIT(1)
+#define	CRG_U3DC_CFG1_PPC_EVENT_EN		BIT(3)
+#define	CRG_U3DC_CFG1_PRC_EVENT_EN		BIT(4)
+#define	CRG_U3DC_CFG1_PLC_EVENT_EN		BIT(5)
+#define	CRG_U3DC_CFG1_CEC_EVENT_EN		BIT(6)
+
+#define	CRG_U3DC_CFG1_U3_ENTRY_EN		BIT(8)
+#define	CRG_U3DC_CFG1_L1_ENTRY_EN		BIT(9)
+#define	CRG_U3DC_CFG1_U3_RESUME_EN		BIT(10)
+#define	CRG_U3DC_CFG1_L1_RESUME_EN		BIT(11)
+#define	CRG_U3DC_CFG1_INACTIVE_PLC_EN		BIT(12)
+#define	CRG_U3DC_CFG1_U3_RESUME_NORESP_PLC_EN		BIT(13)
+#define	CRG_U3DC_CFG1_U2_RESUME_NORESP_PLC_EN		BIT(14)
+
+#define	CRG_U3DC_CFG1_SETUP_EVENT_EN	BIT(16)
+
+/* ctrl register*/
+#define	CRG_U3DC_CTRL_RUN			BIT(0)
+#define	CRG_U3DC_CTRL_STOP			(0)
+#define	CRG_U3DC_CTRL_SWRST			BIT(1)
+#define	CRG_U3DC_CTRL_INT_EN		BIT(2)
+#define	CRG_U3DC_CTRL_SYSERR_EN		BIT(3)
+#define	CRG_U3DC_CTRL_EWE			BIT(10)
+#define	CRG_U3DC_CTRL_KP_CNCT		BIT(11)
+
+/*status register*/
+#define CRG_U3DC_STATUS_DEV_CTRL_HALT	BIT(0)
+#define CRG_U3DC_STATUS_SYS_ERR			BIT(2)
+#define CRG_U3DC_STATUS_EINT			BIT(3)
+
+/*portsc register*/
+#define CRG_U3DC_PORTSC_CCS			BIT(0)
+#define CRG_U3DC_PORTSC_PED			BIT(1)
+#define CRG_U3DC_PORTSC_PP			BIT(3)
+#define CRG_U3DC_PORTSC_PR			BIT(4)
+
+#define CRG_U3DC_PORTSC_PLS_SHIFT	(5)
+#define CRG_U3DC_PORTSC_PLS_MASK	(0xf << CRG_U3DC_PORTSC_PLS_SHIFT)
+#define CRG_U3DC_PORTSC_PLS(fv)		(MAKEF_VAR(CRG_U3DC_PORTSC_PLS, (fv)))
+#define CRG_U3DC_PORTSC_PLS_GET(v)	(GETF(CRG_U3DC_PORTSC_PLS, (v)))
+
+#define CRG_U3DC_PORTSC_SPEED_SHIFT	(10)
+#define CRG_U3DC_PORTSC_SPEED_MASK	\
+		(0xf << CRG_U3DC_PORTSC_SPEED_SHIFT)
+#define CRG_U3DC_PORTSC_SPEED(fv)	\
+		(MAKEF_VAR(CRG_U3DC_PORTSC_SPEED, (fv)))
+#define CRG_U3DC_PORTSC_SPEED_GET(v)	\
+		(GETF(CRG_U3DC_PORTSC_SPEED, (v)))
+#define CRG_U3DC_PORTSC_SPEED_FS	(0x1)
+#define CRG_U3DC_PORTSC_SPEED_LS	(0x2)
+#define CRG_U3DC_PORTSC_SPEED_HS	(0x3)
+#define CRG_U3DC_PORTSC_SPEED_SS	(0x4)
+#define CRG_U3DC_PORTSC_SPEED_SSP	(0x5)
+
+#define CRG_U3DC_PORTSC_LWS			BIT(16)
+#define CRG_U3DC_PORTSC_CSC			BIT(17)
+#define CRG_U3DC_PORTSC_PEC			BIT(18)
+#define CRG_U3DC_PORTSC_PPC			BIT(20)
+#define CRG_U3DC_PORTSC_PRC			BIT(21)
+#define CRG_U3DC_PORTSC_PLC			BIT(22)
+#define CRG_U3DC_PORTSC_CEC			BIT(23)
+#define CRG_U3DC_PORTSC_WCE			BIT(25)
+#define CRG_U3DC_PORTSC_WDE			BIT(26)
+#define CRG_U3DC_PORTSC_WPR			BIT(31)
+
+#define PORTSC_W1C_MASK		(CRG_U3DC_PORTSC_CSC |	\
+					CRG_U3DC_PORTSC_PEC |	\
+					CRG_U3DC_PORTSC_PPC |	\
+					CRG_U3DC_PORTSC_PRC |	\
+					CRG_U3DC_PORTSC_PLC |	\
+					CRG_U3DC_PORTSC_CEC)
+#define PORTSC_WRITE_MASK	(~PORTSC_W1C_MASK)
+
+/* u3portpmsc */
+#define CRG_U3DC_U3PORTPM_U1TMOUT_SHIFT		(0)
+#define CRG_U3DC_U3PORTPM_U1TMOUT_MASK	\
+		(0xff << CRG_U3DC_U3PORTPM_U1TMOUT_SHIFT)
+#define CRG_U3DC_U3PORTPM_U1TMOUT(fv)	\
+		(MAKEF_VAR(CRG_U3DC_U3PORTPM_U1TMOUT, (fv)))
+
+#define CRG_U3DC_U3PORTPM_U2TMOUT_SHIFT		(8)
+#define CRG_U3DC_U3PORTPM_U2TMOUT_MASK	\
+		(0xff << CRG_U3DC_U3PORTPM_U2TMOUT_SHIFT)
+#define CRG_U3DC_U3PORTPM_U2TMOUT(fv)	\
+		(MAKEF_VAR(CRG_U3DC_U3PORTPM_U2TMOUT, (fv)))
+
+#define CRG_U3DC_U3PORTPM_FLA			BIT(16)
+
+#define CRG_U3DC_U3PORTPM_U1IEN_SHIFT		(20)
+#define CRG_U3DC_U3PORTPM_U1IEN		\
+		(1L << CRG_U3DC_U3PORTPM_U1IEN_SHIFT)
+
+#define CRG_U3DC_U3PORTPM_U2IEN_SHIFT		(21)
+#define CRG_U3DC_U3PORTPM_U2IEN		\
+		(1L << CRG_U3DC_U3PORTPM_U2IEN_SHIFT)
+
+#define CRG_U3DC_U3PORTPM_U1AEN_SHIFT		(22)
+#define CRG_U3DC_U3PORTPM_U1AEN		\
+		(1L << CRG_U3DC_U3PORTPM_U1AEN_SHIFT)
+
+#define CRG_U3DC_U3PORTPM_U2AEN_SHIFT		(23)
+#define CRG_U3DC_U3PORTPM_U2AEN		\
+		(1L << CRG_U3DC_U3PORTPM_U2AEN_SHIFT)
+
+#define CRG_U3DC_U3PORTPM_U1U2TMOUT_SHIFT	(24)
+#define CRG_U3DC_U3PORTPM_U1U2TMOUT_MASK \
+		(0xff << CRG_U3DC_U3PORTPM_U1U2TMOUT_SHIFT)
+
+/* u2portpmsc */
+#define CRG_U3DC_U2PORTPM_RJ_TH_SHIFT		(0)
+#define CRG_U3DC_U2PORTPM_RJ_TH_MASK	\
+	(0xf << CRG_U3DC_U2PORTPM_RJ_TH_SHIFT)
+#define CRG_U3DC_U2PORTPM_RJ_TH(fv)	\
+	(MAKEF_VAR(CRG_U3DC_U2PORTPM_RJ_TH, (fv)))
+
+#define CRG_U3DC_U2PORTPM_DS_TH_SHIFT		(4)
+#define CRG_U3DC_U2PORTPM_DS_TH_MASK	\
+		(0xf << CRG_U3DC_U2PORTPM_DS_TH_SHIFT)
+#define CRG_U3DC_U2PORTPM_DS_TH(fv)	\
+		(MAKEF_VAR(CRG_U3DC_U2PORTPM_DS_TH, (fv)))
+
+#define CRG_U3DC_U2PORTPM_LPM_EN		BIT(8)
+#define CRG_U3DC_U2PORTPM_RJ_TH_EN		BIT(9)
+#define CRG_U3DC_U2PORTPM_DS_EN			BIT(10)
+#define CRG_U3DC_U2PORTPM_SLP_EN		BIT(11)
+#define CRG_U3DC_U2PORTPM_LPM_FACK		BIT(12)
+#define CRG_U3DC_U2PORTPM_L1_AEX		BIT(13)
+#define CRG_U3DC_U2PORTPM_H_B_SHIFT		(16)
+#define CRG_U3DC_U2PORTPM_H_B_MASK	\
+		(0xf << CRG_U3DC_U2PORTPM_H_B_SHIFT)
+#define CRG_U3DC_U2PORTPM_H_B(fv)	\
+		(MAKEF_VAR(CRG_U3DC_U2PORTPM_H_B, (fv)))
+
+#define CRG_U3DC_U2PORTPM_RWE			BIT(20)
+
+#define CRG_U3DC_U2PORTPM_TM_SHIFT		(28)
+#define CRG_U3DC_U2PORTPM_TM_MASK	\
+		(0xf << CRG_U3DC_U2PORTPM_TM_SHIFT)
+#define CRG_U3DC_U2PORTPM_TM(fv)	\
+		(MAKEF_VAR(CRG_U3DC_U2PORTPM_TM, (fv)))
+
+/* doorbell register*/
+#define CRG_U3DC_DB_TARGET_SHIFT		(0)
+#define CRG_U3DC_DB_TARGET_MASK		\
+		(0x1f << CRG_U3DC_DB_TARGET_SHIFT)
+#define CRG_U3DC_DB_TARGET(fv)		\
+		(MAKEF_VAR(CRG_U3DC_DB_TARGET, (fv)))
+
+/* odb registers*/
+#define CRG_U3DC_ODBCFG_2N_OFFSET_SHIFT		(0)
+#define CRG_U3DC_ODBCFG_2N_OFFSET_MASK		\
+		(0x3ff << CRG_U3DC_ODBCFG_2N_OFFSET_SHIFT)
+#define CRG_U3DC_ODBCFG_2N_OFFSET(fv)		\
+		(MAKEF_VAR(CRG_U3DC_ODBCFG_2N_OFFSET, (fv)))
+
+#define CRG_U3DC_ODBCFG_2N_SIZE_SHIFT		(10)
+#define CRG_U3DC_ODBCFG_2N_SIZE_MASK		\
+		(0x7 << CRG_U3DC_ODBCFG_2N_SIZE_SHIFT)
+#define CRG_U3DC_ODBCFG_2N_SIZE(fv)		\
+		(MAKEF_VAR(CRG_U3DC_ODBCFG_2N_SIZE, (fv)))
+
+#define CRG_U3DC_ODBCFG_2N1_OFFSET_SHIFT	(16)
+#define CRG_U3DC_ODBCFG_2N1_OFFSET_MASK		\
+		(0x3ff << CRG_U3DC_ODBCFG_2N1_OFFSET_SHIFT)
+#define CRG_U3DC_ODBCFG_2N1_OFFSET(fv)		\
+		(MAKEF_VAR(CRG_U3DC_ODBCFG_2N1_OFFSET, (fv)))
+
+#define CRG_U3DC_ODBCFG_2N1_SIZE_SHIFT		(26)
+#define CRG_U3DC_ODBCFG_2N1_SIZE_MASK		\
+		(0x7 << CRG_U3DC_ODBCFG_2N1_SIZE_SHIFT)
+#define CRG_U3DC_ODBCFG_2N1_SIZE(fv)		\
+		(MAKEF_VAR(CRG_U3DC_ODBCFG_2N1_SIZE, (fv)))
+
+/* command control register*/
+#define	CRG_U3DC_CMD_CTRL_ACTIVE_SHIFT		(0)
+#define	CRG_U3DC_CMD_CTRL_ACTIVE	\
+		(1L << CRG_U3DC_CMD_CTRL_ACTIVE_SHIFT)
+#define	CRG_U3DC_CMD_CTRL_IOC_SHIFT		(1)
+#define	CRG_U3DC_CMD_CTRL_IOC_EN	\
+		(1L << CRG_U3DC_CMD_CTRL_IOC_SHIFT)
+
+#define	CRG_U3DC_CMD_CTRL_TYPE_SHIFT		(4)
+#define	CRG_U3DC_CMD_CTRL_TYPE_MASK	\
+		(0xf << CRG_U3DC_CMD_CTRL_TYPE_SHIFT)
+#define CRG_U3DC_CMD_CTRL_TYPE(fv)	\
+		(MAKEF_VAR(CRG_U3DC_CMD_CTRL_TYPE, (fv)))
+
+#define	CRG_U3DC_CMD_CTRL_STATUS_SHIFT		(16)
+#define	CRG_U3DC_CMD_CTRL_STATUS_MASK	\
+		(0xf << CRG_U3DC_CMD_CTRL_STATUS_SHIFT)
+#define CRG_U3DC_CMD_CTRL_STATUS(fv)	\
+		(MAKEF_VAR(CRG_U3DC_CMD_CTRL_STATUS, (fv)))
+#define CRG_U3DC_CMD_CTRL_STATUS_GET(v)	\
+		(GETF(CRG_U3DC_CMD_CTRL_STATUS, (v)))
+
+#define	CRG_U3DC_CMD_INIT_EP0			(0L)
+#define	CRG_U3DC_CMD_UPDATE_EP0			(1L)
+#define	CRG_U3DC_CMD_SET_ADDRESS		(2L)
+#define	CRG_U3DC_CMD_SEND_DEV_NOTIFY		(3L)
+#define	CRG_U3DC_CMD_CONFIG_EP			(4L)
+#define	CRG_U3DC_CMD_SET_HALT			(5L)
+#define	CRG_U3DC_CMD_CLR_HALT			(6L)
+#define	CRG_U3DC_CMD_RST_SEQNUM			(7L)
+#define	CRG_U3DC_CMD_STOP_EP			(8L)
+#define	CRG_U3DC_CMD_SET_TR_DQPTR		(9L)
+#define	CRG_U3DC_CMD_FORCE_FLOW_CTRL		(10L)
+#define	CRG_U3DC_CMD_REQ_LDM_EXCHAG		(11L)
+
+/* int register*/
+/* iman bits*/
+#define	CRG_U3DC_IMAN_INT_PEND			BIT(0)
+#define	CRG_U3DC_IMAN_INT_EN			BIT(1)
+
+/* erdp bits*/
+#define CRG_U3DC_ERDPLO_EHB			BIT(3)
+#define CRG_U3DC_ERDPLO_ADDRLO(fv)	((fv) & 0xfffffff0)
+
+/*command params*/
+/*command0 init ep0*/
+#define CRG_CMD0_0_DQPTRLO_SHIFT	(4)
+#define CRG_CMD0_0_DQPTRLO_MASK	\
+		(0x0fffffff << CRG_CMD0_0_DQPTRLO_SHIFT)
+
+#define CRG_CMD0_0_DCS_SHIFT		(0)
+#define CRG_CMD0_0_DCS_MASK		(0x1 << CRG_CMD0_0_DCS_SHIFT)
+#define CRG_CMD0_0_DCS(fv)		(MAKEF_VAR(CRG_CMD0_0_DCS, (fv)))
+
+/*command1 update ep0 */
+#define CRG_CMD1_0_MPS_SHIFT		(16)
+#define CRG_CMD1_0_MPS_MASK		(0xffff << CRG_CMD1_0_MPS_SHIFT)
+#define CRG_CMD1_0_MPS(fv)		(MAKEF_VAR(CRG_CMD1_0_MPS, (fv)))
+
+/*command2 set addr */
+#define CRG_CMD2_0_DEV_ADDR_SHIFT	(0)
+#define CRG_CMD2_0_DEV_ADDR_MASK	(0xff << CRG_CMD2_0_DEV_ADDR_SHIFT)
+#define CRG_CMD2_0_DEV_ADDR(fv)		(MAKEF_VAR(CRG_CMD2_0_DEV_ADDR, (fv)))
+
+#define CRG_UDC_MODE_REG		0x20fc
+/* Vendor specific register */
+#define CRG_UDC_VENDOR_REG		0x210c
+#define CRG_UDC_VBUS_DETECT			BIT(26)
+/*command type*/
+enum crg_cmd_type {
+	CRG_CMD_INIT_EP0 = 0,
+	CRG_CMD_UPDATE_EP0_CFG = 1,
+	CRG_CMD_SET_ADDR = 2,
+	CRG_CMD_SEND_DEV_NOTIFICATION = 3,
+	CRG_CMD_CONFIG_EP = 4,
+	CRG_CMD_SET_HALT = 5,
+	CRG_CMD_CLEAR_HALT = 6,
+	CRG_CMD_RESET_SEQNUM = 7,
+	CRG_CMD_STOP_EP = 8,
+	CRG_CMD_SET_TR_DQPTR = 9,
+	CRG_CMD_FORCE_FLOW_CONTROL = 10,
+	CRG_CMD_REQ_LDM_EXCHANGE = 11
+};
+
+struct crg_gadget_dev;
+
+struct crg_udc_platdata {
+	int num_out_eps;
+	int num_in_eps;
+};
+
+#endif /* __CRG_UDC_H__ */

-- 
2.34.1
Re: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
Posted by Greg Kroah-Hartman 3 days, 18 hours ago
On Mon, Feb 02, 2026 at 05:16:29AM -0800, Vladimir Moravcevic wrote:
> Add Corigine USB IP Driver for Axiado AX3000 SoC's
> USB peripheral (USB 2.0/3.0).
> The driver is based on the Corigine USB IP core with
> Axiado-specific enhancements including VBUS detection and USB link
> stability fixes.
> 
> The driver supports both USB 2.0 High-Speed and USB 3.0 SuperSpeed
> modes with control, bulk, interrupt, and isochronous transfer types.
> 
> Co-developed-by: Krutik Shah <krutikshah@axiado.com>
> Signed-off-by: Krutik Shah <krutikshah@axiado.com>
> Co-developed-by: Prasad Bolisetty <pbolisetty@axiado.com>
> Signed-off-by: Prasad Bolisetty <pbolisetty@axiado.com>
> Signed-off-by: Vladimir Moravcevic <vmoravcevic@axiado.com>
> ---
>  drivers/usb/gadget/udc/Kconfig   |   15 +
>  drivers/usb/gadget/udc/Makefile  |    1 +
>  drivers/usb/gadget/udc/crg_udc.c | 4522 ++++++++++++++++++++++++++++++++++++++
>  drivers/usb/gadget/udc/crg_udc.h |  364 +++
>  4 files changed, 4902 insertions(+)
> 
> diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
> index 26460340fbc9..b94d113aad99 100644
> --- a/drivers/usb/gadget/udc/Kconfig
> +++ b/drivers/usb/gadget/udc/Kconfig
> @@ -417,6 +417,21 @@ config USB_ASPEED_UDC
>  	  dynamically linked module called "aspeed_udc" and force all
>  	  gadget drivers to also be dynamically linked.
>  
> +config USB_CRG_UDC
> +	tristate "AXIADO CORIGINE-based AX3000 Device Controller"
> +	depends on ARCH_AXIADO || COMPILE_TEST
> +	depends on USB_GADGET
> +	help
> +	  Enables AX3000 USB device controller driver for Axiado
> +	  SoCs and evaluation boards.
> +
> +	  Based on the Corigine USB IP core driver with Axiado specific
> +	  enhancements. Supports USB 2.0 (High-Speed) and USB 3.0
> +	  (SuperSpeed), including control, bulk, interrupt, and
> +	  isochronous transfers.
> +
> +	  Say "y" to build statically, or "m" to build as a module.

What is the module name?  The other entries in this file all describe
this.

> --- /dev/null
> +++ b/drivers/usb/gadget/udc/crg_udc.c
> @@ -0,0 +1,4522 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)

That is very odd, and I need a bit of justification as to why, and how,
MIT is allowed here.  Did you look at any of the existing gadget udc
drivers when working on this code?  If so, how can MIT still work?

Anyway, as this is a "not normal" selection for this type of driver, I
will need a signed-off-by from your corporate lawyer with the reason why
it is dual licensed described in the changelog comment for it showing
that you all understand all of the issues involved in doing something
like this, and attempting to keep it under a dual license over time.

thanks,

greg k-h

> +//
> +// Copyright (c) 2019 Corigine Inc.
> +// Copyright (c) 2022-2026 Axiado Corporation.
> +//
> +
> +#include <linux/net.h>
> +#include <asm/byteorder.h>
> +#include <linux/errno.h>
> +#include <linux/io.h>
> +#include <linux/unaligned.h>
> +#include <linux/types.h>
> +#include <linux/bitops.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/irqreturn.h>
> +#include <linux/interrupt.h>
> +#include <linux/ctype.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/kthread.h>
> +#include <linux/err.h>
> +#include <linux/wait.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_gpio.h>
> +#include <linux/scatterlist.h>
> +#include "crg_udc.h"
> +
> +#define INIT_ZERO					-1

Why is "ZERO" defined as -1?

> +#define UDC_FALSE					false

Please just use "false" where needed.

> +
> +#define MAX_PACKET_SIZE 1024
> +
> +#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)

Isn't this in the dma headers somewhere instead?  if not, why not?

And you mix tabs with spaces after the "#define" on these lists, please
don't.


> +
> +#define CRG_ERST_SIZE 1
> +#define CRG_EVENT_RING_SIZE 256

Why no tabs here, but:

> +#define CRG_NUM_EP_CX	32

Tabs here?  Be consistent please.

> +#define TRB_MAX_BUFFER_SIZE		65536
> +#define CRGUDC_CONTROL_EP_TD_RING_SIZE	16
> +#define CRGUDC_BULK_EP_TD_RING_SIZE	1024
> +#define CRGUDC_ISOC_EP_TD_RING_SIZE	32
> +#define CRGUDC_INT_EP_TD_RING_SIZE	8
> +#define CRGUDC_ROLE_DEVICE		0x1
> +
> +#define	U1_TIMEOUT_VAL	0x70
> +#define	U2_TIMEOUT_VAL	0x70

And then tabs here after "define"?

Anyway, it just stands out instantly as something odd.

> +
> +#define STATE_USB_LINK_STABLE 4
> +
> +/*********Feature switches********************/
> +#define U12_FORBIDDEN	1
> +#define U12_INITIATE_FORBIDDEN 1
> +#define CRG_UDC_INT_EN
> +#define REINIT_EP0_ON_BUS_RESET

We do not have "feature switches" in kernel drivers that require you to
rebuild the code.  Please handle these properly like all other drivers
do (i.e. not this way.)

> +/*Table 127*/

No spaces?

Anyway, what is "table 127"?  And what is it for?

> +enum TRB_CMPL_CODES_E {
> +	CMPL_CODE_INVALID       = 0,
> +	CMPL_CODE_SUCCESS,
> +	CMPL_CODE_DATA_BUFFER_ERR,
> +	CMPL_CODE_BABBLE_DETECTED_ERR,
> +	CMPL_CODE_USB_TRANS_ERR,
> +	CMPL_CODE_TRB_ERR,  /*5*/

If this really is "5", then set it to 5!


> +	CMPL_CODE_TRB_STALL,
> +	CMPL_CODE_INVALID_STREAM_TYPE_ERR = 10,
> +	CMPL_CODE_SHORT_PKT = 13,
> +	CMPL_CODE_RING_UNDERRUN,
> +	CMPL_CODE_RING_OVERRUN, /*15*/

Same here.  Don't assume that enums will be properly set without
actually setting them all, as I don't think the C standard guarantees
this (I could be wrong, but it can trip you up...)

If you want a specific value, set it so you _know_ it will be correct.

> +	CMPL_CODE_EVENT_RING_FULL_ERR = 21,
> +	CMPL_CODE_STOPPED = 26,
> +	CMPL_CODE_STOPPED_LENGTH_INVALID = 27,
> +	CMPL_CODE_ISOCH_BUFFER_OVERRUN = 31,
> +	/*192-224 vendor defined error*/

You are the vendor!

> +	CMPL_CODE_PROTOCOL_STALL = 192,
> +	CMPL_CODE_SETUP_TAG_MISMATCH = 193,
> +	CMPL_CODE_HALTED = 194,
> +	CMPL_CODE_HALTED_LENGTH_INVALID = 195,
> +	CMPL_CODE_DISABLED = 196,
> +	CMPL_CODE_DISABLED_LENGTH_INVALID = 197,
> +};
> +
> +static const char driver_name[] = "crg_udc";

Why is this needed and why not use KBUILD_MODNAME instead?

> +
> +struct buffer_info {
> +	void *vaddr;

What is a vaddr?

I'll stop here.  Also note the 0-day bot issues that it found, which
precludes us from take this as-is.

thanks,

greg k-h
Re: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
Posted by Krzysztof Kozlowski 3 days, 18 hours ago
On 02/02/2026 14:16, Vladimir Moravcevic wrote:
> Add Corigine USB IP Driver for Axiado AX3000 SoC's
> USB peripheral (USB 2.0/3.0).
> The driver is based on the Corigine USB IP core with
> Axiado-specific enhancements including VBUS detection and USB link
> stability fixes.


This driver looks way too complicated for simple USB controller, so I
guess you just re-implemented a lot of Linux stack or other drivers.

Also did not pass basic litmus test for sending usu 15 year old junk
code, which disqualifies it from review IMO. There is simply no point to
review code from 15 yaers ago - you should never start with such code.

> +static const struct crg_udc_priv ax3000_plat_setup_gen2 = {
> +	.plat_setup_gen3 = false,
> +};
> +
> +static const struct crg_udc_priv ax3000_plat_setup_gen3 = {
> +	.plat_setup_gen3 = true,
> +};
> +
> +/**
> + * crg_gadget_probe - Initializes gadget driver
> + *
> + *
> + * Returns 0 on success otherwise negative errno.
> + */

Completely pointless and wrongly placed comment. Do not ever add such
comments.

> +
> +static const struct of_device_id of_crg_udc_match[] = {
> +	{
> +		.compatible = "axiado,ax3000-udc",
> +		.data = &ax3000_plat_setup_gen2
> +	},
> +	{
> +		.compatible = "axiado,ax3000-udc-gen3",
> +		.data = &ax3000_plat_setup_gen3
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, of_crg_udc_match);
> +
> +static int crg_udc_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	int i;
> +	struct crg_gadget_dev *crg_udc;
> +	static int udc_gcnt = INIT_ZERO;
> +	char udc_gname[10] = {""};
> +	const struct crg_udc_priv *priv;
> +
> +	priv = of_device_get_match_data(&pdev->dev);
> +	sprintf(udc_gname, "gadget-%d", udc_gcnt);
> +	crg_udc = devm_kzalloc(&pdev->dev, sizeof(*crg_udc), GFP_KERNEL);
> +	if (!crg_udc)
> +		return -ENOMEM;
> +	crg_udc->dev = &pdev->dev;
> +
> +	spin_lock_init(&crg_udc->udc_lock);
> +	platform_set_drvdata(pdev, crg_udc);
> +
> +	dev_set_name(&crg_udc->gadget.dev, udc_gname);
> +	crg_udc->gadget.ops = &crg_gadget_ops;
> +	crg_udc->gadget.ep0 = &crg_udc->udc_ep[0].usb_ep;
> +	crg_udc->gadget.dev.parent = &pdev->dev;
> +	INIT_LIST_HEAD(&crg_udc->gadget.ep_list);
> +	if (priv->plat_setup_gen3) {
> +		crg_udc->gadget.max_speed = USB_SPEED_SUPER;
> +		crg_udc->gadget.speed = USB_SPEED_SUPER;
> +	} else {
> +		crg_udc->gadget.max_speed = USB_SPEED_HIGH;
> +		crg_udc->gadget.speed = USB_SPEED_HIGH;
> +	}
> +	crg_udc->gadget.name = udc_gname;
> +	crg_udc->gadget.sg_supported = true;
> +	dev_dbg(crg_udc->dev, "%s sg support\n", __func__);
> +	crg_udc->connected = 0;
> +	crg_udc->dev_addr = 0;
> +
> +	crg_udc->udc_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!crg_udc->udc_res) {
> +		dev_err(&pdev->dev, "missing memory resource\n");
> +		return -ENODEV;
> +	}
> +
> +	crg_udc->mmio_virt_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(crg_udc->mmio_virt_base)) {
> +		dev_err(&pdev->dev, "mmio ioremap failed\n");
> +		return PTR_ERR(crg_udc->mmio_virt_base);
> +	}
> +
> +	/* set controller device role*/
> +	writel((readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) |
> +		 CRGUDC_ROLE_DEVICE),
> +		 crg_udc->mmio_virt_base + CRG_UDC_MODE_REG);
> +	for (i = 0; i < CRG_RING_NUM; i++) {
> +		crg_udc->uicr[i] = crg_udc->mmio_virt_base +
> +				CRG_UICR_OFFSET + i * CRG_UICR_STRIDE;
> +
> +		dev_dbg(crg_udc->dev, "crg_udc->uicr[%d] = %p\n", i,
> +			crg_udc->uicr[i]);
> +	}
> +	crg_udc->uccr = crg_udc->mmio_virt_base + CRG_UCCR_OFFSET;
> +
> +	crg_udc_reset(crg_udc);
> +
> +	crg_udc_clear_portpm(crg_udc);
> +
> +	ret = reset_data_struct(crg_udc);
> +	if (ret) {
> +		dev_err(crg_udc->dev, "reset_data_struct error\n");
> +		goto err0;
> +	}
> +
> +	init_ep_info(crg_udc);
> +	init_ep0(crg_udc);
> +
> +	EP0_Start(crg_udc);

Did you read coding style?

> +
> +	crg_gadget_irq_init(pdev, crg_udc);
> +
> +	ret = usb_add_gadget_udc(&pdev->dev, &crg_udc->gadget);
> +	if (ret)
> +		goto err0;
> +
> +	udc_gcnt++;
> +
> +	return 0;
> +
> +err0:
> +	return -1;

What?

> +}
> +
> +static void crg_udc_remove(struct platform_device *pdev)
> +{
> +	struct crg_gadget_dev *crg_udc = platform_get_drvdata(pdev);
> +	u32 tmp = 0;
> +
> +	dev_dbg(crg_udc->dev, "%s %d called\n", __func__, __LINE__);
> +
> +	crg_udc->device_state = USB_STATE_ATTACHED;
> +	crg_vbus_detect(crg_udc, 0);
> +
> +	usb_del_gadget_udc(&crg_udc->gadget);
> +
> +	/* set controller host role*/
> +	tmp = readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) & ~0x1;
> +	writel(tmp, crg_udc->mmio_virt_base + CRG_UDC_MODE_REG);
> +
> +	if (crg_udc->irq)
> +		free_irq(crg_udc->irq, crg_udc);
> +
> +	platform_set_drvdata(pdev, 0);
> +
> +	dev_dbg(crg_udc->dev, "%s %d gadget remove\n", __func__, __LINE__);

Drop all such debugs.

> +
> +}
> +
> +static void crg_udc_shutdown(struct platform_device *pdev)
> +{
> +	struct crg_gadget_dev *crg_udc = platform_get_drvdata(pdev);
> +
> +	dev_dbg(crg_udc->dev, "%s %d called\n", __func__, __LINE__);

It's really pointless code.

> +
> +	crg_udc->device_state = USB_STATE_ATTACHED;
> +	crg_vbus_detect(crg_udc, 0);
> +	usb_del_gadget_udc(&crg_udc->gadget);
> +
> +	if (crg_udc->irq)
> +		free_irq(crg_udc->irq, crg_udc);
> +	/*
> +	 * Clear the drvdata pointer.
> +	 */
> +	platform_set_drvdata(pdev, 0);
> +}
> +
> +#ifdef CONFIG_PM
> +static int crg_udc_suspend(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static int crg_udc_resume(struct device *dev)
> +{
> +
> +
> +	return 0;
> +}
> +#else
> +#define crg_udc_suspend	NULL
> +#define crg_udc_resume	NULL
> +#endif
> +
> +static const struct dev_pm_ops crg_udc_pm_ops = {
> +	.suspend = crg_udc_suspend,
> +	.resume = crg_udc_resume,
> +};
> +
> +static struct platform_driver crg_udc_driver = {
> +	.probe = crg_udc_probe,
> +	.remove = crg_udc_remove,
> +	.shutdown = crg_udc_shutdown,
> +	.driver			= {
> +		.name		= "crg_udc",
> +		.owner		= THIS_MODULE,

Do not upstream 10 or 15 year old driver. Why do we need to repeat all
the same comments as we repeated for last 15 years? Take newest driver
as starting point, not 15 year old code. You just replicated all old issues.



Best regards,
Krzysztof
Re: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
Posted by kernel test robot 6 days, 8 hours ago
Hi Vladimir,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 63804fed149a6750ffd28610c5c1c98cce6bd377]

url:    https://github.com/intel-lab-lkp/linux/commits/Vladimir-Moravcevic/dt-bindings-usb-axiado-ax3000-udc-Add-Axiado-UDC/20260202-211951
base:   63804fed149a6750ffd28610c5c1c98cce6bd377
patch link:    https://lore.kernel.org/r/20260202-axiado-ax3000-usb-device-controller-v1-2-45ce0a8b014f%40axiado.com
patch subject: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
config: nios2-allmodconfig (https://download.01.org/0day-ci/archive/20260203/202602030223.QlbiPC8d-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260203/202602030223.QlbiPC8d-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602030223.QlbiPC8d-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/linux/printk.h:621,
                    from include/asm-generic/bug.h:31,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/random.h:6,
                    from include/linux/net.h:18,
                    from drivers/usb/gadget/udc/crg_udc.c:7:
   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_epcx_setup':
>> drivers/usb/gadget/udc/crg_udc.c:624:31: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'unsigned int' [-Wformat=]
     624 |         dev_dbg(crg_udc->dev, "DCI %d, sizeof ep_cx %ld\n", DCI, sizeof(struct ep_cx_s));
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:231:29: note: in definition of macro '__dynamic_func_call_cls'
     231 |                 func(&id, ##__VA_ARGS__);                       \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:261:9: note: in expansion of macro '_dynamic_func_call_cls'
     261 |         _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:284:9: note: in expansion of macro '_dynamic_func_call'
     284 |         _dynamic_func_call(fmt, __dynamic_dev_dbg,              \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:30: note: in expansion of macro 'dev_fmt'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                              ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:624:9: note: in expansion of macro 'dev_dbg'
     624 |         dev_dbg(crg_udc->dev, "DCI %d, sizeof ep_cx %ld\n", DCI, sizeof(struct ep_cx_s));
         |         ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:624:55: note: format string is defined here
     624 |         dev_dbg(crg_udc->dev, "DCI %d, sizeof ep_cx %ld\n", DCI, sizeof(struct ep_cx_s));
         |                                                     ~~^
         |                                                       |
         |                                                       long int
         |                                                     %d
   In file included from include/linux/printk.h:621,
                    from include/asm-generic/bug.h:31,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/random.h:6,
                    from include/linux/net.h:18,
                    from drivers/usb/gadget/udc/crg_udc.c:7:
   drivers/usb/gadget/udc/crg_udc.c: In function 'setup_datastage_trb':
>> drivers/usb/gadget/udc/crg_udc.c:774:31: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'dma_addr_t' {aka 'unsigned int'} [-Wformat=]
     774 |         dev_dbg(crg_udc->dev, "dma = 0x%llx, ", usb_req->dma);
         |                               ^~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:231:29: note: in definition of macro '__dynamic_func_call_cls'
     231 |                 func(&id, ##__VA_ARGS__);                       \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:261:9: note: in expansion of macro '_dynamic_func_call_cls'
     261 |         _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:284:9: note: in expansion of macro '_dynamic_func_call'
     284 |         _dynamic_func_call(fmt, __dynamic_dev_dbg,              \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:30: note: in expansion of macro 'dev_fmt'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                              ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:774:9: note: in expansion of macro 'dev_dbg'
     774 |         dev_dbg(crg_udc->dev, "dma = 0x%llx, ", usb_req->dma);
         |         ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:774:43: note: format string is defined here
     774 |         dev_dbg(crg_udc->dev, "dma = 0x%llx, ", usb_req->dma);
         |                                        ~~~^
         |                                           |
         |                                           long long unsigned int
         |                                        %x
   In file included from include/linux/printk.h:621,
                    from include/asm-generic/bug.h:31,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/random.h:6,
                    from include/linux/net.h:18,
                    from drivers/usb/gadget/udc/crg_udc.c:7:
   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_queue_trbs':
>> drivers/usb/gadget/udc/crg_udc.c:896:25: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
     896 |                         (void *)sg_addr, buffer_length, num_trbs_needed);
         |                         ^
   include/linux/dynamic_debug.h:231:29: note: in definition of macro '__dynamic_func_call_cls'
     231 |                 func(&id, ##__VA_ARGS__);                       \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:261:9: note: in expansion of macro '_dynamic_func_call_cls'
     261 |         _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:284:9: note: in expansion of macro '_dynamic_func_call'
     284 |         _dynamic_func_call(fmt, __dynamic_dev_dbg,              \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:894:17: note: in expansion of macro 'dev_dbg'
     894 |                 dev_dbg(crg_udc->dev,
         |                 ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:881:13: warning: variable 'num_sgs' set but not used [-Wunused-but-set-variable]
     881 |         u32 num_sgs = 0;
         |             ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_ep_enable':
   drivers/usb/gadget/udc/crg_udc.c:1812:26: warning: variable 'uccr' set but not used [-Wunused-but-set-variable]
    1812 |         struct crg_uccr *uccr;
         |                          ^~~~
   drivers/usb/gadget/udc/crg_udc.c:1811:25: warning: variable 'epcx' set but not used [-Wunused-but-set-variable]
    1811 |         struct ep_cx_s *epcx;
         |                         ^~~~
   In file included from include/linux/printk.h:621,
                    from include/asm-generic/bug.h:31,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/random.h:6,
                    from include/linux/net.h:18,
                    from drivers/usb/gadget/udc/crg_udc.c:7:
   drivers/usb/gadget/udc/crg_udc.c: In function 'init_ep0':
   drivers/usb/gadget/udc/crg_udc.c:2681:31: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'dma_addr_t' {aka 'unsigned int'} [-Wformat=]
    2681 |         dev_dbg(crg_udc->dev, "ep0 ring dma addr = 0x%llx\n", udc_ep_ptr->tran_ring_info.dma);
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:231:29: note: in definition of macro '__dynamic_func_call_cls'
     231 |                 func(&id, ##__VA_ARGS__);                       \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:261:9: note: in expansion of macro '_dynamic_func_call_cls'
     261 |         _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:284:9: note: in expansion of macro '_dynamic_func_call'
     284 |         _dynamic_func_call(fmt, __dynamic_dev_dbg,              \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:30: note: in expansion of macro 'dev_fmt'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                              ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:2681:9: note: in expansion of macro 'dev_dbg'
    2681 |         dev_dbg(crg_udc->dev, "ep0 ring dma addr = 0x%llx\n", udc_ep_ptr->tran_ring_info.dma);
         |         ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:2681:57: note: format string is defined here
    2681 |         dev_dbg(crg_udc->dev, "ep0 ring dma addr = 0x%llx\n", udc_ep_ptr->tran_ring_info.dma);
         |                                                      ~~~^
         |                                                         |
         |                                                         long long unsigned int
         |                                                      %x
   In file included from include/linux/printk.h:621,
                    from include/asm-generic/bug.h:31,
                    from ./arch/nios2/include/generated/asm/bug.h:1,
                    from include/linux/bug.h:5,
                    from include/linux/random.h:6,
                    from include/linux/net.h:18,
                    from drivers/usb/gadget/udc/crg_udc.c:7:
   drivers/usb/gadget/udc/crg_udc.c: In function 'getstatusrequest':
   drivers/usb/gadget/udc/crg_udc.c:3131:31: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'dma_addr_t' {aka 'unsigned int'} [-Wformat=]
    3131 |         dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.dma = 0x%llx\n",
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:231:29: note: in definition of macro '__dynamic_func_call_cls'
     231 |                 func(&id, ##__VA_ARGS__);                       \
         |                             ^~~~~~~~~~~
   include/linux/dynamic_debug.h:261:9: note: in expansion of macro '_dynamic_func_call_cls'
     261 |         _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:284:9: note: in expansion of macro '_dynamic_func_call'
     284 |         _dynamic_func_call(fmt, __dynamic_dev_dbg,              \
         |         ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/dev_printk.h:165:30: note: in expansion of macro 'dev_fmt'
     165 |         dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                              ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:3131:9: note: in expansion of macro 'dev_dbg'
    3131 |         dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.dma = 0x%llx\n",
         |         ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c:3131:64: note: format string is defined here
    3131 |         dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.dma = 0x%llx\n",
         |                                                             ~~~^
         |                                                                |
         |                                                                long long unsigned int
         |                                                             %x
   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_common_irq':
   drivers/usb/gadget/udc/crg_udc.c:4250:13: warning: variable 'retval' set but not used [-Wunused-but-set-variable]
    4250 |         int retval = 0;


vim +624 drivers/usb/gadget/udc/crg_udc.c

   609	
   610	static void crg_udc_epcx_setup(struct crg_udc_ep *udc_ep)
   611	{
   612		struct crg_gadget_dev *crg_udc = udc_ep->crg_udc;
   613		const struct usb_endpoint_descriptor *desc = udc_ep->desc;
   614		const struct usb_ss_ep_comp_descriptor *comp_desc = udc_ep->comp_desc;
   615		u8 DCI = udc_ep->DCI;
   616		struct ep_cx_s *epcx = (struct ep_cx_s *)(crg_udc->p_epcx + DCI - 2);
   617		enum EP_TYPE_E ep_type;
   618		u16 maxburst = 0;
   619		u8 maxstreams = 0;
   620		u16 maxsize;
   621		u32 dw;
   622	
   623		dev_dbg(crg_udc->dev, "crgudc->p_epcx %p, epcx %p\n", crg_udc->p_epcx, epcx);
 > 624		dev_dbg(crg_udc->dev, "DCI %d, sizeof ep_cx %ld\n", DCI, sizeof(struct ep_cx_s));
   625		dev_dbg(crg_udc->dev, "desc epaddr = 0x%x\n", desc->bEndpointAddress);
   626	
   627		/*corigine gadget dir should be opposite to host dir*/
   628		if (usb_endpoint_dir_out(desc))
   629			ep_type = usb_endpoint_type(desc) + EP_TYPE_INVALID2;
   630		else
   631			ep_type = usb_endpoint_type(desc);
   632	
   633		maxsize = usb_endpoint_maxp(desc) & 0x07ff; /* D[0:10] */
   634	
   635		if (crg_udc->gadget.speed >= USB_SPEED_SUPER) {
   636			maxburst = comp_desc->bMaxBurst;
   637	
   638			if (usb_endpoint_xfer_bulk(udc_ep->desc))
   639				maxstreams = comp_desc->bmAttributes & 0x1f;
   640	
   641		} else if ((crg_udc->gadget.speed == USB_SPEED_HIGH ||
   642			crg_udc->gadget.speed == USB_SPEED_FULL) &&
   643				(usb_endpoint_xfer_int(udc_ep->desc) ||
   644					usb_endpoint_xfer_isoc(udc_ep->desc))) {
   645			if (crg_udc->gadget.speed == USB_SPEED_HIGH)
   646				maxburst = (usb_endpoint_maxp(desc) >> 11) & 0x3;
   647			if (maxburst == 0x3) {
   648				dev_err(crg_udc->dev, "invalid maxburst\n");
   649				maxburst = 0x2;
   650			}
   651		}
   652	
   653		/* fill ep_dw0 */
   654		dw = 0;
   655		dw = SETF_VAR(EP_CX_LOGICAL_EP_NUM, dw, udc_ep->DCI / 2);
   656		dw = SETF_VAR(EP_CX_INTERVAL, dw, desc->bInterval);
   657		if (maxstreams) {
   658			dev_err(crg_udc->dev, "%s maxstream=%d is not expected\n",
   659				__func__, maxstreams);
   660		}
   661		epcx->dw0 = cpu_to_le32(dw);
   662	
   663		/* fill ep_dw1 */
   664		dw = 0;
   665		dw = SETF_VAR(EP_CX_EP_TYPE, dw, ep_type);
   666		dw = SETF_VAR(EP_CX_MAX_PACKET_SIZE, dw, maxsize);
   667		dw = SETF_VAR(EP_CX_MAX_BURST_SIZE, dw, maxburst);
   668		epcx->dw1 = cpu_to_le32(dw);
   669	
   670		/* fill ep_dw2 */
   671		dw = lower_32_bits(udc_ep->tran_ring_info.dma) & EP_CX_TR_DQPT_LO_MASK;
   672		dw = SETF_VAR(EP_CX_DEQ_CYC_STATE, dw, udc_ep->pcs);
   673		epcx->dw2 = cpu_to_le32(dw);
   674	
   675		/* fill ep_dw3 */
   676		dw = upper_32_bits(udc_ep->tran_ring_info.dma);
   677		epcx->dw3 = cpu_to_le32(dw);
   678		/* Ensure that epcx is updated */
   679		wmb();
   680	}
   681	
   682	static void crg_udc_epcx_update_dqptr(struct crg_udc_ep *udc_ep)
   683	{
   684		struct crg_gadget_dev *crg_udc = udc_ep->crg_udc;
   685		u8 DCI = udc_ep->DCI;
   686		struct ep_cx_s *epcx = (struct ep_cx_s *)(crg_udc->p_epcx + DCI - 2);
   687		u32 dw;
   688		dma_addr_t dqptaddr;
   689		u32 cmd_param0;
   690	
   691		if (DCI == 0) {
   692			dev_err(crg_udc->dev, "%s Cannot update dqptr for ep0\n", __func__);
   693			return;
   694		}
   695	
   696		dqptaddr = tran_trb_virt_to_dma(udc_ep, udc_ep->deq_pt);
   697	
   698		/* fill ep_dw2 */
   699		dw = lower_32_bits(dqptaddr) & EP_CX_TR_DQPT_LO_MASK;
   700		dw = SETF_VAR(EP_CX_DEQ_CYC_STATE, dw, udc_ep->pcs);
   701		epcx->dw2 = cpu_to_le32(dw);
   702	
   703		/* fill ep_dw3 */
   704		dw = upper_32_bits(dqptaddr);
   705		epcx->dw3 = cpu_to_le32(dw);
   706	
   707		cmd_param0 = (0x1 << udc_ep->DCI);
   708		/* Ensure that dqptr is updated */
   709		wmb();
   710	
   711		crg_issue_command(crg_udc, CRG_CMD_SET_TR_DQPTR, cmd_param0, 0);
   712	}
   713	
   714	static void setup_status_trb(struct crg_gadget_dev *crg_udc,
   715			struct transfer_trb_s *p_trb,
   716			struct usb_request *usb_req, u8 pcs, u8 set_addr, u8 stall)
   717	{
   718		u32 tmp, dir = 0;
   719	
   720		/* There are some cases where seutp_status_trb() is called with
   721		 * usb_req set to NULL.
   722		 */
   723	
   724		p_trb->dw0 = 0;
   725		p_trb->dw1 = 0;
   726	
   727		dev_dbg(crg_udc->dev, "data_buf_ptr_lo = 0x%x, data_buf_ptr_hi = 0x%x\n",
   728			p_trb->dw0, p_trb->dw1);
   729	
   730		tmp = 0;
   731		tmp = SETF_VAR(TRB_INTR_TARGET, tmp, 0);
   732		p_trb->dw2 = tmp;
   733	
   734		tmp = 0;
   735		tmp = SETF_VAR(TRB_CYCLE_BIT, tmp, pcs);
   736		tmp = SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, 1);/*IOC:1*/
   737		tmp = SETF_VAR(TRB_TYPE, tmp, TRB_TYPE_XFER_STATUS_STAGE);
   738	
   739		dir = (crg_udc->setup_status == STATUS_STAGE_XFER) ? 0 : 1;
   740		tmp = SETF_VAR(DATA_STAGE_TRB_DIR, tmp, dir);
   741	
   742		tmp = SETF_VAR(TRB_SETUP_TAG, tmp, crg_udc->setup_tag);
   743		tmp = SETF_VAR(STATUS_STAGE_TRB_STALL, tmp, stall);
   744		tmp = SETF_VAR(STATUS_STAGE_TRB_SET_ADDR, tmp, set_addr);
   745	
   746		p_trb->dw3 = tmp;
   747		dev_dbg(crg_udc->dev, "trb_dword2 = 0x%x, trb_dword3 = 0x%x\n",
   748				p_trb->dw2, p_trb->dw3);
   749		/* Ensure that status trb is updated */
   750		wmb();
   751	}
   752	
   753	static void knock_doorbell(struct crg_gadget_dev *crg_udc, int DCI)
   754	{
   755		u32 tmp;
   756		struct crg_uccr *uccr;
   757	
   758		uccr = crg_udc->uccr;
   759		/* Ensure evreything is written before notifying the HW */
   760		wmb();
   761	
   762		tmp = CRG_U3DC_DB_TARGET(DCI);
   763		dev_dbg(crg_udc->dev, "DOORBELL = 0x%x\n", tmp);
   764		writel(tmp, &uccr->doorbell);
   765	}
   766	
   767	static void setup_datastage_trb(struct crg_gadget_dev *crg_udc,
   768			struct transfer_trb_s *p_trb, struct usb_request *usb_req,
   769			u8 pcs, u32 num_trb, u32 transfer_length, u32 td_size,
   770			u8 IOC, u8 AZP, u8 dir, u8 setup_tag)
   771	{
   772		u32 tmp;
   773	
 > 774		dev_dbg(crg_udc->dev, "dma = 0x%llx, ", usb_req->dma);
   775		dev_dbg(crg_udc->dev, "buf = 0x%lx, ", (unsigned long)usb_req->buf);
   776	
   777		p_trb->dw0 = lower_32_bits(usb_req->dma);
   778		p_trb->dw1 = upper_32_bits(usb_req->dma);
   779	
   780		dev_dbg(crg_udc->dev, "data_buf_ptr_lo = 0x%x, data_buf_ptr_hi = 0x%x\n",
   781			p_trb->dw0, p_trb->dw1);
   782	
   783	
   784		/* TRB_Transfer_Length
   785		 *For USB_DIR_OUT, this field is the number of data bytes expected from
   786		 *xhc. For USB_DIR_IN, this field is the number of data bytes the device
   787		 *will send.
   788		 */
   789		tmp = 0;
   790		tmp = SETF_VAR(TRB_TRANSFER_LEN, tmp, transfer_length);
   791		tmp = SETF_VAR(TRB_TD_SIZE, tmp, td_size);
   792		tmp = SETF_VAR(TRB_INTR_TARGET, tmp, 0);
   793		p_trb->dw2 = tmp;
   794	
   795		tmp = 0;
   796		tmp = SETF_VAR(TRB_CYCLE_BIT, tmp, pcs);
   797		tmp = SETF_VAR(TRB_INTR_ON_SHORT_PKT, tmp, 1);
   798		tmp = SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, IOC);
   799		tmp = SETF_VAR(TRB_TYPE, tmp, TRB_TYPE_XFER_DATA_STAGE);
   800		tmp = SETF_VAR(TRB_APPEND_ZLP, tmp, AZP);
   801		tmp = SETF_VAR(DATA_STAGE_TRB_DIR, tmp, dir);
   802		tmp = SETF_VAR(TRB_SETUP_TAG, tmp, setup_tag);
   803	
   804		p_trb->dw3 = tmp;
   805		/* Ensure that datastage trb is updated */
   806		wmb();
   807	
   808		dev_dbg(crg_udc->dev, "trb_dword0 = 0x%x, trb_dword1 = 0x%x trb_dword2 = 0x%x, trb_dword3 = 0x%x\n",
   809				p_trb->dw0, p_trb->dw1, p_trb->dw2, p_trb->dw3);
   810	}
   811	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
Posted by kernel test robot 6 days, 8 hours ago
Hi Vladimir,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 63804fed149a6750ffd28610c5c1c98cce6bd377]

url:    https://github.com/intel-lab-lkp/linux/commits/Vladimir-Moravcevic/dt-bindings-usb-axiado-ax3000-udc-Add-Axiado-UDC/20260202-211951
base:   63804fed149a6750ffd28610c5c1c98cce6bd377
patch link:    https://lore.kernel.org/r/20260202-axiado-ax3000-usb-device-controller-v1-2-45ce0a8b014f%40axiado.com
patch subject: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20260203/202602030131.VCTzZ4me-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260203/202602030131.VCTzZ4me-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602030131.VCTzZ4me-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_queue_trbs':
>> drivers/usb/gadget/udc/crg_udc.c:881:13: warning: variable 'num_sgs' set but not used [-Wunused-but-set-variable]
     881 |         u32 num_sgs = 0;
         |             ^~~~~~~
   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_ep_enable':
>> drivers/usb/gadget/udc/crg_udc.c:1812:26: warning: variable 'uccr' set but not used [-Wunused-but-set-variable]
    1812 |         struct crg_uccr *uccr;
         |                          ^~~~
>> drivers/usb/gadget/udc/crg_udc.c:1811:25: warning: variable 'epcx' set but not used [-Wunused-but-set-variable]
    1811 |         struct ep_cx_s *epcx;
         |                         ^~~~
   drivers/usb/gadget/udc/crg_udc.c: In function 'crg_udc_common_irq':
>> drivers/usb/gadget/udc/crg_udc.c:4250:13: warning: variable 'retval' set but not used [-Wunused-but-set-variable]
    4250 |         int retval = 0;
         |             ^~~~~~
   drivers/usb/gadget/udc/crg_udc.c: At top level:
>> drivers/usb/gadget/udc/crg_udc.c:126:19: warning: 'driver_name' defined but not used [-Wunused-const-variable=]
     126 | static const char driver_name[] = "crg_udc";
         |                   ^~~~~~~~~~~
--
>> Warning: drivers/usb/gadget/udc/crg_udc.c:4325 cannot understand function prototype: 'const struct of_device_id of_crg_udc_match[] ='


vim +/num_sgs +881 drivers/usb/gadget/udc/crg_udc.c

   858	
   859	static int crg_udc_queue_trbs(struct crg_udc_ep *udc_ep_ptr,
   860			struct crg_udc_request *udc_req_ptr,  bool b_isoc,
   861			u32 xfer_ring_size,
   862			u32 num_trbs_needed, u64 buffer_length)
   863	{
   864		struct crg_gadget_dev *crg_udc = udc_ep_ptr->crg_udc;
   865		struct transfer_trb_s *p_xfer_ring = udc_ep_ptr->first_trb;
   866		u32 num_trbs_ava = 0;
   867		struct usb_request *usb_req = &udc_req_ptr->usb_req;
   868		u64 buff_len_temp = 0;
   869		u32 i, j = 1;
   870		struct transfer_trb_s *enq_pt = udc_ep_ptr->enq_pt;
   871		u8 td_size;
   872		u8 chain_bit = 1;
   873		u8 short_pkt = 0;
   874		u8 intr_on_compl = 0;
   875		u32 count;
   876		bool full_td = true;
   877		u32 intr_rate;
   878		dma_addr_t trb_buf_addr;
   879		bool need_zlp = false;
   880		struct scatterlist *sg = NULL;
 > 881		u32 num_sgs = 0;
   882		u64 sg_addr = 0;
   883	
   884		dev_dbg(crg_udc->dev, "%s %s\n", __func__, udc_ep_ptr->usb_ep.name);
   885		if (udc_req_ptr->usb_req.num_sgs) {
   886			num_sgs = udc_req_ptr->usb_req.num_sgs;
   887			sg = udc_req_ptr->usb_req.sg;
   888			sg_addr = (u64) sg_dma_address(sg);
   889			buffer_length = sg_dma_len(sg);
   890	
   891			dev_dbg(crg_udc->dev, "num_sgs = %d, num_mapped_sgs = %d\n",
   892				udc_req_ptr->usb_req.num_sgs,
   893				udc_req_ptr->usb_req.num_mapped_sgs);
   894			dev_dbg(crg_udc->dev,
   895				"sg_addr = %p, buffer_length = %llu, num_trbs = %d\n",
   896				(void *)sg_addr, buffer_length, num_trbs_needed);
   897		}
   898	
   899		if (!b_isoc) {
   900			if (udc_req_ptr->usb_req.zero == 1 &&
   901				udc_req_ptr->usb_req.length != 0 &&
   902				((udc_req_ptr->usb_req.length %
   903				  udc_ep_ptr->usb_ep.maxpacket) == 0)) {
   904				need_zlp = true;
   905			}
   906		}
   907	
   908		td_size = num_trbs_needed;
   909	
   910		num_trbs_ava = room_on_ring(crg_udc, xfer_ring_size,
   911			p_xfer_ring, udc_ep_ptr->enq_pt, udc_ep_ptr->deq_pt);
   912	
   913		/* trb_buf_addr points to the addr of the buffer that we write in
   914		 * each TRB. If this function is called to complete the pending TRB
   915		 * transfers of a previous request, point it to the buffer that is
   916		 * not transferred, or else point it to the starting address of the
   917		 * buffer received in usb_request
   918		 */
   919		if (udc_req_ptr->trbs_needed) {
   920			/* Here udc_req_ptr->trbs_needed is used to indicate if we
   921			 * are completing a previous req
   922			 */
   923			trb_buf_addr = usb_req->dma +
   924				(usb_req->length - udc_req_ptr->buff_len_left);
   925		} else {
   926			if (sg_addr)
   927				trb_buf_addr = sg_addr;
   928			else
   929				trb_buf_addr = usb_req->dma;
   930		}
   931	
   932		if (num_trbs_ava >= num_trbs_needed) {
   933			count = num_trbs_needed;
   934		} else {
   935			if (b_isoc) {
   936				struct crg_udc_request *udc_req_ptr_temp;
   937				u8 temp = 0;
   938	
   939				list_for_each_entry(udc_req_ptr_temp,
   940						&udc_ep_ptr->queue, queue) {
   941					temp++;
   942				}
   943	
   944				if (temp >= 2) {
   945					dev_err(crg_udc->dev, "%s don't do isoc discard\n", __func__);
   946					/*  we already scheduled two mfi in advance. */
   947					return 0;
   948				}
   949			}
   950	
   951			/* always keep one trb for zlp. */
   952			count = num_trbs_ava;
   953			full_td = false;
   954			dev_dbg(crg_udc->dev, "TRB Ring Full. Avail: 0x%x Req: 0x%x\n",
   955					num_trbs_ava, num_trbs_needed);
   956			udc_ep_ptr->tran_ring_full = true;
   957	
   958			/*if there is still some trb not queued,
   959			 *it means last queued
   960			 *trb is not the last trb of TD, so no need zlp
   961			 */
   962			need_zlp = false;
   963		}
   964	
   965		for (i = 0; i < count; i++) {
   966			if ((udc_req_ptr->usb_req.num_sgs) && (buffer_length == 0)) {
   967				sg = sg_next(sg);
   968				if (sg) {
   969					trb_buf_addr = (u64) sg_dma_address(sg);
   970					buffer_length = sg_dma_len(sg);
   971					dev_dbg(crg_udc->dev,
   972						"trb_buf_addr = %p, num_trbs = %d\n",
   973						(void *)trb_buf_addr, num_trbs_needed);
   974					dev_dbg(crg_udc->dev, "buffer_length = %llu\n",
   975						buffer_length);
   976				} else {
   977					dev_err(crg_udc->dev,
   978						"scatterlist ended unexpectedly (i=%d, count=%d)\n",
   979						i, count);
   980					return -EINVAL;
   981				}
   982			}
   983	
   984			if (buffer_length > TRB_MAX_BUFFER_SIZE)
   985				buff_len_temp = TRB_MAX_BUFFER_SIZE;
   986			else
   987				buff_len_temp = buffer_length;
   988	
   989			buffer_length -= buff_len_temp;
   990	
   991			if (usb_endpoint_dir_out(udc_ep_ptr->desc))
   992				short_pkt = 1;
   993	
   994			if ((buffer_length == 0) && (i == (count - 1))) {
   995				chain_bit = 0;
   996				intr_on_compl = 1;
   997				udc_req_ptr->all_trbs_queued = 1;
   998			}
   999	
  1000	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki