Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

ben@fluff.org.uk and committed by
Pierre Ossman
f87e6d00 9c2e7e40

+96 -19
+92 -19
drivers/mmc/host/s3cmci.c
··· 13 13 #include <linux/clk.h> 14 14 #include <linux/mmc/host.h> 15 15 #include <linux/platform_device.h> 16 + #include <linux/cpufreq.h> 16 17 #include <linux/irq.h> 17 18 #include <linux/io.h> 18 19 ··· 1034 1033 s3cmci_send_request(mmc); 1035 1034 } 1036 1035 1036 + static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios) 1037 + { 1038 + u32 mci_psc; 1039 + 1040 + /* Set clock */ 1041 + for (mci_psc = 0; mci_psc < 255; mci_psc++) { 1042 + host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); 1043 + 1044 + if (host->real_rate <= ios->clock) 1045 + break; 1046 + } 1047 + 1048 + if (mci_psc > 255) 1049 + mci_psc = 255; 1050 + 1051 + host->prescaler = mci_psc; 1052 + writel(host->prescaler, host->base + S3C2410_SDIPRE); 1053 + 1054 + /* If requested clock is 0, real_rate will be 0, too */ 1055 + if (ios->clock == 0) 1056 + host->real_rate = 0; 1057 + } 1058 + 1037 1059 static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1038 1060 { 1039 1061 struct s3cmci_host *host = mmc_priv(mmc); 1040 - u32 mci_psc, mci_con; 1062 + u32 mci_con; 1041 1063 1042 1064 /* Set the power state */ 1043 1065 ··· 1098 1074 break; 1099 1075 } 1100 1076 1101 - /* Set clock */ 1102 - for (mci_psc = 0; mci_psc < 255; mci_psc++) { 1103 - host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); 1104 - 1105 - if (host->real_rate <= ios->clock) 1106 - break; 1107 - } 1108 - 1109 - if (mci_psc > 255) 1110 - mci_psc = 255; 1111 - 1112 - host->prescaler = mci_psc; 1113 - writel(host->prescaler, host->base + S3C2410_SDIPRE); 1114 - 1115 - /* If requested clock is 0, real_rate will be 0, too */ 1116 - if (ios->clock == 0) 1117 - host->real_rate = 0; 1077 + s3cmci_set_clk(host, ios); 1118 1078 1119 1079 /* Set CLOCK_ENABLE */ 1120 1080 if (ios->clock) ··· 1155 1147 /* This is currently here to avoid a number of if (host->pdata) 1156 1148 * checks. Any zero fields to ensure reaonable defaults are picked. */ 1157 1149 }; 1150 + 1151 + #ifdef CONFIG_CPU_FREQ 1152 + 1153 + static int s3cmci_cpufreq_transition(struct notifier_block *nb, 1154 + unsigned long val, void *data) 1155 + { 1156 + struct s3cmci_host *host; 1157 + struct mmc_host *mmc; 1158 + unsigned long newclk; 1159 + unsigned long flags; 1160 + 1161 + host = container_of(nb, struct s3cmci_host, freq_transition); 1162 + newclk = clk_get_rate(host->clk); 1163 + mmc = host->mmc; 1164 + 1165 + if ((val == CPUFREQ_PRECHANGE && newclk > host->clk_rate) || 1166 + (val == CPUFREQ_POSTCHANGE && newclk < host->clk_rate)) { 1167 + spin_lock_irqsave(&mmc->lock, flags); 1168 + 1169 + host->clk_rate = newclk; 1170 + 1171 + if (mmc->ios.power_mode != MMC_POWER_OFF && 1172 + mmc->ios.clock != 0) 1173 + s3cmci_set_clk(host, &mmc->ios); 1174 + 1175 + spin_unlock_irqrestore(&mmc->lock, flags); 1176 + } 1177 + 1178 + return 0; 1179 + } 1180 + 1181 + static inline int s3cmci_cpufreq_register(struct s3cmci_host *host) 1182 + { 1183 + host->freq_transition.notifier_call = s3cmci_cpufreq_transition; 1184 + 1185 + return cpufreq_register_notifier(&host->freq_transition, 1186 + CPUFREQ_TRANSITION_NOTIFIER); 1187 + } 1188 + 1189 + static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) 1190 + { 1191 + cpufreq_unregister_notifier(&host->freq_transition, 1192 + CPUFREQ_TRANSITION_NOTIFIER); 1193 + } 1194 + 1195 + #else 1196 + static inline int s3cmci_cpufreq_register(struct s3cmci_host *host) 1197 + { 1198 + return 0; 1199 + } 1200 + 1201 + static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) 1202 + { 1203 + } 1204 + #endif 1158 1205 1159 1206 static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) 1160 1207 { ··· 1361 1298 (host->is2440?"2440":""), 1362 1299 host->base, host->irq, host->irq_cd, host->dma); 1363 1300 1301 + ret = s3cmci_cpufreq_register(host); 1302 + if (ret) { 1303 + dev_err(&pdev->dev, "failed to register cpufreq\n"); 1304 + goto free_dmabuf; 1305 + } 1306 + 1364 1307 ret = mmc_add_host(mmc); 1365 1308 if (ret) { 1366 1309 dev_err(&pdev->dev, "failed to add mmc host.\n"); 1367 - goto free_dmabuf; 1310 + goto free_cpufreq; 1368 1311 } 1369 1312 1370 1313 platform_set_drvdata(pdev, mmc); 1371 1314 dev_info(&pdev->dev, "initialisation done.\n"); 1372 1315 1373 1316 return 0; 1317 + 1318 + free_cpufreq: 1319 + s3cmci_cpufreq_deregister(host); 1374 1320 1375 1321 free_dmabuf: 1376 1322 clk_disable(host->clk); ··· 1414 1342 if (host->irq_cd >= 0) 1415 1343 free_irq(host->irq_cd, host); 1416 1344 1345 + s3cmci_cpufreq_deregister(host); 1417 1346 mmc_remove_host(mmc); 1418 1347 clk_disable(host->clk); 1419 1348 }
+4
drivers/mmc/host/s3cmci.h
··· 67 67 68 68 unsigned int ccnt, dcnt; 69 69 struct tasklet_struct pio_tasklet; 70 + 71 + #ifdef CONFIG_CPU_FREQ 72 + struct notifier_block freq_transition; 73 + #endif 70 74 };