USB: ehci-fsl: add MPC5121E specific suspend and resume
Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
3dacdf11f1
commit
13b7ee2a95
@ -328,6 +328,149 @@ struct ehci_fsl {
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata = dev->platform_data;
|
||||
u32 tmp;
|
||||
|
||||
#ifdef DEBUG
|
||||
u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
|
||||
mode &= USBMODE_CM_MASK;
|
||||
tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
|
||||
|
||||
dev_dbg(dev, "suspend=%d already_suspended=%d "
|
||||
"mode=%d usbcmd %08x\n", pdata->suspended,
|
||||
pdata->already_suspended, mode, tmp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the controller is already suspended, then this must be a
|
||||
* PM suspend. Remember this fact, so that we will leave the
|
||||
* controller suspended at PM resume time.
|
||||
*/
|
||||
if (pdata->suspended) {
|
||||
dev_dbg(dev, "already suspended, leaving early\n");
|
||||
pdata->already_suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "suspending...\n");
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
dev->power.power_state = PMSG_SUSPEND;
|
||||
|
||||
/* ignore non-host interrupts */
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* stop the controller */
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
tmp &= ~CMD_RUN;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->command);
|
||||
|
||||
/* save EHCI registers */
|
||||
pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
|
||||
pdata->pm_command &= ~CMD_RUN;
|
||||
pdata->pm_status = ehci_readl(ehci, &ehci->regs->status);
|
||||
pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
|
||||
pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
|
||||
pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
|
||||
pdata->pm_configured_flag =
|
||||
ehci_readl(ehci, &ehci->regs->configured_flag);
|
||||
pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||
pdata->pm_usbgenctrl = ehci_readl(ehci,
|
||||
hcd->regs + FSL_SOC_USB_USBGENCTRL);
|
||||
|
||||
/* clear the W1C bits */
|
||||
pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
|
||||
|
||||
pdata->suspended = 1;
|
||||
|
||||
/* clear PP to cut power to the port */
|
||||
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||
tmp &= ~PORT_POWER;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata = dev->platform_data;
|
||||
u32 tmp;
|
||||
|
||||
dev_dbg(dev, "suspend=%d already_suspended=%d\n",
|
||||
pdata->suspended, pdata->already_suspended);
|
||||
|
||||
/*
|
||||
* If the controller was already suspended at suspend time,
|
||||
* then don't resume it now.
|
||||
*/
|
||||
if (pdata->already_suspended) {
|
||||
dev_dbg(dev, "already suspended, leaving early\n");
|
||||
pdata->already_suspended = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pdata->suspended) {
|
||||
dev_dbg(dev, "not suspended, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdata->suspended = 0;
|
||||
|
||||
dev_dbg(dev, "resuming...\n");
|
||||
|
||||
/* set host mode */
|
||||
tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
|
||||
ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
|
||||
|
||||
ehci_writel(ehci, pdata->pm_usbgenctrl,
|
||||
hcd->regs + FSL_SOC_USB_USBGENCTRL);
|
||||
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
|
||||
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
|
||||
|
||||
/* restore EHCI registers */
|
||||
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
|
||||
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
|
||||
ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
|
||||
ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
|
||||
ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
|
||||
ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
|
||||
ehci_writel(ehci, pdata->pm_configured_flag,
|
||||
&ehci->regs->configured_flag);
|
||||
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
dev->power.power_state = PMSG_ON;
|
||||
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
tmp |= CMD_RUN;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->command);
|
||||
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PPC_MPC512x */
|
||||
|
||||
static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
@ -341,6 +484,11 @@ static int ehci_fsl_drv_suspend(struct device *dev)
|
||||
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
return ehci_fsl_mpc512x_drv_suspend(dev);
|
||||
}
|
||||
|
||||
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
|
||||
device_may_wakeup(dev));
|
||||
if (!fsl_deep_sleep())
|
||||
@ -357,6 +505,11 @@ static int ehci_fsl_drv_resume(struct device *dev)
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
return ehci_fsl_mpc512x_drv_resume(dev);
|
||||
}
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!fsl_deep_sleep())
|
||||
return 0;
|
||||
|
@ -27,6 +27,10 @@
|
||||
#define PORT_PTS_SERIAL (3<<30)
|
||||
#define PORT_PTS_PTW (1<<28)
|
||||
#define FSL_SOC_USB_PORTSC2 0x188
|
||||
#define FSL_SOC_USB_USBMODE 0x1a8
|
||||
#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
|
||||
#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
|
||||
#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
|
||||
|
||||
#define FSL_SOC_USB_USBGENCTRL 0x200
|
||||
#define USBGENCTRL_PPP (1 << 3)
|
||||
|
@ -79,6 +79,21 @@ struct fsl_usb2_platform_data {
|
||||
unsigned have_sysif_regs:1;
|
||||
unsigned invert_drvvbus:1;
|
||||
unsigned invert_pwr_fault:1;
|
||||
|
||||
unsigned suspended:1;
|
||||
unsigned already_suspended:1;
|
||||
|
||||
/* register save area for suspend/resume */
|
||||
u32 pm_command;
|
||||
u32 pm_status;
|
||||
u32 pm_intr_enable;
|
||||
u32 pm_frame_index;
|
||||
u32 pm_segment;
|
||||
u32 pm_frame_list;
|
||||
u32 pm_async_next;
|
||||
u32 pm_configured_flag;
|
||||
u32 pm_portsc;
|
||||
u32 pm_usbgenctrl;
|
||||
};
|
||||
|
||||
/* Flags in fsl_usb2_mph_platform_data */
|
||||
|
Loading…
Reference in New Issue
Block a user