diff options
Diffstat (limited to 'drivers/mmc')
-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); |