/* * NVT680 UDC Driver supports Bulk transfer so far * * Copyright (C) 2017 Novatek Technology Corporation * * Author : Klins Chen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "nvt520.h" #define DRIVER_DESC "NOVATEK iVot USB Device NVT520 Controller Driver" #define DRIVER_VERSION "19-May-2020" static const char udc_name[] = "nvt,nvt520_udc"; //static const char * const nvt680_ep_name[] = { // "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8"}; static const struct { const char *name; const struct usb_ep_caps caps; } ep_info[] = { #define EP_INFO(_name, _caps) \ { \ .name = _name, \ .caps = _caps, \ } EP_INFO("ep0", USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), EP_INFO("ep1", USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), EP_INFO("ep2", USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), EP_INFO("ep3", USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_ALL)), EP_INFO("ep4", USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), EP_INFO("ep5", USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), #undef EP_INFO }; #define NVTUSB_DEBUG 0 #if NVTUSB_DEBUG #define numsg printk #define itfnumsg printk #define devnumsg printk #define ep0numsg printk #define intrmsg printk #else #define numsg pr_debug #define itfnumsg pr_debug #define devnumsg pr_debug #define ep0numsg pr_debug #define intrmsg pr_debug #endif #if 1 #define USB_GETREG(x) ioread32(nvt680->reg + (x)) #define USB_SETREG(x, y) iowrite32((y), nvt680->reg + (x)); static int nvt680_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags); void usbnvt_set_ep0_done(struct nvt680_udc *nvt680); BOOL usbnvt_ep_stall_status(struct nvt680_udc *nvt680, UINT32 EPn); void usbnvt_set_ep_stall(struct nvt680_udc *nvt680, UINT32 ep_number); void usbnvt_clr_ep_stall(struct nvt680_udc *nvt680, UINT32 EPn); void usbnvt_mask_ep_interrupt(struct nvt680_udc *nvt680, UINT32 EPn); void usbnvt_unmask_ep_interrupt(struct nvt680_udc *nvt680, UINT32 EPn); void nvt680_stop_ep_transfer(struct nvt680_ep *ep); void nvt680_enable_ep_transfer(struct nvt680_ep *ep); void usbnvt_set_ep_write(struct nvt680_udc *nvt680, UINT32 EPn, dma_addr_t d_adr, UINT32 length); void usbnvt_set_ep_read(struct nvt680_udc *nvt680, UINT32 EPn, dma_addr_t d_adr, UINT32 length); #if 1 static void nvt680_done(struct nvt680_ep *ep, struct nvt680_request *req, int status) { unsigned long flags; if(ep->epnum) { itfnumsg("nvt680_done %d\n", ep->epnum); } else { ep0numsg("nvt680_done %d\n", ep->epnum); } spin_lock_irqsave(&ep->nvt680->lock, flags); list_del_init(&req->queue); spin_unlock_irqrestore(&ep->nvt680->lock, flags); /* don't modify queue heads during completion callback */ if (ep->nvt680->gadget.speed == USB_SPEED_UNKNOWN) { req->req.status = -ESHUTDOWN; } else { req->req.status = status; } if(req->req.complete != NULL) { req->req.complete(&ep->ep, &req->req); } if ((ep->epnum)&&(status == 0)) { if (list_empty(&ep->queue)) { nvt680_stop_ep_transfer(ep); } else { if (ep->type != USB_ENDPOINT_XFER_ISOC) { nvt680_enable_ep_transfer(ep); } else { dma_addr_t d_adr; UINT32 d_len, epnum = ep->epnum; struct nvt680_udc *nvt680; nvt680 = ep->nvt680; if(ep->dir_in) { ep = nvt680->ep[epnum]; req = list_entry(ep->queue.next, struct nvt680_request, queue); if ((req->req.length == 0) && (req->req.actual == 0)) { T_USB_DEVMAXPS_EP_REG DevEPMaxPS; spin_lock_irqsave(&nvt680->lock, flags); DevEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)); DevEPMaxPS.bit.TX0BYTE_IEP = 1; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)), DevEPMaxPS.reg); spin_unlock_irqrestore(&nvt680->lock, flags); do { DevEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)); if(!DevEPMaxPS.bit.TX0BYTE_IEP) { break; } msleep(1); }while(DevEPMaxPS.bit.TX0BYTE_IEP); nvt680_done(ep, req, 0); } else { d_len = req->req.length; d_adr = dma_map_single(NULL, (u8 *)(req->req.buf), d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_mapping_error(NULL, d_adr)) { pr_err("dma_mapping_error\n"); } dma_sync_single_for_device(NULL, d_adr, d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->req.actual = d_len; ep->d_adr = d_adr; ep->d_len = d_len; usbnvt_set_ep_write(nvt680, epnum, d_adr, d_len); nvt680_stop_ep_transfer(ep); } } else { dma_addr_t d_adr; UINT32 d_len, epnum = ep->epnum; T_USB_DEVFIFOBYTECNT0_REG reg_devfifo_bc; ep = nvt680->ep[epnum]; req = list_entry(ep->queue.next, struct nvt680_request, queue); //reg_devfifo_bc.reg = USB_GETREG(USB_DEVFIFOBYTECNT0_REG_OFS+((epnum-1)<<2)); //d_len = reg_devfifo_bc.bit.BC_F0; reg_devfifo_bc.reg = USB_GETREG(USB_DEVFIFOBYTECNT0_REG_OFS+((nvt680->ep_2_fifo[epnum]>>1)<<2)); d_len = (reg_devfifo_bc.reg >> ((nvt680->ep_2_fifo[epnum]&0x1)<<4)) & 0x7FF; if(!(d_len & 511)) { d_len = req->req.length; } d_adr = dma_map_single(NULL, (u8 *)(req->req.buf), d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_mapping_error(NULL, d_adr)) { pr_err("dma_mapping_error\n"); } dma_sync_single_for_device(NULL, d_adr, d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->req.actual = d_len; ep->d_adr = d_adr; ep->d_len = d_len; usbnvt_set_ep_read(nvt680, epnum, d_adr, d_len); nvt680_stop_ep_transfer(ep); } } } } } static int nvt680_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) { struct nvt680_ep *ep; struct nvt680_udc *nvt680; unsigned long flags; int ret = 0; ep = container_of(_ep, struct nvt680_ep, ep); nvt680 = ep->nvt680; if (value) { usbnvt_set_ep_stall(nvt680, ep->epnum); ep->stall = 1; if (wedge) ep->wedged = 1; } else { T_USB_DEVMAXPS_EP_REG devEPMaxPS; spin_lock_irqsave(&ep->nvt680->lock, flags); devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((ep->epnum - 1) << 2)); devEPMaxPS.bit.RSTG_EP = 1; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((ep->epnum - 1) << 2)), devEPMaxPS.reg); devEPMaxPS.bit.RSTG_EP = 0; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((ep->epnum - 1) << 2)), devEPMaxPS.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); usbnvt_clr_ep_stall(nvt680, ep->epnum); ep->stall = 0; ep->wedged = 0; if (!list_empty(&ep->queue)) { if (list_empty(&ep->queue)) { nvt680_stop_ep_transfer(ep); } else { nvt680_enable_ep_transfer(ep); } } } return ret; } static void nvt680_start_ep0_data(struct nvt680_ep *ep, struct nvt680_request *req) { u32 *buffer; u32 value,length,i=0; s32 opsize; T_USB_DEVINTMASKGROUP0_REG reg_mask_g0; T_USB_DEVCXCFGFIFOSTATUS_REG reg_cxcfg; unsigned long flags; struct nvt680_udc *nvt680 = ep->nvt680; buffer = (u32 *)(req->req.buf + req->req.actual); if (req->req.length - req->req.actual > 64) { length = 64; if (ep->dir_in) { spin_lock_irqsave(&ep->nvt680->lock, flags); reg_mask_g0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); reg_mask_g0.bit.MCX_IN_INT = 0; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, reg_mask_g0.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); } } else { length = req->req.length - req->req.actual; if (ep->dir_in) { spin_lock_irqsave(&ep->nvt680->lock, flags); reg_mask_g0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); reg_mask_g0.bit.MCX_IN_INT = 1; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, reg_mask_g0.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); } } reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); if(reg_cxcfg.bit.CX_DATAPORT_EN) pr_err("DATAPORT EN ERROR!!!\n"); if (ep->dir_in) { ep0numsg("fotg200_start_ep0_data IN 0x%X act=0x%X len=%d\n",req->req.length,req->req.actual,length); spin_lock_irqsave(&ep->nvt680->lock, flags); reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); reg_cxcfg.bit.CX_FNT_IN = length; reg_cxcfg.bit.CX_DATAPORT_EN = 1; USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, reg_cxcfg.reg); opsize = length; while(opsize>0) { USB_SETREG(USB_DEVCXDATAPORT_REG_OFS, buffer[i++]); opsize-=4; } reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); reg_cxcfg.bit.CX_DATAPORT_EN = 0; USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, reg_cxcfg.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); } else { ep0numsg("fotg200_start_ep0_data OUT 0x%X act=0x%X\n",req->req.length,req->req.actual); reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); opsize = reg_cxcfg.bit.CX_FNT_OUT; while(!opsize) { msleep(1); reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); opsize = reg_cxcfg.bit.CX_FNT_OUT; } spin_lock_irqsave(&ep->nvt680->lock, flags); reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); reg_cxcfg.bit.CX_DATAPORT_EN = 1; USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, reg_cxcfg.reg); while(opsize>0) { value = USB_GETREG(USB_DEVCXDATAPORT_REG_OFS); if(opsize>=4) { buffer[i++] = value; } else if (opsize==3) { buffer[i] &= ~0xFFFFFF; value &= 0xFFFFFF; buffer[i] += value; } else if (opsize==2) { buffer[i] &= ~0xFFFF; value &= 0xFFFF; buffer[i] += value; } else if (opsize==1) { buffer[i] &= ~0xFF; value &= 0xFF; buffer[i] += value; } opsize-=4; } reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); reg_cxcfg.bit.CX_DATAPORT_EN = 0; USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, reg_cxcfg.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); } /* update actual transfer length */ req->req.actual += length; } static void nvt680_ep0_queue(struct nvt680_ep *ep, struct nvt680_request *req) { unsigned long flags; struct nvt680_udc *nvt680 = ep->nvt680; ep0numsg("nvt680_ep0_queue <%d>\n", req->req.length); if (!req->req.length) { usbnvt_set_ep0_done(nvt680); nvt680_done(ep, req, 0); return; } if (ep->dir_in) { /* if IN */ if (req->req.length) { nvt680_start_ep0_data(ep, req); } else { pr_err("%s : req->req.length = 0x%x\n", __func__, req->req.length); } if ((req->req.length == req->req.actual) || (req->req.actual < ep->ep.maxpacket)) { nvt680_done(ep, req, 0); usbnvt_set_ep0_done(nvt680); } } else { /* OUT */ T_USB_DEVINTMASKGROUP0_REG reg_mask_g0; spin_lock_irqsave(&ep->nvt680->lock, flags); reg_mask_g0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); reg_mask_g0.bit.MCX_OUT_INT = 0; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, reg_mask_g0.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); } } static void nvt680_get_status(struct nvt680_udc *nvt680, struct usb_ctrlrequest *ctrl) { u8 epnum; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: nvt680->ep0_data = 1 << USB_DEVICE_SELF_POWERED; break; case USB_RECIP_INTERFACE: nvt680->ep0_data = 0; break; case USB_RECIP_ENDPOINT: epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; if (epnum) nvt680->ep0_data = usbnvt_ep_stall_status(nvt680, epnum)<< USB_ENDPOINT_HALT; else usbnvt_set_ep_stall(nvt680, 0); break; default: usbnvt_set_ep_stall(nvt680, 0); return; /* exit */ } nvt680->ep0_req->buf = &nvt680->ep0_data; nvt680->ep0_req->length = 2; nvt680_ep_queue(nvt680->gadget.ep0, nvt680->ep0_req, GFP_KERNEL); } static void nvt680_clear_feature(struct nvt680_udc *nvt680, struct usb_ctrlrequest *ctrl) { struct nvt680_ep *ep = nvt680->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: usbnvt_set_ep0_done(nvt680); break; case USB_RECIP_INTERFACE: usbnvt_set_ep0_done(nvt680); break; case USB_RECIP_ENDPOINT: if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { if (ep->wedged) { usbnvt_set_ep0_done(nvt680); break; } usbnvt_clr_ep_stall(nvt680, ep->epnum); if (ep->stall) { printk("nvt680_clear_feature nvt680_set_halt_and_wedge\r\n"); nvt680_set_halt_and_wedge(&ep->ep, 0, 0); } } usbnvt_set_ep0_done(nvt680); break; default: usbnvt_set_ep_stall(nvt680, 0); break; } } static void nvt680_set_feature(struct nvt680_udc *nvt680, struct usb_ctrlrequest *ctrl) { switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: usbnvt_set_ep0_done(nvt680); break; case USB_RECIP_INTERFACE: usbnvt_set_ep0_done(nvt680); break; case USB_RECIP_ENDPOINT: { u8 epnum; epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; usbnvt_set_ep_stall(nvt680, epnum); usbnvt_set_ep0_done(nvt680); } break; default: usbnvt_set_ep_stall(nvt680, 0); break; } } static void nvt680_set_fifo_cfg(struct nvt680_ep *ep, u32 epnum, u32 dir_in,u32 type, u32 mps) { struct nvt680_udc *nvt680 = ep->nvt680; T_USB_DEVBUFCFG0_REG reg_devbufcfg0; T_USB_DEVMAXPS_EP_REG DevEPMaxPS; unsigned long flags; spin_lock_irqsave(&nvt680->lock, flags); DevEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)); DevEPMaxPS.bit.MAXPS_EP = mps; if (ep->type == USB_ENDPOINT_XFER_ISOC) { if ((ep->ep.maxpacket == 0x400)&&(ep->ep.mult == 1)) DevEPMaxPS.bit.TX_NUM_HBW_EP = 2; else DevEPMaxPS.bit.TX_NUM_HBW_EP = 1; } else { DevEPMaxPS.bit.TX_NUM_HBW_EP = 0; } if (dir_in > 0) { DevEPMaxPS.bit.DIR_EP = 0; DevEPMaxPS.bit.FNO_IEP = nvt680->ep_2_fifo[epnum]; } else { DevEPMaxPS.bit.DIR_EP = 1; DevEPMaxPS.bit.FNO_OEP = nvt680->ep_2_fifo[epnum]; } USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)), DevEPMaxPS.reg); { u8 startfifo,regofs; startfifo = nvt680->ep_2_fifo[epnum]; if(startfifo < 4) { regofs = 0; } else { regofs = 4; startfifo -= 4; } reg_devbufcfg0.reg = USB_GETREG(USB_DEVBUFCFG0_REG_OFS+regofs); if(mps <= 512) { reg_devbufcfg0.reg &= ~(0xFF << (startfifo<<3)); reg_devbufcfg0.reg |= (type << (startfifo<<3));//buf_type reg_devbufcfg0.reg |= (0x0 << (startfifo<<3));//buf_blkno reg_devbufcfg0.reg |= (0 << (startfifo<<3));//buf_blksz if(dir_in > 0) reg_devbufcfg0.reg |= (0x20<< (startfifo<<3));//dir_fifo reg_devbufcfg0.reg |= (0x80 << (startfifo<<3));//buf_en } else if ((ep->ep.maxpacket == 0x400)&&(ep->ep.mult == 1)&&(ep->type == USB_ENDPOINT_XFER_ISOC)&&(regofs==4)) { reg_devbufcfg0.reg = 0x353535B5; } else { reg_devbufcfg0.reg &= ~(0xFFFF << (startfifo<<3)); reg_devbufcfg0.reg |= (type << (startfifo<<3));//buf_type reg_devbufcfg0.reg |= (0 << (startfifo<<3));//buf_blkno reg_devbufcfg0.reg |= (0x10 << (startfifo<<3));//buf_blksz if(dir_in > 0) reg_devbufcfg0.reg |= (0x20<< (startfifo<<3));//dir_fifo reg_devbufcfg0.reg |= (0x80 << (startfifo<<3));//buf_en reg_devbufcfg0.reg |= (type << ((startfifo<<3)+8));//buf_type reg_devbufcfg0.reg |= (0 << ((startfifo<<3)+8));//buf_blkno reg_devbufcfg0.reg |= (0x10 << ((startfifo<<3)+8));//buf_blksz if(dir_in > 0) reg_devbufcfg0.reg |= (0x20<< ((startfifo<<3)+8));//dir_fifo } USB_SETREG(USB_DEVBUFCFG0_REG_OFS+regofs, reg_devbufcfg0.reg); } spin_unlock_irqrestore(&nvt680->lock, flags); } static int nvt680_config_ep(struct nvt680_ep *ep, const struct usb_endpoint_descriptor *desc) { struct nvt680_udc *nvt680 = ep->nvt680; if ((ep->ep.mult == 1) && (ep->type == USB_ENDPOINT_XFER_ISOC) && (ep->ep.maxpacket == 0x400)) { if ((nvt680->fifo_vld_msk & 0x0F) == 0x0F) { nvt680->ep_2_fifo[ep->epnum] = 0; nvt680->fifo_2_ep[nvt680->ep_2_fifo[ep->epnum]] = ep->epnum; nvt680->fifo_vld_msk &= 0xF0; } else { pr_err("FIFO 4-7 for isoc-in 2048 not available\n"); return -ENOPKG; } #if 1 } else if (ep->type == USB_ENDPOINT_XFER_ISOC) { u8 i,chkmsk; if (ep->ep.mult) { pr_err("mult is supported!\n"); } if (ep->ep.maxpacket > 512) chkmsk = 0x3; else chkmsk = 0x1; for (i=4; i < 8; i+=2) { if (((nvt680->fifo_vld_msk>>i) & chkmsk) == chkmsk) { nvt680->ep_2_fifo[ep->epnum] = i; nvt680->fifo_2_ep[nvt680->ep_2_fifo[ep->epnum]] = ep->epnum; nvt680->fifo_vld_msk = nvt680->fifo_vld_msk & ~(chkmsk << i); break; } if (i==6) { pr_err("FIFO search not available\n"); return -ENOPKG; } } #endif } else { u8 i,chkmsk; if (ep->ep.mult) { pr_err("mult is supported!\n"); } if (ep->ep.maxpacket > 512) chkmsk = 0x3; else chkmsk = 0x1; for (i=4; i < 8; i++) { if (((nvt680->fifo_vld_msk>>i) & chkmsk) == chkmsk) { nvt680->ep_2_fifo[ep->epnum] = i; nvt680->fifo_2_ep[nvt680->ep_2_fifo[ep->epnum]] = ep->epnum; nvt680->fifo_vld_msk = nvt680->fifo_vld_msk & ~(chkmsk << i); break; } //if (i==7) { // pr_err("FIFO search not available\n"); // return -ENOPKG; //} } if (i==8) { for (i=0; i < 4; i++) { if (((nvt680->fifo_vld_msk>>i) & chkmsk) == chkmsk) { nvt680->ep_2_fifo[ep->epnum] = i; nvt680->fifo_2_ep[nvt680->ep_2_fifo[ep->epnum]] = ep->epnum; nvt680->fifo_vld_msk = nvt680->fifo_vld_msk & ~(chkmsk << i); break; } if (i==3) { pr_err("FIFO search not available\n"); return -ENOPKG; } } } } nvt680_set_fifo_cfg(ep, ep->epnum, ep->dir_in, ep->type, ep->ep.maxpacket); nvt680->ep_en &= ~(0x1<epnum); nvt680->ep[ep->epnum] = ep; return 0; } void nvt680_enable_ep_transfer(struct nvt680_ep *ep) { struct nvt680_udc *nvt680 = ep->nvt680; devnumsg("nvt680_enable_ep_transfer %d\n", ep->epnum); usbnvt_unmask_ep_interrupt(nvt680, ep->epnum); } void nvt680_stop_ep_transfer(struct nvt680_ep *ep) { struct nvt680_udc *nvt680 = ep->nvt680; devnumsg("nvt680_stop_ep_transfer %d\n", ep->epnum); usbnvt_mask_ep_interrupt(nvt680, ep->epnum); } static int nvt680_ep_release(struct nvt680_ep *ep) { struct nvt680_udc *nvt680 = ep->nvt680; T_USB_DEVMAXPS_EP_REG devEPMaxPS; unsigned long flags; if (!ep->epnum) return 0; spin_lock_irqsave(&ep->nvt680->lock, flags); devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((ep->epnum - 1) << 2)); devEPMaxPS.bit.RSTG_EP = 1; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((ep->epnum - 1) << 2)), devEPMaxPS.reg); devEPMaxPS.bit.RSTG_EP = 0; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((ep->epnum - 1) << 2)), devEPMaxPS.reg); spin_unlock_irqrestore(&ep->nvt680->lock, flags); //ep->epnum = 0; ep->stall = 0; ep->wedged = 0; #if 1 if ((ep->ep.mult == 1) && (ep->type == USB_ENDPOINT_XFER_ISOC) && (ep->ep.maxpacket == 0x400)) { if ((nvt680->fifo_vld_msk & 0xF0) == 0) { //nvt680->ep_2_fifo[ep->epnum] = 0xF; //nvt680->fifo_2_ep[nvt680->ep_2_fifo[ep->epnum]] = ep->epnum; nvt680->fifo_vld_msk |= 0xF; } else { pr_err("FIFO 0-3 for isoc-in 2048 unmap error\n"); } } else { u8 chkmsk; if (ep->ep.mult) { pr_err("mult is supported!\n"); } if (ep->ep.maxpacket > 512) chkmsk = 0x3; else chkmsk = 0x1; if (((nvt680->fifo_vld_msk >> nvt680->ep_2_fifo[ep->epnum]) & chkmsk) == 0) { //nvt680->ep_2_fifo[ep->epnum] = 0xF; //nvt680->fifo_2_ep[nvt680->ep_2_fifo[ep->epnum]] = ep->epnum; nvt680->fifo_vld_msk = nvt680->fifo_vld_msk | (chkmsk << nvt680->ep_2_fifo[ep->epnum]); } else { pr_err("FIFO unmap error\n"); } } nvt680->ep_en |= (0x1<epnum); #endif return 0; } #endif void usbnvt_set_ep_read(struct nvt680_udc *nvt680, UINT32 EPn, dma_addr_t d_adr, UINT32 length) { #if 1 UINT32 fifonum; UINT32 uiRegOfs; unsigned long flags; fifonum = nvt680->ep_2_fifo[EPn]; if(fifonum >= 4) { T_USB_DEVDMA2CTRL0_REG devDMAxCtl; T_USB_DEVDMA2CTRL1_REG devDMAxCtl2; uiRegOfs = (fifonum-4) << 3; itfnumsg("usbnvt_set_ep_read: EP%d Addr=0x%08X Size=0x%08X\n", EPn, d_adr, length); devDMAxCtl.reg = USB_GETREG(USB_DEVDMA2CTRL0_REG_OFS + uiRegOfs); if (devDMAxCtl.bit.DMA_START == 1) { printk("EP%d: DMA-%d not available\r\n", EPn, fifonum); return; } spin_lock_irqsave(&nvt680->lock, flags); devDMAxCtl.bit.DMA_TYPE = 0;// FIFO to memory devDMAxCtl.bit.DMA_LEN = length; USB_SETREG(USB_DEVDMA2CTRL0_REG_OFS + uiRegOfs, devDMAxCtl.reg); // set Dma Addr devDMAxCtl2.reg = d_adr; USB_SETREG(USB_DEVDMA2CTRL1_REG_OFS + uiRegOfs, devDMAxCtl2.reg); // start Dma devDMAxCtl.bit.DMA_START = 1; USB_SETREG(USB_DEVDMA2CTRL0_REG_OFS + uiRegOfs, devDMAxCtl.reg); spin_unlock_irqrestore(&nvt680->lock, flags); }else { T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL2_REG devDMACtl2; T_USB_DEVACCFIFO_REG devAccFifo; do { devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); if(devDMACtl1.bit.DMA_START) { cpu_relax(); udelay(100); } }while(devDMACtl1.bit.DMA_START); // Config DMA direction & length devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DMA_TYPE = 0; // FIFO to memory devDMACtl1.bit.DMA_LEN = length; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); devAccFifo.reg = 0; devAccFifo.bit.ACC_F0_3 = fifonum; USB_SETREG(USB_DEVACCFIFO_REG_OFS, devAccFifo.reg); // set Dma Addr devDMACtl2.reg = d_adr; USB_SETREG(USB_DEVDMACTRL2_REG_OFS, devDMACtl2.reg); // start Dma devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DMA_START = 1; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); } #else printk("usbnvt_set_ep_read: EP%d Addr=0x%08X Size=0x%08X\n", EPn, d_adr, length); #endif } void usbnvt_set_ep_write(struct nvt680_udc *nvt680, UINT32 EPn, dma_addr_t d_adr, UINT32 length) { #if 1 UINT32 fifonum; UINT32 uiRegOfs; unsigned long flags; fifonum = nvt680->ep_2_fifo[EPn]; if(fifonum >= 4) { T_USB_DEVDMA2CTRL0_REG devDMAxCtl; T_USB_DEVDMA2CTRL1_REG devDMAxCtl2; uiRegOfs = (fifonum-4) << 3; itfnumsg("usbnvt_set_ep_write: EP%d Addr=0x%08X Size=0x%08X\n", EPn, d_adr, length); //do { // devDMAxCtl.reg = USB_GETREG(USB_DEVDMA2CTRL0_REG_OFS + uiRegOfs); //} while(devDMAxCtl.bit.DMA_START == 1); if (devDMAxCtl.bit.DMA_START == 1) { printk("EP%d: DMA-%d not available\r\n", EPn, fifonum); return; } spin_lock_irqsave(&nvt680->lock, flags); devDMAxCtl.bit.DMA_TYPE = 1;// memory to FIFO devDMAxCtl.bit.DMA_LEN = length; USB_SETREG(USB_DEVDMA2CTRL0_REG_OFS + uiRegOfs, devDMAxCtl.reg); // set Dma Addr devDMAxCtl2.reg = d_adr; USB_SETREG(USB_DEVDMA2CTRL1_REG_OFS + uiRegOfs, devDMAxCtl2.reg); // start Dma devDMAxCtl.bit.DMA_START = 1; USB_SETREG(USB_DEVDMA2CTRL0_REG_OFS + uiRegOfs, devDMAxCtl.reg); spin_unlock_irqrestore(&nvt680->lock, flags); }else { T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL2_REG devDMACtl2; T_USB_DEVACCFIFO_REG devAccFifo; do { devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); if(devDMACtl1.bit.DMA_START) { cpu_relax(); udelay(100); } }while(devDMACtl1.bit.DMA_START); // Config DMA direction & length devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DMA_TYPE = 1; // memory to FIFO devDMACtl1.bit.DMA_LEN = length; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); devAccFifo.reg = 0; devAccFifo.bit.ACC_F0_3 = fifonum; USB_SETREG(USB_DEVACCFIFO_REG_OFS, devAccFifo.reg); // set Dma Addr devDMACtl2.reg = d_adr; USB_SETREG(USB_DEVDMACTRL2_REG_OFS, devDMACtl2.reg); // start Dma devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DMA_START = 1; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); } #else printk("usbnvt_set_ep_write: EP%d Addr=0x%08X Size=0x%08X\n", EPn, d_adr, length); #endif return; } BOOL usbnvt_get_ep_direction_in(struct nvt680_udc *nvt680, UINT32 EPn) { T_USB_DEVMAXPS_EP_REG devEPMaxPS; devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)); return !devEPMaxPS.bit.DIR_EP; } void usbnvt_mask_ep_interrupt(struct nvt680_udc *nvt680, UINT32 EPn) { T_USB_DEVINTMASKGROUP0_REG devIntMskGrp0; T_USB_DEVINTMASKGROUP1_REG intGroup1Mask; unsigned long flags; if (EPn == 0) { devIntMskGrp0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); devIntMskGrp0.bit.MCX_IN_INT = 1; devIntMskGrp0.bit.MCX_OUT_INT = 1; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, devIntMskGrp0.reg); return; } if(nvt680->ep_2_fifo[EPn] == 0xF) { printk("usbnvt_unmask_ep_interrupt ERROR!!!!!!!!!!!!!!!!!!!!!!\r\n"); } devnumsg("usbnvt_mask_ep_interrupt %d\n", EPn); spin_lock_irqsave(&nvt680->lock, flags); if (usbnvt_get_ep_direction_in(nvt680, EPn)) { intGroup1Mask.reg = USB_GETREG(USB_DEVINTMASKGROUP1_REG_OFS); intGroup1Mask.reg |= (0x1 << (16 + nvt680->ep_2_fifo[EPn])); USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, intGroup1Mask.reg); } else { intGroup1Mask.reg = USB_GETREG(USB_DEVINTMASKGROUP1_REG_OFS); intGroup1Mask.reg |= (0x3 << ( nvt680->ep_2_fifo[EPn] << 1)); USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, intGroup1Mask.reg); } spin_unlock_irqrestore(&nvt680->lock, flags); } void usbnvt_unmask_ep_interrupt(struct nvt680_udc *nvt680, UINT32 EPn) { T_USB_DEVINTMASKGROUP0_REG devIntMskGrp0; T_USB_DEVINTMASKGROUP1_REG intGroup1Mask; unsigned long flags; if (EPn == 0) { devIntMskGrp0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); devIntMskGrp0.bit.MCX_IN_INT = 0; devIntMskGrp0.bit.MCX_OUT_INT = 0; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, devIntMskGrp0.reg); return; } if(nvt680->ep_2_fifo[EPn] == 0xF) { printk("usbnvt_unmask_ep_interrupt ERROR!!!!!!!!!!!!!!!!!!!!!!\r\n"); } devnumsg("usbnvt_unmask_ep_interrupt %d\n", EPn); spin_lock_irqsave(&nvt680->lock, flags); if (usbnvt_get_ep_direction_in(nvt680, EPn)) { intGroup1Mask.reg = USB_GETREG(USB_DEVINTMASKGROUP1_REG_OFS); intGroup1Mask.reg &= ~(0x1 << (16 + nvt680->ep_2_fifo[EPn])); USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, intGroup1Mask.reg); } else { intGroup1Mask.reg = USB_GETREG(USB_DEVINTMASKGROUP1_REG_OFS); intGroup1Mask.reg &= ~(0x3 << ( nvt680->ep_2_fifo[EPn] << 1)); USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, intGroup1Mask.reg); } spin_unlock_irqrestore(&nvt680->lock, flags); } BOOL usbnvt_ep_stall_status(struct nvt680_udc *nvt680, UINT32 EPn) { T_USB_DEVMAXPS_EP_REG devEPMaxPS; devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)); return devEPMaxPS.bit.STL_EP; } BOOL usbnvt_is_highspeed_enabled(struct nvt680_udc *nvt680) { T_USB_DEVMAINCTRL_REG devMainCtl; devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); return (BOOL)(devMainCtl.bit.HS_EN); } void usbnvt_set_ep0_done(struct nvt680_udc *nvt680) { T_USB_DEVCXCFGFIFOSTATUS_REG reg_cxcfg; unsigned long flags; ep0numsg("usbnvt_set_ep0_done\n"); spin_lock_irqsave(&nvt680->lock, flags); reg_cxcfg.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); reg_cxcfg.bit.CX_DONE = 1; USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, reg_cxcfg.reg); spin_unlock_irqrestore(&nvt680->lock, flags); } void usbnvt_set_ep_stall(struct nvt680_udc *nvt680, UINT32 ep_number) { T_USB_DEVMAXPS_EP_REG devEPMaxPS; T_USB_DEVCXCFGFIFOSTATUS_REG devCXCFG; unsigned long flags; //printk("usbnvt_set_ep_stall %d\r\n", ep_number); spin_lock_irqsave(&nvt680->lock, flags); if (ep_number == 0) { devCXCFG.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); devCXCFG.bit.CX_STL = 1; USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, devCXCFG.reg); } else if (ep_number <= 15) { devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((ep_number - 1) << 2)); devEPMaxPS.bit.STL_EP = 1; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((ep_number - 1) << 2)), devEPMaxPS.reg); } spin_unlock_irqrestore(&nvt680->lock, flags); } void usbnvt_clr_ep_stall(struct nvt680_udc *nvt680, UINT32 EPn) { T_USB_DEVMAXPS_EP_REG devEPMaxPS; unsigned long flags; spin_lock_irqsave(&nvt680->lock, flags); devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)); devEPMaxPS.bit.STL_EP = 0; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)), devEPMaxPS.reg); spin_unlock_irqrestore(&nvt680->lock, flags); } void usbnvt_set_id(struct nvt680_udc *nvt680, BOOL device) { T_USB_TOP_REG RegTop; RegTop.reg = USB_GETREG(USB_TOP_REG_OFS); RegTop.bit.ID = device; USB_SETREG(USB_TOP_REG_OFS, RegTop.reg); } static void usbnvt_enable_highspeed(struct nvt680_udc *nvt680, BOOL highspeed) { T_USB_DEVMAINCTRL_REG devMainCtl; devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); if (highspeed) { devMainCtl.bit.FORCE_FS = 0; // bit[9] } else { devMainCtl.bit.FORCE_FS = 1; // bit[9] } USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); } void usbnvt_clr_fifo(struct nvt680_udc *nvt680) { T_USB_DEVTEST_REG devTest; devTest.reg = USB_GETREG(USB_DEVTEST_REG_OFS); devTest.bit.TST_CLRFF = 1; USB_SETREG(USB_DEVTEST_REG_OFS, devTest.reg); } void usbnvt_power_on_init(struct nvt680_udc *nvt680) { T_USB_DEVDMACTRL0_REG devDMACtl0; T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_HCMISC_REG hcMiscReg; itfnumsg("%s: enter\r\n", __func__); //default set to device mode usbnvt_set_id(nvt680, TRUE); //It is possible that loader has turn off the USB physical layer. //So we should turn on the usb physical layer. devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DEVPHY_SUSPEND = 0; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); usbnvt_enable_highspeed(nvt680, TRUE); // Bug fix for host resume pulse hcMiscReg.reg = USB_GETREG(USB_HCMISC_REG_OFS); hcMiscReg.bit.RESM_SE0_CNT = 0x22; USB_SETREG(USB_HCMISC_REG_OFS, hcMiscReg.reg); // set DMA access SDRAM devDMACtl0.reg = USB_GETREG(USB_DEVDMACTRL0_REG_OFS); devDMACtl0.bit.USB_ACCESS_SELECT = 0; USB_SETREG(USB_DEVDMACTRL0_REG_OFS, devDMACtl0.reg); // Clear FIFOs usbnvt_clr_fifo(nvt680); //USB Device is unattached. //Disable USB physcial layer. IT will auto re-function when USB plug-in devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1.bit.DEVPHY_SUSPEND = 1; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); { T_USB_DCD_COUNTER_REG RegDcdCnt; RegDcdCnt.reg = USB_GETREG(USB_DCD_COUNTER_REG_OFS); RegDcdCnt.bit.DCD_COUNT = 2; USB_SETREG(USB_DCD_COUNTER_REG_OFS, RegDcdCnt.reg); } { UINT16 data=0; INT32 result=0; UINT32 temp; UINT8 u2_trim_swctrl=6, u2_trim_sqsel=4, u2_trim_resint=8; #define U2PHY_SETREG(ofs,value) writel((value), (volatile void __iomem *)(0xFD601000+((ofs)<<2))) #define U2PHY_GETREG(ofs) readl((volatile void __iomem *)(0xFD601000+((ofs)<<2))) result= efuse_readParamOps(EFUSE_USBC_TRIM_DATA, &data); if(result == 0) { u2_trim_swctrl = data&0x7; u2_trim_sqsel = (data>>3)&0x7; u2_trim_resint = (data>>6)&0x1F; } U2PHY_SETREG(0x51, 0x20); U2PHY_SETREG(0x50, 0x30); temp = U2PHY_GETREG(0x06); temp &= ~(0x7<<1); temp |= (u2_trim_swctrl<<1); U2PHY_SETREG(0x06, temp); temp = U2PHY_GETREG(0x05); temp &= ~(0x7<<2); temp |= (u2_trim_sqsel<<2); U2PHY_SETREG(0x05, temp); U2PHY_SETREG(0x52, 0x60+u2_trim_resint); U2PHY_SETREG(0x51, 0x00); writel(0x100+u2_trim_resint, (volatile unsigned long *)(0xFD600000+0x30C)); } itfnumsg("%s: exit\r\n", __func__); } void usbnvt_init_controller(struct nvt680_udc *nvt680) { T_USB_DEVADDR_REG devAddr; T_USB_PHYTSTSELECT_REG devPhyTest; T_USB_DEVIDLECNT_REG devIdleCnt; T_USB_DEVMAINCTRL_REG devMainCtl; T_USB_DEVTEST_REG devTest; T_USB_GLOBALINTMASK_REG glbIntMsk; T_USB_DEVINTMASKGROUP0_REG devIntMskGrp0; T_USB_DEVINTMASKGROUP2_REG devIntMskGrp2; T_USB_OTGCTRLSTATUS_REG otgCtrlSts; T_USB_DEVDMACTRL1_REG devDMACtl1; T_USB_DEVDMACTRL1_REG devDMACtl1_bak; T_USB_TOP_REG RegTop; RegTop.reg = USB_GETREG(USB_TOP_REG_OFS); RegTop.bit.VBUSI = 1; USB_SETREG(USB_TOP_REG_OFS, RegTop.reg); // decrease VBUS debounce time from 540us to 200us otgCtrlSts.reg = USB_GETREG(USB_OTGCTRLSTATUS_REG_OFS); otgCtrlSts.bit.Vbus_FLT_SEL = 1; USB_SETREG(USB_OTGCTRLSTATUS_REG_OFS, otgCtrlSts.reg); //turn on the usb physical layer. devDMACtl1.reg = USB_GETREG(USB_DEVDMACTRL1_REG_OFS); devDMACtl1_bak.reg = devDMACtl1.reg; devDMACtl1.bit.DEVPHY_SUSPEND = 0; USB_SETREG(USB_DEVDMACTRL1_REG_OFS, devDMACtl1.reg); if (devDMACtl1_bak.bit.DEVPHY_SUSPEND == 1) { // wait VBUS debounce time passed udelay(200); } //set USB Device in unconfigure state devAddr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); devAddr.bit.AFT_CONF = 0; USB_SETREG(USB_DEVADDR_REG_OFS, devAddr.reg); // chip enable devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.CHIP_EN = 1; devMainCtl.bit.HALF_SPEED = 0; // Fix printer connect fail if test mode is enabled devMainCtl.bit.RESET_DEBOUNCE_INTERVAL = 5; // set debounce time to 5ms USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // suspend counter devIdleCnt.reg = USB_GETREG(USB_DEVIDLECNT_REG_OFS); devIdleCnt.bit.IDLE_CNT = 7; USB_SETREG(USB_DEVIDLECNT_REG_OFS, devIdleCnt.reg); // clear interrupt USB_SETREG(USB_DEVINTGROUP2_REG_OFS, 0xFFFFFFFF); // disable all fifo interrupt USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, 0xFFFFFF); // soft reset devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.SFRST = 1; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // soft reset clear devMainCtl.bit.SFRST = 0; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); // clear all fifo devTest.reg = USB_GETREG(USB_DEVTEST_REG_OFS); devTest.bit.TST_CLRFF = 1; USB_SETREG(USB_DEVTEST_REG_OFS, devTest.reg); // disable Host & OTG interrupt glbIntMsk.reg = USB_GETREG(USB_GLOBALINTMASK_REG_OFS); glbIntMsk.bit.MOTG_INT = 1; glbIntMsk.bit.MHC_INT = 1; USB_SETREG(USB_GLOBALINTMASK_REG_OFS, glbIntMsk.reg); // maks CX_IN/CX_OUT/CX_COMEND interrupt devIntMskGrp0.reg = USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS); devIntMskGrp0.bit.MCX_IN_INT = 1; devIntMskGrp0.bit.MCX_OUT_INT = 1; devIntMskGrp0.bit.MCX_COMEND = 1; USB_SETREG(USB_DEVINTMASKGROUP0_REG_OFS, devIntMskGrp0.reg); // mask DEV_IDLE interrupt devIntMskGrp2.reg = USB_GETREG(USB_DEVINTMASKGROUP2_REG_OFS); devIntMskGrp2.bit.MDEV_IDLE = 1; devIntMskGrp2.bit.MDEV_WAKEUP_BYVBUS = 1; USB_SETREG(USB_DEVINTMASKGROUP2_REG_OFS, devIntMskGrp2.reg); // enable global interrupt devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.GLINT_EN = 1; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = 1; USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); } static void usbnvt_global_interrupt_enable(struct nvt680_udc *nvt680, BOOL enable) { T_USB_DEVMAINCTRL_REG reg_devmainctrl; unsigned long flags; spin_lock_irqsave(&nvt680->lock, flags); reg_devmainctrl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); reg_devmainctrl.bit.GLINT_EN = enable; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, reg_devmainctrl.reg); spin_unlock_irqrestore(&nvt680->lock, flags); } static void usbnvt_intr_g2_busreset(struct nvt680_udc *nvt680) { T_USB_DEVINTMASKGROUP1_REG devIntMskGrp1; T_USB_DEVTEST_REG devTest; T_USB_DEVCXCFGFIFOSTATUS_REG devCXCFG; T_USB_DEVMAINCTRL_REG devMainCtl; T_USB_DEVFIFOBYTECNT0_REG devFIFOByteCnt; UINT32 i; unsigned long flags; ep0numsg("usbintr G2: bus-reset\n"); spin_lock_irqsave(&nvt680->lock, flags); //Set USB device Addr=0 & not in configured state USB_SETREG(USB_DEVADDR_REG_OFS, 0); // disable FIFO0 IN int // TODO Review devIntMskGrp1.reg = USB_GETREG(USB_DEVINTMASKGROUP1_REG_OFS); devIntMskGrp1.bit.MF0_IN_INT = 1; // bit[16] USB_SETREG(USB_DEVINTMASKGROUP1_REG_OFS, devIntMskGrp1.reg); // Clear All FIFO devTest.reg = USB_GETREG(USB_DEVTEST_REG_OFS); devTest.bit.TST_CLRFF = 1; // bit[0] USB_SETREG(USB_DEVTEST_REG_OFS, devTest.reg); for (i = 0; i < 4; i++) { devFIFOByteCnt.reg = USB_GETREG(USB_DEVFIFOBYTECNT0_REG_OFS + (i << 2)); devFIFOByteCnt.bit.FFRST0 = 1; devFIFOByteCnt.bit.FFRST1 = 1; USB_SETREG(USB_DEVFIFOBYTECNT0_REG_OFS, devFIFOByteCnt.reg + (i << 2)); } // clear EP0 Stall devCXCFG.reg = USB_GETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS); devCXCFG.bit.CX_STL = 0; // bit[2] USB_SETREG(USB_DEVCXCFGFIFOSTATUS_REG_OFS, devCXCFG.reg); // In 2.0 spec page255, the remote wakeup should be disabled after bus reset. devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); devMainCtl.bit.CAP_RMWAKUP = 0; USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); spin_unlock_irqrestore(&nvt680->lock, flags); } static void usbnvt_intr_g2_suspend(struct nvt680_udc *nvt680) { T_USB_DEVFIFOBYTECNT0_REG devFIFOByteCnt; //T_USB_DEVMAINCTRL_REG devMainCtl; UINT32 i; unsigned long flags; ep0numsg("usbintr G2: suspend\n"); spin_lock_irqsave(&nvt680->lock, flags); //Clear all USB FIFOs for (i = 0; i < 4; i++) { devFIFOByteCnt.reg = USB_GETREG(USB_DEVFIFOBYTECNT0_REG_OFS + (i << 2)); devFIFOByteCnt.bit.FFRST0 = 1; devFIFOByteCnt.bit.FFRST1 = 1; USB_SETREG(USB_DEVFIFOBYTECNT0_REG_OFS, devFIFOByteCnt.reg + (i << 2)); } //***************************************** //Defualt mode to enter suspend. //devMainCtl.reg = USB_GETREG(USB_DEVMAINCTRL_REG_OFS); //devMainCtl.bit.GOSUSP = 1; //USB_SETREG(USB_DEVMAINCTRL_REG_OFS, devMainCtl.reg); //***************************************** spin_unlock_irqrestore(&nvt680->lock, flags); } static void usbnvt_intr_g0_setup(struct nvt680_udc *nvt680) { struct usb_ctrlrequest ctrl; UINT32 *pControlData = (UINT32 *)(&ctrl); unsigned long flags; *pControlData++ = USB_GETREG(USB_DEVDMACTRL3_REG_OFS); *pControlData = USB_GETREG(USB_DEVDMACTRL3_REG_OFS); ep0numsg("usbintr G0: CX_SETUP_INT 0x%02X 0x%02X 0x%04X 0x%04X 0x%04X\n" , ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, ctrl.wIndex, ctrl.wLength); nvt680->ep[0]->dir_in = ctrl.bRequestType & USB_DIR_IN; nvt680->gadget.speed = USB_GETREG(USB_DEVMAINCTRL_REG_OFS) & (0x1<<6) ? USB_SPEED_HIGH : USB_SPEED_FULL; /* Handle SETUP */ if ((ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl.bRequest) { case USB_REQ_GET_STATUS: nvt680_get_status(nvt680, &ctrl); ep0numsg("USB_REQ_GET_STATUS\n"); break; case USB_REQ_CLEAR_FEATURE: nvt680_clear_feature(nvt680, &ctrl); ep0numsg("USB_REQ_CLEAR_FEATURE\n"); break; case USB_REQ_SET_FEATURE: nvt680_set_feature(nvt680, &ctrl); ep0numsg("USB_REQ_SET_FEATURE\n"); break; case USB_REQ_SET_ADDRESS: { T_USB_DEVADDR_REG reg_dev_addr; ep0numsg("USB_REQ_SET_ADDRESS\n"); spin_lock_irqsave(&nvt680->lock, flags); reg_dev_addr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); reg_dev_addr.bit.DEVADR = ctrl.wValue & 0x7F; USB_SETREG(USB_DEVADDR_REG_OFS, reg_dev_addr.reg); spin_unlock_irqrestore(&nvt680->lock, flags); usbnvt_set_ep0_done(nvt680); } break; case USB_REQ_SET_CONFIGURATION: { T_USB_DEVADDR_REG devAddr; spin_lock_irqsave(&nvt680->lock, flags); if (ctrl.wValue == 0) { devAddr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); devAddr.bit.AFT_CONF = 0; USB_SETREG(USB_DEVADDR_REG_OFS, devAddr.reg); } else { UINT32 EPn; T_USB_DEVMAXPS_EP_REG devEPMaxPS; // Clear All EPx & FIFOx map register USB_SETREG(USB_DEVMAXPS_EP1_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP2_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP3_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP4_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP5_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP6_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP7_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP8_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP9_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP10_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP11_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP12_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP13_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP14_REG_OFS, 0x88000200); USB_SETREG(USB_DEVMAXPS_EP15_REG_OFS, 0x88000200); USB_SETREG(USB_DEVBUFCFG0_REG_OFS, 0); USB_SETREG(USB_DEVBUFCFG1_REG_OFS, 0); usbnvt_clr_fifo(nvt680); for (EPn = 1; EPn <= 15; EPn++) { // Reset Toggle sequence for IN EP devEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)); devEPMaxPS.bit.RSTG_EP = 1; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)), devEPMaxPS.reg); devEPMaxPS.bit.RSTG_EP = 0; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((EPn - 1) << 2)), devEPMaxPS.reg); } devAddr.reg = USB_GETREG(USB_DEVADDR_REG_OFS); devAddr.bit.AFT_CONF = 1; USB_SETREG(USB_DEVADDR_REG_OFS, devAddr.reg); if (usbnvt_is_highspeed_enabled(nvt680)) { USB_SETREG(USB_DEVSOFTIMERMASK_REG_OFS, 0x44c); } else { USB_SETREG(USB_DEVSOFTIMERMASK_REG_OFS, 0x2710); } } spin_unlock_irqrestore(&nvt680->lock, flags); // The ep enable would be invoked here if (nvt680->driver->setup(&nvt680->gadget, &ctrl) < 0) { usbnvt_set_ep_stall(nvt680, 0); ep0numsg("SET STALL\n"); } //else { // Must not set done here. because gadget would send 0 byte ep0. // The done is set induced by that 0byte request. // usbnvt_set_ep0_done(nvt680); //} ep0numsg("USB_REQ_SET_CONFIGURATION\n"); } break; default: { if (nvt680->driver->setup(&nvt680->gadget, &ctrl) < 0) { usbnvt_set_ep_stall(nvt680, 0); ep0numsg("SET STALL\n"); } } break; } } else { if (nvt680->driver->setup(&nvt680->gadget, &ctrl) < 0) { usbnvt_set_ep_stall(nvt680, 0); ep0numsg("SET STALL\n"); } } } static void usbnvt_intr_g0_cx_in(struct nvt680_udc *nvt680) { struct nvt680_ep *ep = nvt680->ep[0]; ep0numsg("nvt680_ep0in\n"); if ((!list_empty(&ep->queue)) && (ep->dir_in)) { struct nvt680_request *req; req = list_entry(ep->queue.next, struct nvt680_request, queue); if (req->req.length) { nvt680_start_ep0_data(ep, req); } if ((req->req.length == req->req.actual) || (req->req.actual < ep->ep.maxpacket)) { nvt680_done(ep, req, 0); usbnvt_set_ep0_done(nvt680); } } else { usbnvt_set_ep0_done(nvt680); } } static void usbnvt_intr_g0_cx_out(struct nvt680_udc *nvt680) { struct nvt680_ep *ep = nvt680->ep[0]; ep0numsg("nvt680_ep0out\n"); if (!list_empty(&ep->queue) && !ep->dir_in) { struct nvt680_request *req; req = list_first_entry(&ep->queue, struct nvt680_request, queue); if (req->req.length) { nvt680_start_ep0_data(ep, req); } if ((req->req.length == req->req.actual) || (req->req.actual < ep->ep.maxpacket)) { nvt680_done(ep, req, 0); usbnvt_set_ep0_done(nvt680); } } else { numsg("%s : empty queue\n", __func__); } } static void usbnvt_intr_g0_cx_abort(struct nvt680_udc *nvt680) { T_USB_DEVINTGROUP0_REG devIntGrp0; unsigned long flags; ep0numsg("nvt680_cx_abort\n"); spin_lock_irqsave(&nvt680->lock, flags); devIntGrp0.reg = USB_GETREG(USB_DEVINTGROUP0_REG_OFS); devIntGrp0.bit.CX_COMABORT_INT = 0; USB_SETREG(USB_DEVINTGROUP0_REG_OFS, devIntGrp0.reg); spin_unlock_irqrestore(&nvt680->lock, flags); } #endif //////////////////////////////////////////////////////////////////////////////////////////// #if 1 static irqreturn_t nvt680_interrupt(int irq, void *_nvt680) { struct nvt680_udc *nvt680 = _nvt680; //intrmsg("nvt680_interrupt\n"); usbnvt_global_interrupt_enable(nvt680, FALSE); return IRQ_WAKE_THREAD; } static irqreturn_t nvt680_thread_interrupt(int irq, void *_nvt680) { struct nvt680_udc *nvt680 = _nvt680; T_USB_DEVINTGROUP_REG devIntGrp; T_USB_DEVINTGROUP0_REG devIntGrp0; T_USB_DEVINTGROUP1_REG devIntGrp1; T_USB_DEVINTGROUP2_REG devIntGrp2; unsigned long flags, fifono; devIntGrp.reg = USB_GETREG(USB_DEVINTGROUP_REG_OFS) & (~USB_GETREG(USB_DEVINTGROUPMASK_REG_OFS)); if (devIntGrp.bit.INT_G2) { //USB_SETREG(USB_DEVINTMASKGROUP2_REG_OFS, (((0xF<<(4+7))+0x30000))); devIntGrp2.reg = USB_GETREG(USB_DEVINTGROUP2_REG_OFS) & ( ~USB_GETREG(USB_DEVINTMASKGROUP2_REG_OFS)); USB_SETREG(USB_DEVINTGROUP2_REG_OFS, devIntGrp2.reg); //intrmsg("usbintr G2: 0x%08X\n", devIntGrp2.reg); if(devIntGrp2.bit.USBRST_INT) { usbnvt_intr_g2_busreset(nvt680); } if(devIntGrp2.bit.SUSP_INT) { usbnvt_intr_g2_suspend(nvt680); } if(devIntGrp2.bit.RESM_INT) { ep0numsg("usbintr G2: resume\n"); } // DMA-1 for(fifono=0; fifono < 1; fifono++) { if(devIntGrp2.reg & (0x1 << (fifono+7))) { struct nvt680_ep *ep; struct nvt680_request *req; int epnum; fifono = USB_GETREG(USB_DEVACCFIFO_REG_OFS); epnum = nvt680->fifo_2_ep[fifono]; if(epnum == 0xF) { pr_err("*************fifo_2_ep cmplt mapping_error %d 0x%08X****************\n", (int)fifono, devIntGrp2.reg); } ep = nvt680->ep[epnum]; intrmsg("usbintr G2: DMA%d_CMPLT\n", (int)fifono); spin_lock_irqsave(&nvt680->lock, flags); if(ep->d_adr && ep->d_len) { dma_unmap_single(NULL, ep->d_adr, ep->d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ep->d_adr = 0; ep->d_len = 0; } spin_unlock_irqrestore(&nvt680->lock, flags); //printk("&&&& %d %d\n\n",fifono,list_empty(&ep->queue)); if(!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct nvt680_request, queue); nvt680_done(ep, req, 0); } } } // DMA-2~5 for(fifono=4; fifono < 8; fifono++) { if(devIntGrp2.reg & (0x1 << (fifono+5))) { struct nvt680_ep *ep; struct nvt680_request *req; int epnum = nvt680->fifo_2_ep[fifono]; if(epnum == 0xF) { pr_err("*************fifo_2_ep cmplt mapping_error %d 0x%08X****************\n", (int)fifono, devIntGrp2.reg); } ep = nvt680->ep[epnum]; intrmsg("usbintr G2: DMA%d_CMPLT\n", (int)fifono-2); spin_lock_irqsave(&nvt680->lock, flags); if(ep->d_adr && ep->d_len) { dma_unmap_single(NULL, ep->d_adr, ep->d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ep->d_adr = 0; ep->d_len = 0; } spin_unlock_irqrestore(&nvt680->lock, flags); //printk("&&&& %d %d\n\n",fifono,list_empty(&ep->queue)); if(!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct nvt680_request, queue); nvt680_done(ep, req, 0); } } } if(devIntGrp2.bit.SEQ_ERR_INT) { intrmsg("usbintr G2: SEQ_ERR_INT\n"); } if(devIntGrp2.bit.SEQ_ABORT_INT) { intrmsg("usbintr G2: SEQ_ABORT_INT\n"); } if(devIntGrp2.bit.TX0BYTE_INT) { intrmsg("usbintr G2: TX0BYTE_INT\n"); USB_SETREG(USB_DEVTX0BYTE_REG_OFS, 0); } if(devIntGrp2.bit.RX0BYTE_INT) { intrmsg("usbintr G2: RX0BYTE_INT\n"); USB_SETREG(USB_DEVRX0BYTE_REG_OFS, 0); } if(devIntGrp2.bit.DEV_IDLE) { intrmsg("usbintr G2: DEV_IDLE\n"); } if(devIntGrp2.bit.DEV_WAKEUP_BYVBUS) { intrmsg("usbintr G2: DEV_WAKEUP_BYVBUS\n"); } } if (devIntGrp.bit.INT_G0) { devIntGrp0.reg = USB_GETREG(USB_DEVINTGROUP0_REG_OFS) & ( ~ USB_GETREG(USB_DEVINTMASKGROUP0_REG_OFS)); ep0numsg("usbintr G0: 0x%08X\n", devIntGrp0.reg); if(devIntGrp0.bit.CX_SETUP_INT) { usbnvt_intr_g0_setup(nvt680); } if(devIntGrp0.bit.CX_IN_INT) { usbnvt_intr_g0_cx_in(nvt680); } if(devIntGrp0.bit.CX_OUT_INT) { usbnvt_intr_g0_cx_out(nvt680); } if(devIntGrp0.bit.CX_COMEND) { printk("CX_COMEND ??\n"); } if(devIntGrp0.bit.CX_COMFAIL_INT) { spin_lock_irqsave(&nvt680->lock, flags); devIntGrp0.reg = USB_GETREG(USB_DEVINTGROUP0_REG_OFS); devIntGrp0.bit.CX_COMFAIL_INT = 0; USB_SETREG(USB_DEVINTGROUP0_REG_OFS, devIntGrp0.reg); spin_unlock_irqrestore(&nvt680->lock, flags); usbnvt_set_ep_stall(nvt680, 0); } if(devIntGrp0.bit.CX_COMABORT_INT) { usbnvt_intr_g0_cx_abort(nvt680); } } if (devIntGrp.bit.INT_G1) { devIntGrp1.reg = USB_GETREG(USB_DEVINTGROUP1_REG_OFS) & ( ~ USB_GETREG(USB_DEVINTMASKGROUP1_REG_OFS)); intrmsg("usbintr G1: 0x%08X\n", devIntGrp1.reg); /* fifo out */ for(fifono = 0; fifono < 8; fifono++) { // (devIntGrp1.bit.F0_OUT_INT || devIntGrp1.bit.F0_SPK_INT) if(devIntGrp1.reg & (0x3 << (fifono<<1))) { struct nvt680_ep *ep; struct nvt680_request *req; dma_addr_t d_adr; UINT32 d_len, epnum = nvt680->fifo_2_ep[fifono]; T_USB_DEVFIFOBYTECNT0_REG reg_devfifo_bc; if(epnum == 0xF) { pr_err("fifo_2_ep out mapping_error %d\n", (int)fifono); } ep = nvt680->ep[epnum]; req = list_entry(ep->queue.next, struct nvt680_request, queue); //reg_devfifo_bc.reg = USB_GETREG(USB_DEVFIFOBYTECNT0_REG_OFS+((epnum-1)<<2)); //d_len = reg_devfifo_bc.bit.BC_F0; reg_devfifo_bc.reg = USB_GETREG(USB_DEVFIFOBYTECNT0_REG_OFS+((nvt680->ep_2_fifo[epnum]>>1)<<2)); d_len = (reg_devfifo_bc.reg >> ((nvt680->ep_2_fifo[epnum]&0x1)<<4)) & 0x7FF; if(!(d_len & 511)) { d_len = req->req.length; } d_adr = dma_map_single(NULL, (u8 *)(req->req.buf), d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_mapping_error(NULL, d_adr)) { pr_err("dma_mapping_error\n"); } dma_sync_single_for_device(NULL, d_adr, d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->req.actual = d_len; ep->d_adr = d_adr; ep->d_len = d_len; usbnvt_set_ep_read(nvt680, epnum, d_adr, d_len); //nvt680_stop_ep_transfer(ep); usbnvt_mask_ep_interrupt(nvt680, epnum); } } /* fifo in */ for(fifono = 0; fifono < 8; fifono++) { if(devIntGrp1.reg & (0x1 << (fifono+16))) { struct nvt680_ep *ep; struct nvt680_request *req; dma_addr_t d_adr; UINT32 d_len, epnum = nvt680->fifo_2_ep[fifono]; if(epnum == 0xF) { pr_err("fifo_2_ep in mapping_error %d\n", (int)fifono); } ep = nvt680->ep[epnum]; req = list_entry(ep->queue.next, struct nvt680_request, queue); if ((req->req.length == 0) && (req->req.actual == 0)) { T_USB_DEVMAXPS_EP_REG DevEPMaxPS; spin_lock_irqsave(&nvt680->lock, flags); DevEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)); DevEPMaxPS.bit.TX0BYTE_IEP = 1; USB_SETREG((USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)), DevEPMaxPS.reg); spin_unlock_irqrestore(&nvt680->lock, flags); do { DevEPMaxPS.reg = USB_GETREG(USB_DEVMAXPS_EP1_REG_OFS + ((epnum - 1) << 2)); if(!DevEPMaxPS.bit.TX0BYTE_IEP) { break; } msleep(1); }while(DevEPMaxPS.bit.TX0BYTE_IEP); nvt680_done(ep, req, 0); } else { d_len = req->req.length; d_adr = dma_map_single(NULL, (u8 *)(req->req.buf), d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_mapping_error(NULL, d_adr)) { pr_err("dma_mapping_error\n"); } dma_sync_single_for_device(NULL, d_adr, d_len, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->req.actual = d_len; ep->d_adr = d_adr; ep->d_len = d_len; usbnvt_set_ep_write(nvt680, epnum, d_adr, d_len); //nvt680_stop_ep_transfer(ep); usbnvt_mask_ep_interrupt(nvt680, epnum); } } } } usbnvt_global_interrupt_enable(nvt680, TRUE); return IRQ_HANDLED; } #endif static int nvt680_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct nvt680_ep *ep; #define QH_ISO_MULT(x) ((x >> 11) & 0x03) ep = container_of(_ep, struct nvt680_ep, ep); ep->desc = desc; ep->epnum = usb_endpoint_num(desc); ep->type = usb_endpoint_type(desc); ep->dir_in = usb_endpoint_dir_in(desc); ep->ep.maxpacket = usb_endpoint_maxp(desc)& 0x07ff; ep->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc)); itfnumsg("fotg200_ep_enable: ep-desc len=0x%X type=0x%X epaddr=0x%X attr=0x%X MaxPkt=0x%X intval=0x%X mult=%d\n" ,desc->bLength,desc->bDescriptorType ,desc->bEndpointAddress,desc->bmAttributes,desc->wMaxPacketSize,desc->bInterval, ep->ep.mult); //printk("fotg200_ep_enable: ep-desc len=0x%X type=0x%X epaddr=0x%X attr=0x%X MaxPkt=0x%X intval=0x%X mult=%d\n" // ,desc->bLength,desc->bDescriptorType ,desc->bEndpointAddress,desc->bmAttributes,desc->wMaxPacketSize,desc->bInterval, ep->ep.mult); return nvt680_config_ep(ep, desc); } static int nvt680_ep_disable(struct usb_ep *_ep) { struct nvt680_ep *ep; struct nvt680_request *req; BUG_ON(!_ep); itfnumsg("nvt680_ep_disable\n"); ep = container_of(_ep, struct nvt680_ep, ep); //printk("nvt680_ep_disable %d\n",ep->epnum); while (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct nvt680_request, queue); nvt680_done(ep, req, -ESHUTDOWN); } return nvt680_ep_release(ep); } static struct usb_request *nvt680_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct nvt680_request *req; itfnumsg("nvt680_ep_alloc_request\n"); req = kzalloc(sizeof(struct nvt680_request), gfp_flags); if (!req) return NULL; INIT_LIST_HEAD(&req->queue); return &req->req; } static void nvt680_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) { struct nvt680_request *req; itfnumsg("nvt680_ep_free_request\n"); req = container_of(_req, struct nvt680_request, req); kfree(req); } static int nvt680_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct nvt680_ep *ep; struct nvt680_request *req; unsigned long flags; int empty_list = 0; ep = container_of(_ep, struct nvt680_ep, ep); req = container_of(_req, struct nvt680_request, req); if(ep->epnum) { itfnumsg("nvt680_ep_queue %d\n", ep->epnum); } else { ep0numsg("nvt680_ep0_queue %d\n", ep->epnum); } if (ep->nvt680->gadget.speed == USB_SPEED_UNKNOWN) { printk("unknown speed\n"); return -ESHUTDOWN; } spin_lock_irqsave(&ep->nvt680->lock, flags); empty_list = list_empty(&ep->queue); list_add_tail(&req->queue, &ep->queue); req->req.actual = 0; req->req.status = -EINPROGRESS; spin_unlock_irqrestore(&ep->nvt680->lock, flags); if (!ep->epnum) { /* ep0 */ nvt680_ep0_queue(ep, req); } else if (empty_list) { nvt680_enable_ep_transfer(ep); } return 0; } static int nvt680_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) { struct nvt680_ep *ep; struct nvt680_request *req; itfnumsg("nvt680_ep_dequeue\n"); ep = container_of(_ep, struct nvt680_ep, ep); req = container_of(_req, struct nvt680_request, req); if (!list_empty(&ep->queue)) { nvt680_done(ep, req, -ECONNRESET); } return 0; } static int nvt680_ep_set_halt(struct usb_ep *_ep, int value) { itfnumsg("nvt680_ep_set_halt\n"); return nvt680_set_halt_and_wedge(_ep, value, 0); } static int nvt680_ep_set_wedge(struct usb_ep *_ep) { itfnumsg("nvt680_ep_set_wedge\n"); return nvt680_set_halt_and_wedge(_ep, 1, 1); } static void nvt680_ep_fifo_flush(struct usb_ep *_ep) { itfnumsg("nvt680_ep_fifo_flush\n"); } static int nvt680_fifo_status(struct usb_ep *ep) { itfnumsg("nvt680_fifo_status\n"); return 0; } static struct usb_ep_ops nvt680_ep_ops = { .enable = nvt680_ep_enable, .disable = nvt680_ep_disable, .alloc_request = nvt680_ep_alloc_request, .free_request = nvt680_ep_free_request, .queue = nvt680_ep_queue, .dequeue = nvt680_ep_dequeue, .set_halt = nvt680_ep_set_halt, .fifo_flush = nvt680_ep_fifo_flush, .set_wedge = nvt680_ep_set_wedge, .fifo_status= nvt680_fifo_status, }; static int nvt680_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct nvt680_udc *nvt680 = gadget_to_nvt680(g); int i, ret = 0; itfnumsg("nvt680_udc_start %d\n", nvt680->irq_no); usbnvt_power_on_init(nvt680); usbnvt_init_controller(nvt680); for (i = 0; i < NVT680_MAX_NUM_EP; i++) { nvt680->ep_2_fifo[i]=0xF; } for (i = 0; i < 8; i++) { nvt680->fifo_2_ep[i]=0xF; } nvt680->fifo_vld_msk = 0xff; nvt680->fifo_vld_idx = 0; #if 1 ret = request_threaded_irq(nvt680->irq_no, nvt680_interrupt, nvt680_thread_interrupt, IRQF_SHARED, udc_name, nvt680); if (ret < 0) { pr_err("request_irq error (%d)\n", ret); goto err_irq; } #endif /* hook up the driver */ driver->driver.bus = NULL; nvt680->driver = driver; return 0; err_irq: free_irq(nvt680->irq_no, nvt680); return ret; } static int nvt680_udc_stop(struct usb_gadget *g) { struct nvt680_udc *nvt680 = gadget_to_nvt680(g); unsigned long flags; u32 value; itfnumsg("nvt680_udc_stop\n"); spin_lock_irqsave(&nvt680->lock, flags); //fotg210_init(fotg210); nvt680->driver = NULL; //nvt680_enable_unplugsuspend(nvt680); /* enable device global interrupt */ value = ioread32((void __iomem *)0xFD0200A4); value &= ~(0x1<<19); iowrite32(value, (void __iomem *)0xFD0200A4); value |= (0x1<<19); iowrite32(value, (void __iomem *)0xFD0200A4); spin_unlock_irqrestore(&nvt680->lock, flags); return 0; } /** * nvt680_udc_pullup - Enable/disable pullup on D+ line. * @gadget: USB slave device. * @is_on: 0 to disable pullup, 1 to enable. * * See notes in bcm63xx_select_pullup(). */ static int nvt680_udc_pullup(struct usb_gadget *gadget, int is_on) { T_USB_PHYTSTSELECT_REG devPhyTest; struct nvt680_udc *nvt680 = gadget_to_nvt680(gadget); itfnumsg("nvt680_udc_pullup %d\n", is_on); devPhyTest.reg = USB_GETREG(USB_PHYTSTSELECT_REG_OFS); devPhyTest.bit.UNPLUG = !is_on; USB_SETREG(USB_PHYTSTSELECT_REG_OFS, devPhyTest.reg); return 0; } static int nvt680_udc_get_frame(struct usb_gadget *g) { itfnumsg("nvt680_udc_get_frame\n"); return 0;// return 11 bits SOF number } static struct usb_gadget_ops nvt680_gadget_ops = { .get_frame = nvt680_udc_get_frame, .udc_start = nvt680_udc_start, .udc_stop = nvt680_udc_stop, .pullup = nvt680_udc_pullup, }; static int nvt680_udc_remove(struct platform_device *pdev) { struct nvt680_udc *nvt680 = platform_get_drvdata(pdev); itfnumsg("nvt680_udc_remove\n"); usb_del_gadget_udc(&nvt680->gadget); free_irq(platform_get_irq(pdev, 0), nvt680); nvt680_ep_free_request(&nvt680->ep[0]->ep, nvt680->ep0_req); iounmap(nvt680->reg); kfree(nvt680); { struct resource *res; struct clk *source_clk; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); source_clk = clk_get(&pdev->dev, "f0600000.usb20"); if (IS_ERR(source_clk)) { printk("faile to get clock f0600000.usb20\n"); } else { /* toggle reset */ clk_prepare(source_clk); clk_unprepare(source_clk); clk_put(source_clk); } } return 0; } static int nvt680_udc_probe(struct platform_device *pdev) { struct resource *res, *ires; struct nvt680_udc *nvt680 = NULL; struct nvt680_ep *_ep[NVT680_MAX_NUM_EP]; int ret = 0; int i; itfnumsg("nvt680_udc_probe\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { pr_err("platform_get_resource error.\n"); return -ENODEV; } ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!ires) { pr_err("platform_get_resource IORESOURCE_IRQ error.\n"); return -ENODEV; } ret = -ENOMEM; /* initialize nvt680_udc data struct */ nvt680 = kzalloc(sizeof(struct nvt680_udc), GFP_KERNEL); if (nvt680 == NULL) { pr_err("kzalloc error\n"); goto err_alloc; } for (i = 0; i < NVT680_MAX_NUM_EP; i++) { _ep[i] = kzalloc(sizeof(struct nvt680_ep), GFP_KERNEL); if (_ep[i] == NULL) { pr_err("_ep kzalloc error\n"); goto err_alloc; } nvt680->ep[i] = _ep[i]; nvt680->ep_2_fifo[i]=0xF; } for (i = 0; i < 8; i++) { nvt680->fifo_2_ep[i]=0xF; } if (!request_mem_region(res->start, resource_size(res), pdev->name)) { pr_err("failed to request memory resource %s\n", pdev->name); goto err_alloc; } nvt680->reg = ioremap_nocache(res->start, resource_size(res)); if (nvt680->reg == NULL) { pr_err("ioremap error.\n"); goto err_map; } spin_lock_init(&nvt680->lock); platform_set_drvdata(pdev, nvt680); nvt680->gadget.ops = &nvt680_gadget_ops; nvt680->gadget.max_speed = USB_SPEED_HIGH; nvt680->gadget.dev.parent = &pdev->dev; nvt680->gadget.dev.dma_mask = pdev->dev.dma_mask; nvt680->gadget.name = udc_name; INIT_LIST_HEAD(&nvt680->gadget.ep_list); for (i = 0; i < NVT680_MAX_NUM_EP; i++) { struct nvt680_ep *ep = nvt680->ep[i]; if (i) { INIT_LIST_HEAD(&nvt680->ep[i]->ep.ep_list); list_add_tail(&nvt680->ep[i]->ep.ep_list, &nvt680->gadget.ep_list); } ep->nvt680 = nvt680; INIT_LIST_HEAD(&ep->queue); //ep->ep.name = nvt680_ep_name[i]; ep->ep.name = ep_info[i].name; ep->ep.caps = ep_info[i].caps; ep->ep.ops = &nvt680_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); } usb_ep_set_maxpacket_limit(&nvt680->ep[0]->ep, 0x40); nvt680->gadget.ep0 = &nvt680->ep[0]->ep; INIT_LIST_HEAD(&nvt680->gadget.ep0->ep_list); nvt680->ep0_req = nvt680_ep_alloc_request(&nvt680->ep[0]->ep, GFP_KERNEL); if (nvt680->ep0_req == NULL) goto err_req; usbnvt_power_on_init(nvt680); nvt680->irq_no = ires->start; ret = usb_add_gadget_udc(&pdev->dev, &nvt680->gadget); if (ret) goto err_add_udc; dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; err_add_udc: err_req: nvt680_ep_free_request(&nvt680->ep[0]->ep, nvt680->ep0_req); err_map: if (nvt680->reg) iounmap(nvt680->reg); err_alloc: kfree(nvt680); return ret; } #ifdef CONFIG_OF static const struct of_device_id of_nvt680_match[] = { { .compatible = "nvt,fotg200_udc" }, { }, }; MODULE_DEVICE_TABLE(of, of_nvt680_match); #endif static struct platform_driver nvt680_driver = { .driver = { .name = (char *)udc_name, #ifdef CONFIG_OF .of_match_table = of_match_ptr(of_nvt680_match), #endif }, .probe = nvt680_udc_probe, .remove = nvt680_udc_remove, }; module_platform_driver(nvt680_driver); MODULE_AUTHOR("Klins Chen "); MODULE_LICENSE("GPL"); MODULE_VERSION("1.01.001"); MODULE_DESCRIPTION(DRIVER_DESC);