diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-05 13:18:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-05 13:18:21 -0400 |
commit | 0a053e8c71d666daf30da2d407147b1293923d8b (patch) | |
tree | 9ba3967845db9053cb2ca045f01a9454eb5e6230 /drivers/mmc/core | |
parent | 601cc11d054ae4b5e9b5babec3d8e4667a2cb9b5 (diff) | |
parent | 32ab83a56fdf42f543b86c349143c2a86ead9707 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (42 commits)
atmel-mci: fix sdc_reg typo
tmio_mmc: add maintainer
mmc: Add OpenFirmware bindings for SDHCI driver
sdhci: Add quirk for forcing maximum block size to 2048 bytes
sdhci: Add quirk for controllers that need IRQ re-init after reset
sdhci: Add quirk for controllers that need small delays for PIO
sdhci: Add set_clock callback and a quirk for nonstandard clocks
sdhci: Add get_{max,timeout}_clock callbacks
sdhci: Add support for hosts reporting inverted write-protect state
sdhci: Add support for card-detection polling
sdhci: Enable only relevant (DMA/PIO) interrupts during transfers
sdhci: Split card-detection IRQs management from sdhci_init()
sdhci: Add support for bus-specific IO memory accessors
mmc_spi: adjust for delayed data token response
omap_hsmmc: Wait for SDBP
omap_hsmmc: Fix MMC3 dma
omap_hsmmc: Disable SDBP at suspend
omap_hsmmc: Do not prefix slot name
omap_hsmmc: Allow cover switch to cause rescan
omap_hsmmc: Add 8-bit bus width mode support
...
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/bus.c | 8 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 18 | ||||
-rw-r--r-- | drivers/mmc/core/debugfs.c | 67 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_cis.c | 8 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 8 |
5 files changed, 109 insertions, 0 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index f210a8ee686..bdb165f9304 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c | |||
@@ -84,6 +84,14 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
84 | } | 84 | } |
85 | 85 | ||
86 | retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); | 86 | retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); |
87 | if (retval) | ||
88 | return retval; | ||
89 | |||
90 | /* | ||
91 | * Request the mmc_block device. Note: that this is a direct request | ||
92 | * for the module it carries no information as to what is inserted. | ||
93 | */ | ||
94 | retval = add_uevent_var(env, "MODALIAS=mmc:block"); | ||
87 | 95 | ||
88 | return retval; | 96 | return retval; |
89 | } | 97 | } |
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1445ea8f10a..fa073ab3fa3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -298,6 +298,21 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) | |||
298 | data->timeout_clks = 0; | 298 | data->timeout_clks = 0; |
299 | } | 299 | } |
300 | } | 300 | } |
301 | /* | ||
302 | * Some cards need very high timeouts if driven in SPI mode. | ||
303 | * The worst observed timeout was 900ms after writing a | ||
304 | * continuous stream of data until the internal logic | ||
305 | * overflowed. | ||
306 | */ | ||
307 | if (mmc_host_is_spi(card->host)) { | ||
308 | if (data->flags & MMC_DATA_WRITE) { | ||
309 | if (data->timeout_ns < 1000000000) | ||
310 | data->timeout_ns = 1000000000; /* 1s */ | ||
311 | } else { | ||
312 | if (data->timeout_ns < 100000000) | ||
313 | data->timeout_ns = 100000000; /* 100ms */ | ||
314 | } | ||
315 | } | ||
301 | } | 316 | } |
302 | EXPORT_SYMBOL(mmc_set_data_timeout); | 317 | EXPORT_SYMBOL(mmc_set_data_timeout); |
303 | 318 | ||
@@ -915,6 +930,7 @@ void mmc_stop_host(struct mmc_host *host) | |||
915 | spin_unlock_irqrestore(&host->lock, flags); | 930 | spin_unlock_irqrestore(&host->lock, flags); |
916 | #endif | 931 | #endif |
917 | 932 | ||
933 | cancel_delayed_work(&host->detect); | ||
918 | mmc_flush_scheduled_work(); | 934 | mmc_flush_scheduled_work(); |
919 | 935 | ||
920 | mmc_bus_get(host); | 936 | mmc_bus_get(host); |
@@ -942,6 +958,7 @@ void mmc_stop_host(struct mmc_host *host) | |||
942 | */ | 958 | */ |
943 | int mmc_suspend_host(struct mmc_host *host, pm_message_t state) | 959 | int mmc_suspend_host(struct mmc_host *host, pm_message_t state) |
944 | { | 960 | { |
961 | cancel_delayed_work(&host->detect); | ||
945 | mmc_flush_scheduled_work(); | 962 | mmc_flush_scheduled_work(); |
946 | 963 | ||
947 | mmc_bus_get(host); | 964 | mmc_bus_get(host); |
@@ -975,6 +992,7 @@ int mmc_resume_host(struct mmc_host *host) | |||
975 | mmc_bus_get(host); | 992 | mmc_bus_get(host); |
976 | if (host->bus_ops && !host->bus_dead) { | 993 | if (host->bus_ops && !host->bus_dead) { |
977 | mmc_power_up(host); | 994 | mmc_power_up(host); |
995 | mmc_select_voltage(host, host->ocr); | ||
978 | BUG_ON(!host->bus_ops->resume); | 996 | BUG_ON(!host->bus_ops->resume); |
979 | host->bus_ops->resume(host); | 997 | host->bus_ops->resume(host); |
980 | } | 998 | } |
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 1237bb4c722..610dbd1fcc8 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c | |||
@@ -184,6 +184,68 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) | |||
184 | DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get, | 184 | DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get, |
185 | NULL, "%08llx\n"); | 185 | NULL, "%08llx\n"); |
186 | 186 | ||
187 | #define EXT_CSD_STR_LEN 1025 | ||
188 | |||
189 | static int mmc_ext_csd_open(struct inode *inode, struct file *filp) | ||
190 | { | ||
191 | struct mmc_card *card = inode->i_private; | ||
192 | char *buf; | ||
193 | ssize_t n = 0; | ||
194 | u8 *ext_csd; | ||
195 | int err, i; | ||
196 | |||
197 | buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL); | ||
198 | if (!buf) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | ext_csd = kmalloc(512, GFP_KERNEL); | ||
202 | if (!ext_csd) { | ||
203 | err = -ENOMEM; | ||
204 | goto out_free; | ||
205 | } | ||
206 | |||
207 | mmc_claim_host(card->host); | ||
208 | err = mmc_send_ext_csd(card, ext_csd); | ||
209 | mmc_release_host(card->host); | ||
210 | if (err) | ||
211 | goto out_free; | ||
212 | |||
213 | for (i = 511; i >= 0; i--) | ||
214 | n += sprintf(buf + n, "%02x", ext_csd[i]); | ||
215 | n += sprintf(buf + n, "\n"); | ||
216 | BUG_ON(n != EXT_CSD_STR_LEN); | ||
217 | |||
218 | filp->private_data = buf; | ||
219 | kfree(ext_csd); | ||
220 | return 0; | ||
221 | |||
222 | out_free: | ||
223 | kfree(buf); | ||
224 | kfree(ext_csd); | ||
225 | return err; | ||
226 | } | ||
227 | |||
228 | static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf, | ||
229 | size_t cnt, loff_t *ppos) | ||
230 | { | ||
231 | char *buf = filp->private_data; | ||
232 | |||
233 | return simple_read_from_buffer(ubuf, cnt, ppos, | ||
234 | buf, EXT_CSD_STR_LEN); | ||
235 | } | ||
236 | |||
237 | static int mmc_ext_csd_release(struct inode *inode, struct file *file) | ||
238 | { | ||
239 | kfree(file->private_data); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static struct file_operations mmc_dbg_ext_csd_fops = { | ||
244 | .open = mmc_ext_csd_open, | ||
245 | .read = mmc_ext_csd_read, | ||
246 | .release = mmc_ext_csd_release, | ||
247 | }; | ||
248 | |||
187 | void mmc_add_card_debugfs(struct mmc_card *card) | 249 | void mmc_add_card_debugfs(struct mmc_card *card) |
188 | { | 250 | { |
189 | struct mmc_host *host = card->host; | 251 | struct mmc_host *host = card->host; |
@@ -211,6 +273,11 @@ void mmc_add_card_debugfs(struct mmc_card *card) | |||
211 | &mmc_dbg_card_status_fops)) | 273 | &mmc_dbg_card_status_fops)) |
212 | goto err; | 274 | goto err; |
213 | 275 | ||
276 | if (mmc_card_mmc(card)) | ||
277 | if (!debugfs_create_file("ext_csd", S_IRUSR, root, card, | ||
278 | &mmc_dbg_ext_csd_fops)) | ||
279 | goto err; | ||
280 | |||
214 | return; | 281 | return; |
215 | 282 | ||
216 | err: | 283 | err: |
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 956bd767750..963f2937c5e 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c | |||
@@ -223,10 +223,18 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) | |||
223 | if (tpl_code == 0xff) | 223 | if (tpl_code == 0xff) |
224 | break; | 224 | break; |
225 | 225 | ||
226 | /* null entries have no link field or data */ | ||
227 | if (tpl_code == 0x00) | ||
228 | continue; | ||
229 | |||
226 | ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); | 230 | ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); |
227 | if (ret) | 231 | if (ret) |
228 | break; | 232 | break; |
229 | 233 | ||
234 | /* a size of 0xff also means we're done */ | ||
235 | if (tpl_link == 0xff) | ||
236 | break; | ||
237 | |||
230 | this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL); | 238 | this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL); |
231 | if (!this) | 239 | if (!this) |
232 | return -ENOMEM; | 240 | return -ENOMEM; |
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index c8fa095a448..4eb7825fd1a 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c | |||
@@ -76,6 +76,10 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
76 | BUG_ON(!card); | 76 | BUG_ON(!card); |
77 | BUG_ON(fn > 7); | 77 | BUG_ON(fn > 7); |
78 | 78 | ||
79 | /* sanity check */ | ||
80 | if (addr & ~0x1FFFF) | ||
81 | return -EINVAL; | ||
82 | |||
79 | memset(&cmd, 0, sizeof(struct mmc_command)); | 83 | memset(&cmd, 0, sizeof(struct mmc_command)); |
80 | 84 | ||
81 | cmd.opcode = SD_IO_RW_DIRECT; | 85 | cmd.opcode = SD_IO_RW_DIRECT; |
@@ -125,6 +129,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
125 | WARN_ON(blocks == 0); | 129 | WARN_ON(blocks == 0); |
126 | WARN_ON(blksz == 0); | 130 | WARN_ON(blksz == 0); |
127 | 131 | ||
132 | /* sanity check */ | ||
133 | if (addr & ~0x1FFFF) | ||
134 | return -EINVAL; | ||
135 | |||
128 | memset(&mrq, 0, sizeof(struct mmc_request)); | 136 | memset(&mrq, 0, sizeof(struct mmc_request)); |
129 | memset(&cmd, 0, sizeof(struct mmc_command)); | 137 | memset(&cmd, 0, sizeof(struct mmc_command)); |
130 | memset(&data, 0, sizeof(struct mmc_data)); | 138 | memset(&data, 0, sizeof(struct mmc_data)); |