aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/omap.c67
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
99struct mmc_omap_host; 99struct 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
743void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed) 743void 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
756static void mmc_omap_switch_timer(unsigned long arg) 764static 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
763static void mmc_omap_cover_handler(struct work_struct *work) 770static 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);