From: Pierre Ossman Add support for Secure Digital specific features in the wbsd driver. Adds support for read-only switch and wide bus transfers. Signed-off-by: Pierre Ossman Cc: Russell King Signed-off-by: Andrew Morton --- drivers/mmc/wbsd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++------ drivers/mmc/wbsd.h | 3 ++ 2 files changed, 58 insertions(+), 6 deletions(-) diff -puN drivers/mmc/wbsd.c~mmc-wbsd-secure-digital-support drivers/mmc/wbsd.c --- 25/drivers/mmc/wbsd.c~mmc-wbsd-secure-digital-support Wed Aug 17 15:44:38 2005 +++ 25-akpm/drivers/mmc/wbsd.c Wed Aug 17 15:44:38 2005 @@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbs * 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 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 Vdd %u width %u\n", + ios->clock, ios->bus_mode, ios->power_mode, ios->vdd, + ios->bus_width); spin_lock_bh(&host->lock); @@ -1009,7 +1027,8 @@ static void wbsd_set_ios(struct mmc_host */ setup = wbsd_read_index(host, WBSD_IDX_SETUP); if ((ios->power_mode == MMC_POWER_ON) && - (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)) + (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) && + (ios->bus_width == MMC_BUS_WIDTH_1)) { setup |= WBSD_DAT3_H; host->flags |= WBSD_FIGNORE_DETECT; @@ -1021,12 +1040,41 @@ static void wbsd_set_ios(struct mmc_host } 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, }; /*****************************************************************************\ @@ -1324,6 +1372,7 @@ static int __devinit wbsd_alloc_mmc(stru 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); diff -puN drivers/mmc/wbsd.h~mmc-wbsd-secure-digital-support drivers/mmc/wbsd.h --- 25/drivers/mmc/wbsd.h~mmc-wbsd-secure-digital-support Wed Aug 17 15:44:38 2005 +++ 25-akpm/drivers/mmc/wbsd.h Wed Aug 17 15:44:38 2005 @@ -106,6 +106,8 @@ #define WBSD_CLK_16M 0x02 #define WBSD_CLK_24M 0x03 +#define WBSD_DATA_WIDTH 0x01 + #define WBSD_DAT3_H 0x08 #define WBSD_FIFO_RESET 0x04 #define WBSD_SOFT_RESET 0x02 @@ -164,6 +166,7 @@ struct wbsd_host int firsterr; /* See fifo functions */ u8 clk; /* Current clock speed */ + unsigned char bus_width; /* Current bus width */ int config; /* Config port */ u8 unlock_code; /* Code to unlock config */ _