diff options
author | Daniel Mack <zonque@gmail.com> | 2013-11-26 07:31:14 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-11-26 11:58:16 -0500 |
commit | 869c597829817af4b9f85c5e4181c622918dc781 (patch) | |
tree | 412253db26f14c15ec9f41a8302cf6e422e1a609 /drivers/usb/musb/musb_dsps.c | |
parent | b991f9b77c029135f6e0d1d5d16869ebf755c4c0 (diff) |
usb: musb: dsps: add support for suspend and resume
The dsps platform needs to save save some registers at suspend time and
restore them after resume. This patch adds a struct for these registers,
and also lets the musb core know that the core registers need to be
saved as well.
We also have to explicitly de-assert the port reset upon resume on this
platform, but musb_port_reset() should not be called from glue layers.
Hence, introduce a flag in struct musb_hdrc_config for this.
Signed-off-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb/musb_dsps.c')
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 3f3724471667..7cfa6e80ad60 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
@@ -113,6 +113,19 @@ struct dsps_musb_wrapper { | |||
113 | u8 poll_seconds; | 113 | u8 poll_seconds; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | /* | ||
117 | * register shadow for suspend | ||
118 | */ | ||
119 | struct dsps_context { | ||
120 | u32 control; | ||
121 | u32 epintr; | ||
122 | u32 coreintr; | ||
123 | u32 phy_utmi; | ||
124 | u32 mode; | ||
125 | u32 tx_mode; | ||
126 | u32 rx_mode; | ||
127 | }; | ||
128 | |||
116 | /** | 129 | /** |
117 | * DSPS glue structure. | 130 | * DSPS glue structure. |
118 | */ | 131 | */ |
@@ -122,6 +135,8 @@ struct dsps_glue { | |||
122 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ | 135 | const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ |
123 | struct timer_list timer; /* otg_workaround timer */ | 136 | struct timer_list timer; /* otg_workaround timer */ |
124 | unsigned long last_timer; /* last timer data for each instance */ | 137 | unsigned long last_timer; /* last timer data for each instance */ |
138 | |||
139 | struct dsps_context context; | ||
125 | }; | 140 | }; |
126 | 141 | ||
127 | static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) | 142 | static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) |
@@ -559,6 +574,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, | |||
559 | 574 | ||
560 | config->num_eps = get_int_prop(dn, "mentor,num-eps"); | 575 | config->num_eps = get_int_prop(dn, "mentor,num-eps"); |
561 | config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); | 576 | config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); |
577 | config->host_port_deassert_reset_at_resume = 1; | ||
562 | pdata.mode = get_musb_port_mode(dev); | 578 | pdata.mode = get_musb_port_mode(dev); |
563 | /* DT keeps this entry in mA, musb expects it as per USB spec */ | 579 | /* DT keeps this entry in mA, musb expects it as per USB spec */ |
564 | pdata.power = get_int_prop(dn, "mentor,power") / 2; | 580 | pdata.power = get_int_prop(dn, "mentor,power") / 2; |
@@ -683,11 +699,52 @@ static const struct of_device_id musb_dsps_of_match[] = { | |||
683 | }; | 699 | }; |
684 | MODULE_DEVICE_TABLE(of, musb_dsps_of_match); | 700 | MODULE_DEVICE_TABLE(of, musb_dsps_of_match); |
685 | 701 | ||
702 | #ifdef CONFIG_PM | ||
703 | static int dsps_suspend(struct device *dev) | ||
704 | { | ||
705 | struct dsps_glue *glue = dev_get_drvdata(dev); | ||
706 | const struct dsps_musb_wrapper *wrp = glue->wrp; | ||
707 | struct musb *musb = platform_get_drvdata(glue->musb); | ||
708 | void __iomem *mbase = musb->ctrl_base; | ||
709 | |||
710 | glue->context.control = dsps_readl(mbase, wrp->control); | ||
711 | glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); | ||
712 | glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); | ||
713 | glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); | ||
714 | glue->context.mode = dsps_readl(mbase, wrp->mode); | ||
715 | glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); | ||
716 | glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int dsps_resume(struct device *dev) | ||
722 | { | ||
723 | struct dsps_glue *glue = dev_get_drvdata(dev); | ||
724 | const struct dsps_musb_wrapper *wrp = glue->wrp; | ||
725 | struct musb *musb = platform_get_drvdata(glue->musb); | ||
726 | void __iomem *mbase = musb->ctrl_base; | ||
727 | |||
728 | dsps_writel(mbase, wrp->control, glue->context.control); | ||
729 | dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); | ||
730 | dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); | ||
731 | dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); | ||
732 | dsps_writel(mbase, wrp->mode, glue->context.mode); | ||
733 | dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); | ||
734 | dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | #endif | ||
739 | |||
740 | static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); | ||
741 | |||
686 | static struct platform_driver dsps_usbss_driver = { | 742 | static struct platform_driver dsps_usbss_driver = { |
687 | .probe = dsps_probe, | 743 | .probe = dsps_probe, |
688 | .remove = dsps_remove, | 744 | .remove = dsps_remove, |
689 | .driver = { | 745 | .driver = { |
690 | .name = "musb-dsps", | 746 | .name = "musb-dsps", |
747 | .pm = &dsps_pm_ops, | ||
691 | .of_match_table = musb_dsps_of_match, | 748 | .of_match_table = musb_dsps_of_match, |
692 | }, | 749 | }, |
693 | }; | 750 | }; |