diff options
Diffstat (limited to 'drivers/mmc/host/omap.c')
-rw-r--r-- | drivers/mmc/host/omap.c | 93 |
1 files changed, 36 insertions, 57 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 98b6b6ef7e5c..5c2e58b29305 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/omap-dma.h> | 26 | #include <linux/omap-dma.h> |
27 | #include <linux/mmc/host.h> | 27 | #include <linux/mmc/host.h> |
28 | #include <linux/mmc/card.h> | 28 | #include <linux/mmc/card.h> |
29 | #include <linux/mmc/mmc.h> | ||
29 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
30 | #include <linux/scatterlist.h> | 31 | #include <linux/scatterlist.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
@@ -130,7 +131,6 @@ struct mmc_omap_host { | |||
130 | u32 dma_rx_burst; | 131 | u32 dma_rx_burst; |
131 | struct dma_chan *dma_tx; | 132 | struct dma_chan *dma_tx; |
132 | u32 dma_tx_burst; | 133 | u32 dma_tx_burst; |
133 | struct resource *mem_res; | ||
134 | void __iomem *virt_base; | 134 | void __iomem *virt_base; |
135 | unsigned int phys_base; | 135 | unsigned int phys_base; |
136 | int irq; | 136 | int irq; |
@@ -153,7 +153,6 @@ struct mmc_omap_host { | |||
153 | u32 total_bytes_left; | 153 | u32 total_bytes_left; |
154 | 154 | ||
155 | unsigned features; | 155 | unsigned features; |
156 | unsigned use_dma:1; | ||
157 | unsigned brs_received:1, dma_done:1; | 156 | unsigned brs_received:1, dma_done:1; |
158 | unsigned dma_in_use:1; | 157 | unsigned dma_in_use:1; |
159 | spinlock_t dma_lock; | 158 | spinlock_t dma_lock; |
@@ -338,6 +337,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) | |||
338 | u32 cmdreg; | 337 | u32 cmdreg; |
339 | u32 resptype; | 338 | u32 resptype; |
340 | u32 cmdtype; | 339 | u32 cmdtype; |
340 | u16 irq_mask; | ||
341 | 341 | ||
342 | host->cmd = cmd; | 342 | host->cmd = cmd; |
343 | 343 | ||
@@ -390,12 +390,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) | |||
390 | OMAP_MMC_WRITE(host, CTO, 200); | 390 | OMAP_MMC_WRITE(host, CTO, 200); |
391 | OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); | 391 | OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); |
392 | OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); | 392 | OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); |
393 | OMAP_MMC_WRITE(host, IE, | 393 | irq_mask = OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | |
394 | OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | | 394 | OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | |
395 | OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | | 395 | OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | |
396 | OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | | 396 | OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | |
397 | OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | | 397 | OMAP_MMC_STAT_END_OF_DATA; |
398 | OMAP_MMC_STAT_END_OF_DATA); | 398 | if (cmd->opcode == MMC_ERASE) |
399 | irq_mask &= ~OMAP_MMC_STAT_DATA_TOUT; | ||
400 | OMAP_MMC_WRITE(host, IE, irq_mask); | ||
399 | OMAP_MMC_WRITE(host, CMD, cmdreg); | 401 | OMAP_MMC_WRITE(host, CMD, cmdreg); |
400 | } | 402 | } |
401 | 403 | ||
@@ -945,7 +947,7 @@ static void | |||
945 | mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) | 947 | mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) |
946 | { | 948 | { |
947 | struct mmc_data *data = req->data; | 949 | struct mmc_data *data = req->data; |
948 | int i, use_dma, block_size; | 950 | int i, use_dma = 1, block_size; |
949 | unsigned sg_len; | 951 | unsigned sg_len; |
950 | 952 | ||
951 | host->data = data; | 953 | host->data = data; |
@@ -970,13 +972,10 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) | |||
970 | sg_len = (data->blocks == 1) ? 1 : data->sg_len; | 972 | sg_len = (data->blocks == 1) ? 1 : data->sg_len; |
971 | 973 | ||
972 | /* Only do DMA for entire blocks */ | 974 | /* Only do DMA for entire blocks */ |
973 | use_dma = host->use_dma; | 975 | for (i = 0; i < sg_len; i++) { |
974 | if (use_dma) { | 976 | if ((data->sg[i].length % block_size) != 0) { |
975 | for (i = 0; i < sg_len; i++) { | 977 | use_dma = 0; |
976 | if ((data->sg[i].length % block_size) != 0) { | 978 | break; |
977 | use_dma = 0; | ||
978 | break; | ||
979 | } | ||
980 | } | 979 | } |
981 | } | 980 | } |
982 | 981 | ||
@@ -1239,7 +1238,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) | |||
1239 | 1238 | ||
1240 | mmc->caps = 0; | 1239 | mmc->caps = 0; |
1241 | if (host->pdata->slots[id].wires >= 4) | 1240 | if (host->pdata->slots[id].wires >= 4) |
1242 | mmc->caps |= MMC_CAP_4_BIT_DATA; | 1241 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_ERASE; |
1243 | 1242 | ||
1244 | mmc->ops = &mmc_omap_ops; | 1243 | mmc->ops = &mmc_omap_ops; |
1245 | mmc->f_min = 400000; | 1244 | mmc->f_min = 400000; |
@@ -1262,6 +1261,13 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) | |||
1262 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | 1261 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; |
1263 | mmc->max_seg_size = mmc->max_req_size; | 1262 | mmc->max_seg_size = mmc->max_req_size; |
1264 | 1263 | ||
1264 | if (slot->pdata->get_cover_state != NULL) { | ||
1265 | setup_timer(&slot->cover_timer, mmc_omap_cover_timer, | ||
1266 | (unsigned long)slot); | ||
1267 | tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, | ||
1268 | (unsigned long)slot); | ||
1269 | } | ||
1270 | |||
1265 | r = mmc_add_host(mmc); | 1271 | r = mmc_add_host(mmc); |
1266 | if (r < 0) | 1272 | if (r < 0) |
1267 | goto err_remove_host; | 1273 | goto err_remove_host; |
@@ -1278,11 +1284,6 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) | |||
1278 | &dev_attr_cover_switch); | 1284 | &dev_attr_cover_switch); |
1279 | if (r < 0) | 1285 | if (r < 0) |
1280 | goto err_remove_slot_name; | 1286 | goto err_remove_slot_name; |
1281 | |||
1282 | setup_timer(&slot->cover_timer, mmc_omap_cover_timer, | ||
1283 | (unsigned long)slot); | ||
1284 | tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, | ||
1285 | (unsigned long)slot); | ||
1286 | tasklet_schedule(&slot->cover_tasklet); | 1287 | tasklet_schedule(&slot->cover_tasklet); |
1287 | } | 1288 | } |
1288 | 1289 | ||
@@ -1333,21 +1334,19 @@ static int mmc_omap_probe(struct platform_device *pdev) | |||
1333 | return -EPROBE_DEFER; | 1334 | return -EPROBE_DEFER; |
1334 | } | 1335 | } |
1335 | 1336 | ||
1336 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1337 | host = devm_kzalloc(&pdev->dev, sizeof(struct mmc_omap_host), |
1338 | GFP_KERNEL); | ||
1339 | if (host == NULL) | ||
1340 | return -ENOMEM; | ||
1341 | |||
1337 | irq = platform_get_irq(pdev, 0); | 1342 | irq = platform_get_irq(pdev, 0); |
1338 | if (res == NULL || irq < 0) | 1343 | if (irq < 0) |
1339 | return -ENXIO; | 1344 | return -ENXIO; |
1340 | 1345 | ||
1341 | res = request_mem_region(res->start, resource_size(res), | 1346 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1342 | pdev->name); | 1347 | host->virt_base = devm_ioremap_resource(&pdev->dev, res); |
1343 | if (res == NULL) | 1348 | if (IS_ERR(host->virt_base)) |
1344 | return -EBUSY; | 1349 | return PTR_ERR(host->virt_base); |
1345 | |||
1346 | host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL); | ||
1347 | if (host == NULL) { | ||
1348 | ret = -ENOMEM; | ||
1349 | goto err_free_mem_region; | ||
1350 | } | ||
1351 | 1350 | ||
1352 | INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work); | 1351 | INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work); |
1353 | INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); | 1352 | INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); |
@@ -1369,20 +1368,11 @@ static int mmc_omap_probe(struct platform_device *pdev) | |||
1369 | platform_set_drvdata(pdev, host); | 1368 | platform_set_drvdata(pdev, host); |
1370 | 1369 | ||
1371 | host->id = pdev->id; | 1370 | host->id = pdev->id; |
1372 | host->mem_res = res; | ||
1373 | host->irq = irq; | ||
1374 | host->use_dma = 1; | ||
1375 | host->irq = irq; | 1371 | host->irq = irq; |
1376 | host->phys_base = host->mem_res->start; | 1372 | host->phys_base = res->start; |
1377 | host->virt_base = ioremap(res->start, resource_size(res)); | ||
1378 | if (!host->virt_base) | ||
1379 | goto err_ioremap; | ||
1380 | |||
1381 | host->iclk = clk_get(&pdev->dev, "ick"); | 1373 | host->iclk = clk_get(&pdev->dev, "ick"); |
1382 | if (IS_ERR(host->iclk)) { | 1374 | if (IS_ERR(host->iclk)) |
1383 | ret = PTR_ERR(host->iclk); | 1375 | return PTR_ERR(host->iclk); |
1384 | goto err_free_mmc_host; | ||
1385 | } | ||
1386 | clk_enable(host->iclk); | 1376 | clk_enable(host->iclk); |
1387 | 1377 | ||
1388 | host->fclk = clk_get(&pdev->dev, "fck"); | 1378 | host->fclk = clk_get(&pdev->dev, "fck"); |
@@ -1460,12 +1450,6 @@ err_free_dma: | |||
1460 | err_free_iclk: | 1450 | err_free_iclk: |
1461 | clk_disable(host->iclk); | 1451 | clk_disable(host->iclk); |
1462 | clk_put(host->iclk); | 1452 | clk_put(host->iclk); |
1463 | err_free_mmc_host: | ||
1464 | iounmap(host->virt_base); | ||
1465 | err_ioremap: | ||
1466 | kfree(host); | ||
1467 | err_free_mem_region: | ||
1468 | release_mem_region(res->start, resource_size(res)); | ||
1469 | return ret; | 1453 | return ret; |
1470 | } | 1454 | } |
1471 | 1455 | ||
@@ -1493,13 +1477,8 @@ static int mmc_omap_remove(struct platform_device *pdev) | |||
1493 | if (host->dma_rx) | 1477 | if (host->dma_rx) |
1494 | dma_release_channel(host->dma_rx); | 1478 | dma_release_channel(host->dma_rx); |
1495 | 1479 | ||
1496 | iounmap(host->virt_base); | ||
1497 | release_mem_region(pdev->resource[0].start, | ||
1498 | pdev->resource[0].end - pdev->resource[0].start + 1); | ||
1499 | destroy_workqueue(host->mmc_omap_wq); | 1480 | destroy_workqueue(host->mmc_omap_wq); |
1500 | 1481 | ||
1501 | kfree(host); | ||
1502 | |||
1503 | return 0; | 1482 | return 0; |
1504 | } | 1483 | } |
1505 | 1484 | ||