static int s3c_udc_resume(struct platform_device *pdev) { //#ifndef CONFIG_PM usb_pm_state = 1; return 0; #if 0 #if 1 //first check status of connection DEBUG_PM("[%s]: fsa9480_check_usb_connection\n", __func__); msleep(200); fsa9480_check_usb_connection(); return 0; #else // chekc udc_resume_speed & udc_resume_state struct s3c_udc *dev = platform_get_drvdata(pdev); u32 tmp; DEBUG_PM("[%s]: System Resume \n", __func__); #if NO_USING_USB_SWITCH DEBUG_PM("[%s]: NO_USING_USB_SWITCH just return\n", __func__); return 0; #endif //if not suspended as connected if (dev->udc_resume_state == USB_STATE_CONFIGURED) { DEBUG_PM("[%s]: USB connected before suspend \n", __func__); } else { DEBUG_PM("[%s]: USB not connected before suspend\n", __func__); return 0; } switch(pm_policy) { case ALL_POWER_DOWN: s3c_udc_power_up(); break; case CLOCK_GATING: s3c_udc_resume_clock_gating(); break; case OPHYPWR_FORCE_SUSPEND: tmp = readl(S3C_USBOTG_PHYPWR); tmp &= ~(1<<FORCE_SUSPEND); writel(tmp, S3C_USBOTG_PHYPWR); break; default: DEBUG_ERROR("[%s]: not proper pm_policy\n", __func__); } return 0; #endif #endif }
/* * power down s3c-udc power & disable otg clock */ void s3c_udc_power_down(void) { struct s3c_udc *dev = the_controller; unsigned long flags; /* Confirm No caller with spin_lock come here */ if (dev->udc_state != USB_STATE_SUSPENDED && dev->gadget.speed != USB_SPEED_UNKNOWN ) { //s3c_udc_set_disconnect_state(dev); S3C_UDC_LOCK_IRQSAVE(&dev->lock, flags); s3c_udc_stop_activity(dev, dev->driver); S3C_UDC_UNLOCK_IRQRESTORE(&dev->lock, flags); } if(dev->udc_state > USB_STATE_NOTATTACHED) { /* s3c_udc_disable() set dev->udc_state = USB_STATE_NOTATTACHED; */ s3c_udc_disable(dev); S3C_UDC_POWER_OFF: if(dev->clocked) { if (!IS_ERR(otg_clock) && otg_clock != NULL) { clk_disable(otg_clock); dev->clocked = 0; DEBUG_PM("[%s] clk_disable() OK.\n", __func__); } else DEBUG_ERROR("[%s] otg_clock error\n", __func__); } else DEBUG_PM("[%s] already clk_disabled\n", __func__); fsa9480_s3c_udc_off(); if(dev->clocked) { /* Just in case */ DEBUG_ERROR("\n[%s] readl(S3C_UDC_OTG_GINTMSK) || dev->clocked\n", __func__); DEBUG_ERROR("\n[%s] Power OFF again.\n", __func__); goto S3C_UDC_POWER_OFF; } DEBUG_PM("[%s] \n", __func__); } else { DEBUG_PM("[%s] skipped , already powered off\n", __func__); if(dev->clocked) { /* Just in case */ DEBUG_ERROR("\n[%s] readl(S3C_UDC_OTG_GINTMSK) || dev->clocked\n", __func__); DEBUG_ERROR("\n[%s] Power OFF again.\n", __func__); goto S3C_UDC_POWER_OFF; } } dev->powered = 0; #ifdef CONFIG_CPU_FREQ set_dvfs_level(1); #endif /* CONFIG_CPU_FREQ */ }
/* * AHB clock gating for suspend */ int s3c_udc_suspend_clock_gating(void) { u32 uReg; DEBUG_PM("[%s]\n", __func__); uReg = readl(S3C_UDC_OTG_PCGCCTL); writel(uReg|1<<STOP_PCLK_BIT|1<<GATE_HCLK_BIT, S3C_UDC_OTG_PCGCCTL); DEBUG_PM("[%s] : S3C_UDC_OTG_PCGCCTL 0x%x \n", __func__, uReg); return 0; }
/* * AHB clock gating for resume */ int s3c_udc_resume_clock_gating(void) { u32 uReg; DEBUG_PM("[%s]\n", __FUNCTION__); uReg = readl(S3C_UDC_OTG_PCGCCTL); uReg &= ~(1<<STOP_PCLK_BIT|1<<GATE_HCLK_BIT); writel(uReg, S3C_UDC_OTG_PCGCCTL); DEBUG_PM("[%s] : S3C_UDC_OTG_PCGCCTL 0x%x \n", __FUNCTION__, uReg); return 0; }
/* * power down s3c-udc power & disable otg clock */ void s3c_udc_power_down(void) { struct s3c_udc *dev = the_controller; /* Confirm */ if (dev->udc_state != USB_STATE_SUSPENDED) { //s3c_udc_set_disconnect_state(dev); s3c_udc_stop_activity(dev, dev->driver); } if(dev->udc_state > USB_STATE_NOTATTACHED) { /* s3c_udc_disable() set dev->udc_state = USB_STATE_NOTATTACHED; */ s3c_udc_disable(dev); S3C_UDC_POWER_OFF: if(dev->clocked) { if (!IS_ERR(otg_clock) && otg_clock != NULL) { clk_disable(otg_clock); dev->clocked = 0; DEBUG_PM("[%s] clk_disable() OK.\n", __func__); } else DEBUG_ERROR("[%s] otg_clock error\n", __func__); } else DEBUG_PM("[%s] already clk_disabled\n", __func__); fsa9480_s3c_udc_off(); if(dev->clocked) { /* Just in case */ DEBUG_ERROR("\n[%s] readl(S3C_UDC_OTG_GINTMSK) || dev->clocked\n", __func__); DEBUG_ERROR("\n[%s] Power OFF again.\n", __func__); goto S3C_UDC_POWER_OFF; } DEBUG_PM("[%s] \n", __func__); } else { DEBUG_PM("[%s] skipped , already powered off\n", __func__); if(dev->clocked) { /* Just in case */ DEBUG_ERROR("\n[%s] readl(S3C_UDC_OTG_GINTMSK) || dev->clocked\n", __func__); DEBUG_ERROR("\n[%s] Power OFF again.\n", __func__); goto S3C_UDC_POWER_OFF; } } dev->powered = 0; }
/* * power up s3c-udc power & enable otg clock */ void s3c_udc_power_up(void) { struct s3c_udc *dev = the_controller; #ifdef CONFIG_CPU_FREQ set_dvfs_level(0); #endif /* CONFIG_CPU_FREQ */ if(dev->udc_state == USB_STATE_NOTATTACHED) { DEBUG_PM("[%s] \n", __func__); S3C_UDC_POWER_UP: fsa9480_s3c_udc_on(); if(!dev->clocked) { if(clk_enable(otg_clock) != 0) { DEBUG_ERROR("\n[%s] clk_enable(otg_clock) failed.\n", __func__); } else { dev->clocked = 1; DEBUG_PM("\n[%s] clk_enable(otg_clock) OK.\n", __func__); } } else DEBUG_PM("\n[%s] already clk_enabled.\n", __func__); if(s3c_udc_enable(dev) != 0 || !dev->clocked) { /* Just in case */ DEBUG_ERROR("\n[%s] FAIL TO s3c_udc_enable()\n", __func__); DEBUG_ERROR("\n[%s] Power UP again.\n", __func__); goto S3C_UDC_POWER_UP; } else DEBUG_PM("\n[%s] POWER-UP OK!.\n", __func__); } else { DEBUG_PM("[%s] skipped , already powered up\n", __func__); if(!readl(S3C_UDC_OTG_GINTMSK) || !dev->clocked) { /* Just in case */ DEBUG_ERROR("\n[%s] !readl(S3C_UDC_OTG_GINTMSK) || !dev->clocked\n", __func__); DEBUG_ERROR("\n[%s] Power UP again.\n", __func__); goto S3C_UDC_POWER_UP; } } dev->powered = 1; }
/* * usb_gadget_ops pullup */ static int s3c_udc_pullup(struct usb_gadget *gadget, int is_on) { //#ifdef CONFIG_PM #if 0 //logical if (is_on) { s3c_udc_soft_connect(); } else { s3c_udc_soft_disconnect(); } #else struct s3c_udc *dev = the_controller; unsigned long flags; //UDC power on/off if (is_on) { DEBUG_PM("[%s] is_on[%d]\n", __func__, is_on); /* * if early s3c_udc_power_up make * fsa9480_check_usb_connection failed to detect USB connection */ #if NO_USING_USB_SWITCH s3c_udc_power_up(); #else fsa9480_check_usb_connection(); #endif } else { DEBUG_PM("[%s] is_on[%d]\n", __func__, is_on); S3C_UDC_LOCK_IRQSAVE(&dev->lock, flags); s3c_udc_stop_activity(dev, dev->driver); s3c_udc_power_down(); S3C_UDC_UNLOCK_IRQRESTORE(&dev->lock, flags); } #endif return 0; }
/* * s3c_udc_disable - disable USB device controller */ static void s3c_udc_disable(struct s3c_udc *dev) { DEBUG_PM("%s: %p\n", __func__, dev); s3c_udc_set_address(dev, 0); dev->ep0state = WAIT_FOR_SETUP; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->udc_state = USB_STATE_NOTATTACHED; writel(readl(S3C_USBOTG_PHYPWR)|(1<<OTG_DISABLE)|(1<<ANALOG_POWERDOWN), S3C_USBOTG_PHYPWR); }
static int s3c_udc_resume(struct platform_device *pdev) { // struct s3c_udc *dev = platform_get_drvdata(pdev); u32 tmp; DEBUG_PM("[%s]: System Resume \n", __FUNCTION__); //if not suspended as connected #ifndef CONFIG_MACH_SMDK6410 if (dev->udc_resume_state == USB_STATE_CONFIGURED) { DEBUG_PM("[%s]: USB connected before suspend \n", __FUNCTION__); } else { DEBUG_PM("[%s]: USB not connected before suspend\n", __FUNCTION__); return 0; } #endif /* CONFIG_MACH_SMDK6410 */ switch(pm_policy) { case ALL_POWER_DOWN: s3c_udc_power_up(); break; case CLOCK_GATING: s3c_udc_resume_clock_gating(); break; case OPHYPWR_FORCE_SUSPEND: tmp = readl(S3C_USBOTG_PHYPWR); tmp &= ~(1); writel(tmp, S3C_USBOTG_PHYPWR); break; default: printk("[%s]: not proper pm_policy\n", __FUNCTION__); } return 0; }
static int s3c_udc_suspend(struct platform_device *pdev, pm_message_t state) { struct s3c_udc *dev = platform_get_drvdata(pdev); DEBUG_PM("[%s]: System Suspend \n", __FUNCTION__); //save the state of connection to udc_resume_state if (dev->gadget.speed != USB_SPEED_UNKNOWN) { dev->udc_resume_state = dev->udc_state; DEBUG_PM("[%s]: USB connected at suspend\n", __FUNCTION__); } else { dev->udc_resume_state = dev->udc_state; DEBUG_PM("[%s]: USB not connected at suspend\n", __FUNCTION__); } switch(pm_policy) { case ALL_POWER_DOWN: s3c_udc_soft_disconnect(); stop_activity(dev, dev->driver); //confirm clk disable s3c_udc_power_down(); break; case CLOCK_GATING: s3c_udc_suspend_clock_gating(); break; case OPHYPWR_FORCE_SUSPEND: writel((readl(S3C_USBOTG_PHYPWR)|1), S3C_USBOTG_PHYPWR); break; default: printk("[%s]: not proper pm_policy\n", __FUNCTION__); } return 0; }
static int s3c_udc_suspend(struct platform_device *pdev, pm_message_t state) { struct s3c_udc *dev = platform_get_drvdata(pdev); unsigned long flags; DEBUG_PM("[%s]: System Suspend \n", __func__); #if NO_USING_USB_SWITCH DEBUG_PM("[%s]: NO_USING_USB_SWITCH just return\n", __func__); return 0; #endif spin_lock_irqsave(&dev->lock, flags); //save the state of connection to udc_resume_state dev->udc_resume_state = dev->udc_state; dev->udc_resume_speed = dev->gadget.speed; if (dev->gadget.speed != USB_SPEED_UNKNOWN) { DEBUG_PM("[%s]: USB enumerated at suspend\n", __func__); //s3c_udc_soft_disconnect(); s3c_udc_stop_activity(dev, dev->driver); } else { DEBUG_PM("[%s] USB not enumerated at suspend\n", __func__); DEBUG_PM("[%s] dev->powered [%d] at suspend\n", __func__, dev->powered); if (dev->powered == 0) { DEBUG_PM("[%s] skip~~ s3c_udc_power_down() at suspend\n", __func__); spin_unlock_irqrestore(&dev->lock, flags); return 0; } } switch(pm_policy) { case ALL_POWER_DOWN: // s3c_udc_stop_activity(dev, dev->driver); //confirm clk disable s3c_udc_power_down(); break; case CLOCK_GATING: s3c_udc_suspend_clock_gating(); break; case OPHYPWR_FORCE_SUSPEND: writel((readl(S3C_USBOTG_PHYPWR)|(1<<FORCE_SUSPEND)), S3C_USBOTG_PHYPWR); break; default: DEBUG_ERROR("[%s]: not proper pm_policy\n", __func__); } spin_unlock_irqrestore(&dev->lock, flags); return 0; }
/* * s3c_udc_disable - disable USB device controller */ static void s3c_udc_disable(struct s3c_udc *dev) { DEBUG_PM("%s: %p\n", __func__, dev); s3c_udc_set_address(dev, 0); //resolved system lockup at switching usb settings mode writel(CORE_SOFT_RESET, S3C_UDC_OTG_GRSTCTL); while(!(readl(S3C_UDC_OTG_GRSTCTL) & (AHB_MASTER_IDLE))) {ndelay(1);} dev->ep0state = WAIT_FOR_SETUP; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->udc_state = USB_STATE_NOTATTACHED; #if USING_MACH_OTG_PHY otg_phy_off(); #else writel(readl(S3C_USBOTG_PHYPWR)|(0x1F<<1), S3C_USBOTG_PHYPWR); writel(0, S5P_USB_PHY_CONTROL); #endif }