Commit 65ae2118 authored by Pierre Ossman's avatar Pierre Ossman Committed by Linus Torvalds

[PATCH] mmc: wbsd Secure Digital support

Add support for Secure Digital specific features in the wbsd driver.  Adds
support for read-only switch and wide bus transfers.
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e619524f
...@@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) ...@@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
* calculate CRC. * calculate CRC.
* *
* Space for CRC must be included in the size. * Space for CRC must be included in the size.
* Two bytes are needed for each data line.
*/ */
if (host->bus_width == MMC_BUS_WIDTH_1)
{
blksize = (1 << data->blksz_bits) + 2; blksize = (1 << data->blksz_bits) + 2;
wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); 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_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_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 * Clear the FIFO. This is needed even for DMA
...@@ -960,9 +977,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) ...@@ -960,9 +977,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
struct wbsd_host* host = mmc_priv(mmc); struct wbsd_host* host = mmc_priv(mmc);
u8 clk, setup, pwr; u8 clk, setup, pwr;
DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u\n", 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->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
ios->vdd); ios->vdd, ios->bus_width);
spin_lock_bh(&host->lock); spin_lock_bh(&host->lock);
...@@ -1010,6 +1027,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) ...@@ -1010,6 +1027,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
setup = wbsd_read_index(host, WBSD_IDX_SETUP); setup = wbsd_read_index(host, WBSD_IDX_SETUP);
if (ios->chip_select == MMC_CS_HIGH) if (ios->chip_select == MMC_CS_HIGH)
{ {
BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
setup |= WBSD_DAT3_H; setup |= WBSD_DAT3_H;
host->flags |= WBSD_FIGNORE_DETECT; host->flags |= WBSD_FIGNORE_DETECT;
} }
...@@ -1025,12 +1043,41 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) ...@@ -1025,12 +1043,41 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
} }
wbsd_write_index(host, WBSD_IDX_SETUP, setup); 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); 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 = { static struct mmc_host_ops wbsd_ops = {
.request = wbsd_request, .request = wbsd_request,
.set_ios = wbsd_set_ios, .set_ios = wbsd_set_ios,
.get_ro = wbsd_get_ro,
}; };
/*****************************************************************************\ /*****************************************************************************\
...@@ -1355,6 +1402,7 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) ...@@ -1355,6 +1402,7 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
mmc->f_min = 375000; mmc->f_min = 375000;
mmc->f_max = 24000000; mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
mmc->caps = MMC_CAP_4_BIT_DATA;
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
......
...@@ -106,6 +106,8 @@ ...@@ -106,6 +106,8 @@
#define WBSD_CLK_16M 0x02 #define WBSD_CLK_16M 0x02
#define WBSD_CLK_24M 0x03 #define WBSD_CLK_24M 0x03
#define WBSD_DATA_WIDTH 0x01
#define WBSD_DAT3_H 0x08 #define WBSD_DAT3_H 0x08
#define WBSD_FIFO_RESET 0x04 #define WBSD_FIFO_RESET 0x04
#define WBSD_SOFT_RESET 0x02 #define WBSD_SOFT_RESET 0x02
...@@ -164,6 +166,7 @@ struct wbsd_host ...@@ -164,6 +166,7 @@ struct wbsd_host
int firsterr; /* See fifo functions */ int firsterr; /* See fifo functions */
u8 clk; /* Current clock speed */ u8 clk; /* Current clock speed */
unsigned char bus_width; /* Current bus width */
int config; /* Config port */ int config; /* Config port */
u8 unlock_code; /* Code to unlock config */ u8 unlock_code; /* Code to unlock config */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment