diff options
Diffstat (limited to 'drivers/mmc/wbsd.c')
-rw-r--r-- | drivers/mmc/wbsd.c | 121 |
1 files changed, 94 insertions, 27 deletions
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 402c2d661fb..e11e55dc892 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,17 +1087,28 @@ static struct mmc_host_ops wbsd_ops = { \*****************************************************************************/ /* - * Helper function for card detection + * Helper function to reset detection ignore */ -static void wbsd_detect_card(unsigned long data) + +static void wbsd_reset_ignore(unsigned long data) { struct wbsd_host *host = (struct wbsd_host*)data; - + BUG_ON(host == NULL); - - DBG("Executing card detection\n"); - - mmc_detect_change(host->mmc); + + 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); } /* @@ -1093,14 +1155,16 @@ static void wbsd_tasklet_card(unsigned long param) DBG("Card inserted\n"); host->flags |= WBSD_FCARD_PRESENT; + spin_unlock(&host->lock); + /* * Delay card detection to allow electrical connections * to stabilise. */ - mod_timer(&host->timer, jiffies + HZ/2); + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); } - - spin_unlock(&host->lock); + else + spin_unlock(&host->lock); } else if (host->flags & WBSD_FCARD_PRESENT) { @@ -1122,8 +1186,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 +1390,16 @@ 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->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 +1437,7 @@ 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); mmc_free_host(mmc); |