aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuha Yrjola <juha.yrjola@solidboot.com>2008-03-26 16:09:08 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-04-18 14:05:28 -0400
commit5a0f3f1f71e0bc4a843673e8e7cf09a32bb07c32 (patch)
tree57a7c457abf51135b9acbebf472a32f57739e1df
parentabfbe5f7854a083ca324282bf7e39f10bc438313 (diff)
MMC: OMAP: Add back cover switch support
This patch adds back MMC cover switch support in a way that supports multiple slots. Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com> Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com> Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r--drivers/mmc/host/omap.c87
1 files changed, 84 insertions, 3 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 59eac7211842..712a9608acf7 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -106,6 +106,10 @@ 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;
110 struct timer_list switch_timer;
111 unsigned cover_open;
112
109 struct mmc_request *mrq; 113 struct mmc_request *mrq;
110 struct mmc_omap_host *host; 114 struct mmc_omap_host *host;
111 struct mmc_host *mmc; 115 struct mmc_host *mmc;
@@ -226,6 +230,25 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot)
226 spin_unlock_irqrestore(&host->slot_lock, flags); 230 spin_unlock_irqrestore(&host->slot_lock, flags);
227} 231}
228 232
233static inline
234int mmc_omap_cover_is_open(struct mmc_omap_slot *slot)
235{
236 return slot->pdata->get_cover_state(mmc_dev(slot->mmc), slot->id);
237}
238
239static ssize_t
240mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
241 char *buf)
242{
243 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
244 struct mmc_omap_slot *slot = mmc_priv(mmc);
245
246 return sprintf(buf, "%s\n", mmc_omap_cover_is_open(slot) ? "open" :
247 "closed");
248}
249
250static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
251
229static ssize_t 252static ssize_t
230mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr, 253mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
231 char *buf) 254 char *buf)
@@ -544,9 +567,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
544 if (host->cmd) { 567 if (host->cmd) {
545 struct mmc_omap_slot *slot = 568 struct mmc_omap_slot *slot =
546 host->current_slot; 569 host->current_slot;
547 dev_err(mmc_dev(host->mmc), 570 if (!mmc_omap_cover_is_open(slot))
548 "command timeout, CMD %d\n", 571 dev_err(mmc_dev(host->mmc),
549 host->cmd->opcode); 572 "command timeout, CMD %d\n",
573 host->cmd->opcode);
550 host->cmd->error = -ETIMEDOUT; 574 host->cmd->error = -ETIMEDOUT;
551 end_command = 1; 575 end_command = 1;
552 } 576 }
@@ -592,6 +616,42 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
592 return IRQ_HANDLED; 616 return IRQ_HANDLED;
593} 617}
594 618
619void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed)
620{
621 struct mmc_omap_host *host = dev_get_drvdata(dev);
622
623 BUG_ON(slot >= host->nr_slots);
624
625 /* Other subsystems can call in here before we're initialised. */
626 if (host->nr_slots == 0 || !host->slots[slot])
627 return;
628
629 schedule_work(&host->slots[slot]->switch_work);
630}
631
632static void mmc_omap_switch_timer(unsigned long arg)
633{
634 struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg;
635
636 schedule_work(&slot->switch_work);
637}
638
639static void mmc_omap_cover_handler(struct work_struct *work)
640{
641 struct mmc_omap_slot *slot = container_of(work, struct mmc_omap_slot,
642 switch_work);
643 int cover_open;
644
645 cover_open = mmc_omap_cover_is_open(slot);
646 if (cover_open != slot->cover_open) {
647 sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch");
648 slot->cover_open = cover_open;
649 dev_info(mmc_dev(slot->mmc), "cover is now %s\n",
650 cover_open ? "open" : "closed");
651 }
652 mmc_detect_change(slot->mmc, slot->id);
653}
654
595/* Prepare to transfer the next segment of a scatterlist */ 655/* Prepare to transfer the next segment of a scatterlist */
596static void 656static void
597mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) 657mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
@@ -1062,8 +1122,24 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
1062 goto err_remove_host; 1122 goto err_remove_host;
1063 } 1123 }
1064 1124
1125 if (slot->pdata->get_cover_state != NULL) {
1126 r = device_create_file(&mmc->class_dev,
1127 &dev_attr_cover_switch);
1128 if (r < 0)
1129 goto err_remove_slot_name;
1130
1131 INIT_WORK(&slot->switch_work, mmc_omap_cover_handler);
1132 init_timer(&slot->switch_timer);
1133 slot->switch_timer.function = mmc_omap_switch_timer;
1134 slot->switch_timer.data = (unsigned long) slot;
1135 schedule_work(&slot->switch_work);
1136 }
1137
1065 return 0; 1138 return 0;
1066 1139
1140err_remove_slot_name:
1141 if (slot->pdata->name != NULL)
1142 device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
1067err_remove_host: 1143err_remove_host:
1068 mmc_remove_host(mmc); 1144 mmc_remove_host(mmc);
1069 mmc_free_host(mmc); 1145 mmc_free_host(mmc);
@@ -1076,6 +1152,11 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)
1076 1152
1077 if (slot->pdata->name != NULL) 1153 if (slot->pdata->name != NULL)
1078 device_remove_file(&mmc->class_dev, &dev_attr_slot_name); 1154 device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
1155 if (slot->pdata->get_cover_state != NULL)
1156 device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
1157
1158 del_timer_sync(&slot->switch_timer);
1159 flush_scheduled_work();
1079 1160
1080 mmc_remove_host(mmc); 1161 mmc_remove_host(mmc);
1081 mmc_free_host(mmc); 1162 mmc_free_host(mmc);