diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/omap.c | 87 |
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 | ||
233 | static inline | ||
234 | int 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 | |||
239 | static ssize_t | ||
240 | mmc_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 | |||
250 | static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL); | ||
251 | |||
229 | static ssize_t | 252 | static ssize_t |
230 | mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr, | 253 | mmc_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 | ||
619 | void 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 | |||
632 | static 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 | |||
639 | static 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 */ |
596 | static void | 656 | static void |
597 | mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) | 657 | mmc_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 | ||
1140 | err_remove_slot_name: | ||
1141 | if (slot->pdata->name != NULL) | ||
1142 | device_remove_file(&mmc->class_dev, &dev_attr_slot_name); | ||
1067 | err_remove_host: | 1143 | err_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); |