nt9856x/BSP/linux-kernel/drivers/usb/gadget/udc/nvt-udc520.c
2023-03-28 15:07:53 +08:00

2376 lines
61 KiB
C
Executable File

/*
* NVT680 UDC Driver supports Bulk transfer so far
*
* Copyright (C) 2017 Novatek Technology Corporation
*
* Author : Klins Chen <klins_chen@novatek.com.tw>
*
* 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 <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <plat/efuse_protected.h>
#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<<ep->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<<ep->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 <klins_chen@novatek.com.tw>");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.01.001");
MODULE_DESCRIPTION(DRIVER_DESC);