aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/sdhci.c')
-rw-r--r--drivers/mmc/sdhci.c131
1 files changed, 65 insertions, 66 deletions
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index c2d13d7e9911..7522f76b15ec 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -22,9 +22,6 @@
#include "sdhci.h"
#define DRIVER_NAME "sdhci"
-#define DRIVER_VERSION "0.12"
-
-#define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
@@ -37,6 +34,7 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like some resets when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -65,6 +63,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = SDHCI_QUIRK_FORCE_DMA,
},
+ {
+ .vendor = PCI_VENDOR_ID_ENE,
+ .device = PCI_DEVICE_ID_ENE_CB712_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ },
+
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -145,8 +151,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
/* hw clears the bit when it's done */
while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
if (timeout == 0) {
- printk(KERN_ERR "%s: Reset 0x%x never completed. "
- "Please report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
sdhci_dumpregs(host);
return;
@@ -197,15 +202,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
* *
\*****************************************************************************/
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
- return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -240,7 +239,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = 0;
data = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
if (chunk_remain == 0) {
@@ -264,16 +263,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -290,7 +286,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
data = 0;
bytes = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
size = min(host->size, host->remain);
@@ -314,16 +310,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -372,7 +365,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
/* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288);
- BUG_ON(data->blksz > host->max_block);
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
/* timeout in us */
@@ -477,12 +470,11 @@ static void sdhci_finish_data(struct sdhci_host *host)
if ((data->error == MMC_ERR_NONE) && blocks) {
printk(KERN_ERR "%s: Controller signalled completion even "
- "though there were blocks left. Please report this "
- "to " BUGMAIL ".\n", mmc_hostname(host->mmc));
+ "though there were blocks left.\n",
+ mmc_hostname(host->mmc));
data->error = MMC_ERR_FAILED;
} else if (host->size != 0) {
- printk(KERN_ERR "%s: %d bytes were left untransferred. "
- "Please report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: %d bytes were left untransferred.\n",
mmc_hostname(host->mmc), host->size);
data->error = MMC_ERR_FAILED;
}
@@ -529,8 +521,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
printk(KERN_ERR "%s: Controller never released "
- "inhibit bit(s). Please report this to "
- BUGMAIL ".\n", mmc_hostname(host->mmc));
+ "inhibit bit(s).\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
cmd->error = MMC_ERR_FAILED;
tasklet_schedule(&host->finish_tasklet);
@@ -551,8 +542,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_set_transfer_mode(host, cmd->data);
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
- printk(KERN_ERR "%s: Unsupported response type! "
- "Please report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Unsupported response type!\n",
mmc_hostname(host->mmc));
cmd->error = MMC_ERR_INVALID;
tasklet_schedule(&host->finish_tasklet);
@@ -650,9 +640,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
- printk(KERN_ERR "%s: Internal clock never stabilised. "
- "Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Internal clock never "
+ "stabilised.\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
@@ -674,10 +663,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
if (host->power == power)
return;
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
- if (power == (unsigned short)-1)
+ if (power == (unsigned short)-1) {
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
goto out;
+ }
+
+ /*
+ * Spec says that we should clear the power reg before setting
+ * a new value. Some controllers don't seem to like this though.
+ */
+ if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
pwr = SDHCI_POWER_ON;
@@ -895,9 +891,8 @@ static void sdhci_timeout_timer(unsigned long data)
spin_lock_irqsave(&host->lock, flags);
if (host->mrq) {
- printk(KERN_ERR "%s: Timeout waiting for hardware interrupt. "
- "Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Timeout waiting for hardware "
+ "interrupt.\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
if (host->data) {
@@ -931,8 +926,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
printk(KERN_ERR "%s: Got command interrupt even though no "
"command operation was in progress.\n",
mmc_hostname(host->mmc));
- printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
@@ -968,8 +961,6 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
printk(KERN_ERR "%s: Got data interrupt even though no "
"data operation was in progress.\n",
mmc_hostname(host->mmc));
- printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
@@ -1041,8 +1032,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= SDHCI_INT_BUS_POWER;
if (intmask) {
- printk(KERN_ERR "%s: Unexpected interrupt 0x%08x. Please "
- "report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), intmask);
sdhci_dumpregs(host);
@@ -1109,7 +1099,9 @@ static int sdhci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
for (i = 0;i < chip->num_slots;i++) {
if (!chip->hosts[i])
@@ -1274,15 +1266,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
- host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
- if (host->max_block >= 3) {
- printk(KERN_ERR "%s: Invalid maximum block size.\n",
- host->slot_descr);
- ret = -ENODEV;
- goto unmap;
- }
- host->max_block = 512 << host->max_block;
-
/*
* Set host parameters.
*/
@@ -1294,9 +1277,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
- else if (caps & SDHCI_CAN_VDD_300)
+ if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
- else if (caps & SDHCI_CAN_VDD_180)
+ if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
@@ -1326,15 +1309,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB), which means (512 KiB/512=) 1024 entries.
+ * size (512KiB).
*/
- mmc->max_sectors = 1024;
+ mmc->max_req_size = 524288;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of sectors.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. This varies from controller to controller and
+ * is specified in the capabilities register.
+ */
+ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+ if (mmc->max_blk_size >= 3) {
+ printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+ /*
+ * Maximum block count.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = 65535;
/*
* Init tasklets.
@@ -1513,8 +1514,7 @@ static struct pci_driver sdhci_driver = {
static int __init sdhci_drv_init(void)
{
printk(KERN_INFO DRIVER_NAME
- ": Secure Digital Host Controller Interface driver, "
- DRIVER_VERSION "\n");
+ ": Secure Digital Host Controller Interface driver\n");
printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
return pci_register_driver(&sdhci_driver);
@@ -1536,7 +1536,6 @@ module_param(debug_quirks, uint, 0444);
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
-MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");