diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-s3c.c')
-rw-r--r-- | drivers/mmc/host/sdhci-s3c.c | 78 |
1 files changed, 17 insertions, 61 deletions
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 7e14db07eb30..bad0e00a3e8f 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c | |||
@@ -51,7 +51,7 @@ struct sdhci_s3c { | |||
51 | struct platform_device *pdev; | 51 | struct platform_device *pdev; |
52 | struct resource *ioarea; | 52 | struct resource *ioarea; |
53 | struct s3c_sdhci_platdata *pdata; | 53 | struct s3c_sdhci_platdata *pdata; |
54 | unsigned int cur_clk; | 54 | int cur_clk; |
55 | int ext_cd_irq; | 55 | int ext_cd_irq; |
56 | int ext_cd_gpio; | 56 | int ext_cd_gpio; |
57 | 57 | ||
@@ -78,32 +78,6 @@ static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) | |||
78 | } | 78 | } |
79 | 79 | ||
80 | /** | 80 | /** |
81 | * get_curclk - convert ctrl2 register to clock source number | ||
82 | * @ctrl2: Control2 register value. | ||
83 | */ | ||
84 | static u32 get_curclk(u32 ctrl2) | ||
85 | { | ||
86 | ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; | ||
87 | ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; | ||
88 | |||
89 | return ctrl2; | ||
90 | } | ||
91 | |||
92 | static void sdhci_s3c_check_sclk(struct sdhci_host *host) | ||
93 | { | ||
94 | struct sdhci_s3c *ourhost = to_s3c(host); | ||
95 | u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2); | ||
96 | |||
97 | if (get_curclk(tmp) != ourhost->cur_clk) { | ||
98 | dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n"); | ||
99 | |||
100 | tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; | ||
101 | tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; | ||
102 | writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * sdhci_s3c_get_max_clk - callback to get maximum clock frequency. | 81 | * sdhci_s3c_get_max_clk - callback to get maximum clock frequency. |
108 | * @host: The SDHCI host instance. | 82 | * @host: The SDHCI host instance. |
109 | * | 83 | * |
@@ -115,11 +89,6 @@ static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host) | |||
115 | unsigned long rate, max = 0; | 89 | unsigned long rate, max = 0; |
116 | int src; | 90 | int src; |
117 | 91 | ||
118 | /* note, a reset will reset the clock source */ | ||
119 | |||
120 | sdhci_s3c_check_sclk(host); | ||
121 | |||
122 | |||
123 | for (src = 0; src < MAX_BUS_CLK; src++) { | 92 | for (src = 0; src < MAX_BUS_CLK; src++) { |
124 | rate = ourhost->clk_rates[src]; | 93 | rate = ourhost->clk_rates[src]; |
125 | if (rate > max) | 94 | if (rate > max) |
@@ -206,20 +175,22 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) | |||
206 | struct clk *clk = ourhost->clk_bus[best_src]; | 175 | struct clk *clk = ourhost->clk_bus[best_src]; |
207 | 176 | ||
208 | clk_prepare_enable(clk); | 177 | clk_prepare_enable(clk); |
209 | clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); | 178 | if (ourhost->cur_clk >= 0) |
210 | 179 | clk_disable_unprepare( | |
211 | /* turn clock off to card before changing clock source */ | 180 | ourhost->clk_bus[ourhost->cur_clk]); |
212 | writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); | ||
213 | 181 | ||
214 | ourhost->cur_clk = best_src; | 182 | ourhost->cur_clk = best_src; |
215 | host->max_clk = ourhost->clk_rates[best_src]; | 183 | host->max_clk = ourhost->clk_rates[best_src]; |
216 | |||
217 | ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); | ||
218 | ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; | ||
219 | ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; | ||
220 | writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); | ||
221 | } | 184 | } |
222 | 185 | ||
186 | /* turn clock off to card before changing clock source */ | ||
187 | writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); | ||
188 | |||
189 | ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); | ||
190 | ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; | ||
191 | ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; | ||
192 | writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); | ||
193 | |||
223 | /* reprogram default hardware configuration */ | 194 | /* reprogram default hardware configuration */ |
224 | writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, | 195 | writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, |
225 | host->ioaddr + S3C64XX_SDHCI_CONTROL4); | 196 | host->ioaddr + S3C64XX_SDHCI_CONTROL4); |
@@ -573,6 +544,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) | |||
573 | sc->host = host; | 544 | sc->host = host; |
574 | sc->pdev = pdev; | 545 | sc->pdev = pdev; |
575 | sc->pdata = pdata; | 546 | sc->pdata = pdata; |
547 | sc->cur_clk = -1; | ||
576 | 548 | ||
577 | platform_set_drvdata(pdev, host); | 549 | platform_set_drvdata(pdev, host); |
578 | 550 | ||
@@ -595,13 +567,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) | |||
595 | continue; | 567 | continue; |
596 | 568 | ||
597 | clks++; | 569 | clks++; |
598 | |||
599 | /* | ||
600 | * save current clock index to know which clock bus | ||
601 | * is used later in overriding functions. | ||
602 | */ | ||
603 | sc->cur_clk = ptr; | ||
604 | |||
605 | sc->clk_rates[ptr] = clk_get_rate(sc->clk_bus[ptr]); | 570 | sc->clk_rates[ptr] = clk_get_rate(sc->clk_bus[ptr]); |
606 | 571 | ||
607 | dev_info(dev, "clock source %d: %s (%ld Hz)\n", | 572 | dev_info(dev, "clock source %d: %s (%ld Hz)\n", |
@@ -614,10 +579,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) | |||
614 | goto err_no_busclks; | 579 | goto err_no_busclks; |
615 | } | 580 | } |
616 | 581 | ||
617 | #ifndef CONFIG_PM_RUNTIME | ||
618 | clk_prepare_enable(sc->clk_bus[sc->cur_clk]); | ||
619 | #endif | ||
620 | |||
621 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 582 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
622 | host->ioaddr = devm_ioremap_resource(&pdev->dev, res); | 583 | host->ioaddr = devm_ioremap_resource(&pdev->dev, res); |
623 | if (IS_ERR(host->ioaddr)) { | 584 | if (IS_ERR(host->ioaddr)) { |
@@ -730,10 +691,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) | |||
730 | return 0; | 691 | return 0; |
731 | 692 | ||
732 | err_req_regs: | 693 | err_req_regs: |
733 | #ifndef CONFIG_PM_RUNTIME | ||
734 | clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); | ||
735 | #endif | ||
736 | |||
737 | err_no_busclks: | 694 | err_no_busclks: |
738 | clk_disable_unprepare(sc->clk_io); | 695 | clk_disable_unprepare(sc->clk_io); |
739 | 696 | ||
@@ -764,9 +721,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev) | |||
764 | pm_runtime_dont_use_autosuspend(&pdev->dev); | 721 | pm_runtime_dont_use_autosuspend(&pdev->dev); |
765 | pm_runtime_disable(&pdev->dev); | 722 | pm_runtime_disable(&pdev->dev); |
766 | 723 | ||
767 | #ifndef CONFIG_PM_RUNTIME | ||
768 | clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); | ||
769 | #endif | ||
770 | clk_disable_unprepare(sc->clk_io); | 724 | clk_disable_unprepare(sc->clk_io); |
771 | 725 | ||
772 | sdhci_free_host(host); | 726 | sdhci_free_host(host); |
@@ -800,7 +754,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev) | |||
800 | 754 | ||
801 | ret = sdhci_runtime_suspend_host(host); | 755 | ret = sdhci_runtime_suspend_host(host); |
802 | 756 | ||
803 | clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); | 757 | if (ourhost->cur_clk >= 0) |
758 | clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); | ||
804 | clk_disable_unprepare(busclk); | 759 | clk_disable_unprepare(busclk); |
805 | return ret; | 760 | return ret; |
806 | } | 761 | } |
@@ -813,7 +768,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev) | |||
813 | int ret; | 768 | int ret; |
814 | 769 | ||
815 | clk_prepare_enable(busclk); | 770 | clk_prepare_enable(busclk); |
816 | clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); | 771 | if (ourhost->cur_clk >= 0) |
772 | clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); | ||
817 | ret = sdhci_runtime_resume_host(host); | 773 | ret = sdhci_runtime_resume_host(host); |
818 | return ret; | 774 | return ret; |
819 | } | 775 | } |