diff options
author | Chaithrika U S <chaithrika@ti.com> | 2009-12-14 21:01:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-15 11:53:34 -0500 |
commit | 7e30b8decbb1a5853522936eb613803a480312c3 (patch) | |
tree | 732912dc3d9a6838782375f457579a701ce84ace /drivers/mmc | |
parent | 3d348aaf5b4b7d5a65123f4afad3eae416b2903b (diff) |
davinci: mmc: add cpufreq support
Add cpufreq support to MMC driver. The clock divider value has to be
modified according to the controller input frequency.
Signed-off-by: Chaithrika U S <chaithrika@ti.com>
Cc: Linus Walleij <linus.ml.walleij@gmail.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/davinci_mmc.c | 100 |
1 files changed, 84 insertions, 16 deletions
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 6c76f64f46db..dd45e7c3517e 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/cpufreq.h> | ||
28 | #include <linux/mmc/host.h> | 29 | #include <linux/mmc/host.h> |
29 | #include <linux/io.h> | 30 | #include <linux/io.h> |
30 | #include <linux/irq.h> | 31 | #include <linux/irq.h> |
@@ -200,6 +201,9 @@ struct mmc_davinci_host { | |||
200 | u8 version; | 201 | u8 version; |
201 | /* for ns in one cycle calculation */ | 202 | /* for ns in one cycle calculation */ |
202 | unsigned ns_in_one_cycle; | 203 | unsigned ns_in_one_cycle; |
204 | #ifdef CONFIG_CPU_FREQ | ||
205 | struct notifier_block freq_transition; | ||
206 | #endif | ||
203 | }; | 207 | }; |
204 | 208 | ||
205 | 209 | ||
@@ -739,27 +743,12 @@ static unsigned int calculate_freq_for_card(struct mmc_davinci_host *host, | |||
739 | return mmc_push_pull_divisor; | 743 | return mmc_push_pull_divisor; |
740 | } | 744 | } |
741 | 745 | ||
742 | static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 746 | static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) |
743 | { | 747 | { |
744 | unsigned int open_drain_freq = 0, mmc_pclk = 0; | 748 | unsigned int open_drain_freq = 0, mmc_pclk = 0; |
745 | unsigned int mmc_push_pull_freq = 0; | 749 | unsigned int mmc_push_pull_freq = 0; |
746 | struct mmc_davinci_host *host = mmc_priv(mmc); | 750 | struct mmc_davinci_host *host = mmc_priv(mmc); |
747 | 751 | ||
748 | mmc_pclk = host->mmc_input_clk; | ||
749 | dev_dbg(mmc_dev(host->mmc), | ||
750 | "clock %dHz busmode %d powermode %d Vdd %04x\n", | ||
751 | ios->clock, ios->bus_mode, ios->power_mode, | ||
752 | ios->vdd); | ||
753 | if (ios->bus_width == MMC_BUS_WIDTH_4) { | ||
754 | dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n"); | ||
755 | writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_WIDTH_4_BIT, | ||
756 | host->base + DAVINCI_MMCCTL); | ||
757 | } else { | ||
758 | dev_dbg(mmc_dev(host->mmc), "Disabling 4 bit mode\n"); | ||
759 | writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_WIDTH_4_BIT, | ||
760 | host->base + DAVINCI_MMCCTL); | ||
761 | } | ||
762 | |||
763 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { | 752 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { |
764 | u32 temp; | 753 | u32 temp; |
765 | 754 | ||
@@ -798,6 +787,29 @@ static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
798 | 787 | ||
799 | udelay(10); | 788 | udelay(10); |
800 | } | 789 | } |
790 | } | ||
791 | |||
792 | static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||
793 | { | ||
794 | unsigned int mmc_pclk = 0; | ||
795 | struct mmc_davinci_host *host = mmc_priv(mmc); | ||
796 | |||
797 | mmc_pclk = host->mmc_input_clk; | ||
798 | dev_dbg(mmc_dev(host->mmc), | ||
799 | "clock %dHz busmode %d powermode %d Vdd %04x\n", | ||
800 | ios->clock, ios->bus_mode, ios->power_mode, | ||
801 | ios->vdd); | ||
802 | if (ios->bus_width == MMC_BUS_WIDTH_4) { | ||
803 | dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n"); | ||
804 | writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_WIDTH_4_BIT, | ||
805 | host->base + DAVINCI_MMCCTL); | ||
806 | } else { | ||
807 | dev_dbg(mmc_dev(host->mmc), "Disabling 4 bit mode\n"); | ||
808 | writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_WIDTH_4_BIT, | ||
809 | host->base + DAVINCI_MMCCTL); | ||
810 | } | ||
811 | |||
812 | calculate_clk_divider(mmc, ios); | ||
801 | 813 | ||
802 | host->bus_mode = ios->bus_mode; | 814 | host->bus_mode = ios->bus_mode; |
803 | if (ios->power_mode == MMC_POWER_UP) { | 815 | if (ios->power_mode == MMC_POWER_UP) { |
@@ -1040,6 +1052,52 @@ static struct mmc_host_ops mmc_davinci_ops = { | |||
1040 | 1052 | ||
1041 | /*----------------------------------------------------------------------*/ | 1053 | /*----------------------------------------------------------------------*/ |
1042 | 1054 | ||
1055 | #ifdef CONFIG_CPU_FREQ | ||
1056 | static int mmc_davinci_cpufreq_transition(struct notifier_block *nb, | ||
1057 | unsigned long val, void *data) | ||
1058 | { | ||
1059 | struct mmc_davinci_host *host; | ||
1060 | unsigned int mmc_pclk; | ||
1061 | struct mmc_host *mmc; | ||
1062 | unsigned long flags; | ||
1063 | |||
1064 | host = container_of(nb, struct mmc_davinci_host, freq_transition); | ||
1065 | mmc = host->mmc; | ||
1066 | mmc_pclk = clk_get_rate(host->clk); | ||
1067 | |||
1068 | if (val == CPUFREQ_POSTCHANGE) { | ||
1069 | spin_lock_irqsave(&mmc->lock, flags); | ||
1070 | host->mmc_input_clk = mmc_pclk; | ||
1071 | calculate_clk_divider(mmc, &mmc->ios); | ||
1072 | spin_unlock_irqrestore(&mmc->lock, flags); | ||
1073 | } | ||
1074 | |||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | static inline int mmc_davinci_cpufreq_register(struct mmc_davinci_host *host) | ||
1079 | { | ||
1080 | host->freq_transition.notifier_call = mmc_davinci_cpufreq_transition; | ||
1081 | |||
1082 | return cpufreq_register_notifier(&host->freq_transition, | ||
1083 | CPUFREQ_TRANSITION_NOTIFIER); | ||
1084 | } | ||
1085 | |||
1086 | static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) | ||
1087 | { | ||
1088 | cpufreq_unregister_notifier(&host->freq_transition, | ||
1089 | CPUFREQ_TRANSITION_NOTIFIER); | ||
1090 | } | ||
1091 | #else | ||
1092 | static inline int mmc_davinci_cpufreq_register(struct mmc_davinci_host *host) | ||
1093 | { | ||
1094 | return 0; | ||
1095 | } | ||
1096 | |||
1097 | static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) | ||
1098 | { | ||
1099 | } | ||
1100 | #endif | ||
1043 | static void __init init_mmcsd_host(struct mmc_davinci_host *host) | 1101 | static void __init init_mmcsd_host(struct mmc_davinci_host *host) |
1044 | { | 1102 | { |
1045 | /* DAT line portion is diabled and in reset state */ | 1103 | /* DAT line portion is diabled and in reset state */ |
@@ -1169,6 +1227,12 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) | |||
1169 | 1227 | ||
1170 | platform_set_drvdata(pdev, host); | 1228 | platform_set_drvdata(pdev, host); |
1171 | 1229 | ||
1230 | ret = mmc_davinci_cpufreq_register(host); | ||
1231 | if (ret) { | ||
1232 | dev_err(&pdev->dev, "failed to register cpufreq\n"); | ||
1233 | goto cpu_freq_fail; | ||
1234 | } | ||
1235 | |||
1172 | ret = mmc_add_host(mmc); | 1236 | ret = mmc_add_host(mmc); |
1173 | if (ret < 0) | 1237 | if (ret < 0) |
1174 | goto out; | 1238 | goto out; |
@@ -1186,6 +1250,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) | |||
1186 | return 0; | 1250 | return 0; |
1187 | 1251 | ||
1188 | out: | 1252 | out: |
1253 | mmc_davinci_cpufreq_deregister(host); | ||
1254 | cpu_freq_fail: | ||
1189 | if (host) { | 1255 | if (host) { |
1190 | davinci_release_dma_channels(host); | 1256 | davinci_release_dma_channels(host); |
1191 | 1257 | ||
@@ -1215,6 +1281,8 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) | |||
1215 | 1281 | ||
1216 | platform_set_drvdata(pdev, NULL); | 1282 | platform_set_drvdata(pdev, NULL); |
1217 | if (host) { | 1283 | if (host) { |
1284 | mmc_davinci_cpufreq_deregister(host); | ||
1285 | |||
1218 | mmc_remove_host(host->mmc); | 1286 | mmc_remove_host(host->mmc); |
1219 | free_irq(host->irq, host); | 1287 | free_irq(host->irq, host); |
1220 | 1288 | ||