diff options
| -rw-r--r-- | drivers/mmc/host/omap.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 3d59c5d81b3d..ab0974d261e5 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
| @@ -138,6 +138,11 @@ struct mmc_omap_host { | |||
| 138 | unsigned abort:1; | 138 | unsigned abort:1; |
| 139 | struct timer_list cmd_abort_timer; | 139 | struct timer_list cmd_abort_timer; |
| 140 | 140 | ||
| 141 | struct work_struct slot_release_work; | ||
| 142 | struct mmc_omap_slot *next_slot; | ||
| 143 | struct work_struct send_stop_work; | ||
| 144 | struct mmc_data *stop_data; | ||
| 145 | |||
| 141 | unsigned int sg_len; | 146 | unsigned int sg_len; |
| 142 | int sg_idx; | 147 | int sg_idx; |
| 143 | u16 * buffer; | 148 | u16 * buffer; |
| @@ -236,6 +241,21 @@ no_claim: | |||
| 236 | static void mmc_omap_start_request(struct mmc_omap_host *host, | 241 | static void mmc_omap_start_request(struct mmc_omap_host *host, |
| 237 | struct mmc_request *req); | 242 | struct mmc_request *req); |
| 238 | 243 | ||
| 244 | static void mmc_omap_slot_release_work(struct work_struct *work) | ||
| 245 | { | ||
| 246 | struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, | ||
| 247 | slot_release_work); | ||
| 248 | struct mmc_omap_slot *next_slot = host->next_slot; | ||
| 249 | struct mmc_request *rq; | ||
| 250 | |||
| 251 | host->next_slot = NULL; | ||
| 252 | mmc_omap_select_slot(next_slot, 1); | ||
| 253 | |||
| 254 | rq = next_slot->mrq; | ||
| 255 | next_slot->mrq = NULL; | ||
| 256 | mmc_omap_start_request(host, rq); | ||
| 257 | } | ||
| 258 | |||
| 239 | static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) | 259 | static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) |
| 240 | { | 260 | { |
| 241 | struct mmc_omap_host *host = slot->host; | 261 | struct mmc_omap_host *host = slot->host; |
| @@ -257,21 +277,19 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) | |||
| 257 | /* Check for any pending requests */ | 277 | /* Check for any pending requests */ |
| 258 | for (i = 0; i < host->nr_slots; i++) { | 278 | for (i = 0; i < host->nr_slots; i++) { |
| 259 | struct mmc_omap_slot *new_slot; | 279 | struct mmc_omap_slot *new_slot; |
| 260 | struct mmc_request *rq; | ||
| 261 | 280 | ||
| 262 | if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) | 281 | if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) |
| 263 | continue; | 282 | continue; |
| 264 | 283 | ||
| 284 | BUG_ON(host->next_slot != NULL); | ||
| 265 | new_slot = host->slots[i]; | 285 | new_slot = host->slots[i]; |
| 266 | /* The current slot should not have a request in queue */ | 286 | /* The current slot should not have a request in queue */ |
| 267 | BUG_ON(new_slot == host->current_slot); | 287 | BUG_ON(new_slot == host->current_slot); |
| 268 | 288 | ||
| 289 | host->next_slot = new_slot; | ||
| 269 | host->mmc = new_slot->mmc; | 290 | host->mmc = new_slot->mmc; |
| 270 | spin_unlock_irqrestore(&host->slot_lock, flags); | 291 | spin_unlock_irqrestore(&host->slot_lock, flags); |
| 271 | mmc_omap_select_slot(new_slot, 1); | 292 | schedule_work(&host->slot_release_work); |
| 272 | rq = new_slot->mrq; | ||
| 273 | new_slot->mrq = NULL; | ||
| 274 | mmc_omap_start_request(host, rq); | ||
| 275 | return; | 293 | return; |
| 276 | } | 294 | } |
| 277 | 295 | ||
| @@ -400,6 +418,20 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, | |||
| 400 | dma_data_dir); | 418 | dma_data_dir); |
| 401 | } | 419 | } |
| 402 | 420 | ||
| 421 | static void mmc_omap_send_stop_work(struct work_struct *work) | ||
| 422 | { | ||
| 423 | struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, | ||
| 424 | send_stop_work); | ||
| 425 | struct mmc_omap_slot *slot = host->current_slot; | ||
| 426 | struct mmc_data *data = host->stop_data; | ||
| 427 | unsigned long tick_ns; | ||
| 428 | |||
| 429 | tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq; | ||
| 430 | ndelay(8*tick_ns); | ||
| 431 | |||
| 432 | mmc_omap_start_command(host, data->stop); | ||
| 433 | } | ||
| 434 | |||
| 403 | static void | 435 | static void |
| 404 | mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) | 436 | mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) |
| 405 | { | 437 | { |
| @@ -424,7 +456,8 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) | |||
| 424 | return; | 456 | return; |
| 425 | } | 457 | } |
| 426 | 458 | ||
| 427 | mmc_omap_start_command(host, data->stop); | 459 | host->stop_data = data; |
| 460 | schedule_work(&host->send_stop_work); | ||
| 428 | } | 461 | } |
| 429 | 462 | ||
| 430 | static void | 463 | static void |
| @@ -1389,6 +1422,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev) | |||
| 1389 | goto err_free_mem_region; | 1422 | goto err_free_mem_region; |
| 1390 | } | 1423 | } |
| 1391 | 1424 | ||
| 1425 | INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work); | ||
| 1426 | INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); | ||
| 1427 | |||
| 1392 | INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); | 1428 | INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); |
| 1393 | setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, | 1429 | setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, |
| 1394 | (unsigned long) host); | 1430 | (unsigned long) host); |
