Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6
[powerpc.git] / drivers / mmc / sdhci.c
index 315ab49..20711ac 100644 (file)
@@ -4,8 +4,9 @@
  *  Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  */
 
 #include <linux/delay.h>
@@ -21,7 +22,7 @@
 #include "sdhci.h"
 
 #define DRIVER_NAME "sdhci"
-#define DRIVER_VERSION "0.11"
+#define DRIVER_VERSION "0.12"
 
 #define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
 
 
 static unsigned int debug_nodma = 0;
 static unsigned int debug_forcedma = 0;
+static unsigned int debug_quirks = 0;
+
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<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)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
-       /* handle any SD host controller */
-       {PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)},
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_VENDOR_ID_IBM,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_CLOCK_BEFORE_RESET |
+                                 SDHCI_QUIRK_FORCE_DMA,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA |
+                                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_TI,
+               .device         = PCI_DEVICE_ID_TI_XX21_XX11_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA,
+       },
+
+       {       /* Generic SD host controller */
+               PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+       },
+
        { /* end: all zeroes */ },
 };
 
@@ -93,6 +128,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        unsigned long timeout;
 
+       if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+               if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+                       SDHCI_CARD_PRESENT))
+                       return;
+       }
+
        writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
 
        if (mask & SDHCI_RESET_ALL)
@@ -439,9 +480,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
                        "though there were blocks left. Please report this "
                        "to " BUGMAIL ".\n", mmc_hostname(host->mmc));
                data->error = MMC_ERR_FAILED;
-       }
-
-       if (host->size != 0) {
+       } else if (host->size != 0) {
                printk(KERN_ERR "%s: %d bytes were left untransferred. "
                        "Please report this to " BUGMAIL ".\n",
                        mmc_hostname(host->mmc), host->size);
@@ -536,7 +575,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        if (cmd->data)
                flags |= SDHCI_CMD_DATA;
 
-       writel(SDHCI_MAKE_CMD(cmd->opcode, flags),
+       writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
                host->ioaddr + SDHCI_COMMAND);
 }
 
@@ -687,6 +726,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        } else
                sdhci_send_command(host, mrq->cmd);
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -723,6 +763,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                ctrl &= ~SDHCI_CTRL_4BITBUS;
        writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -807,6 +848,19 @@ static void sdhci_tasklet_finish(unsigned long param)
        if ((mrq->cmd->error != MMC_ERR_NONE) ||
                (mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
                (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+
+               /* Some controllers need this kick or reset won't work here */
+               if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
+                       unsigned int clock;
+
+                       /* This is to force an update */
+                       clock = host->clock;
+                       host->clock = 0;
+                       sdhci_set_clock(host, clock);
+               }
+
+               /* Spec says we should do both at the same time, but Ricoh
+                  controllers do not like that. */
                sdhci_reset(host, SDHCI_RESET_CMD);
                sdhci_reset(host, SDHCI_RESET_DATA);
        }
@@ -817,6 +871,7 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        sdhci_deactivate_led(host);
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 
        mmc_request_done(host->mmc, mrq);
@@ -850,6 +905,7 @@ static void sdhci_timeout_timer(unsigned long data)
                }
        }
 
+       mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -987,6 +1043,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
 
        result = IRQ_HANDLED;
 
+       mmiowb();
 out:
        spin_unlock(&host->lock);
 
@@ -1052,6 +1109,7 @@ static int sdhci_resume (struct pci_dev *pdev)
                if (chip->hosts[i]->flags & SDHCI_USE_DMA)
                        pci_set_master(pdev);
                sdhci_init(chip->hosts[i]);
+               mmiowb();
                ret = mmc_resume_host(chip->hosts[i]->mmc);
                if (ret)
                        return ret;
@@ -1125,6 +1183,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        host = mmc_priv(mmc);
        host->mmc = mmc;
 
+       host->chip = chip;
+       chip->hosts[slot] = host;
+
        host->bar = first_bar + slot;
 
        host->addr = pci_resource_start(pdev, host->bar);
@@ -1151,10 +1212,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
        if (version != 0) {
                printk(KERN_ERR "%s: Unknown controller version (%d). "
-                       "Cowardly refusing to continue.\n", host->slot_descr,
+                       "You may experience problems.\n", host->slot_descr,
                        version);
-               ret = -ENODEV;
-               goto unmap;
        }
 
        caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
@@ -1164,7 +1223,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        else if (debug_forcedma) {
                DBG("DMA forced on\n");
                host->flags |= SDHCI_USE_DMA;
-       } else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
+       } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+               host->flags |= SDHCI_USE_DMA;
+       else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
                DBG("Controller doesn't have DMA interface\n");
        else if (!(caps & SDHCI_CAN_DO_DMA))
                DBG("Controller doesn't have DMA capability\n");
@@ -1220,7 +1281,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        mmc->ops = &sdhci_ops;
        mmc->f_min = host->max_clk / 256;
        mmc->f_max = host->max_clk;
-       mmc->caps = MMC_CAP_4_BIT_DATA;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
 
        mmc->ocr_avail = 0;
        if (caps & SDHCI_CAN_VDD_330)
@@ -1270,7 +1331,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
        setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
 
-       ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ,
+       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
                host->slot_descr, host);
        if (ret)
                goto untasklet;
@@ -1281,8 +1342,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        sdhci_dumpregs(host);
 #endif
 
-       host->chip = chip;
-       chip->hosts[slot] = host;
+       mmiowb();
 
        mmc_add_host(mmc);
 
@@ -1373,6 +1433,10 @@ static int __devinit sdhci_probe(struct pci_dev *pdev,
        }
 
        chip->pdev = pdev;
+       chip->quirks = ent->driver_data;
+
+       if (debug_quirks)
+               chip->quirks = debug_quirks;
 
        chip->num_slots = slots;
        pci_set_drvdata(pdev, chip);
@@ -1453,6 +1517,7 @@ module_exit(sdhci_drv_exit);
 
 module_param(debug_nodma, uint, 0444);
 module_param(debug_forcedma, uint, 0444);
+module_param(debug_quirks, uint, 0444);
 
 MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
 MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
@@ -1461,3 +1526,4 @@ MODULE_LICENSE("GPL");
 
 MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
 MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");