aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorben@fluff.org.uk <ben@fluff.org.uk>2008-10-14 19:17:16 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-10-15 12:04:52 -0400
commitf87e6d00fbd367f2d61fd600b5f8bd6e39d63f3f (patch)
tree43988efa9573fdf804eea29509b2034fd3077447 /drivers/mmc
parent9c2e7e40bf85684eebc019e915c39c4c07c734fa (diff)
s3cmci: cpufreq support
Support for cpu frequency changing. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/s3cmci.c111
-rw-r--r--drivers/mmc/host/s3cmci.h4
2 files changed, 96 insertions, 19 deletions
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 2af630639910..a73ffb9d7b21 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -13,6 +13,7 @@
13#include <linux/clk.h> 13#include <linux/clk.h>
14#include <linux/mmc/host.h> 14#include <linux/mmc/host.h>
15#include <linux/platform_device.h> 15#include <linux/platform_device.h>
16#include <linux/cpufreq.h>
16#include <linux/irq.h> 17#include <linux/irq.h>
17#include <linux/io.h> 18#include <linux/io.h>
18 19
@@ -1033,10 +1034,33 @@ static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1033 s3cmci_send_request(mmc); 1034 s3cmci_send_request(mmc);
1034} 1035}
1035 1036
1037static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios)
1038{
1039 u32 mci_psc;
1040
1041 /* Set clock */
1042 for (mci_psc = 0; mci_psc < 255; mci_psc++) {
1043 host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
1044
1045 if (host->real_rate <= ios->clock)
1046 break;
1047 }
1048
1049 if (mci_psc > 255)
1050 mci_psc = 255;
1051
1052 host->prescaler = mci_psc;
1053 writel(host->prescaler, host->base + S3C2410_SDIPRE);
1054
1055 /* If requested clock is 0, real_rate will be 0, too */
1056 if (ios->clock == 0)
1057 host->real_rate = 0;
1058}
1059
1036static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1060static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1037{ 1061{
1038 struct s3cmci_host *host = mmc_priv(mmc); 1062 struct s3cmci_host *host = mmc_priv(mmc);
1039 u32 mci_psc, mci_con; 1063 u32 mci_con;
1040 1064
1041 /* Set the power state */ 1065 /* Set the power state */
1042 1066
@@ -1074,23 +1098,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1074 break; 1098 break;
1075 } 1099 }
1076 1100
1077 /* Set clock */ 1101 s3cmci_set_clk(host, ios);
1078 for (mci_psc = 0; mci_psc < 255; mci_psc++) {
1079 host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
1080
1081 if (host->real_rate <= ios->clock)
1082 break;
1083 }
1084
1085 if (mci_psc > 255)
1086 mci_psc = 255;
1087
1088 host->prescaler = mci_psc;
1089 writel(host->prescaler, host->base + S3C2410_SDIPRE);
1090
1091 /* If requested clock is 0, real_rate will be 0, too */
1092 if (ios->clock == 0)
1093 host->real_rate = 0;
1094 1102
1095 /* Set CLOCK_ENABLE */ 1103 /* Set CLOCK_ENABLE */
1096 if (ios->clock) 1104 if (ios->clock)
@@ -1148,6 +1156,61 @@ static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
1148 * checks. Any zero fields to ensure reaonable defaults are picked. */ 1156 * checks. Any zero fields to ensure reaonable defaults are picked. */
1149}; 1157};
1150 1158
1159#ifdef CONFIG_CPU_FREQ
1160
1161static int s3cmci_cpufreq_transition(struct notifier_block *nb,
1162 unsigned long val, void *data)
1163{
1164 struct s3cmci_host *host;
1165 struct mmc_host *mmc;
1166 unsigned long newclk;
1167 unsigned long flags;
1168
1169 host = container_of(nb, struct s3cmci_host, freq_transition);
1170 newclk = clk_get_rate(host->clk);
1171 mmc = host->mmc;
1172
1173 if ((val == CPUFREQ_PRECHANGE && newclk > host->clk_rate) ||
1174 (val == CPUFREQ_POSTCHANGE && newclk < host->clk_rate)) {
1175 spin_lock_irqsave(&mmc->lock, flags);
1176
1177 host->clk_rate = newclk;
1178
1179 if (mmc->ios.power_mode != MMC_POWER_OFF &&
1180 mmc->ios.clock != 0)
1181 s3cmci_set_clk(host, &mmc->ios);
1182
1183 spin_unlock_irqrestore(&mmc->lock, flags);
1184 }
1185
1186 return 0;
1187}
1188
1189static inline int s3cmci_cpufreq_register(struct s3cmci_host *host)
1190{
1191 host->freq_transition.notifier_call = s3cmci_cpufreq_transition;
1192
1193 return cpufreq_register_notifier(&host->freq_transition,
1194 CPUFREQ_TRANSITION_NOTIFIER);
1195}
1196
1197static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
1198{
1199 cpufreq_unregister_notifier(&host->freq_transition,
1200 CPUFREQ_TRANSITION_NOTIFIER);
1201}
1202
1203#else
1204static inline int s3cmci_cpufreq_register(struct s3cmci_host *host)
1205{
1206 return 0;
1207}
1208
1209static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
1210{
1211}
1212#endif
1213
1151static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) 1214static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
1152{ 1215{
1153 struct s3cmci_host *host; 1216 struct s3cmci_host *host;
@@ -1298,10 +1361,16 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
1298 (host->is2440?"2440":""), 1361 (host->is2440?"2440":""),
1299 host->base, host->irq, host->irq_cd, host->dma); 1362 host->base, host->irq, host->irq_cd, host->dma);
1300 1363
1364 ret = s3cmci_cpufreq_register(host);
1365 if (ret) {
1366 dev_err(&pdev->dev, "failed to register cpufreq\n");
1367 goto free_dmabuf;
1368 }
1369
1301 ret = mmc_add_host(mmc); 1370 ret = mmc_add_host(mmc);
1302 if (ret) { 1371 if (ret) {
1303 dev_err(&pdev->dev, "failed to add mmc host.\n"); 1372 dev_err(&pdev->dev, "failed to add mmc host.\n");
1304 goto free_dmabuf; 1373 goto free_cpufreq;
1305 } 1374 }
1306 1375
1307 platform_set_drvdata(pdev, mmc); 1376 platform_set_drvdata(pdev, mmc);
@@ -1309,6 +1378,9 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
1309 1378
1310 return 0; 1379 return 0;
1311 1380
1381 free_cpufreq:
1382 s3cmci_cpufreq_deregister(host);
1383
1312 free_dmabuf: 1384 free_dmabuf:
1313 clk_disable(host->clk); 1385 clk_disable(host->clk);
1314 1386
@@ -1342,6 +1414,7 @@ static void s3cmci_shutdown(struct platform_device *pdev)
1342 if (host->irq_cd >= 0) 1414 if (host->irq_cd >= 0)
1343 free_irq(host->irq_cd, host); 1415 free_irq(host->irq_cd, host);
1344 1416
1417 s3cmci_cpufreq_deregister(host);
1345 mmc_remove_host(mmc); 1418 mmc_remove_host(mmc);
1346 clk_disable(host->clk); 1419 clk_disable(host->clk);
1347} 1420}
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
index 37d9c60010c9..7e39109587f9 100644
--- a/drivers/mmc/host/s3cmci.h
+++ b/drivers/mmc/host/s3cmci.h
@@ -67,4 +67,8 @@ struct s3cmci_host {
67 67
68 unsigned int ccnt, dcnt; 68 unsigned int ccnt, dcnt;
69 struct tasklet_struct pio_tasklet; 69 struct tasklet_struct pio_tasklet;
70
71#ifdef CONFIG_CPU_FREQ
72 struct notifier_block freq_transition;
73#endif
70}; 74};