diff options
author | San Mehat <san@google.com> | 2009-11-13 16:42:06 -0500 |
---|---|---|
committer | Daniel Walker <dwalker@codeaurora.org> | 2010-03-18 16:15:05 -0400 |
commit | 865c8064a2fb07100525097983966b8e789bde1a (patch) | |
tree | 986ccc9240af2343e4d12084217d1b8fcd6cdf6f /drivers/mmc | |
parent | 5b00f40f90e7b17c11cf388680f43e8466b3666d (diff) |
mmc: msm_sdcc: Driver clocking/irq improvements
- Clocks are now disabled after 1 second of inactivity
- Fixed issue which was causing us to loop through our ISR twice
- Bump core clock enable delay to 30us
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 | 89 | ||||
-rw-r--r-- | drivers/mmc/host/msm_sdcc.h | 2 |
2 files changed, 63 insertions, 28 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 02bec7c739e0..b4b637223b75 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
@@ -57,6 +57,32 @@ static unsigned int msmsdcc_sdioirq; | |||
57 | #define PIO_SPINMAX 30 | 57 | #define PIO_SPINMAX 30 |
58 | #define CMD_SPINMAX 20 | 58 | #define CMD_SPINMAX 20 |
59 | 59 | ||
60 | |||
61 | static inline int | ||
62 | msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) | ||
63 | { | ||
64 | int rc; | ||
65 | WARN_ON(enable == host->clks_on); | ||
66 | if (enable) { | ||
67 | rc = clk_enable(host->pclk); | ||
68 | if (rc) | ||
69 | return rc; | ||
70 | rc = clk_enable(host->clk); | ||
71 | if (rc) { | ||
72 | clk_disable(host->pclk); | ||
73 | return rc; | ||
74 | } | ||
75 | udelay(30); | ||
76 | host->clks_on = 1; | ||
77 | } else { | ||
78 | clk_disable(host->clk); | ||
79 | clk_disable(host->pclk); | ||
80 | host->clks_on = 0; | ||
81 | } | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | |||
60 | static void | 86 | static void |
61 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | 87 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, |
62 | u32 c); | 88 | u32 c); |
@@ -76,6 +102,8 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
76 | if (mrq->cmd->error == -ETIMEDOUT) | 102 | if (mrq->cmd->error == -ETIMEDOUT) |
77 | mdelay(5); | 103 | mdelay(5); |
78 | 104 | ||
105 | if (host->use_bustimer) | ||
106 | mod_timer(&host->busclk_timer, jiffies + HZ); | ||
79 | /* | 107 | /* |
80 | * Need to drop the host lock here; mmc_request_done may call | 108 | * Need to drop the host lock here; mmc_request_done may call |
81 | * back into the driver... | 109 | * back into the driver... |
@@ -676,6 +704,12 @@ msmsdcc_irq(int irq, void *dev_id) | |||
676 | status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); | 704 | status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); |
677 | writel(status, base + MMCICLEAR); | 705 | writel(status, base + MMCICLEAR); |
678 | 706 | ||
707 | if (status & MCI_SDIOINTR) | ||
708 | status &= ~MCI_SDIOINTR; | ||
709 | |||
710 | if (!status) | ||
711 | break; | ||
712 | |||
679 | msmsdcc_handle_irq_data(host, status, base); | 713 | msmsdcc_handle_irq_data(host, status, base); |
680 | 714 | ||
681 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | 715 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | |
@@ -729,6 +763,8 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
729 | } | 763 | } |
730 | 764 | ||
731 | host->curr.mrq = mrq; | 765 | host->curr.mrq = mrq; |
766 | if (!host->clks_on) | ||
767 | msmsdcc_enable_clocks(host, 1); | ||
732 | 768 | ||
733 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) | 769 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) |
734 | msmsdcc_start_data(host, mrq->data); | 770 | msmsdcc_start_data(host, mrq->data); |
@@ -750,29 +786,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
750 | spin_unlock_irqrestore(&host->lock, flags); | 786 | spin_unlock_irqrestore(&host->lock, flags); |
751 | } | 787 | } |
752 | 788 | ||
753 | static int inline | ||
754 | msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) | ||
755 | { | ||
756 | int rc; | ||
757 | if (enable) { | ||
758 | rc = clk_enable(host->pclk); | ||
759 | if (rc) | ||
760 | return rc; | ||
761 | rc = clk_enable(host->clk); | ||
762 | if (rc) { | ||
763 | clk_disable(host->pclk); | ||
764 | return rc; | ||
765 | } | ||
766 | host->clks_on = 1; | ||
767 | udelay(10); | ||
768 | } else { | ||
769 | clk_disable(host->clk); | ||
770 | clk_disable(host->pclk); | ||
771 | host->clks_on = 0; | ||
772 | } | ||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static void | 789 | static void |
777 | msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 790 | msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
778 | { | 791 | { |
@@ -782,10 +795,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
782 | unsigned long flags; | 795 | unsigned long flags; |
783 | 796 | ||
784 | spin_lock_irqsave(&host->lock, flags); | 797 | spin_lock_irqsave(&host->lock, flags); |
785 | if (ios->clock) { | 798 | if (!host->clks_on) |
799 | msmsdcc_enable_clocks(host, 1); | ||
786 | 800 | ||
787 | if (!host->clks_on) | 801 | if (ios->clock) { |
788 | msmsdcc_enable_clocks(host, 1); | ||
789 | if (ios->clock != host->clk_rate) { | 802 | if (ios->clock != host->clk_rate) { |
790 | rc = clk_set_rate(host->clk, ios->clock); | 803 | rc = clk_set_rate(host->clk, ios->clock); |
791 | if (rc < 0) | 804 | if (rc < 0) |
@@ -829,8 +842,7 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
829 | host->pwr = pwr; | 842 | host->pwr = pwr; |
830 | writel(pwr, host->base + MMCIPOWER); | 843 | writel(pwr, host->base + MMCIPOWER); |
831 | } | 844 | } |
832 | 845 | if (host->clks_on) | |
833 | if (!(clk & MCI_CLK_ENABLE) && host->clks_on) | ||
834 | msmsdcc_enable_clocks(host, 0); | 846 | msmsdcc_enable_clocks(host, 0); |
835 | spin_unlock_irqrestore(&host->lock, flags); | 847 | spin_unlock_irqrestore(&host->lock, flags); |
836 | } | 848 | } |
@@ -909,6 +921,19 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) | |||
909 | msmsdcc_check_status((unsigned long) host); | 921 | msmsdcc_check_status((unsigned long) host); |
910 | } | 922 | } |
911 | 923 | ||
924 | static void | ||
925 | msmsdcc_busclk_expired(unsigned long _data) | ||
926 | { | ||
927 | struct msmsdcc_host *host = (struct msmsdcc_host *) _data; | ||
928 | unsigned long flags; | ||
929 | |||
930 | spin_lock_irqsave(&host->lock, flags); | ||
931 | if (host->clks_on) | ||
932 | msmsdcc_enable_clocks(host, 0); | ||
933 | |||
934 | spin_unlock_irqrestore(&host->lock, flags); | ||
935 | } | ||
936 | |||
912 | /* | 937 | /* |
913 | * called when a command expires. | 938 | * called when a command expires. |
914 | * Dump some debugging, and then error | 939 | * Dump some debugging, and then error |
@@ -942,6 +967,8 @@ msmsdcc_command_expired(unsigned long _data) | |||
942 | host->curr.mrq = NULL; | 967 | host->curr.mrq = NULL; |
943 | host->curr.cmd = NULL; | 968 | host->curr.cmd = NULL; |
944 | 969 | ||
970 | if (host->clks_on) | ||
971 | msmsdcc_enable_clocks(host, 0); | ||
945 | spin_unlock_irqrestore(&host->lock, flags); | 972 | spin_unlock_irqrestore(&host->lock, flags); |
946 | mmc_request_done(host->mmc, mrq); | 973 | mmc_request_done(host->mmc, mrq); |
947 | } | 974 | } |
@@ -1048,6 +1075,8 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1048 | 1075 | ||
1049 | host->cmdpoll = 1; | 1076 | host->cmdpoll = 1; |
1050 | 1077 | ||
1078 | host->use_bustimer = 1; | ||
1079 | |||
1051 | host->base = ioremap(memres->start, PAGE_SIZE); | 1080 | host->base = ioremap(memres->start, PAGE_SIZE); |
1052 | if (!host->base) { | 1081 | if (!host->base) { |
1053 | ret = -ENOMEM; | 1082 | ret = -ENOMEM; |
@@ -1167,6 +1196,10 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1167 | host->command_timer.data = (unsigned long) host; | 1196 | host->command_timer.data = (unsigned long) host; |
1168 | host->command_timer.function = msmsdcc_command_expired; | 1197 | host->command_timer.function = msmsdcc_command_expired; |
1169 | 1198 | ||
1199 | init_timer(&host->busclk_timer); | ||
1200 | host->busclk_timer.data = (unsigned long) host; | ||
1201 | host->busclk_timer.function = msmsdcc_busclk_expired; | ||
1202 | |||
1170 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, | 1203 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, |
1171 | DRIVER_NAME " (cmd)", host); | 1204 | DRIVER_NAME " (cmd)", host); |
1172 | if (ret) | 1205 | if (ret) |
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 8c8448469811..6846bd7dff22 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h | |||
@@ -214,6 +214,8 @@ struct msmsdcc_host { | |||
214 | struct clk *pclk; /* SDCC peripheral bus clock */ | 214 | struct clk *pclk; /* SDCC peripheral bus clock */ |
215 | unsigned int clks_on; /* set if clocks are enabled */ | 215 | unsigned int clks_on; /* set if clocks are enabled */ |
216 | struct timer_list command_timer; | 216 | struct timer_list command_timer; |
217 | struct timer_list busclk_timer; | ||
218 | int use_bustimer; | ||
217 | 219 | ||
218 | unsigned int eject; /* eject state */ | 220 | unsigned int eject; /* eject state */ |
219 | 221 | ||