diff options
author | San Mehat <san@google.com> | 2009-11-08 16:00:37 -0500 |
---|---|---|
committer | Daniel Walker <dwalker@codeaurora.org> | 2010-03-18 15:57:46 -0400 |
commit | 4adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80 (patch) | |
tree | eeb534208a0f77994594dfe0738c85d8ef8c27fa /drivers/mmc | |
parent | 5b8a2fb34f5670b1f07483bfa40de9ce539dbdb2 (diff) |
mmc: msm_sdcc: Clean up clock management and add a 10us delay after enabling clocks
It appears that in some cases there may be a delay on the ARM9 in enabling our clock.
As a result, we may put the controller into a bad state. Delay 10us after enabling
clocks to let the peripheral settle. Note - this is all imperical.
Also ensure set_ios() callback grabs the host lock.
Signed-off-by: San Mehat <san@google.com>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 80 |
1 files changed, 40 insertions, 40 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 4c068e5fe6b2..977932a4bf4b 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
@@ -735,20 +735,42 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
735 | spin_unlock_irqrestore(&host->lock, flags); | 735 | spin_unlock_irqrestore(&host->lock, flags); |
736 | } | 736 | } |
737 | 737 | ||
738 | static int inline | ||
739 | msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) | ||
740 | { | ||
741 | int rc; | ||
742 | if (enable) { | ||
743 | rc = clk_enable(host->pclk); | ||
744 | if (rc) | ||
745 | return rc; | ||
746 | rc = clk_enable(host->clk); | ||
747 | if (rc) { | ||
748 | clk_disable(host->pclk); | ||
749 | return rc; | ||
750 | } | ||
751 | host->clks_on = 1; | ||
752 | udelay(10); | ||
753 | } else { | ||
754 | clk_disable(host->clk); | ||
755 | clk_disable(host->pclk); | ||
756 | host->clks_on = 0; | ||
757 | } | ||
758 | return 0; | ||
759 | } | ||
760 | |||
738 | static void | 761 | static void |
739 | msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 762 | msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
740 | { | 763 | { |
741 | struct msmsdcc_host *host = mmc_priv(mmc); | 764 | struct msmsdcc_host *host = mmc_priv(mmc); |
742 | u32 clk = 0, pwr = 0; | 765 | u32 clk = 0, pwr = 0; |
743 | int rc; | 766 | int rc; |
767 | unsigned long flags; | ||
744 | 768 | ||
769 | spin_lock_irqsave(&host->lock, flags); | ||
745 | if (ios->clock) { | 770 | if (ios->clock) { |
746 | 771 | ||
747 | if (!host->clks_on) { | 772 | if (!host->clks_on) |
748 | clk_enable(host->pclk); | 773 | msmsdcc_enable_clocks(host, 1); |
749 | clk_enable(host->clk); | ||
750 | host->clks_on = 1; | ||
751 | } | ||
752 | if (ios->clock != host->clk_rate) { | 774 | if (ios->clock != host->clk_rate) { |
753 | rc = clk_set_rate(host->clk, ios->clock); | 775 | rc = clk_set_rate(host->clk, ios->clock); |
754 | if (rc < 0) | 776 | if (rc < 0) |
@@ -793,11 +815,9 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
793 | writel(pwr, host->base + MMCIPOWER); | 815 | writel(pwr, host->base + MMCIPOWER); |
794 | } | 816 | } |
795 | 817 | ||
796 | if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { | 818 | if (!(clk & MCI_CLK_ENABLE) && host->clks_on) |
797 | clk_disable(host->clk); | 819 | msmsdcc_enable_clocks(host, 0); |
798 | clk_disable(host->pclk); | 820 | spin_unlock_irqrestore(&host->lock, flags); |
799 | host->clks_on = 0; | ||
800 | } | ||
801 | } | 821 | } |
802 | 822 | ||
803 | static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | 823 | static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) |
@@ -899,7 +919,6 @@ msmsdcc_command_expired(unsigned long _data) | |||
899 | pr_err("%s: Command timeout (%p %p %p %p)\n", | 919 | pr_err("%s: Command timeout (%p %p %p %p)\n", |
900 | mmc_hostname(host->mmc), mrq, mrq->cmd, | 920 | mmc_hostname(host->mmc), mrq, mrq->cmd, |
901 | mrq->data, host->dma.sg); | 921 | mrq->data, host->dma.sg); |
902 | |||
903 | mrq->cmd->error = -ETIMEDOUT; | 922 | mrq->cmd->error = -ETIMEDOUT; |
904 | msmsdcc_stop_data(host); | 923 | msmsdcc_stop_data(host); |
905 | 924 | ||
@@ -1031,31 +1050,21 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1031 | */ | 1050 | */ |
1032 | msmsdcc_init_dma(host); | 1051 | msmsdcc_init_dma(host); |
1033 | 1052 | ||
1034 | /* | 1053 | /* Get our clocks */ |
1035 | * Setup main peripheral bus clock | ||
1036 | */ | ||
1037 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); | 1054 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); |
1038 | if (IS_ERR(host->pclk)) { | 1055 | if (IS_ERR(host->pclk)) { |
1039 | ret = PTR_ERR(host->pclk); | 1056 | ret = PTR_ERR(host->pclk); |
1040 | goto host_free; | 1057 | goto host_free; |
1041 | } | 1058 | } |
1042 | 1059 | ||
1043 | ret = clk_enable(host->pclk); | ||
1044 | if (ret) | ||
1045 | goto pclk_put; | ||
1046 | |||
1047 | host->pclk_rate = clk_get_rate(host->pclk); | ||
1048 | |||
1049 | /* | ||
1050 | * Setup SDC MMC clock | ||
1051 | */ | ||
1052 | host->clk = clk_get(&pdev->dev, "sdc_clk"); | 1060 | host->clk = clk_get(&pdev->dev, "sdc_clk"); |
1053 | if (IS_ERR(host->clk)) { | 1061 | if (IS_ERR(host->clk)) { |
1054 | ret = PTR_ERR(host->clk); | 1062 | ret = PTR_ERR(host->clk); |
1055 | goto pclk_disable; | 1063 | goto pclk_put; |
1056 | } | 1064 | } |
1057 | 1065 | ||
1058 | ret = clk_enable(host->clk); | 1066 | /* Enable clocks */ |
1067 | ret = msmsdcc_enable_clocks(host, 1); | ||
1059 | if (ret) | 1068 | if (ret) |
1060 | goto clk_put; | 1069 | goto clk_put; |
1061 | 1070 | ||
@@ -1065,10 +1074,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1065 | goto clk_disable; | 1074 | goto clk_disable; |
1066 | } | 1075 | } |
1067 | 1076 | ||
1077 | host->pclk_rate = clk_get_rate(host->pclk); | ||
1068 | host->clk_rate = clk_get_rate(host->clk); | 1078 | host->clk_rate = clk_get_rate(host->clk); |
1069 | 1079 | ||
1070 | host->clks_on = 1; | ||
1071 | |||
1072 | /* | 1080 | /* |
1073 | * Setup MMC host structure | 1081 | * Setup MMC host structure |
1074 | */ | 1082 | */ |
@@ -1187,11 +1195,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1187 | if (host->stat_irq) | 1195 | if (host->stat_irq) |
1188 | free_irq(host->stat_irq, host); | 1196 | free_irq(host->stat_irq, host); |
1189 | clk_disable: | 1197 | clk_disable: |
1190 | clk_disable(host->clk); | 1198 | msmsdcc_enable_clocks(host, 0); |
1191 | clk_put: | 1199 | clk_put: |
1192 | clk_put(host->clk); | 1200 | clk_put(host->clk); |
1193 | pclk_disable: | ||
1194 | clk_disable(host->pclk); | ||
1195 | pclk_put: | 1201 | pclk_put: |
1196 | clk_put(host->pclk); | 1202 | clk_put(host->pclk); |
1197 | host_free: | 1203 | host_free: |
@@ -1217,11 +1223,8 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) | |||
1217 | if (!rc) { | 1223 | if (!rc) { |
1218 | writel(0, host->base + MMCIMASK0); | 1224 | writel(0, host->base + MMCIMASK0); |
1219 | 1225 | ||
1220 | if (host->clks_on) { | 1226 | if (host->clks_on) |
1221 | clk_disable(host->clk); | 1227 | msmsdcc_enable_clocks(host, 0); |
1222 | clk_disable(host->pclk); | ||
1223 | host->clks_on = 0; | ||
1224 | } | ||
1225 | } | 1228 | } |
1226 | } | 1229 | } |
1227 | return rc; | 1230 | return rc; |
@@ -1238,11 +1241,8 @@ msmsdcc_resume(struct platform_device *dev) | |||
1238 | 1241 | ||
1239 | spin_lock_irqsave(&host->lock, flags); | 1242 | spin_lock_irqsave(&host->lock, flags); |
1240 | 1243 | ||
1241 | if (!host->clks_on) { | 1244 | if (!host->clks_on) |
1242 | clk_enable(host->pclk); | 1245 | msmsdcc_enable_clocks(host, 1); |
1243 | clk_enable(host->clk); | ||
1244 | host->clks_on = 1; | ||
1245 | } | ||
1246 | 1246 | ||
1247 | writel(host->saved_irq0mask, host->base + MMCIMASK0); | 1247 | writel(host->saved_irq0mask, host->base + MMCIMASK0); |
1248 | 1248 | ||