]> err.no Git - linux-2.6/blobdiff - drivers/mmc/host/s3cmci.c
Merge commit 'kumar/kumar-next'
[linux-2.6] / drivers / mmc / host / s3cmci.c
index a6224f9b28bcad616bb476aeb06b1edecb2ac7b7..be550c26da68d1cc82d2f25ac6880e84c6dae5b3 100644 (file)
@@ -450,6 +450,7 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id)
        }
 
        if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
+               dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n");
                cmd->error = -ETIMEDOUT;
                host->status = "error: command timeout";
                goto fail_transfer;
@@ -505,12 +506,14 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id)
        /* Check for FIFO failure */
        if (host->is2440) {
                if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {
+                       dbg(host, dbg_err, "FIFO failure\n");
                        host->mrq->data->error = -EILSEQ;
                        host->status = "error: 2440 fifo failure";
                        goto fail_transfer;
                }
        } else {
                if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
+                       dbg(host, dbg_err, "FIFO failure\n");
                        cmd->data->error = -EILSEQ;
                        host->status = "error:  fifo failure";
                        goto fail_transfer;
@@ -518,18 +521,21 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id)
        }
 
        if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
+               dbg(host, dbg_err, "bad data crc (outgoing)\n");
                cmd->data->error = -EILSEQ;
                host->status = "error: bad data crc (outgoing)";
                goto fail_transfer;
        }
 
        if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {
+               dbg(host, dbg_err, "bad data crc (incoming)\n");
                cmd->data->error = -EILSEQ;
                host->status = "error: bad data crc (incoming)";
                goto fail_transfer;
        }
 
        if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
+               dbg(host, dbg_err, "data timeout\n");
                cmd->data->error = -ETIMEDOUT;
                host->status = "error: data timeout";
                goto fail_transfer;
@@ -584,7 +590,7 @@ static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
 
        dbg(host, dbg_irq, "card detect\n");
 
-       mmc_detect_change(host->mmc, 500);
+       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
 
        return IRQ_HANDLED;
 }
@@ -801,6 +807,17 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
                return 0;
        }
 
