aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuha Yrjola <juha.yrjola@solidboot.com>2008-03-26 16:08:57 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-04-18 14:05:28 -0400
commitabfbe5f7854a083ca324282bf7e39f10bc438313 (patch)
treec2034a5437daa6fdc973fd2837fa892b4f55e80f
parent4bc9e35556bf4444014ba65b80abb2fb9f70899a (diff)
MMC: OMAP: Introduce new multislot structure and change driver to use it
Introduce new MMC multislot structure and change driver to use it. Note that MMC clocking is now enabled in mmc_omap_select_slot() and disabled in mmc_omap_release_slot(). 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.c402
-rw-r--r--include/asm-arm/arch-omap/mmc.h2
2 files changed, 294 insertions, 110 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 7d17c899c394..59eac7211842 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -32,6 +32,7 @@
32#include <asm/mach-types.h> 32#include <asm/mach-types.h>
33 33
34#include <asm/arch/board.h> 34#include <asm/arch/board.h>
35#include <asm/arch/mmc.h>
35#include <asm/arch/gpio.h> 36#include <asm/arch/gpio.h>
36#include <asm/arch/dma.h> 37#include <asm/arch/dma.h>
37#include <asm/arch/mux.h> 38#include <asm/arch/mux.h>
@@ -95,6 +96,22 @@
95 * when the cover switch is open */ 96 * when the cover switch is open */
96#define OMAP_MMC_SWITCH_POLL_DELAY 500 97#define OMAP_MMC_SWITCH_POLL_DELAY 500
97 98
99struct mmc_omap_host;
100
101struct mmc_omap_slot {
102 int id;
103 unsigned int vdd;
104 u16 saved_con;
105 u16 bus_mode;
106 unsigned int fclk_freq;
107 unsigned powered:1;
108
109 struct mmc_request *mrq;
110 struct mmc_omap_host *host;
111 struct mmc_host *mmc;
112 struct omap_mmc_slot_data *pdata;
113};
114
98struct mmc_omap_host { 115struct mmc_omap_host {
99 int initialized; 116 int initialized;
100 int suspended; 117 int suspended;
@@ -129,13 +146,98 @@ struct mmc_omap_host {
129 unsigned dma_len; 146 unsigned dma_len;
130 147
131 short power_pin; 148 short power_pin;
132 short wp_pin;
133 149
134 struct work_struct switch_work; 150 struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS];
135 struct timer_list switch_timer; 151 struct mmc_omap_slot *current_slot;
136 int switch_last_state; 152 spinlock_t slot_lock;
153 wait_queue_head_t slot_wq;
154 int nr_slots;
155
156 struct omap_mmc_platform_data *pdata;
137}; 157};
138 158
159static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
160{
161 struct mmc_omap_host *host = slot->host;
162 unsigned long flags;
163
164 if (claimed)
165 goto no_claim;
166 spin_lock_irqsave(&host->slot_lock, flags);
167 while (host->mmc != NULL) {
168 spin_unlock_irqrestore(&host->slot_lock, flags);
169 wait_event(host->slot_wq, host->mmc == NULL);
170 spin_lock_irqsave(&host->slot_lock, flags);
171 }
172 host->mmc = slot->mmc;
173 spin_unlock_irqrestore(&host->slot_lock, flags);
174no_claim:
175 clk_enable(host->fclk);
176 if (host->current_slot != slot) {
177 if (host->pdata->switch_slot != NULL)
178 host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id);
179 host->current_slot = slot;
180 }
181
182 /* Doing the dummy read here seems to work around some bug
183 * at least in OMAP24xx silicon where the command would not
184 * start after writing the CMD register. Sigh. */
185 OMAP_MMC_READ(host, CON);
186
187 OMAP_MMC_WRITE(host, CON, slot->saved_con);
188}
189
190static void mmc_omap_start_request(struct mmc_omap_host *host,
191 struct mmc_request *req);
192
193static void mmc_omap_release_slot(struct mmc_omap_slot *slot)
194{
195 struct mmc_omap_host *host = slot->host;
196 unsigned long flags;
197 int i;
198
199 BUG_ON(slot == NULL || host->mmc == NULL);
200 clk_disable(host->fclk);
201
202 spin_lock_irqsave(&host->slot_lock, flags);
203 /* Check for any pending requests */
204 for (i = 0; i < host->nr_slots; i++) {
205 struct mmc_omap_slot *new_slot;
206 struct mmc_request *rq;
207
208 if (host->slots[i] == NULL || host->slots[i]->mrq == NULL)
209 continue;
210
211 new_slot = host->slots[i];
212 /* The current slot should not have a request in queue */
213 BUG_ON(new_slot == host->current_slot);
214
215 host->mmc = new_slot->mmc;
216 spin_unlock_irqrestore(&host->slot_lock, flags);
217 mmc_omap_select_slot(new_slot, 1);
218 rq = new_slot->mrq;
219 new_slot->mrq = NULL;
220 mmc_omap_start_request(host, rq);
221 return;
222 }
223
224 host->mmc = NULL;
225 wake_up(&host->slot_wq);
226 spin_unlock_irqrestore(&host->slot_lock, flags);
227}
228
229static ssize_t
230mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
231 char *buf)
232{
233 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
234 struct mmc_omap_slot *slot = mmc_priv(mmc);
235
236 return sprintf(buf, "%s\n", slot->pdata->name);
237}
238
239static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
240
139static void 241static void
140mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) 242mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
141{ 243{
@@ -180,7 +282,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
180 282
181 cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); 283 cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
182 284
183 if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) 285 if (host->current_slot->bus_mode == MMC_BUSMODE_OPENDRAIN)
184 cmdreg |= 1 << 6; 286 cmdreg |= 1 << 6;
185 287
186 if (cmd->flags & MMC_RSP_BUSY) 288 if (cmd->flags & MMC_RSP_BUSY)
@@ -189,8 +291,6 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
189 if (host->data && !(host->data->flags & MMC_DATA_WRITE)) 291 if (host->data && !(host->data->flags & MMC_DATA_WRITE))
190 cmdreg |= 1 << 15; 292 cmdreg |= 1 << 15;
191 293
192 clk_enable(host->fclk);
193
194 OMAP_MMC_WRITE(host, CTO, 200); 294 OMAP_MMC_WRITE(host, CTO, 200);
195 OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); 295 OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
196 OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); 296 OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
@@ -442,6 +542,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
442 if (status & OMAP_MMC_STAT_CMD_TOUT) { 542 if (status & OMAP_MMC_STAT_CMD_TOUT) {
443 /* Timeouts are routine with some commands */ 543 /* Timeouts are routine with some commands */
444 if (host->cmd) { 544 if (host->cmd) {
545 struct mmc_omap_slot *slot =
546 host->current_slot;
445 dev_err(mmc_dev(host->mmc), 547 dev_err(mmc_dev(host->mmc),
446 "command timeout, CMD %d\n", 548 "command timeout, CMD %d\n",
447 host->cmd->opcode); 549 host->cmd->opcode);
@@ -747,11 +849,10 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
747 } 849 }
748} 850}
749 851
750static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) 852static void mmc_omap_start_request(struct mmc_omap_host *host,
853 struct mmc_request *req)
751{ 854{
752 struct mmc_omap_host *host = mmc_priv(mmc); 855 BUG_ON(host->mrq != NULL);
753
754 WARN_ON(host->mrq != NULL);
755 856
756 host->mrq = req; 857 host->mrq = req;
757 858
@@ -760,6 +861,26 @@ static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
760 mmc_omap_start_command(host, req->cmd); 861 mmc_omap_start_command(host, req->cmd);
761 if (host->dma_in_use) 862 if (host->dma_in_use)
762 omap_start_dma(host->dma_ch); 863 omap_start_dma(host->dma_ch);
864 BUG_ON(irqs_disabled());
865}
866
867static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
868{
869 struct mmc_omap_slot *slot = mmc_priv(mmc);
870 struct mmc_omap_host *host = slot->host;
871 unsigned long flags;
872
873 spin_lock_irqsave(&host->slot_lock, flags);
874 if (host->mmc != NULL) {
875 BUG_ON(slot->mrq != NULL);
876 slot->mrq = req;
877 spin_unlock_irqrestore(&host->slot_lock, flags);
878 return;
879 } else
880 host->mmc = mmc;
881 spin_unlock_irqrestore(&host->slot_lock, flags);
882 mmc_omap_select_slot(slot, 1);
883 mmc_omap_start_request(host, req);
763} 884}
764 885
765static void innovator_fpga_socket_power(int on) 886static void innovator_fpga_socket_power(int on)
@@ -813,7 +934,8 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
813 934
814static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios) 935static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
815{ 936{
816 struct mmc_omap_host *host = mmc_priv(mmc); 937 struct mmc_omap_slot *slot = mmc_priv(mmc);
938 struct mmc_omap_host *host = slot->host;
817 int func_clk_rate = clk_get_rate(host->fclk); 939 int func_clk_rate = clk_get_rate(host->fclk);
818 int dsor; 940 int dsor;
819 941
@@ -830,6 +952,8 @@ static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
830 if (dsor > 250) 952 if (dsor > 250)
831 dsor = 250; 953 dsor = 250;
832 954
955 slot->fclk_freq = func_clk_rate / dsor;
956
833 if (ios->bus_width == MMC_BUS_WIDTH_4) 957 if (ios->bus_width == MMC_BUS_WIDTH_4)
834 dsor |= 1 << 15; 958 dsor |= 1 << 15;
835 959
@@ -838,9 +962,9 @@ static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
838 962
839static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 963static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
840{ 964{
841 struct mmc_omap_host *host = mmc_priv(mmc); 965 struct mmc_omap_slot *slot = mmc_priv(mmc);
842 int dsor; 966 struct mmc_omap_host *host = slot->host;
843 int i; 967 int i, dsor;
844 968
845 dsor = mmc_omap_calc_divisor(mmc, ios); 969 dsor = mmc_omap_calc_divisor(mmc, ios);
846 host->bus_mode = ios->bus_mode; 970 host->bus_mode = ios->bus_mode;
@@ -878,32 +1002,101 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
878 clk_disable(host->fclk); 1002 clk_disable(host->fclk);
879} 1003}
880 1004
881static int mmc_omap_get_ro(struct mmc_host *mmc)
882{
883 struct mmc_omap_host *host = mmc_priv(mmc);
884
885 return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
886}
887
888static const struct mmc_host_ops mmc_omap_ops = { 1005static const struct mmc_host_ops mmc_omap_ops = {
889 .request = mmc_omap_request, 1006 .request = mmc_omap_request,
890 .set_ios = mmc_omap_set_ios, 1007 .set_ios = mmc_omap_set_ios,
891 .get_ro = mmc_omap_get_ro,
892}; 1008};
893 1009
894static int __init mmc_omap_probe(struct platform_device *pdev) 1010static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
895{ 1011{
896 struct omap_mmc_conf *minfo = pdev->dev.platform_data; 1012 struct mmc_omap_slot *slot = NULL;
897 struct mmc_host *mmc; 1013 struct mmc_host *mmc;
1014 int r;
1015
1016 mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host->dev);
1017 if (mmc == NULL)
1018 return -ENOMEM;
1019
1020 slot = mmc_priv(mmc);
1021 slot->host = host;
1022 slot->mmc = mmc;
1023 slot->id = id;
1024 slot->pdata = &host->pdata->slots[id];
1025
1026 host->slots[id] = slot;
1027
1028 mmc->caps = MMC_CAP_MULTIWRITE;
1029 if (host->pdata->conf.wire4)
1030 mmc->caps |= MMC_CAP_4_BIT_DATA;
1031
1032 mmc->ops = &mmc_omap_ops;
1033 mmc->f_min = 400000;
1034
1035 if (cpu_class_is_omap2())
1036 mmc->f_max = 48000000;
1037 else
1038 mmc->f_max = 24000000;
1039 if (host->pdata->max_freq)
1040 mmc->f_max = min(host->pdata->max_freq, mmc->f_max);
1041 mmc->ocr_avail = slot->pdata->ocr_mask;
1042
1043 /* Use scatterlist DMA to reduce per-transfer costs.
1044 * NOTE max_seg_size assumption that small blocks aren't
1045 * normally used (except e.g. for reading SD registers).
1046 */
1047 mmc->max_phys_segs = 32;
1048 mmc->max_hw_segs = 32;
1049 mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
1050 mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
1051 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
1052 mmc->max_seg_size = mmc->max_req_size;
1053
1054 r = mmc_add_host(mmc);
1055 if (r < 0)
1056 goto err_remove_host;
1057
1058 if (slot->pdata->name != NULL) {
1059 r = device_create_file(&mmc->class_dev,
1060 &dev_attr_slot_name);
1061 if (r < 0)
1062 goto err_remove_host;
1063 }
1064
1065 return 0;
1066
1067err_remove_host:
1068 mmc_remove_host(mmc);
1069 mmc_free_host(mmc);
1070 return r;
1071}
1072
1073static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)
1074{
1075 struct mmc_host *mmc = slot->mmc;
1076
1077 if (slot->pdata->name != NULL)
1078 device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
1079
1080 mmc_remove_host(mmc);
1081 mmc_free_host(mmc);
1082}
1083
1084static int __init mmc_omap_probe(struct platform_device *pdev)
1085{
1086 struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
898 struct mmc_omap_host *host = NULL; 1087 struct mmc_omap_host *host = NULL;
899 struct resource *res; 1088 struct resource *res;
900 int ret = 0; 1089 int i, ret = 0;
901 int irq; 1090 int irq;
902 1091
903 if (minfo == NULL) { 1092 if (pdata == NULL) {
904 dev_err(&pdev->dev, "platform data missing\n"); 1093 dev_err(&pdev->dev, "platform data missing\n");
905 return -ENXIO; 1094 return -ENXIO;
906 } 1095 }
1096 if (pdata->nr_slots == 0) {
1097 dev_err(&pdev->dev, "no slots\n");
1098 return -ENXIO;
1099 }
907 1100
908 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1101 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
909 irq = platform_get_irq(pdev, 0); 1102 irq = platform_get_irq(pdev, 0);
@@ -911,28 +1104,39 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
911 return -ENXIO; 1104 return -ENXIO;
912 1105
913 res = request_mem_region(res->start, res->end - res->start + 1, 1106 res = request_mem_region(res->start, res->end - res->start + 1,
914 pdev->name); 1107 pdev->name);
915 if (res == NULL) 1108 if (res == NULL)
916 return -EBUSY; 1109 return -EBUSY;
917 1110
918 mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev); 1111 host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL);
919 if (mmc == NULL) { 1112 if (host == NULL) {
920 ret = -ENOMEM; 1113 ret = -ENOMEM;
921 goto err_free_mem_region; 1114 goto err_free_mem_region;
922 } 1115 }
923 1116
924 host = mmc_priv(mmc);
925 host->mmc = mmc;
926
927 spin_lock_init(&host->dma_lock); 1117 spin_lock_init(&host->dma_lock);
928 init_timer(&host->dma_timer); 1118 init_timer(&host->dma_timer);
1119 spin_lock_init(&host->slot_lock);
1120 init_waitqueue_head(&host->slot_wq);
1121
929 host->dma_timer.function = mmc_omap_dma_timer; 1122 host->dma_timer.function = mmc_omap_dma_timer;
930 host->dma_timer.data = (unsigned long) host; 1123 host->dma_timer.data = (unsigned long) host;
931 1124
1125 host->pdata = pdata;
1126 host->dev = &pdev->dev;
1127 platform_set_drvdata(pdev, host);
1128
932 host->id = pdev->id; 1129 host->id = pdev->id;
933 host->mem_res = res; 1130 host->mem_res = res;
934 host->irq = irq; 1131 host->irq = irq;
935 1132
1133 host->use_dma = 1;
1134 host->dma_ch = -1;
1135
1136 host->irq = irq;
1137 host->phys_base = host->mem_res->start;
1138 host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
1139
936 if (cpu_is_omap24xx()) { 1140 if (cpu_is_omap24xx()) {
937 host->iclk = clk_get(&pdev->dev, "mmc_ick"); 1141 host->iclk = clk_get(&pdev->dev, "mmc_ick");
938 if (IS_ERR(host->iclk)) 1142 if (IS_ERR(host->iclk))
@@ -950,70 +1154,34 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
950 goto err_free_iclk; 1154 goto err_free_iclk;
951 } 1155 }
952 1156
953 /* REVISIT: 1157 ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
954 * Also, use minfo->cover to decide how to manage 1158 if (ret)
955 * the card detect sensing. 1159 goto err_free_fclk;
956 */
957 host->power_pin = minfo->power_pin;
958 host->wp_pin = minfo->wp_pin;
959 host->use_dma = 1;
960 host->dma_ch = -1;
961
962 host->irq = irq;
963 host->phys_base = host->mem_res->start;
964 host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
965
966 mmc->ops = &mmc_omap_ops;
967 mmc->f_min = 400000;
968 mmc->f_max = 24000000;
969 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
970 mmc->caps = MMC_CAP_MULTIWRITE;
971 1160
972 if (minfo->wire4) 1161 if (pdata->init != NULL) {
973 mmc->caps |= MMC_CAP_4_BIT_DATA; 1162 ret = pdata->init(&pdev->dev);
1163 if (ret < 0)
1164 goto err_free_irq;
1165 }
974 1166
975 /* Use scatterlist DMA to reduce per-transfer costs. 1167 host->nr_slots = pdata->nr_slots;
976 * NOTE max_seg_size assumption that small blocks aren't 1168 for (i = 0; i < pdata->nr_slots; i++) {
977 * normally used (except e.g. for reading SD registers). 1169 ret = mmc_omap_new_slot(host, i);
978 */ 1170 if (ret < 0) {
979 mmc->max_phys_segs = 32; 1171 while (--i >= 0)
980 mmc->max_hw_segs = 32; 1172 mmc_omap_remove_slot(host->slots[i]);
981 mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
982 mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
983 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
984 mmc->max_seg_size = mmc->max_req_size;
985 1173
986 if (host->power_pin >= 0) { 1174 goto err_plat_cleanup;
987 if ((ret = omap_request_gpio(host->power_pin)) != 0) {
988 dev_err(mmc_dev(host->mmc),
989 "Unable to get GPIO pin for MMC power\n");
990 goto err_free_fclk;
991 } 1175 }
992 omap_set_gpio_direction(host->power_pin, 0);
993 } 1176 }
994 1177
995 ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
996 if (ret)
997 goto err_free_power_gpio;
998
999 host->dev = &pdev->dev;
1000 platform_set_drvdata(pdev, host);
1001
1002 mmc_add_host(mmc);
1003
1004 return 0; 1178 return 0;
1005 1179
1006 /* FIXME: Free other resources too. */ 1180err_plat_cleanup:
1007 if (host) { 1181 if (pdata->cleanup)
1008 if (host->iclk && !IS_ERR(host->iclk)) 1182 pdata->cleanup(&pdev->dev);
1009 clk_put(host->iclk); 1183err_free_irq:
1010 if (host->fclk && !IS_ERR(host->fclk)) 1184 free_irq(host->irq, host);
1011 clk_put(host->fclk);
1012 mmc_free_host(host->mmc);
1013 }
1014err_free_power_gpio:
1015 if (host->power_pin >= 0)
1016 omap_free_gpio(host->power_pin);
1017err_free_fclk: 1185err_free_fclk:
1018 clk_put(host->fclk); 1186 clk_put(host->fclk);
1019err_free_iclk: 1187err_free_iclk:
@@ -1022,7 +1190,7 @@ err_free_iclk:
1022 clk_put(host->iclk); 1190 clk_put(host->iclk);
1023 } 1191 }
1024err_free_mmc_host: 1192err_free_mmc_host:
1025 mmc_free_host(host->mmc); 1193 kfree(host);
1026err_free_mem_region: 1194err_free_mem_region:
1027 release_mem_region(res->start, res->end - res->start + 1); 1195 release_mem_region(res->start, res->end - res->start + 1);
1028 return ret; 1196 return ret;
@@ -1031,16 +1199,18 @@ err_free_mem_region:
1031static int mmc_omap_remove(struct platform_device *pdev) 1199static int mmc_omap_remove(struct platform_device *pdev)
1032{ 1200{
1033 struct mmc_omap_host *host = platform_get_drvdata(pdev); 1201 struct mmc_omap_host *host = platform_get_drvdata(pdev);
1202 int i;
1034 1203
1035 platform_set_drvdata(pdev, NULL); 1204 platform_set_drvdata(pdev, NULL);
1036 1205
1037 BUG_ON(host == NULL); 1206 BUG_ON(host == NULL);
1038 1207
1039 mmc_remove_host(host->mmc); 1208 for (i = 0; i < host->nr_slots; i++)
1040 free_irq(host->irq, host); 1209 mmc_omap_remove_slot(host->slots[i]);
1210
1211 if (host->pdata->cleanup)
1212 host->pdata->cleanup(&pdev->dev);
1041 1213
1042 if (host->power_pin >= 0)
1043 omap_free_gpio(host->power_pin);
1044 if (host->iclk && !IS_ERR(host->iclk)) 1214 if (host->iclk && !IS_ERR(host->iclk))
1045 clk_put(host->iclk); 1215 clk_put(host->iclk);
1046 if (host->fclk && !IS_ERR(host->fclk)) 1216 if (host->fclk && !IS_ERR(host->fclk))
@@ -1049,7 +1219,7 @@ static int mmc_omap_remove(struct platform_device *pdev)
1049 release_mem_region(pdev->resource[0].start, 1219 release_mem_region(pdev->resource[0].start,
1050 pdev->resource[0].end - pdev->resource[0].start + 1); 1220 pdev->resource[0].end - pdev->resource[0].start + 1);
1051 1221
1052 mmc_free_host(host->mmc); 1222 kfree(host);
1053 1223
1054 return 0; 1224 return 0;
1055} 1225}
@@ -1057,35 +1227,47 @@ static int mmc_omap_remove(struct platform_device *pdev)
1057#ifdef CONFIG_PM 1227#ifdef CONFIG_PM
1058static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg) 1228static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
1059{ 1229{
1060 int ret = 0; 1230 int i, ret = 0;
1061 struct mmc_omap_host *host = platform_get_drvdata(pdev); 1231 struct mmc_omap_host *host = platform_get_drvdata(pdev);
1062 1232
1063 if (host && host->suspended) 1233 if (host == NULL || host->suspended)
1064 return 0; 1234 return 0;
1065 1235
1066 if (host) { 1236 for (i = 0; i < host->nr_slots; i++) {
1067 ret = mmc_suspend_host(host->mmc, mesg); 1237 struct mmc_omap_slot *slot;
1068 if (ret == 0) 1238
1069 host->suspended = 1; 1239 slot = host->slots[i];
1240 ret = mmc_suspend_host(slot->mmc, mesg);
1241 if (ret < 0) {
1242 while (--i >= 0) {
1243 slot = host->slots[i];
1244 mmc_resume_host(slot->mmc);
1245 }
1246 return ret;
1247 }
1070 } 1248 }
1071 return ret; 1249 host->suspended = 1;
1250 return 0;
1072} 1251}
1073 1252
1074static int mmc_omap_resume(struct platform_device *pdev) 1253static int mmc_omap_resume(struct platform_device *pdev)
1075{ 1254{
1076 int ret = 0; 1255 int i, ret = 0;
1077 struct mmc_omap_host *host = platform_get_drvdata(pdev); 1256 struct mmc_omap_host *host = platform_get_drvdata(pdev);
1078 1257
1079 if (host && !host->suspended) 1258 if (host == NULL || !host->suspended)
1080 return 0; 1259 return 0;
1081 1260
1082 if (host) { 1261 for (i = 0; i < host->nr_slots; i++) {
1083 ret = mmc_resume_host(host->mmc); 1262 struct mmc_omap_slot *slot;
1084 if (ret == 0) 1263 slot = host->slots[i];
1085 host->suspended = 0; 1264 ret = mmc_resume_host(slot->mmc);
1086 } 1265 if (ret < 0)
1266 return ret;
1087 1267
1088 return ret; 1268 host->suspended = 0;
1269 }
1270 return 0;
1089} 1271}
1090#else 1272#else
1091#define mmc_omap_suspend NULL 1273#define mmc_omap_suspend NULL
diff --git a/include/asm-arm/arch-omap/mmc.h b/include/asm-arm/arch-omap/mmc.h
index b70e37b61242..c9588f49eb52 100644
--- a/include/asm-arm/arch-omap/mmc.h
+++ b/include/asm-arm/arch-omap/mmc.h
@@ -18,6 +18,8 @@
18#define OMAP_MMC_MAX_SLOTS 2 18#define OMAP_MMC_MAX_SLOTS 2
19 19
20struct omap_mmc_platform_data { 20struct omap_mmc_platform_data {
21 struct omap_mmc_conf conf;
22
21 unsigned enabled:1; 23 unsigned enabled:1;
22 /* number of slots on board */ 24 /* number of slots on board */
23 unsigned nr_slots:2; 25 unsigned nr_slots:2;