/* * until it becomes enabled, this UDC should be completely invisible * to any USB host. */ static int udc_enable(struct s3c_udc *dev) { u32 uTemp; DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); uTemp = readl(S3C_OTHERS); uTemp |= (1<<16); // USB_SIG_MASK writel(uTemp, S3C_OTHERS); // 1. Initializes OTG Phy. writel(0x0, S3C_USBOTG_PHYPWR); // writel(0x20, S3C_USBOTG_PHYCLK); writel(0x02, S3C_USBOTG_PHYCLK); /* 2010-0208, modified by CVKK(JC) */ writel(0x1, S3C_USBOTG_RSTCON); udelay(50); writel(0x0, S3C_USBOTG_RSTCON); udelay(50); dev->udc_state = USB_STATE_POWERED; dev->gadget.speed = USB_SPEED_UNKNOWN; reconfig_usbd(dev); DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n", readl(S3C_UDC_OTG_GINTMSK)); return 0; }
/* until it's enabled, this UDC should be completely invisible * to any USB host. */ static int udc_enable(struct s3c_udc *dev) { DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); /* if reset by sleep wakeup, control the retention I/O cell */ if (__raw_readl(S3C_RSTSTAT) & 0x8) __raw_writel(__raw_readl(S3C_RSTCON)|(1<<16), S3C_RSTCON); /* USB Port is Normal mode */ __raw_writel(__raw_readl(S3C2410_MISCCR)&~(1<<12), S3C2410_MISCCR); /* PHY power enable */ __raw_writel(__raw_readl(S3C_PWRCFG)|(1<<4), S3C_PWRCFG); /* USB device 2.0 must reset like bellow, * 1st phy reset and after at least 10us, func_reset & host reset * phy reset can reset bellow registers. */ /* PHY 2.0 S/W reset */ __raw_writel((0<<2)|(0<<1)|(1<<0), S3C_URSTCON); udelay(20); /* phy reset must be asserted for at 10us */ /*Function 2.0, Host 1.1 S/W reset*/ __raw_writel((1<<2)|(1<<1)|(0<<0), S3C_URSTCON); __raw_writel((0<<2)|(0<<1)|(0<<0), S3C_URSTCON); /* 48Mhz,Crystal,External X-tal,device */ __raw_writel((0<<3)|(0<<2)|(1<<1)|(0<<0), S3C_PHYCTRL); /* 48Mhz clock on ,PHY2.0 analog block power on * XO block power on,XO block power in suspend mode, * PHY 2.0 Pll power on ,suspend signal for save mode disable */ __raw_writel((1<<31)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0), S3C_PHYPWR); /* D+ pull up disable(VBUS detect), USB2.0 Function clock Enable, * USB1.1 HOST disable, USB2.0 PHY test enable */ __raw_writel((0<<31)|(1<<2)|(0<<1)|(1<<0), S3C_UCLKCON); __raw_writel(IRQ_USBD, S3C2410_INTPND); __raw_writel(IRQ_USBD, S3C2410_SRCPND); reconfig_usbd(); __raw_writel(__raw_readl(S3C2410_INTMSK)&~(IRQ_USBD), S3C2410_INTMSK); /* D+ pull up , USB2.0 Function clock Enable, * USB1.1 HOST disable,USB2.0 PHY test enable */ __raw_writel((1<<31)|(1<<2)|(0<<1)|(1<<0), S3C_UCLKCON); DEBUG_SETUP("S3C2443 USB Controller Core Initialized\n"); dev->gadget.speed = USB_SPEED_UNKNOWN; return 0; }
/* Register entry point for the peripheral controller driver. */ int usb_gadget_register_driver(struct usb_gadget_driver* driver) { struct elfin_udc *dev = the_controller; int retval; DPRINTK("%s: %s\n", __FUNCTION__, driver->driver.name); if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; /* first hook up the driver ... */ dev->driver = driver; dev->gadget.dev.driver = &driver->driver; device_add(&dev->gadget.dev); retval = driver->bind(&dev->gadget); if (retval) { printk("%s: bind to driver %s --> error %d\n", dev->gadget.name, driver->driver.name, retval); device_del(&dev->gadget.dev); dev->driver = 0; dev->gadget.dev.driver = 0; return retval; } reconfig_usbd(); enable_irq(IRQ_USBD); printk("Registered gadget driver '%s'\n", driver->driver.name); GPIO_ENABLE; /* TODO: callback for checking usb connection */ #ifdef CONFIG_MACH_TOMTOMGO /* Here we should wait until the usb gadget device is completely enumerated if we want debugging support.... */ if (IO_GetInput(USB_HOST_DETECT)) { usb_enum_completion = kmalloc(sizeof(struct completion), GFP_KERNEL); init_completion(usb_enum_completion); wait_for_completion(usb_enum_completion); } #endif return 0; }
/* * elfin usb client interrupt handler. */ static irqreturn_t s3c_udc_irq(int irq, void *_dev) { struct s3c_udc *dev = _dev; u32 intr_status; u32 usb_status, ep_ctrl, gintmsk; spin_lock(&dev->lock); intr_status = readl(S3C_UDC_OTG_GINTSTS); gintmsk = readl(S3C_UDC_OTG_GINTMSK); DEBUG_ISR("\n**** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x\n", __FUNCTION__, intr_status, state_names[dev->ep0state], gintmsk); if (!intr_status) { spin_unlock(&dev->lock); return IRQ_HANDLED; } if (intr_status & INT_ENUMDONE) { DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s: Speed Detection interrupt\n", __FUNCTION__); writel(INT_ENUMDONE, S3C_UDC_OTG_GINTSTS); usb_status = (readl(S3C_UDC_OTG_DSTS) & 0x6); if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { DEBUG_SETUP(" %s: Full Speed Detection\n",__FUNCTION__); set_max_pktsize(dev, USB_SPEED_FULL); } else { DEBUG_SETUP(" %s: High Speed Detection : 0x%x\n", __FUNCTION__, usb_status); set_max_pktsize(dev, USB_SPEED_HIGH); } } if (intr_status & INT_EARLY_SUSPEND) { DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s:Early suspend interrupt\n", __FUNCTION__); writel(INT_EARLY_SUSPEND, S3C_UDC_OTG_GINTSTS); } if (intr_status & INT_SUSPEND) { usb_status = readl(S3C_UDC_OTG_DSTS); DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s:Suspend interrupt :(DSTS):0x%x\n", __FUNCTION__, usb_status); writel(INT_SUSPEND, S3C_UDC_OTG_GINTSTS); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->suspend) { dev->driver->suspend(&dev->gadget); } } if (intr_status & INT_RESUME) { DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s: Resume interrupt\n", __FUNCTION__); writel(INT_RESUME, S3C_UDC_OTG_GINTSTS); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume) { dev->driver->resume(&dev->gadget); } } if (intr_status & INT_RESET) { usb_status = readl(S3C_UDC_OTG_GOTGCTL); DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s: Reset interrupt - (GOTGCTL):0x%x\n", __FUNCTION__, usb_status); writel(INT_RESET, S3C_UDC_OTG_GINTSTS); if((usb_status & 0xc0000) == (0x3 << 18)) { if(reset_available) { DEBUG_SETUP(" ===> OTG core got reset (%d)!! \n", reset_available); reconfig_usbd(); dev->ep0state = WAIT_FOR_SETUP; reset_available = 0; } } else { reset_available = 1; DEBUG_SETUP(" RESET handling skipped : reset_available : %d\n", reset_available); } } if (intr_status & INT_RX_FIFO_NOT_EMPTY) { u32 grx_status, packet_status, ep_num, fifoCntByte = 0; /* Mask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk &= ~INT_RX_FIFO_NOT_EMPTY; writel(gintmsk, S3C_UDC_OTG_GINTMSK); grx_status = readl(S3C_UDC_OTG_GRXSTSR); DEBUG_ISR(" INT_RX_FIFO_NOT_EMPTY(GRXSTSR):0x%x, GINTMSK:0x%x\n", grx_status, gintmsk); packet_status = grx_status & 0x1E0000; fifoCntByte = (grx_status & 0x7ff0)>>4; ep_num = grx_status & EP_MASK; if (fifoCntByte) { if (packet_status == SETUP_PKT_RECEIVED) { DEBUG_EP0(" => A SETUP data packet received : %d bytes\n", fifoCntByte); s3c_handle_ep0(dev); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk |= INT_RX_FIFO_NOT_EMPTY; } else if (packet_status == OUT_PKT_RECEIVED) { if(ep_num == EP1_OUT) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL1); DEBUG_ISR(" => A Bulk OUT data packet received : %d bytes, (DOEPCTL1):0x%x\n", fifoCntByte, ep_ctrl); s3c_out_epn(dev, 1); gintmsk = readl(S3C_UDC_OTG_GINTMSK); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL1); } else if (ep_num == EP0_CON) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_EP0(" => A CONTROL OUT data packet received : %d bytes, (DOEPCTL0):0x%x\n", fifoCntByte, ep_ctrl); dev->ep0state = DATA_STATE_RECV; s3c_ep0_read(dev); gintmsk |= INT_RX_FIFO_NOT_EMPTY; } else { DEBUG_ISR(" => Unused EP: %d bytes, (GRXSTSR):0x%x\n", fifoCntByte, grx_status); } } else { grx_status = readl(S3C_UDC_OTG_GRXSTSP); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk |= INT_RX_FIFO_NOT_EMPTY; DEBUG_ISR(" => A reserved packet received : %d bytes\n", fifoCntByte); } } else { if (dev->ep0state == DATA_STATE_XMIT) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_EP0(" => Write ep0 continue... (DOEPCTL0):0x%x\n", ep_ctrl); s3c_ep0_write(dev); } if (packet_status == SETUP_TRANSACTION_COMPLETED) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_EP0(" => A SETUP transaction completed (DOEPCTL0):0x%x\n", ep_ctrl); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL0); } else if (packet_status == OUT_TRANSFER_COMPLELTED) { if (ep_num == EP1_OUT) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL1); DEBUG_ISR(" => An OUT transaction completed (DOEPCTL1):0x%x\n", ep_ctrl); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL1); } else if (ep_num == EP0_CON) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_ISR(" => An OUT transaction completed (DOEPCTL0):0x%x\n", ep_ctrl); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL0); } else { DEBUG_ISR(" => Unused EP: %d bytes, (GRXSTSR):0x%x\n", fifoCntByte, grx_status); } } else if (packet_status == OUT_PKT_RECEIVED) { DEBUG_ISR(" => A OUT PACKET RECEIVED (NO FIFO CNT BYTE)...(GRXSTSR):0x%x\n", grx_status); } else { DEBUG_ISR(" => A RESERVED PACKET RECEIVED (NO FIFO CNT BYTE)...(GRXSTSR):0x%x\n", grx_status); } grx_status = readl(S3C_UDC_OTG_GRXSTSP); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk |= INT_RX_FIFO_NOT_EMPTY; } /* Un/Mask USB OTG 2.0 interrupt sources */ writel(gintmsk, S3C_UDC_OTG_GINTMSK); spin_unlock(&dev->lock); return IRQ_HANDLED; }
static void udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs) { __u8 saveIdx = UD_INDEX; __u8 usb_status = UD_USBINT; __u8 usbd_status = UD_INT; static int sb_debug_cnt = 1; LOG("usb_status = 0x%02x, usbd_status = 0x%02x\n", usb_status, usbd_status); if ( usb_status & UD_USBINT_RESET ) { LOG("\n[%d]RESET interrupt\n",sb_debug_cnt++); if( usbctl_next_state_on_event(kEvReset) != kError ) { LOG("%s Resetting\n",pszMe); ep0_reset(); ep1_reset();/* output */ ep2_reset();/* input */ } // reset_usbd(); reconfig_usbd(); UD_USBINT = UD_USBINT_RESET; //RESET_INT should be cleared after reconfig_usbd().- by samsung src ep0_state = EP0_STATE_IDLE; } /* RESume Interrupt Request */ if ( usb_status & UD_USBINT_RESUM ) { LOG("[%d]RESUME interrupt\n", sb_debug_cnt++); UD_USBINT = UD_USBINT_RESUM;/* clear */ usbctl_next_state_on_event( kEvResume ); } /* SUSpend Interrupt Request */ if ( usb_status & UD_USBINT_SUSPND ) { LOG("[%d]SUSPEND interrupt\n", sb_debug_cnt++); UD_USBINT = UD_USBINT_SUSPND; /* clear */ usbctl_next_state_on_event( kEvSuspend ); } if ( usbd_status & UD_INT_EP0 ) { LOG("\n[%d]EP0 interrupt\n",sb_debug_cnt++); UD_INT = UD_INT_EP0; /* clear */ ep0_int_hndlr(); } /* output */ if ( usbd_status & UD_INT_EP1 ) { LOG("[%d]EP1 interrupt\n", sb_debug_cnt++); UD_INT = UD_INT_EP1;/* clear */ ep1_int_hndlr(usbd_status); } /* input */ if ( usbd_status & UD_INT_EP2 ) { LOG("[%d]EP2 interrupt\n", sb_debug_cnt++); UD_INT = UD_INT_EP2; /* clear */ ep2_int_hndlr(usbd_status); } if(usbd_status & UD_INT_EP3) UD_INT = UD_INT_EP3; if(usbd_status & UD_INT_EP4) UD_INT = UD_INT_EP4; Clear_pending(INT_USBD); UD_INDEX= saveIdx; }