aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/mmci.c
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-09-04 04:05:17 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2013-09-19 15:12:25 -0400
commit1ff44433c661c30afde6e6d2c47a29039a293da4 (patch)
tree6b7629a39c594b3662ac7e7cc31e556829bdfcfb /drivers/mmc/host/mmci.c
parentf829c04204de83aa0d13307d2a2dc07c0d9a94e3 (diff)
ARM: 7834/1: mmc: mmci: Save and restore register context
If a corresponding power domain exists for the device and it manages to cut the domain regulator while the device is runtime suspended, the IP loses it's registers context. We restore the context in the .runtime_resume callback from the existing register caches to adapt to this situation. We also want to make sure the registers are in a known state while restoring context in the case when the power domain did not drop the power, since there are restrictions for the order of writing to these registers. To handle this, we clear the registers in the .runtime_suspend callback. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Rickard Andersson <rickard.andersson@stericsson.com> Reviewed-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc/host/mmci.c')
-rw-r--r--drivers/mmc/host/mmci.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 604e41db00db..d135c76c4855 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -62,6 +62,7 @@ static unsigned int fmax = 515633;
62 * @signal_direction: input/out direction of bus signals can be indicated 62 * @signal_direction: input/out direction of bus signals can be indicated
63 * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock 63 * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
64 * @busy_detect: true if busy detection on dat0 is supported 64 * @busy_detect: true if busy detection on dat0 is supported
65 * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
65 */ 66 */
66struct variant_data { 67struct variant_data {
67 unsigned int clkreg; 68 unsigned int clkreg;
@@ -76,6 +77,7 @@ struct variant_data {
76 bool signal_direction; 77 bool signal_direction;
77 bool pwrreg_clkgate; 78 bool pwrreg_clkgate;
78 bool busy_detect; 79 bool busy_detect;
80 bool pwrreg_nopower;
79}; 81};
80 82
81static struct variant_data variant_arm = { 83static struct variant_data variant_arm = {
@@ -109,6 +111,7 @@ static struct variant_data variant_u300 = {
109 .pwrreg_powerup = MCI_PWR_ON, 111 .pwrreg_powerup = MCI_PWR_ON,
110 .signal_direction = true, 112 .signal_direction = true,
111 .pwrreg_clkgate = true, 113 .pwrreg_clkgate = true,
114 .pwrreg_nopower = true,
112}; 115};
113 116
114static struct variant_data variant_nomadik = { 117static struct variant_data variant_nomadik = {
@@ -121,6 +124,7 @@ static struct variant_data variant_nomadik = {
121 .pwrreg_powerup = MCI_PWR_ON, 124 .pwrreg_powerup = MCI_PWR_ON,
122 .signal_direction = true, 125 .signal_direction = true,
123 .pwrreg_clkgate = true, 126 .pwrreg_clkgate = true,
127 .pwrreg_nopower = true,
124}; 128};
125 129
126static struct variant_data variant_ux500 = { 130static struct variant_data variant_ux500 = {
@@ -135,6 +139,7 @@ static struct variant_data variant_ux500 = {
135 .signal_direction = true, 139 .signal_direction = true,
136 .pwrreg_clkgate = true, 140 .pwrreg_clkgate = true,
137 .busy_detect = true, 141 .busy_detect = true,
142 .pwrreg_nopower = true,
138}; 143};
139 144
140static struct variant_data variant_ux500v2 = { 145static struct variant_data variant_ux500v2 = {
@@ -150,6 +155,7 @@ static struct variant_data variant_ux500v2 = {
150 .signal_direction = true, 155 .signal_direction = true,
151 .pwrreg_clkgate = true, 156 .pwrreg_clkgate = true,
152 .busy_detect = true, 157 .busy_detect = true,
158 .pwrreg_nopower = true,
153}; 159};
154 160
155static int mmci_card_busy(struct mmc_host *mmc) 161static int mmci_card_busy(struct mmc_host *mmc)
@@ -1759,6 +1765,41 @@ static int mmci_resume(struct device *dev)
1759#endif 1765#endif
1760 1766
1761#ifdef CONFIG_PM_RUNTIME 1767#ifdef CONFIG_PM_RUNTIME
1768static void mmci_save(struct mmci_host *host)
1769{
1770 unsigned long flags;
1771
1772 if (host->variant->pwrreg_nopower) {
1773 spin_lock_irqsave(&host->lock, flags);
1774
1775 writel(0, host->base + MMCIMASK0);
1776 writel(0, host->base + MMCIDATACTRL);
1777 writel(0, host->base + MMCIPOWER);
1778 writel(0, host->base + MMCICLOCK);
1779 mmci_reg_delay(host);
1780
1781 spin_unlock_irqrestore(&host->lock, flags);
1782 }
1783
1784}
1785
1786static void mmci_restore(struct mmci_host *host)
1787{
1788 unsigned long flags;
1789
1790 if (host->variant->pwrreg_nopower) {
1791 spin_lock_irqsave(&host->lock, flags);
1792
1793 writel(host->clk_reg, host->base + MMCICLOCK);
1794 writel(host->datactrl_reg, host->base + MMCIDATACTRL);
1795 writel(host->pwr_reg, host->base + MMCIPOWER);
1796 writel(MCI_IRQENABLE, host->base + MMCIMASK0);
1797 mmci_reg_delay(host);
1798
1799 spin_unlock_irqrestore(&host->lock, flags);
1800 }
1801}
1802
1762static int mmci_runtime_suspend(struct device *dev) 1803static int mmci_runtime_suspend(struct device *dev)
1763{ 1804{
1764 struct amba_device *adev = to_amba_device(dev); 1805 struct amba_device *adev = to_amba_device(dev);
@@ -1767,6 +1808,7 @@ static int mmci_runtime_suspend(struct device *dev)
1767 if (mmc) { 1808 if (mmc) {
1768 struct mmci_host *host = mmc_priv(mmc); 1809 struct mmci_host *host = mmc_priv(mmc);
1769 pinctrl_pm_select_sleep_state(dev); 1810 pinctrl_pm_select_sleep_state(dev);
1811 mmci_save(host);
1770 clk_disable_unprepare(host->clk); 1812 clk_disable_unprepare(host->clk);
1771 } 1813 }
1772 1814
@@ -1781,6 +1823,7 @@ static int mmci_runtime_resume(struct device *dev)
1781 if (mmc) { 1823 if (mmc) {
1782 struct mmci_host *host = mmc_priv(mmc); 1824 struct mmci_host *host = mmc_priv(mmc);
1783 clk_prepare_enable(host->clk); 1825 clk_prepare_enable(host->clk);
1826 mmci_restore(host);
1784 pinctrl_pm_select_default_state(dev); 1827 pinctrl_pm_select_default_state(dev);
1785 } 1828 }
1786 1829