Commit 13b7ee2a953f07d994b6bc3439cdd4a718de6f80

Authored by Anatolij Gustschin
Committed by Greg Kroah-Hartman
1 parent 3dacdf11f1

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>

Showing 3 changed files with 172 additions and 0 deletions Side-by-side Diff

drivers/usb/host/ehci-fsl.c
... ... @@ -328,6 +328,149 @@
328 328  
329 329 #ifdef CONFIG_PM
330 330  
  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 +
331 474 static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
332 475 {
333 476 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
... ... @@ -341,6 +484,11 @@
341 484 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
342 485 void __iomem *non_ehci = hcd->regs;
343 486  
  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 +
344 492 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
345 493 device_may_wakeup(dev));
346 494 if (!fsl_deep_sleep())
... ... @@ -356,6 +504,11 @@
356 504 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
357 505 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
358 506 void __iomem *non_ehci = hcd->regs;
  507 +
  508 + if (of_device_is_compatible(dev->parent->of_node,
  509 + "fsl,mpc5121-usb2-dr")) {
  510 + return ehci_fsl_mpc512x_drv_resume(dev);
  511 + }
359 512  
360 513 ehci_prepare_ports_for_controller_resume(ehci);
361 514 if (!fsl_deep_sleep())
drivers/usb/host/ehci-fsl.h
... ... @@ -27,6 +27,10 @@
27 27 #define PORT_PTS_SERIAL (3<<30)
28 28 #define PORT_PTS_PTW (1<<28)
29 29 #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 */
30 34  
31 35 #define FSL_SOC_USB_USBGENCTRL 0x200
32 36 #define USBGENCTRL_PPP (1 << 3)
include/linux/fsl_devices.h
... ... @@ -79,6 +79,21 @@
79 79 unsigned have_sysif_regs:1;
80 80 unsigned invert_drvvbus:1;
81 81 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;
82 97 };
83 98  
84 99 /* Flags in fsl_usb2_mph_platform_data */