aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnatolij Gustschin <agust@denx.de>2011-04-18 16:01:55 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-02 19:59:36 -0400
commit13b7ee2a953f07d994b6bc3439cdd4a718de6f80 (patch)
tree186254ec05ef8b140dc9f191b36193c241a51012
parent3dacdf11f1f82b98d301d5e1d42cdaea9a39968a (diff)
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>
-rw-r--r--drivers/usb/host/ehci-fsl.c153
-rw-r--r--drivers/usb/host/ehci-fsl.h4
-rw-r--r--include/linux/fsl_devices.h15
3 files changed, 172 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 5c761df7fa83..caf3d4ac42bd 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -328,6 +328,149 @@ struct ehci_fsl {
328 328
329#ifdef CONFIG_PM 329#ifdef CONFIG_PM
330 330
331#ifdef CONFIG_PPC_MPC512x
332static 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
401static 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
463static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
464{
465 return 0;
466}
467
468static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
469{
470 return 0;
471}
472#endif /* CONFIG_PPC_MPC512x */
473
331static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) 474static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
332{ 475{
333 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 476 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -341,6 +484,11 @@ static int ehci_fsl_drv_suspend(struct device *dev)
341 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); 484 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
342 void __iomem *non_ehci = hcd->regs; 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 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), 492 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
345 device_may_wakeup(dev)); 493 device_may_wakeup(dev));
346 if (!fsl_deep_sleep()) 494 if (!fsl_deep_sleep())
@@ -357,6 +505,11 @@ static int ehci_fsl_drv_resume(struct device *dev)
357 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 505 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
358 void __iomem *non_ehci = hcd->regs; 506 void __iomem *non_ehci = hcd->regs;
359 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 }
512
360 ehci_prepare_ports_for_controller_resume(ehci); 513 ehci_prepare_ports_for_controller_resume(ehci);
361 if (!fsl_deep_sleep()) 514 if (!fsl_deep_sleep())
362 return 0; 515 return 0;
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 3fabed33d940..491806221165 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -27,6 +27,10 @@
27#define PORT_PTS_SERIAL (3<<30) 27#define PORT_PTS_SERIAL (3<<30)
28#define PORT_PTS_PTW (1<<28) 28#define PORT_PTS_PTW (1<<28)
29#define FSL_SOC_USB_PORTSC2 0x188 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#define FSL_SOC_USB_USBGENCTRL 0x200 35#define FSL_SOC_USB_USBGENCTRL 0x200
32#define USBGENCTRL_PPP (1 << 3) 36#define USBGENCTRL_PPP (1 << 3)
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 4eb56ed75fbc..3773c5dab8f5 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -79,6 +79,21 @@ struct fsl_usb2_platform_data {
79 unsigned have_sysif_regs:1; 79 unsigned have_sysif_regs:1;
80 unsigned invert_drvvbus:1; 80 unsigned invert_drvvbus:1;
81 unsigned invert_pwr_fault:1; 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/* Flags in fsl_usb2_mph_platform_data */ 99/* Flags in fsl_usb2_mph_platform_data */