diff options
Diffstat (limited to 'drivers/mmc/host/msm_sdcc.c')
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 86 |
1 files changed, 58 insertions, 28 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index a4c865a5286b..80d8eb143b48 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
@@ -213,7 +213,8 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) | |||
213 | msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); | 213 | msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); |
214 | msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, | 214 | msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, |
215 | MMCIDATALENGTH); | 215 | MMCIDATALENGTH); |
216 | msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); | 216 | msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & |
217 | (~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); | ||
217 | msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); | 218 | msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); |
218 | 219 | ||
219 | if (host->cmd_cmd) { | 220 | if (host->cmd_cmd) { |
@@ -388,7 +389,7 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
388 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | 389 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, |
389 | host->dma.num_ents, host->dma.dir); | 390 | host->dma.num_ents, host->dma.dir); |
390 | if (n == 0) { | 391 | if (n == 0) { |
391 | printk(KERN_ERR "%s: Unable to map in all sg elements\n", | 392 | pr_err("%s: Unable to map in all sg elements\n", |
392 | mmc_hostname(host->mmc)); | 393 | mmc_hostname(host->mmc)); |
393 | host->dma.sg = NULL; | 394 | host->dma.sg = NULL; |
394 | host->dma.num_ents = 0; | 395 | host->dma.num_ents = 0; |
@@ -474,7 +475,7 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host, | |||
474 | *c |= MCI_CSPM_MCIABORT; | 475 | *c |= MCI_CSPM_MCIABORT; |
475 | 476 | ||
476 | if (host->curr.cmd != NULL) { | 477 | if (host->curr.cmd != NULL) { |
477 | printk(KERN_ERR "%s: Overlapping command requests\n", | 478 | pr_err("%s: Overlapping command requests\n", |
478 | mmc_hostname(host->mmc)); | 479 | mmc_hostname(host->mmc)); |
479 | } | 480 | } |
480 | host->curr.cmd = cmd; | 481 | host->curr.cmd = cmd; |
@@ -543,7 +544,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, | |||
543 | 544 | ||
544 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); | 545 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); |
545 | 546 | ||
546 | msmsdcc_writel(host, pio_irqmask, MMCIMASK1); | 547 | msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & |
548 | (~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); | ||
549 | |||
547 | msmsdcc_writel(host, datactrl, MMCIDATACTRL); | 550 | msmsdcc_writel(host, datactrl, MMCIDATACTRL); |
548 | 551 | ||
549 | if (cmd) { | 552 | if (cmd) { |
@@ -659,8 +662,13 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
659 | { | 662 | { |
660 | struct msmsdcc_host *host = dev_id; | 663 | struct msmsdcc_host *host = dev_id; |
661 | uint32_t status; | 664 | uint32_t status; |
665 | u32 mci_mask0; | ||
662 | 666 | ||
663 | status = msmsdcc_readl(host, MMCISTATUS); | 667 | status = msmsdcc_readl(host, MMCISTATUS); |
668 | mci_mask0 = msmsdcc_readl(host, MMCIMASK0); | ||
669 | |||
670 | if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) | ||
671 | return IRQ_NONE; | ||
664 | 672 | ||
665 | do { | 673 | do { |
666 | unsigned long flags; | 674 | unsigned long flags; |
@@ -719,10 +727,12 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
719 | } while (1); | 727 | } while (1); |
720 | 728 | ||
721 | if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) | 729 | if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) |
722 | msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); | 730 | msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | |
731 | MCI_RXDATAAVLBLMASK, MMCIMASK0); | ||
723 | 732 | ||
724 | if (!host->curr.xfer_remain) | 733 | if (!host->curr.xfer_remain) |
725 | msmsdcc_writel(host, 0, MMCIMASK1); | 734 | msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, |
735 | MMCIMASK0); | ||
726 | 736 | ||
727 | return IRQ_HANDLED; | 737 | return IRQ_HANDLED; |
728 | } | 738 | } |
@@ -854,6 +864,8 @@ msmsdcc_irq(int irq, void *dev_id) | |||
854 | do { | 864 | do { |
855 | status = msmsdcc_readl(host, MMCISTATUS); | 865 | status = msmsdcc_readl(host, MMCISTATUS); |
856 | status &= msmsdcc_readl(host, MMCIMASK0); | 866 | status &= msmsdcc_readl(host, MMCIMASK0); |
867 | if ((status & (~MCI_IRQ_PIO)) == 0) | ||
868 | break; | ||
857 | msmsdcc_writel(host, status, MMCICLEAR); | 869 | msmsdcc_writel(host, status, MMCICLEAR); |
858 | 870 | ||
859 | if (status & MCI_SDIOINTR) | 871 | if (status & MCI_SDIOINTR) |
@@ -939,7 +951,7 @@ static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) | |||
939 | struct msm_mmc_gpio_data *curr; | 951 | struct msm_mmc_gpio_data *curr; |
940 | int i, rc = 0; | 952 | int i, rc = 0; |
941 | 953 | ||
942 | if (!host->plat->gpio_data && host->gpio_config_status == enable) | 954 | if (!host->plat->gpio_data || host->gpio_config_status == enable) |
943 | return; | 955 | return; |
944 | 956 | ||
945 | curr = host->plat->gpio_data; | 957 | curr = host->plat->gpio_data; |
@@ -1052,10 +1064,19 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
1052 | spin_unlock_irqrestore(&host->lock, flags); | 1064 | spin_unlock_irqrestore(&host->lock, flags); |
1053 | } | 1065 | } |
1054 | 1066 | ||
1067 | static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) | ||
1068 | { | ||
1069 | struct msmsdcc_host *host = mmc_priv(mmc); | ||
1070 | |||
1071 | if (host->plat->init_card) | ||
1072 | host->plat->init_card(card); | ||
1073 | } | ||
1074 | |||
1055 | static const struct mmc_host_ops msmsdcc_ops = { | 1075 | static const struct mmc_host_ops msmsdcc_ops = { |
1056 | .request = msmsdcc_request, | 1076 | .request = msmsdcc_request, |
1057 | .set_ios = msmsdcc_set_ios, | 1077 | .set_ios = msmsdcc_set_ios, |
1058 | .enable_sdio_irq = msmsdcc_enable_sdio_irq, | 1078 | .enable_sdio_irq = msmsdcc_enable_sdio_irq, |
1079 | .init_card = msmsdcc_init_card, | ||
1059 | }; | 1080 | }; |
1060 | 1081 | ||
1061 | static void | 1082 | static void |
@@ -1092,7 +1113,7 @@ msmsdcc_platform_status_irq(int irq, void *dev_id) | |||
1092 | { | 1113 | { |
1093 | struct msmsdcc_host *host = dev_id; | 1114 | struct msmsdcc_host *host = dev_id; |
1094 | 1115 | ||
1095 | printk(KERN_DEBUG "%s: %d\n", __func__, irq); | 1116 | pr_debug("%s: %d\n", __func__, irq); |
1096 | msmsdcc_check_status((unsigned long) host); | 1117 | msmsdcc_check_status((unsigned long) host); |
1097 | return IRQ_HANDLED; | 1118 | return IRQ_HANDLED; |
1098 | } | 1119 | } |
@@ -1102,7 +1123,7 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) | |||
1102 | { | 1123 | { |
1103 | struct msmsdcc_host *host = dev_id; | 1124 | struct msmsdcc_host *host = dev_id; |
1104 | 1125 | ||
1105 | printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), | 1126 | pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), |
1106 | card_present); | 1127 | card_present); |
1107 | msmsdcc_check_status((unsigned long) host); | 1128 | msmsdcc_check_status((unsigned long) host); |
1108 | } | 1129 | } |
@@ -1150,7 +1171,6 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1150 | struct msmsdcc_host *host; | 1171 | struct msmsdcc_host *host; |
1151 | struct mmc_host *mmc; | 1172 | struct mmc_host *mmc; |
1152 | struct resource *cmd_irqres = NULL; | 1173 | struct resource *cmd_irqres = NULL; |
1153 | struct resource *pio_irqres = NULL; | ||
1154 | struct resource *stat_irqres = NULL; | 1174 | struct resource *stat_irqres = NULL; |
1155 | struct resource *memres = NULL; | 1175 | struct resource *memres = NULL; |
1156 | struct resource *dmares = NULL; | 1176 | struct resource *dmares = NULL; |
@@ -1175,12 +1195,10 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1175 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 1195 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
1176 | cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | 1196 | cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, |
1177 | "cmd_irq"); | 1197 | "cmd_irq"); |
1178 | pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | ||
1179 | "pio_irq"); | ||
1180 | stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | 1198 | stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, |
1181 | "status_irq"); | 1199 | "status_irq"); |
1182 | 1200 | ||
1183 | if (!cmd_irqres || !pio_irqres || !memres) { | 1201 | if (!cmd_irqres || !memres) { |
1184 | pr_err("%s: Invalid resource\n", __func__); | 1202 | pr_err("%s: Invalid resource\n", __func__); |
1185 | return -ENXIO; | 1203 | return -ENXIO; |
1186 | } | 1204 | } |
@@ -1200,17 +1218,20 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1200 | host->plat = plat; | 1218 | host->plat = plat; |
1201 | host->mmc = mmc; | 1219 | host->mmc = mmc; |
1202 | host->curr.cmd = NULL; | 1220 | host->curr.cmd = NULL; |
1221 | init_timer(&host->busclk_timer); | ||
1222 | host->busclk_timer.data = (unsigned long) host; | ||
1223 | host->busclk_timer.function = msmsdcc_busclk_expired; | ||
1224 | |||
1203 | 1225 | ||
1204 | host->cmdpoll = 1; | 1226 | host->cmdpoll = 1; |
1205 | 1227 | ||
1206 | host->base = ioremap(memres->start, PAGE_SIZE); | 1228 | host->base = ioremap(memres->start, PAGE_SIZE); |
1207 | if (!host->base) { | 1229 | if (!host->base) { |
1208 | ret = -ENOMEM; | 1230 | ret = -ENOMEM; |
1209 | goto out; | 1231 | goto host_free; |
1210 | } | 1232 | } |
1211 | 1233 | ||
1212 | host->cmd_irqres = cmd_irqres; | 1234 | host->cmd_irqres = cmd_irqres; |
1213 | host->pio_irqres = pio_irqres; | ||
1214 | host->memres = memres; | 1235 | host->memres = memres; |
1215 | host->dmares = dmares; | 1236 | host->dmares = dmares; |
1216 | spin_lock_init(&host->lock); | 1237 | spin_lock_init(&host->lock); |
@@ -1221,13 +1242,19 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1221 | /* | 1242 | /* |
1222 | * Setup DMA | 1243 | * Setup DMA |
1223 | */ | 1244 | */ |
1224 | msmsdcc_init_dma(host); | 1245 | if (host->dmares) { |
1246 | ret = msmsdcc_init_dma(host); | ||
1247 | if (ret) | ||
1248 | goto ioremap_free; | ||
1249 | } else { | ||
1250 | host->dma.channel = -1; | ||
1251 | } | ||
1225 | 1252 | ||
1226 | /* Get our clocks */ | 1253 | /* Get our clocks */ |
1227 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); | 1254 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); |
1228 | if (IS_ERR(host->pclk)) { | 1255 | if (IS_ERR(host->pclk)) { |
1229 | ret = PTR_ERR(host->pclk); | 1256 | ret = PTR_ERR(host->pclk); |
1230 | goto host_free; | 1257 | goto dma_free; |
1231 | } | 1258 | } |
1232 | 1259 | ||
1233 | host->clk = clk_get(&pdev->dev, "sdc_clk"); | 1260 | host->clk = clk_get(&pdev->dev, "sdc_clk"); |
@@ -1236,17 +1263,17 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1236 | goto pclk_put; | 1263 | goto pclk_put; |
1237 | } | 1264 | } |
1238 | 1265 | ||
1239 | /* Enable clocks */ | ||
1240 | ret = msmsdcc_enable_clocks(host); | ||
1241 | if (ret) | ||
1242 | goto clk_put; | ||
1243 | |||
1244 | ret = clk_set_rate(host->clk, msmsdcc_fmin); | 1266 | ret = clk_set_rate(host->clk, msmsdcc_fmin); |
1245 | if (ret) { | 1267 | if (ret) { |
1246 | pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); | 1268 | pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); |
1247 | goto clk_disable; | 1269 | goto clk_put; |
1248 | } | 1270 | } |
1249 | 1271 | ||
1272 | /* Enable clocks */ | ||
1273 | ret = msmsdcc_enable_clocks(host); | ||
1274 | if (ret) | ||
1275 | goto clk_put; | ||
1276 | |||
1250 | host->pclk_rate = clk_get_rate(host->pclk); | 1277 | host->pclk_rate = clk_get_rate(host->pclk); |
1251 | host->clk_rate = clk_get_rate(host->clk); | 1278 | host->clk_rate = clk_get_rate(host->clk); |
1252 | 1279 | ||
@@ -1316,16 +1343,12 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1316 | host->eject = !host->oldstat; | 1343 | host->eject = !host->oldstat; |
1317 | } | 1344 | } |
1318 | 1345 | ||
1319 | init_timer(&host->busclk_timer); | ||
1320 | host->busclk_timer.data = (unsigned long) host; | ||
1321 | host->busclk_timer.function = msmsdcc_busclk_expired; | ||
1322 | |||
1323 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, | 1346 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, |
1324 | DRIVER_NAME " (cmd)", host); | 1347 | DRIVER_NAME " (cmd)", host); |
1325 | if (ret) | 1348 | if (ret) |
1326 | goto stat_irq_free; | 1349 | goto stat_irq_free; |
1327 | 1350 | ||
1328 | ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, | 1351 | ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, |
1329 | DRIVER_NAME " (pio)", host); | 1352 | DRIVER_NAME " (pio)", host); |
1330 | if (ret) | 1353 | if (ret) |
1331 | goto cmd_irq_free; | 1354 | goto cmd_irq_free; |
@@ -1368,6 +1391,13 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1368 | clk_put(host->clk); | 1391 | clk_put(host->clk); |
1369 | pclk_put: | 1392 | pclk_put: |
1370 | clk_put(host->pclk); | 1393 | clk_put(host->pclk); |
1394 | dma_free: | ||
1395 | if (host->dmares) | ||
1396 | dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), | ||
1397 | host->dma.nc, host->dma.nc_busaddr); | ||
1398 | ioremap_free: | ||
1399 | tasklet_kill(&host->dma_tlet); | ||
1400 | iounmap(host->base); | ||
1371 | host_free: | 1401 | host_free: |
1372 | mmc_free_host(mmc); | 1402 | mmc_free_host(mmc); |
1373 | out: | 1403 | out: |