diff options
| -rw-r--r-- | drivers/mmc/host/omap.c | 67 |
1 files changed, 40 insertions, 27 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index f7fb97802827..8f393e8ed42f 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
| @@ -94,7 +94,7 @@ | |||
| 94 | 94 | ||
| 95 | /* Specifies how often in millisecs to poll for card status changes | 95 | /* Specifies how often in millisecs to poll for card status changes |
| 96 | * when the cover switch is open */ | 96 | * when the cover switch is open */ |
| 97 | #define OMAP_MMC_SWITCH_POLL_DELAY 500 | 97 | #define OMAP_MMC_COVER_POLL_DELAY 500 |
| 98 | 98 | ||
| 99 | struct mmc_omap_host; | 99 | struct mmc_omap_host; |
| 100 | 100 | ||
| @@ -106,8 +106,8 @@ struct mmc_omap_slot { | |||
| 106 | unsigned int fclk_freq; | 106 | unsigned int fclk_freq; |
| 107 | unsigned powered:1; | 107 | unsigned powered:1; |
| 108 | 108 | ||
| 109 | struct work_struct switch_work; | 109 | struct tasklet_struct cover_tasklet; |
| 110 | struct timer_list switch_timer; | 110 | struct timer_list cover_timer; |
| 111 | unsigned cover_open; | 111 | unsigned cover_open; |
| 112 | 112 | ||
| 113 | struct mmc_request *mrq; | 113 | struct mmc_request *mrq; |
| @@ -740,40 +740,51 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
| 740 | return IRQ_HANDLED; | 740 | return IRQ_HANDLED; |
| 741 | } | 741 | } |
| 742 | 742 | ||
| 743 | void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed) | 743 | void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed) |
| 744 | { | 744 | { |
| 745 | int cover_open; | ||
| 745 | struct mmc_omap_host *host = dev_get_drvdata(dev); | 746 | struct mmc_omap_host *host = dev_get_drvdata(dev); |
| 747 | struct mmc_omap_slot *slot = host->slots[num]; | ||
| 746 | 748 | ||
| 747 | BUG_ON(slot >= host->nr_slots); | 749 | BUG_ON(num >= host->nr_slots); |
| 748 | 750 | ||
| 749 | /* Other subsystems can call in here before we're initialised. */ | 751 | /* Other subsystems can call in here before we're initialised. */ |
| 750 | if (host->nr_slots == 0 || !host->slots[slot]) | 752 | if (host->nr_slots == 0 || !host->slots[num]) |
| 751 | return; | 753 | return; |
| 752 | 754 | ||
| 753 | schedule_work(&host->slots[slot]->switch_work); | 755 | cover_open = mmc_omap_cover_is_open(slot); |
| 756 | if (cover_open != slot->cover_open) { | ||
| 757 | slot->cover_open = cover_open; | ||
| 758 | sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch"); | ||
| 759 | } | ||
| 760 | |||
| 761 | tasklet_hi_schedule(&slot->cover_tasklet); | ||
| 754 | } | 762 | } |
| 755 | 763 | ||
| 756 | static void mmc_omap_switch_timer(unsigned long arg) | 764 | static void mmc_omap_cover_timer(unsigned long arg) |
| 757 | { | 765 | { |
| 758 | struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg; | 766 | struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg; |
| 759 | 767 | tasklet_schedule(&slot->cover_tasklet); | |
| 760 | schedule_work(&slot->switch_work); | ||
| 761 | } | 768 | } |
| 762 | 769 | ||
| 763 | static void mmc_omap_cover_handler(struct work_struct *work) | 770 | static void mmc_omap_cover_handler(unsigned long param) |
| 764 | { | 771 | { |
| 765 | struct mmc_omap_slot *slot = container_of(work, struct mmc_omap_slot, | 772 | struct mmc_omap_slot *slot = (struct mmc_omap_slot *)param; |
| 766 | switch_work); | 773 | int cover_open = mmc_omap_cover_is_open(slot); |
| 767 | int cover_open; | ||
| 768 | 774 | ||
| 769 | cover_open = mmc_omap_cover_is_open(slot); | 775 | mmc_detect_change(slot->mmc, 0); |
| 770 | if (cover_open != slot->cover_open) { | 776 | if (!cover_open) |
| 771 | sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch"); | 777 | return; |
| 772 | slot->cover_open = cover_open; | 778 | |
| 773 | dev_info(mmc_dev(slot->mmc), "cover is now %s\n", | 779 | /* |
| 774 | cover_open ? "open" : "closed"); | 780 | * If no card is inserted, we postpone polling until |
| 775 | } | 781 | * the cover has been closed. |
| 776 | mmc_detect_change(slot->mmc, slot->id); | 782 | */ |
| 783 | if (slot->mmc->card == NULL || !mmc_card_present(slot->mmc->card)) | ||
| 784 | return; | ||
| 785 | |||
| 786 | mod_timer(&slot->cover_timer, | ||
| 787 | jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); | ||
| 777 | } | 788 | } |
| 778 | 789 | ||
| 779 | /* Prepare to transfer the next segment of a scatterlist */ | 790 | /* Prepare to transfer the next segment of a scatterlist */ |
| @@ -1237,10 +1248,11 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) | |||
| 1237 | if (r < 0) | 1248 | if (r < 0) |
| 1238 | goto err_remove_slot_name; | 1249 | goto err_remove_slot_name; |
| 1239 | 1250 | ||
| 1240 | INIT_WORK(&slot->switch_work, mmc_omap_cover_handler); | 1251 | setup_timer(&slot->cover_timer, mmc_omap_cover_timer, |
| 1241 | setup_timer(&slot->switch_timer, mmc_omap_switch_timer, | 1252 | (unsigned long)slot); |
| 1242 | (unsigned long) slot); | 1253 | tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, |
| 1243 | schedule_work(&slot->switch_work); | 1254 | (unsigned long)slot); |
| 1255 | tasklet_schedule(&slot->cover_tasklet); | ||
| 1244 | } | 1256 | } |
| 1245 | 1257 | ||
| 1246 | return 0; | 1258 | return 0; |
| @@ -1263,7 +1275,8 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) | |||
| 1263 | if (slot->pdata->get_cover_state != NULL) | 1275 | if (slot->pdata->get_cover_state != NULL) |
| 1264 | device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); | 1276 | device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); |
| 1265 | 1277 | ||
| 1266 | del_timer_sync(&slot->switch_timer); | 1278 | tasklet_kill(&slot->cover_tasklet); |
| 1279 | del_timer_sync(&slot->cover_timer); | ||
| 1267 | flush_scheduled_work(); | 1280 | flush_scheduled_work(); |
| 1268 | 1281 | ||
| 1269 | mmc_remove_host(mmc); | 1282 | mmc_remove_host(mmc); |
