Skip to content

Commit 13b7ee2

Browse files
vdsaogregkh
authored andcommitted
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>
1 parent 3dacdf1 commit 13b7ee2

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

drivers/usb/host/ehci-fsl.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,149 @@ struct ehci_fsl {
328328

329329
#ifdef CONFIG_PM
330330

331+
#ifdef CONFIG_PPC_MPC512x
332+
static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
333+
{
334+
struct usb_hcd *hcd = dev_get_drvdata(dev);
335+
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
336+
struct fsl_usb2_platform_data *pdata = dev->platform_data;
337+
u32 tmp;
338+
339+
#ifdef DEBUG
340+
u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
341+
mode &= USBMODE_CM_MASK;
342+
tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
343+
344+
dev_dbg(dev, "suspend=%d already_suspended=%d "
345+
"mode=%d usbcmd %08x\n", pdata->suspended,
346+
pdata->already_suspended, mode, tmp);
347+
#endif
348+
349+
/*
350+
* If the controller is already suspended, then this must be a
351+
* PM suspend. Remember this fact, so that we will leave the
352+
* controller suspended at PM resume time.
353+
*/
354+
if (pdata->suspended) {
355+
dev_dbg(dev, "already suspended, leaving early\n");
356+
pdata->already_suspended = 1;
357+
return 0;
358+
}
359+
360+
dev_dbg(dev, "suspending...\n");
361+
362+
hcd->state = HC_STATE_SUSPENDED;
363+
dev->power.power_state = PMSG_SUSPEND;
364+
365+
/* ignore non-host interrupts */
366+
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
367+
368+
/* stop the controller */
369+
tmp = ehci_readl(ehci, &ehci->regs->command);
370+
tmp &= ~CMD_RUN;
371+
ehci_writel(ehci, tmp, &ehci->regs->command);
372+
373+
/* save EHCI registers */
374+
pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
375+
pdata->pm_command &= ~CMD_RUN;
376+
pdata->pm_status = ehci_readl(ehci, &ehci->regs->status);
377+
pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
378+
pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
379+
pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
380+
pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
381+
pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
382+
pdata->pm_configured_flag =
383+
ehci_readl(ehci, &ehci->regs->configured_flag);
384+
pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
385+
pdata->pm_usbgenctrl = ehci_readl(ehci,
386+
hcd->regs + FSL_SOC_USB_USBGENCTRL);
387+
388+
/* clear the W1C bits */
389+
pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
390+
391+
pdata->suspended = 1;
392+
393+
/* clear PP to cut power to the port */
394+
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
395+
tmp &= ~PORT_POWER;
396+
ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
397+
398+
return 0;
399+
}
400+
401+
static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
402+
{
403+
struct usb_hcd *hcd = dev_get_drvdata(dev);
404+
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
405+
struct fsl_usb2_platform_data *pdata = dev->platform_data;
406+
u32 tmp;
407+
408+
dev_dbg(dev, "suspend=%d already_suspended=%d\n",
409+
pdata->suspended, pdata->already_suspended);
410+
411+
/*
412+
* If the controller was already suspended at suspend time,
413+
* then don't resume it now.
414+
*/
415+
if (pdata->already_suspended) {
416+
dev_dbg(dev, "already suspended, leaving early\n");
417+
pdata->already_suspended = 0;
418+
return 0;
419+
}
420+
421+
if (!pdata->suspended) {
422+
dev_dbg(dev, "not suspended, leaving early\n");
423+
return 0;
424+
}
425+
426+
pdata->suspended = 0;
427+
428+
dev_dbg(dev, "resuming...\n");
429+
430+
/* set host mode */
431+
tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
432+
ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
433+
434+
ehci_writel(ehci, pdata->pm_usbgenctrl,
435+
hcd->regs + FSL_SOC_USB_USBGENCTRL);
436+
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
437+
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
438+
439+
/* restore EHCI registers */
440+
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
441+
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
442+
ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
443+
ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
444+
ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
445+
ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
446+
ehci_writel(ehci, pdata->pm_configured_flag,
447+
&ehci->regs->configured_flag);
448+
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
449+
450+
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
451+
hcd->state = HC_STATE_RUNNING;
452+
dev->power.power_state = PMSG_ON;
453+
454+
tmp = ehci_readl(ehci, &ehci->regs->command);
455+
tmp |= CMD_RUN;
456+
ehci_writel(ehci, tmp, &ehci->regs->command);
457+
458+
usb_hcd_resume_root_hub(hcd);
459+
460+
return 0;
461+
}
462+
#else
463+
static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
464+
{
465+
return 0;
466+
}
467+
468+
static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
469+
{
470+
return 0;
471+
}
472+
#endif /* CONFIG_PPC_MPC512x */
473+
331474
static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
332475
{
333476
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -341,6 +484,11 @@ static int ehci_fsl_drv_suspend(struct device *dev)
341484
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
342485
void __iomem *non_ehci = hcd->regs;
343486

487+
if (of_device_is_compatible(dev->parent->of_node,
488+
"fsl,mpc5121-usb2-dr")) {
489+
return ehci_fsl_mpc512x_drv_suspend(dev);
490+
}
491+
344492
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
345493
device_may_wakeup(dev));
346494
if (!fsl_deep_sleep())
@@ -357,6 +505,11 @@ static int ehci_fsl_drv_resume(struct device *dev)
357505
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
358506
void __iomem *non_ehci = hcd->regs;
359507

508+
if (of_device_is_compatible(dev->parent->of_node,
509+
"fsl,mpc5121-usb2-dr")) {
510+
return ehci_fsl_mpc512x_drv_resume(dev);
511+
}
512+
360513
ehci_prepare_ports_for_controller_resume(ehci);
361514
if (!fsl_deep_sleep())
362515
return 0;

drivers/usb/host/ehci-fsl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#define PORT_PTS_SERIAL (3<<30)
2828
#define PORT_PTS_PTW (1<<28)
2929
#define FSL_SOC_USB_PORTSC2 0x188
30+
#define FSL_SOC_USB_USBMODE 0x1a8
31+
#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
32+
#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
33+
#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
3034

3135
#define FSL_SOC_USB_USBGENCTRL 0x200
3236
#define USBGENCTRL_PPP (1 << 3)

include/linux/fsl_devices.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@ struct fsl_usb2_platform_data {
7979
unsigned have_sysif_regs:1;
8080
unsigned invert_drvvbus:1;
8181
unsigned invert_pwr_fault:1;
82+
83+
unsigned suspended:1;
84+
unsigned already_suspended:1;
85+
86+
/* register save area for suspend/resume */
87+
u32 pm_command;
88+
u32 pm_status;
89+
u32 pm_intr_enable;
90+
u32 pm_frame_index;
91+
u32 pm_segment;
92+
u32 pm_frame_list;
93+
u32 pm_async_next;
94+
u32 pm_configured_flag;
95+
u32 pm_portsc;
96+
u32 pm_usbgenctrl;
8297
};
8398

8499
/* Flags in fsl_usb2_mph_platform_data */

0 commit comments

Comments
 (0)