+       if ((data->blksz & 3) != 0) {
+               /* We cannot deal with unaligned blocks with more than
+                * one block being transfered. */
+
+               if (data->blocks > 1)
+                       return -EINVAL;
+
+               /* No support yet for non-word block transfers. */
+               return -EINVAL;
+       }
+
        while (readl(host->base + S3C2410_SDIDSTA) &
               (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
 
@@ -956,8 +973,9 @@ static void s3cmci_send_request(struct mmc_host *mmc)
                host->dcnt++;
 
                if (res) {
-                       cmd->error = -EINVAL;
-                       cmd->data->error = -EINVAL;
+                       dbg(host, dbg_err, "setup data error %d\n", res);
+                       cmd->error = res;
+                       cmd->data->error = res;
 
                        mmc_request_done(mmc, mrq);
                        return;
@@ -969,6 +987,7 @@ static void s3cmci_send_request(struct mmc_host *mmc)
                        res = s3cmci_prepare_pio(host, cmd->data);
 
                if (res) {
+                       dbg(host, dbg_err, "data prepare error %d\n", res);
                        cmd->error = res;
                        cmd->data->error = res;
 
@@ -984,6 +1003,18 @@ static void s3cmci_send_request(struct mmc_host *mmc)
        enable_irq(host->irq);
 }
 
+static int s3cmci_card_present(struct s3cmci_host *host)
+{
+       struct s3c24xx_mci_pdata *pdata = host->pdata;
+       int ret;
+
+       if (pdata->gpio_detect == 0)
+               return -ENOSYS;
+
+       ret = s3c2410_gpio_getpin(pdata->gpio_detect) ? 0 : 1;
+       return ret ^ pdata->detect_invert;
+}
+
 static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct s3cmci_host *host = mmc_priv(mmc);
@@ -992,7 +1023,12 @@ static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        host->cmd_is_stop = 0;
        host->mrq = mrq;
 
-       s3cmci_send_request(mmc);
+       if (s3cmci_card_present(host) == 0) {
+               dbg(host, dbg_err, "%s: no medium present\n", __func__);
+               host->mrq->cmd->error = -ENOMEDIUM;
+               mmc_request_done(mmc, mrq);
+       } else
+               s3cmci_send_request(mmc);
 }
 
 static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1295,21 +1331,30 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
        return ret;
 }
 
+static void s3cmci_shutdown(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct s3cmci_host *host = mmc_priv(mmc);
+
+       if (host->irq_cd >= 0)
+               free_irq(host->irq_cd, host);
+
+       mmc_remove_host(mmc);
+       clk_disable(host->clk);
+}
+
 static int __devexit s3cmci_remove(struct platform_device *pdev)
 {
        struct mmc_host         *mmc  = platform_get_drvdata(pdev);
        struct s3cmci_host      *host = mmc_priv(mmc);
 
-       mmc_remove_host(mmc);
+       s3cmci_shutdown(pdev);
 
-       clk_disable(host->clk);
        clk_put(host->clk);
 
        tasklet_disable(&host->pio_tasklet);
        s3c2410_dma_free(S3CMCI_DMA, &s3cmci_dma_client);
 
-       if (host->irq_cd >= 0)
-               free_irq(host->irq_cd, host);
        free_irq(host->irq, host);
 
        iounmap(host->base);
@@ -1319,17 +1364,17 @@ static int __devexit s3cmci_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit s3cmci_probe_2410(struct platform_device *dev)
+static int __devinit s3cmci_2410_probe(struct platform_device *dev)
 {
        return s3cmci_probe(dev, 0);
 }
 
-static int __devinit s3cmci_probe_2412(struct platform_device *dev)
+static int __devinit s3cmci_2412_probe(struct platform_device *dev)
 {
        return s3cmci_probe(dev, 1);
 }
 
-static int __devinit s3cmci_probe_2440(struct platform_device *dev)
+static int __devinit s3cmci_2440_probe(struct platform_device *dev)
 {
        return s3cmci_probe(dev, 1);
 }
@@ -1356,29 +1401,32 @@ static int s3cmci_resume(struct platform_device *dev)
 #endif /* CONFIG_PM */
 
 
-static struct platform_driver s3cmci_driver_2410 = {
+static struct platform_driver s3cmci_2410_driver = {
        .driver.name    = "s3c2410-sdi",
        .driver.owner   = THIS_MODULE,
-       .probe          = s3cmci_probe_2410,
+       .probe          = s3cmci_2410_probe,
        .remove         = __devexit_p(s3cmci_remove),
+       .shutdown       = s3cmci_shutdown,
        .suspend        = s3cmci_suspend,
        .resume         = s3cmci_resume,
 };
 
-static struct platform_driver s3cmci_driver_2412 = {
+static struct platform_driver s3cmci_2412_driver = {
        .driver.name    = "s3c2412-sdi",
        .driver.owner   = THIS_MODULE,
-       .probe          = s3cmci_probe_2412,
+       .probe          = s3cmci_2412_probe,
        .remove         = __devexit_p(s3cmci_remove),
+       .shutdown       = s3cmci_shutdown,
        .suspend        = s3cmci_suspend,
        .resume         = s3cmci_resume,
 };
 
-static struct platform_driver s3cmci_driver_2440 = {
+static struct platform_driver s3cmci_2440_driver = {
        .driver.name    = "s3c2440-sdi",
        .driver.owner   = THIS_MODULE,
-       .probe          = s3cmci_probe_2440,
+       .probe          = s3cmci_2440_probe,
        .remove         = __devexit_p(s3cmci_remove),
+       .shutdown       = s3cmci_shutdown,
        .suspend        = s3cmci_suspend,
        .resume         = s3cmci_resume,
 };
@@ -1386,17 +1434,17 @@ static struct platform_driver s3cmci_driver_2440 = {
 
 static int __init s3cmci_init(void)
 {
-       platform_driver_register(&s3cmci_driver_2410);
-       platform_driver_register(&s3cmci_driver_2412);
-       platform_driver_register(&s3cmci_driver_2440);
+       platform_driver_register(&s3cmci_2410_driver);
+       platform_driver_register(&s3cmci_2412_driver);
+       platform_driver_register(&s3cmci_2440_driver);
        return 0;
 }
 
 static void __exit s3cmci_exit(void)
 {
-       platform_driver_unregister(&s3cmci_driver_2410);
-       platform_driver_unregister(&s3cmci_driver_2412);
-       platform_driver_unregister(&s3cmci_driver_2440);
+       platform_driver_unregister(&s3cmci_2410_driver);
+       platform_driver_unregister(&s3cmci_2412_driver);
+       platform_driver_unregister(&s3cmci_2440_driver);
 }
 
 module_init(s3cmci_init);