diff options
Diffstat (limited to 'drivers/mmc/host/mmci.c')
-rw-r--r-- | drivers/mmc/host/mmci.c | 43 |
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 | */ |
66 | struct variant_data { | 67 | struct 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 | ||
81 | static struct variant_data variant_arm = { | 83 | static 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 | ||
114 | static struct variant_data variant_nomadik = { | 117 | static 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 | ||
126 | static struct variant_data variant_ux500 = { | 130 | static 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 | ||
140 | static struct variant_data variant_ux500v2 = { | 145 | static 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 | ||
155 | static int mmci_card_busy(struct mmc_host *mmc) | 161 | static 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 |
1768 | static 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 | |||
1786 | static 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 | |||
1762 | static int mmci_runtime_suspend(struct device *dev) | 1803 | static 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 | ||