#include <linux/clk.h>
#include <linux/scatterlist.h>
#include <linux/i2c/tps65010.h>
+#include <linux/slab.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/arch/board.h>
-#include <asm/arch/mmc.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/fpga.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
+#include <mach/gpio.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
#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)
#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
/* 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;
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;
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;
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;
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;
}
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
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);
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)
{
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;
/* 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));
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
{
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) {
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);
}
}
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 */
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)
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);
}
}
}
}
+ 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) {
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 */
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);
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);
}
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);
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);
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;
}
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 = {
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;
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;
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);
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);
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;
}
}
+ host->reg_shift = (cpu_is_omap7xx() ? 1 : 2);
+
return 0;
err_plat_cleanup:
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);
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);
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];
#endif
static struct platform_driver mmc_omap_driver = {
- .probe = mmc_omap_probe,
.remove = mmc_omap_remove,
.suspend = mmc_omap_suspend,
.resume = mmc_omap_resume,
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)