X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmmc%2Fhost%2Fomap.c;h=2b281680e3206da99f9e991d69f12c5edef92754;hb=cc106eb35ed4abea675bce0d8fe40a46ff0b4a72;hp=a1dfa74c50ab6ab68770ff199fffc5421cde6ced;hpb=eb1860bccd01a75b20fd7298af89b9cbda2202ba;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index a1dfa74..2b28168 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -26,43 +26,43 @@ #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #define OMAP_MMC_REG_CMD 0x00 -#define OMAP_MMC_REG_ARGL 0x04 -#define OMAP_MMC_REG_ARGH 0x08 -#define OMAP_MMC_REG_CON 0x0c -#define OMAP_MMC_REG_STAT 0x10 -#define OMAP_MMC_REG_IE 0x14 -#define OMAP_MMC_REG_CTO 0x18 -#define OMAP_MMC_REG_DTO 0x1c -#define OMAP_MMC_REG_DATA 0x20 -#define OMAP_MMC_REG_BLEN 0x24 -#define OMAP_MMC_REG_NBLK 0x28 -#define OMAP_MMC_REG_BUF 0x2c -#define OMAP_MMC_REG_SDIO 0x34 -#define OMAP_MMC_REG_REV 0x3c -#define OMAP_MMC_REG_RSP0 0x40 -#define OMAP_MMC_REG_RSP1 0x44 -#define OMAP_MMC_REG_RSP2 0x48 -#define OMAP_MMC_REG_RSP3 0x4c -#define OMAP_MMC_REG_RSP4 0x50 -#define OMAP_MMC_REG_RSP5 0x54 -#define OMAP_MMC_REG_RSP6 0x58 -#define OMAP_MMC_REG_RSP7 0x5c -#define OMAP_MMC_REG_IOSR 0x60 -#define OMAP_MMC_REG_SYSC 0x64 -#define OMAP_MMC_REG_SYSS 0x68 +#define OMAP_MMC_REG_ARGL 0x01 +#define OMAP_MMC_REG_ARGH 0x02 +#define OMAP_MMC_REG_CON 0x03 +#define OMAP_MMC_REG_STAT 0x04 +#define OMAP_MMC_REG_IE 0x05 +#define OMAP_MMC_REG_CTO 0x06 +#define OMAP_MMC_REG_DTO 0x07 +#define OMAP_MMC_REG_DATA 0x08 +#define OMAP_MMC_REG_BLEN 0x09 +#define OMAP_MMC_REG_NBLK 0x0a +#define OMAP_MMC_REG_BUF 0x0b +#define OMAP_MMC_REG_SDIO 0x0d +#define OMAP_MMC_REG_REV 0x0f +#define OMAP_MMC_REG_RSP0 0x10 +#define OMAP_MMC_REG_RSP1 0x11 +#define OMAP_MMC_REG_RSP2 0x12 +#define OMAP_MMC_REG_RSP3 0x13 +#define OMAP_MMC_REG_RSP4 0x14 +#define OMAP_MMC_REG_RSP5 0x15 +#define OMAP_MMC_REG_RSP6 0x16 +#define OMAP_MMC_REG_RSP7 0x17 +#define OMAP_MMC_REG_IOSR 0x18 +#define OMAP_MMC_REG_SYSC 0x19 +#define OMAP_MMC_REG_SYSS 0x1a #define OMAP_MMC_STAT_CARD_ERR (1 << 14) #define OMAP_MMC_STAT_CARD_IRQ (1 << 13) @@ -78,8 +78,9 @@ #define OMAP_MMC_STAT_CARD_BUSY (1 << 2) #define OMAP_MMC_STAT_END_OF_CMD (1 << 0) -#define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg) -#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg) +#define OMAP_MMC_REG(host, reg) (OMAP_MMC_REG_##reg << (host)->reg_shift) +#define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg)) +#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg)) /* * Command types @@ -94,7 +95,7 @@ /* Specifies how often in millisecs to poll for card status changes * when the cover switch is open */ -#define OMAP_MMC_SWITCH_POLL_DELAY 500 +#define OMAP_MMC_COVER_POLL_DELAY 500 struct mmc_omap_host; @@ -106,8 +107,8 @@ struct mmc_omap_slot { unsigned int fclk_freq; unsigned powered:1; - struct work_struct switch_work; - struct timer_list switch_timer; + struct tasklet_struct cover_tasklet; + struct timer_list cover_timer; unsigned cover_open; struct mmc_request *mrq; @@ -133,9 +134,16 @@ struct mmc_omap_host { int irq; unsigned char bus_mode; unsigned char hw_bus_mode; + unsigned int reg_shift; - struct work_struct cmd_abort; - struct timer_list cmd_timer; + struct work_struct cmd_abort_work; + unsigned abort:1; + struct timer_list cmd_abort_timer; + + struct work_struct slot_release_work; + struct mmc_omap_slot *next_slot; + struct work_struct send_stop_work; + struct mmc_data *stop_data; unsigned int sg_len; int sg_idx; @@ -152,17 +160,44 @@ struct mmc_omap_host { struct timer_list dma_timer; unsigned dma_len; - short power_pin; - struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; struct mmc_omap_slot *current_slot; spinlock_t slot_lock; wait_queue_head_t slot_wq; int nr_slots; + struct timer_list clk_timer; + spinlock_t clk_lock; /* for changing enabled state */ + unsigned int fclk_enabled:1; + struct omap_mmc_platform_data *pdata; }; +static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot) +{ + unsigned long tick_ns; + + if (slot != NULL && slot->host->fclk_enabled && slot->fclk_freq > 0) { + tick_ns = (1000000000 + slot->fclk_freq - 1) / slot->fclk_freq; + ndelay(8 * tick_ns); + } +} + +static void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&host->clk_lock, flags); + if (host->fclk_enabled != enable) { + host->fclk_enabled = enable; + if (enable) + clk_enable(host->fclk); + else + clk_disable(host->fclk); + } + spin_unlock_irqrestore(&host->clk_lock, flags); +} + static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) { struct mmc_omap_host *host = slot->host; @@ -179,52 +214,82 @@ static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) host->mmc = slot->mmc; spin_unlock_irqrestore(&host->slot_lock, flags); no_claim: - clk_enable(host->fclk); + del_timer(&host->clk_timer); + if (host->current_slot != slot || !claimed) + mmc_omap_fclk_offdelay(host->current_slot); + if (host->current_slot != slot) { + OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00); if (host->pdata->switch_slot != NULL) host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id); host->current_slot = slot; } - /* Doing the dummy read here seems to work around some bug - * at least in OMAP24xx silicon where the command would not - * start after writing the CMD register. Sigh. */ - OMAP_MMC_READ(host, CON); + if (claimed) { + mmc_omap_fclk_enable(host, 1); + + /* Doing the dummy read here seems to work around some bug + * at least in OMAP24xx silicon where the command would not + * start after writing the CMD register. Sigh. */ + OMAP_MMC_READ(host, CON); - OMAP_MMC_WRITE(host, CON, slot->saved_con); + OMAP_MMC_WRITE(host, CON, slot->saved_con); + } else + mmc_omap_fclk_enable(host, 0); } static void mmc_omap_start_request(struct mmc_omap_host *host, struct mmc_request *req); -static void mmc_omap_release_slot(struct mmc_omap_slot *slot) +static void mmc_omap_slot_release_work(struct work_struct *work) +{ + struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, + slot_release_work); + struct mmc_omap_slot *next_slot = host->next_slot; + struct mmc_request *rq; + + host->next_slot = NULL; + mmc_omap_select_slot(next_slot, 1); + + rq = next_slot->mrq; + next_slot->mrq = NULL; + mmc_omap_start_request(host, rq); +} + +static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) { struct mmc_omap_host *host = slot->host; unsigned long flags; int i; BUG_ON(slot == NULL || host->mmc == NULL); - clk_disable(host->fclk); + + if (clk_enabled) + /* Keeps clock running for at least 8 cycles on valid freq */ + mod_timer(&host->clk_timer, jiffies + HZ/10); + else { + del_timer(&host->clk_timer); + mmc_omap_fclk_offdelay(slot); + mmc_omap_fclk_enable(host, 0); + } spin_lock_irqsave(&host->slot_lock, flags); /* Check for any pending requests */ for (i = 0; i < host->nr_slots; i++) { struct mmc_omap_slot *new_slot; - struct mmc_request *rq; if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) continue; + BUG_ON(host->next_slot != NULL); new_slot = host->slots[i]; /* The current slot should not have a request in queue */ BUG_ON(new_slot == host->current_slot); + host->next_slot = new_slot; host->mmc = new_slot->mmc; spin_unlock_irqrestore(&host->slot_lock, flags); - mmc_omap_select_slot(new_slot, 1); - rq = new_slot->mrq; - new_slot->mrq = NULL; - mmc_omap_start_request(host, rq); + schedule_work(&host->slot_release_work); return; } @@ -236,7 +301,10 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot) static inline int mmc_omap_cover_is_open(struct mmc_omap_slot *slot) { - return slot->pdata->get_cover_state(mmc_dev(slot->mmc), slot->id); + if (slot->pdata->get_cover_state) + return slot->pdata->get_cover_state(mmc_dev(slot->mmc), + slot->id); + return 0; } static ssize_t @@ -317,7 +385,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) if (host->data && !(host->data->flags & MMC_DATA_WRITE)) cmdreg |= 1 << 15; - mod_timer(&host->cmd_timer, jiffies + HZ/2); + mod_timer(&host->cmd_abort_timer, jiffies + HZ/2); OMAP_MMC_WRITE(host, CTO, 200); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); @@ -350,6 +418,20 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, dma_data_dir); } +static void mmc_omap_send_stop_work(struct work_struct *work) +{ + struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, + send_stop_work); + struct mmc_omap_slot *slot = host->current_slot; + struct mmc_data *data = host->stop_data; + unsigned long tick_ns; + + tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq; + ndelay(8*tick_ns); + + mmc_omap_start_command(host, data->stop); +} + static void mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) { @@ -369,16 +451,17 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) host->mrq = NULL; mmc = host->mmc; - mmc_omap_release_slot(host->current_slot); + mmc_omap_release_slot(host->current_slot, 1); mmc_request_done(mmc, data->mrq); return; } - mmc_omap_start_command(host, data->stop); + host->stop_data = data; + schedule_work(&host->send_stop_work); } static void -mmc_omap_send_abort(struct mmc_omap_host *host) +mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops) { struct mmc_omap_slot *slot = host->current_slot; unsigned int restarts, passes, timeout; @@ -387,7 +470,7 @@ mmc_omap_send_abort(struct mmc_omap_host *host) /* Sending abort takes 80 clocks. Have some extra and round up */ timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq; restarts = 0; - while (restarts < 10000) { + while (restarts < maxloops) { OMAP_MMC_WRITE(host, STAT, 0xFFFF); OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7)); @@ -409,18 +492,13 @@ out: static void mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) { - u16 ie; - if (host->dma_in_use) mmc_omap_release_dma(host, data, 1); host->data = NULL; host->sg_len = 0; - ie = OMAP_MMC_READ(host, IE); - OMAP_MMC_WRITE(host, IE, 0); - OMAP_MMC_WRITE(host, IE, ie); - mmc_omap_send_abort(host); + mmc_omap_send_abort(host, 10000); } static void @@ -476,7 +554,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) { host->cmd = NULL; - del_timer(&host->cmd_timer); + del_timer(&host->cmd_abort_timer); if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { @@ -508,7 +586,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) mmc_omap_abort_xfer(host, host->data); host->mrq = NULL; mmc = host->mmc; - mmc_omap_release_slot(host->current_slot); + mmc_omap_release_slot(host->current_slot, 1); mmc_request_done(mmc, cmd->mrq); } } @@ -520,38 +598,48 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) static void mmc_omap_abort_command(struct work_struct *work) { struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, - cmd_abort); - u16 ie; - - ie = OMAP_MMC_READ(host, IE); - OMAP_MMC_WRITE(host, IE, 0); - - if (!host->cmd) { - OMAP_MMC_WRITE(host, IE, ie); - return; - } + cmd_abort_work); + BUG_ON(!host->cmd); dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n", host->cmd->opcode); - if (host->data && host->dma_in_use) - mmc_omap_release_dma(host, host->data, 1); + if (host->cmd->error == 0) + host->cmd->error = -ETIMEDOUT; - host->data = NULL; - host->sg_len = 0; + if (host->data == NULL) { + struct mmc_command *cmd; + struct mmc_host *mmc; + + cmd = host->cmd; + host->cmd = NULL; + mmc_omap_send_abort(host, 10000); + + host->mrq = NULL; + mmc = host->mmc; + mmc_omap_release_slot(host->current_slot, 1); + mmc_request_done(mmc, cmd->mrq); + } else + mmc_omap_cmd_done(host, host->cmd); - mmc_omap_send_abort(host); - host->cmd->error = -ETIMEDOUT; - mmc_omap_cmd_done(host, host->cmd); - OMAP_MMC_WRITE(host, IE, ie); + host->abort = 0; + enable_irq(host->irq); } static void mmc_omap_cmd_timer(unsigned long data) { struct mmc_omap_host *host = (struct mmc_omap_host *) data; + unsigned long flags; - schedule_work(&host->cmd_abort); + spin_lock_irqsave(&host->slot_lock, flags); + if (host->cmd != NULL && !host->abort) { + OMAP_MMC_WRITE(host, IE, 0); + disable_irq(host->irq); + host->abort = 1; + schedule_work(&host->cmd_abort_work); + } + spin_unlock_irqrestore(&host->slot_lock, flags); } /* PIO only */ @@ -567,6 +655,14 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host) host->buffer_bytes_left = host->total_bytes_left; } +static void +mmc_omap_clk_timer(unsigned long data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + + mmc_omap_fclk_enable(host, 0); +} + /* PIO only */ static void mmc_omap_xfer_data(struct mmc_omap_host *host, int write) @@ -586,9 +682,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write) host->data->bytes_xfered += n; if (write) { - __raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n); + __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); } else { - __raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n); + __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); } } @@ -725,6 +821,15 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) } } + if (cmd_error && host->data) { + del_timer(&host->cmd_abort_timer); + host->abort = 1; + OMAP_MMC_WRITE(host, IE, 0); + disable_irq_nosync(host->irq); + schedule_work(&host->cmd_abort_work); + return IRQ_HANDLED; + } + if (end_command) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { @@ -737,40 +842,51 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) return IRQ_HANDLED; } -void omap_mmc_notify_cover_event(struct device *dev, int slot, int is_closed) +void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed) { + int cover_open; struct mmc_omap_host *host = dev_get_drvdata(dev); + struct mmc_omap_slot *slot = host->slots[num]; - BUG_ON(slot >= host->nr_slots); + BUG_ON(num >= host->nr_slots); /* Other subsystems can call in here before we're initialised. */ - if (host->nr_slots == 0 || !host->slots[slot]) + if (host->nr_slots == 0 || !host->slots[num]) return; - schedule_work(&host->slots[slot]->switch_work); + cover_open = mmc_omap_cover_is_open(slot); + if (cover_open != slot->cover_open) { + slot->cover_open = cover_open; + sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch"); + } + + tasklet_hi_schedule(&slot->cover_tasklet); } -static void mmc_omap_switch_timer(unsigned long arg) +static void mmc_omap_cover_timer(unsigned long arg) { struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg; - - schedule_work(&slot->switch_work); + tasklet_schedule(&slot->cover_tasklet); } -static void mmc_omap_cover_handler(struct work_struct *work) +static void mmc_omap_cover_handler(unsigned long param) { - struct mmc_omap_slot *slot = container_of(work, struct mmc_omap_slot, - switch_work); - int cover_open; + struct mmc_omap_slot *slot = (struct mmc_omap_slot *)param; + int cover_open = mmc_omap_cover_is_open(slot); - cover_open = mmc_omap_cover_is_open(slot); - if (cover_open != slot->cover_open) { - sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch"); - slot->cover_open = cover_open; - dev_info(mmc_dev(slot->mmc), "cover is now %s\n", - cover_open ? "open" : "closed"); - } - mmc_detect_change(slot->mmc, slot->id); + mmc_detect_change(slot->mmc, 0); + if (!cover_open) + return; + + /* + * If no card is inserted, we postpone polling until + * the cover has been closed. + */ + if (slot->mmc->card == NULL || !mmc_card_present(slot->mmc->card)) + return; + + mod_timer(&slot->cover_timer, + jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); } /* Prepare to transfer the next segment of a scatterlist */ @@ -786,7 +902,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) int dst_port = 0; int sync_dev = 0; - data_addr = host->phys_base + OMAP_MMC_REG_DATA; + data_addr = host->phys_base + OMAP_MMC_REG(host, DATA); frame = data->blksz; count = sg_dma_len(sg); @@ -887,7 +1003,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) { - const char *dev_name; + const char *dma_dev_name; int sync_dev, dma_ch, is_read, r; is_read = !(data->flags & MMC_DATA_WRITE); @@ -900,23 +1016,23 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data } if (is_read) { - if (host->id == 1) { + if (host->id == 0) { sync_dev = OMAP_DMA_MMC_RX; - dev_name = "MMC1 read"; + dma_dev_name = "MMC1 read"; } else { sync_dev = OMAP_DMA_MMC2_RX; - dev_name = "MMC2 read"; + dma_dev_name = "MMC2 read"; } } else { - if (host->id == 1) { + if (host->id == 0) { sync_dev = OMAP_DMA_MMC_TX; - dev_name = "MMC1 write"; + dma_dev_name = "MMC1 write"; } else { sync_dev = OMAP_DMA_MMC2_TX; - dev_name = "MMC2 write"; + dma_dev_name = "MMC2 write"; } } - r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb, + r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb, host, &dma_ch); if (r != 0) { dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r); @@ -1120,14 +1236,16 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct mmc_omap_slot *slot = mmc_priv(mmc); struct mmc_omap_host *host = slot->host; int i, dsor; - - dsor = mmc_omap_calc_divisor(mmc, ios); + int clk_enabled; mmc_omap_select_slot(slot, 0); + dsor = mmc_omap_calc_divisor(mmc, ios); + if (ios->vdd != slot->vdd) slot->vdd = ios->vdd; + clk_enabled = 0; switch (ios->power_mode) { case MMC_POWER_OFF: mmc_omap_set_power(slot, 0, ios->vdd); @@ -1137,6 +1255,8 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mmc_omap_set_power(slot, 1, ios->vdd); goto exit; case MMC_POWER_ON: + mmc_omap_fclk_enable(host, 1); + clk_enabled = 1; dsor |= 1 << 11; break; } @@ -1156,16 +1276,22 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) OMAP_MMC_WRITE(host, CON, dsor); slot->saved_con = dsor; if (ios->power_mode == MMC_POWER_ON) { + /* worst case at 400kHz, 80 cycles makes 200 microsecs */ + int usecs = 250; + /* Send clock cycles, poll completion */ OMAP_MMC_WRITE(host, IE, 0); OMAP_MMC_WRITE(host, STAT, 0xffff); OMAP_MMC_WRITE(host, CMD, 1 << 7); - while ((OMAP_MMC_READ(host, STAT) & 1) == 0); + while (usecs > 0 && (OMAP_MMC_READ(host, STAT) & 1) == 0) { + udelay(1); + usecs--; + } OMAP_MMC_WRITE(host, STAT, 1); } exit: - mmc_omap_release_slot(slot); + mmc_omap_release_slot(slot, clk_enabled); } static const struct mmc_host_ops mmc_omap_ops = { @@ -1191,8 +1317,8 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) host->slots[id] = slot; - mmc->caps = MMC_CAP_MULTIWRITE; - if (host->pdata->conf.wire4) + mmc->caps = 0; + if (host->pdata->slots[id].wires >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; mmc->ops = &mmc_omap_ops; @@ -1234,11 +1360,11 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) if (r < 0) goto err_remove_slot_name; - INIT_WORK(&slot->switch_work, mmc_omap_cover_handler); - init_timer(&slot->switch_timer); - slot->switch_timer.function = mmc_omap_switch_timer; - slot->switch_timer.data = (unsigned long) slot; - schedule_work(&slot->switch_work); + setup_timer(&slot->cover_timer, mmc_omap_cover_timer, + (unsigned long)slot); + tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, + (unsigned long)slot); + tasklet_schedule(&slot->cover_tasklet); } return 0; @@ -1261,7 +1387,8 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) if (slot->pdata->get_cover_state != NULL) device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); - del_timer_sync(&slot->switch_timer); + tasklet_kill(&slot->cover_tasklet); + del_timer_sync(&slot->cover_timer); flush_scheduled_work(); mmc_remove_host(mmc); @@ -1301,19 +1428,21 @@ static int __init mmc_omap_probe(struct platform_device *pdev) goto err_free_mem_region; } - INIT_WORK(&host->cmd_abort, mmc_omap_abort_command); - init_timer(&host->cmd_timer); - host->cmd_timer.function = mmc_omap_cmd_timer; - host->cmd_timer.data = (unsigned long) host; + INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work); + INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); + + INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); + setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, + (unsigned long) host); + + spin_lock_init(&host->clk_lock); + setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); spin_lock_init(&host->dma_lock); - init_timer(&host->dma_timer); + setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); spin_lock_init(&host->slot_lock); init_waitqueue_head(&host->slot_wq); - host->dma_timer.function = mmc_omap_dma_timer; - host->dma_timer.data = (unsigned long) host; - host->pdata = pdata; host->dev = &pdev->dev; platform_set_drvdata(pdev, host); @@ -1323,24 +1452,23 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->irq = irq; host->use_dma = 1; + host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; host->irq = irq; host->phys_base = host->mem_res->start; - host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base); - - if (cpu_is_omap24xx()) { - host->iclk = clk_get(&pdev->dev, "mmc_ick"); - if (IS_ERR(host->iclk)) - goto err_free_mmc_host; - clk_enable(host->iclk); + host->virt_base = ioremap(res->start, res->end - res->start + 1); + if (!host->virt_base) + goto err_ioremap; + + host->iclk = clk_get(&pdev->dev, "ick"); + if (IS_ERR(host->iclk)) { + ret = PTR_ERR(host->iclk); + goto err_free_mmc_host; } + clk_enable(host->iclk); - if (!cpu_is_omap24xx()) - host->fclk = clk_get(&pdev->dev, "mmc_ck"); - else - host->fclk = clk_get(&pdev->dev, "mmc_fck"); - + host->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); goto err_free_iclk; @@ -1367,6 +1495,8 @@ static int __init mmc_omap_probe(struct platform_device *pdev) } } + host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); + return 0; err_plat_cleanup: @@ -1377,11 +1507,11 @@ err_free_irq: err_free_fclk: clk_put(host->fclk); err_free_iclk: - if (host->iclk != NULL) { - clk_disable(host->iclk); - clk_put(host->iclk); - } + clk_disable(host->iclk); + clk_put(host->iclk); err_free_mmc_host: + iounmap(host->virt_base); +err_ioremap: kfree(host); err_free_mem_region: release_mem_region(res->start, res->end - res->start + 1); @@ -1403,11 +1533,13 @@ static int mmc_omap_remove(struct platform_device *pdev) if (host->pdata->cleanup) host->pdata->cleanup(&pdev->dev); - if (host->iclk && !IS_ERR(host->iclk)) - clk_put(host->iclk); - if (host->fclk && !IS_ERR(host->fclk)) - clk_put(host->fclk); + mmc_omap_fclk_enable(host, 0); + free_irq(host->irq, host); + clk_put(host->fclk); + clk_disable(host->iclk); + clk_put(host->iclk); + iounmap(host->virt_base); release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); @@ -1429,7 +1561,7 @@ static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg) struct mmc_omap_slot *slot; slot = host->slots[i]; - ret = mmc_suspend_host(slot->mmc, mesg); + ret = mmc_suspend_host(slot->mmc); if (ret < 0) { while (--i >= 0) { slot = host->slots[i]; @@ -1467,7 +1599,6 @@ static int mmc_omap_resume(struct platform_device *pdev) #endif static struct platform_driver mmc_omap_driver = { - .probe = mmc_omap_probe, .remove = mmc_omap_remove, .suspend = mmc_omap_suspend, .resume = mmc_omap_resume, @@ -1479,7 +1610,7 @@ static struct platform_driver mmc_omap_driver = { static int __init mmc_omap_init(void) { - return platform_driver_register(&mmc_omap_driver); + return platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); } static void __exit mmc_omap_exit(void)