diff options
| author | Pierre Ossman <drzeus@drzeus.cx> | 2005-09-06 18:18:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:51 -0400 |
| commit | 65ae2118e84616680dce37b951ffc366dcce7cf0 (patch) | |
| tree | e4148db8d317b895575cb362e208ff17c1150dd0 /drivers/mmc/wbsd.c | |
| parent | e619524fe5f5b0c13db34ed0f6320d2dcccf6e8d (diff) | |
[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: Pierre Ossman <drzeus@drzeus.cx>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/mmc/wbsd.c')
| -rw-r--r-- | drivers/mmc/wbsd.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 08ae22aed9e8..dec01d38c782 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
| @@ -720,11 +720,28 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) | |||
| 720 | * calculate CRC. | 720 | * calculate CRC. |
| 721 | * | 721 | * |
| 722 | * Space for CRC must be included in the size. | 722 | * Space for CRC must be included in the size. |
| 723 | * Two bytes are needed for each data line. | ||
| 723 | */ | 724 | */ |
| 724 | blksize = (1 << data->blksz_bits) + 2; | 725 | if (host->bus_width == MMC_BUS_WIDTH_1) |
| 726 | { | ||
| 727 | blksize = (1 << data->blksz_bits) + 2; | ||
| 728 | |||
| 729 | wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); | ||
| 730 | wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); | ||
| 731 | } | ||
| 732 | else if (host->bus_width == MMC_BUS_WIDTH_4) | ||
| 733 | { | ||
| 734 | blksize = (1 << data->blksz_bits) + 2 * 4; | ||
| 725 | 735 | ||
| 726 | wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); | 736 | wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0) |
| 727 | wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); | 737 | | WBSD_DATA_WIDTH); |
| 738 | wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); | ||
| 739 | } | ||
| 740 | else | ||
| 741 | { | ||
| 742 | data->error = MMC_ERR_INVALID; | ||
| 743 | return; | ||
| 744 | } | ||
| 728 | 745 | ||
| 729 | /* | 746 | /* |
| 730 | * Clear the FIFO. This is needed even for DMA | 747 | * 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 | struct wbsd_host* host = mmc_priv(mmc); | 977 | struct wbsd_host* host = mmc_priv(mmc); |
| 961 | u8 clk, setup, pwr; | 978 | u8 clk, setup, pwr; |
| 962 | 979 | ||
| 963 | DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u\n", | 980 | DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", |
| 964 | ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, | 981 | ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, |
| 965 | ios->vdd); | 982 | ios->vdd, ios->bus_width); |
| 966 | 983 | ||
| 967 | spin_lock_bh(&host->lock); | 984 | spin_lock_bh(&host->lock); |
| 968 | 985 | ||
| @@ -1010,6 +1027,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) | |||
| 1010 | setup = wbsd_read_index(host, WBSD_IDX_SETUP); | 1027 | setup = wbsd_read_index(host, WBSD_IDX_SETUP); |
| 1011 | if (ios->chip_select == MMC_CS_HIGH) | 1028 | if (ios->chip_select == MMC_CS_HIGH) |
| 1012 | { | 1029 | { |
| 1030 | BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1); | ||
| 1013 | setup |= WBSD_DAT3_H; | 1031 | setup |= WBSD_DAT3_H; |
| 1014 | host->flags |= WBSD_FIGNORE_DETECT; | 1032 | host->flags |= WBSD_FIGNORE_DETECT; |
| 1015 | } | 1033 | } |
| @@ -1025,12 +1043,41 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) | |||
| 1025 | } | 1043 | } |
| 1026 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | 1044 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); |
| 1027 | 1045 | ||
| 1046 | /* | ||
| 1047 | * Store bus width for later. Will be used when | ||
| 1048 | * setting up the data transfer. | ||
| 1049 | */ | ||
| 1050 | host->bus_width = ios->bus_width; | ||
| 1051 | |||
| 1028 | spin_unlock_bh(&host->lock); | 1052 | spin_unlock_bh(&host->lock); |
| 1029 | } | 1053 | } |
| 1030 | 1054 | ||
| 1055 | static int wbsd_get_ro(struct mmc_host* mmc) | ||
| 1056 | { | ||
| 1057 | struct wbsd_host* host = mmc_priv(mmc); | ||
| 1058 | u8 csr; | ||
| 1059 | |||
| 1060 | spin_lock_bh(&host->lock); | ||
| 1061 | |||
| 1062 | csr = inb(host->base + WBSD_CSR); | ||
| 1063 | csr |= WBSD_MSLED; | ||
| 1064 | outb(csr, host->base + WBSD_CSR); | ||
| 1065 | |||
| 1066 | mdelay(1); | ||
| 1067 | |||
| 1068 | csr = inb(host->base + WBSD_CSR); | ||
| 1069 | csr &= ~WBSD_MSLED; | ||
| 1070 | outb(csr, host->base + WBSD_CSR); | ||
| 1071 | |||
| 1072 | spin_unlock_bh(&host->lock); | ||
| 1073 | |||
| 1074 | return csr & WBSD_WRPT; | ||
| 1075 | } | ||
| 1076 | |||
| 1031 | static struct mmc_host_ops wbsd_ops = { | 1077 | static struct mmc_host_ops wbsd_ops = { |
| 1032 | .request = wbsd_request, | 1078 | .request = wbsd_request, |
| 1033 | .set_ios = wbsd_set_ios, | 1079 | .set_ios = wbsd_set_ios, |
| 1080 | .get_ro = wbsd_get_ro, | ||
| 1034 | }; | 1081 | }; |
| 1035 | 1082 | ||
| 1036 | /*****************************************************************************\ | 1083 | /*****************************************************************************\ |
| @@ -1355,6 +1402,7 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) | |||
| 1355 | mmc->f_min = 375000; | 1402 | mmc->f_min = 375000; |
| 1356 | mmc->f_max = 24000000; | 1403 | mmc->f_max = 24000000; |
| 1357 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; | 1404 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; |
| 1405 | mmc->caps = MMC_CAP_4_BIT_DATA; | ||
| 1358 | 1406 | ||
| 1359 | spin_lock_init(&host->lock); | 1407 | spin_lock_init(&host->lock); |
| 1360 | 1408 | ||
