summaryrefslogtreecommitdiff
path: root/drivers/mmc/wbsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/wbsd.c')
-rw-r--r--drivers/mmc/wbsd.c122
1 files changed, 103 insertions, 19 deletions
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 402c2d661fb2..a62c86fef5cc 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -42,7 +42,7 @@
#include "wbsd.h"
#define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.3"
+#define DRIVER_VERSION "1.4"
#ifdef CONFIG_MMC_DEBUG
#define DBG(x...) \
@@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
* calculate CRC.
*
* Space for CRC must be included in the size.
+ * Two bytes are needed for each data line.
*/
- blksize = (1 << data->blksz_bits) + 2;
+ if (host->bus_width == MMC_BUS_WIDTH_1)
+ {
+ blksize = (1 << data->blksz_bits) + 2;
+
+ wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+ wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ }
+ else if (host->bus_width == MMC_BUS_WIDTH_4)
+ {
+ blksize = (1 << data->blksz_bits) + 2 * 4;
- wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
- wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
+ | WBSD_DATA_WIDTH);
+ wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+ }
+ else
+ {
+ data->error = MMC_ERR_INVALID;
+ return;
+ }
/*
* Clear the FIFO. This is needed even for DMA
@@ -960,8 +977,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
struct wbsd_host* host = mmc_priv(mmc);
u8 clk, setup, pwr;
- DBGF("clock %uHz busmode %u powermode %u Vdd %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+ DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+ ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
+ ios->vdd, ios->bus_width);
spin_lock_bh(&host->lock);
@@ -1003,30 +1021,63 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
/*
* MMC cards need to have pin 1 high during init.
- * Init time corresponds rather nicely with the bus mode.
* It wreaks havoc with the card detection though so
- * that needs to be disabed.
+ * that needs to be disabled.
*/
setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- if ((ios->power_mode == MMC_POWER_ON) &&
- (ios->bus_mode == MMC_BUSMODE_OPENDRAIN))
+ if (ios->chip_select == MMC_CS_HIGH)
{
+ BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
setup |= WBSD_DAT3_H;
host->flags |= WBSD_FIGNORE_DETECT;
}
else
{
setup &= ~WBSD_DAT3_H;
- host->flags &= ~WBSD_FIGNORE_DETECT;
+
+ /*
+ * We cannot resume card detection immediatly
+ * because of capacitance and delays in the chip.
+ */
+ mod_timer(&host->ignore_timer, jiffies + HZ/100);
}
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+ /*
+ * Store bus width for later. Will be used when
+ * setting up the data transfer.
+ */
+ host->bus_width = ios->bus_width;
+
+ spin_unlock_bh(&host->lock);
+}
+
+static int wbsd_get_ro(struct mmc_host* mmc)
+{
+ struct wbsd_host* host = mmc_priv(mmc);
+ u8 csr;
+
+ spin_lock_bh(&host->lock);
+
+ csr = inb(host->base + WBSD_CSR);
+ csr |= WBSD_MSLED;
+ outb(csr, host->base + WBSD_CSR);
+
+ mdelay(1);
+
+ csr = inb(host->base + WBSD_CSR);
+ csr &= ~WBSD_MSLED;
+ outb(csr, host->base + WBSD_CSR);
+
spin_unlock_bh(&host->lock);
+
+ return csr & WBSD_WRPT;
}
static struct mmc_host_ops wbsd_ops = {
.request = wbsd_request,
.set_ios = wbsd_set_ios,
+ .get_ro = wbsd_get_ro,
};
/*****************************************************************************\
@@ -1036,6 +1087,31 @@ static struct mmc_host_ops wbsd_ops = {
\*****************************************************************************/
/*
+ * Helper function to reset detection ignore
+ */
+
+static void wbsd_reset_ignore(unsigned long data)
+{
+ struct wbsd_host *host = (struct wbsd_host*)data;
+
+ BUG_ON(host == NULL);
+
+ DBG("Resetting card detection ignore\n");
+
+ spin_lock_bh(&host->lock);
+
+ host->flags &= ~WBSD_FIGNORE_DETECT;
+
+ /*
+ * Card status might have changed during the
+ * blackout.
+ */
+ tasklet_schedule(&host->card_tasklet);
+
+ spin_unlock_bh(&host->lock);
+}
+
+/*
* Helper function for card detection
*/
static void wbsd_detect_card(unsigned long data)
@@ -1046,7 +1122,7 @@ static void wbsd_detect_card(unsigned long data)
DBG("Executing card detection\n");
- mmc_detect_change(host->mmc);
+ mmc_detect_change(host->mmc, 0);
}
/*
@@ -1097,7 +1173,7 @@ static void wbsd_tasklet_card(unsigned long param)
* Delay card detection to allow electrical connections
* to stabilise.
*/
- mod_timer(&host->timer, jiffies + HZ/2);
+ mod_timer(&host->detect_timer, jiffies + HZ/2);
}
spin_unlock(&host->lock);
@@ -1122,8 +1198,10 @@ static void wbsd_tasklet_card(unsigned long param)
*/
spin_unlock(&host->lock);
- mmc_detect_change(host->mmc);
+ mmc_detect_change(host->mmc, 0);
}
+ else
+ spin_unlock(&host->lock);
}
static void wbsd_tasklet_fifo(unsigned long param)
@@ -1324,15 +1402,20 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
spin_lock_init(&host->lock);
/*
- * Set up detection timer
+ * Set up timers
*/
- init_timer(&host->timer);
- host->timer.data = (unsigned long)host;
- host->timer.function = wbsd_detect_card;
+ init_timer(&host->detect_timer);
+ host->detect_timer.data = (unsigned long)host;
+ host->detect_timer.function = wbsd_detect_card;
+
+ init_timer(&host->ignore_timer);
+ host->ignore_timer.data = (unsigned long)host;
+ host->ignore_timer.function = wbsd_reset_ignore;
/*
* Maximum number of segments. Worst case is one sector per segment
@@ -1370,7 +1453,8 @@ static void __devexit wbsd_free_mmc(struct device* dev)
host = mmc_priv(mmc);
BUG_ON(host == NULL);
- del_timer_sync(&host->timer);
+ del_timer_sync(&host->ignore_timer);
+ del_timer_sync(&host->detect_timer);
mmc_free_host(mmc);