Merge tag 'mmc-merge-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / mmc / host / atmel-mci.c
index 852d5fb..ddf096e 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/seq_file.h>
@@ -71,7 +74,7 @@ enum atmci_pdc_buf {
 };
 
 struct atmel_mci_caps {
-       bool    has_dma;
+       bool    has_dma_conf_reg;
        bool    has_pdc;
        bool    has_cfg_reg;
        bool    has_cstor_reg;
@@ -418,7 +421,7 @@ static int atmci_regs_show(struct seq_file *s, void *v)
        atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]);
        atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]);
 
-       if (host->caps.has_dma) {
+       if (host->caps.has_dma_conf_reg) {
                u32 val;
 
                val = buf[ATMCI_DMA / 4];
@@ -500,6 +503,70 @@ err:
        dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmci_dt_ids[] = {
+       { .compatible = "atmel,hsmci" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmci_dt_ids);
+
+static struct mci_platform_data __devinit*
+atmci_of_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *cnp;
+       struct mci_platform_data *pdata;
+       u32 slot_id;
+
+       if (!np) {
+               dev_err(&pdev->dev, "device node not found\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for_each_child_of_node(np, cnp) {
+               if (of_property_read_u32(cnp, "reg", &slot_id)) {
+                       dev_warn(&pdev->dev, "reg property is missing for %s\n",
+                                cnp->full_name);
+                       continue;
+               }
+
+               if (slot_id >= ATMCI_MAX_NR_SLOTS) {
+                       dev_warn(&pdev->dev, "can't have more than %d slots\n",
+                                ATMCI_MAX_NR_SLOTS);
+                       break;
+               }
+
+               if (of_property_read_u32(cnp, "bus-width",
+                                        &pdata->slot[slot_id].bus_width))
+                       pdata->slot[slot_id].bus_width = 1;
+
+               pdata->slot[slot_id].detect_pin =
+                       of_get_named_gpio(cnp, "cd-gpios", 0);
+
+               pdata->slot[slot_id].detect_is_active_high =
+                       of_property_read_bool(cnp, "cd-inverted");
+
+               pdata->slot[slot_id].wp_pin =
+                       of_get_named_gpio(cnp, "wp-gpios", 0);
+       }
+
+       return pdata;
+}
+#else /* CONFIG_OF */
+static inline struct mci_platform_data*
+atmci_of_init(struct platform_device *dev)
+{
+       return ERR_PTR(-EINVAL);
+}
+#endif
+
 static inline unsigned int atmci_get_version(struct atmel_mci *host)
 {
        return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
@@ -774,7 +841,7 @@ static void atmci_dma_complete(void *arg)
 
        dev_vdbg(&host->pdev->dev, "DMA complete\n");
 
-       if (host->caps.has_dma)
+       if (host->caps.has_dma_conf_reg)
                /* Disable DMA hardware handshaking on MCI */
                atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
 
@@ -961,7 +1028,9 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
                maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
        }
 
-       atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | ATMCI_DMAEN);
+       if (host->caps.has_dma_conf_reg)
+               atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) |
+                       ATMCI_DMAEN);
 
        sglen = dma_map_sg(chan->device->dev, data->sg,
                        data->sg_len, direction);
@@ -2046,6 +2115,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        slot->sdc_reg = sdc_reg;
        slot->sdio_irq = sdio_irq;
 
+       dev_dbg(&mmc->class_dev,
+               "slot[%u]: bus_width=%u, detect_pin=%d, "
+               "detect_is_active_high=%s, wp_pin=%d\n",
+               id, slot_data->bus_width, slot_data->detect_pin,
+               slot_data->detect_is_active_high ? "true" : "false",
+               slot_data->wp_pin);
+
        mmc->ops = &atmci_ops;
        mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
        mmc->f_max = host->bus_hz / 2;
@@ -2169,7 +2245,10 @@ static bool atmci_configure_dma(struct atmel_mci *host)
 
        pdata = host->pdev->dev.platform_data;
 
-       if (pdata && find_slave_dev(pdata->dma_slave)) {
+       if (!pdata)
+               return false;
+
+       if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) {
                dma_cap_mask_t mask;
 
                /* Try to grab a DMA channel */
@@ -2210,8 +2289,8 @@ static void __init atmci_get_cap(struct atmel_mci *host)
        dev_info(&host->pdev->dev,
                        "version: 0x%x\n", version);
 
-       host->caps.has_dma = 0;
-       host->caps.has_pdc = 1;
+       host->caps.has_dma_conf_reg = 0;
+       host->caps.has_pdc = ATMCI_PDC_CONNECTED;
        host->caps.has_cfg_reg = 0;
        host->caps.has_cstor_reg = 0;
        host->caps.has_highspeed = 0;
@@ -2228,12 +2307,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
                host->caps.has_odd_clk_div = 1;
        case 0x400:
        case 0x300:
-#ifdef CONFIG_AT_HDMAC
-               host->caps.has_dma = 1;
-#else
-               dev_info(&host->pdev->dev,
-                       "has dma capability but dma engine is not selected, then use pio\n");
-#endif
+               host->caps.has_dma_conf_reg = 1;
                host->caps.has_pdc = 0;
                host->caps.has_cfg_reg = 1;
                host->caps.has_cstor_reg = 1;
@@ -2268,8 +2342,14 @@ static int __init atmci_probe(struct platform_device *pdev)
        if (!regs)
                return -ENXIO;
        pdata = pdev->dev.platform_data;
-       if (!pdata)
-               return -ENXIO;
+       if (!pdata) {
+               pdata = atmci_of_init(pdev);
+               if (IS_ERR(pdata)) {
+                       dev_err(&pdev->dev, "platform data not available\n");
+                       return PTR_ERR(pdata);
+               }
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
@@ -2308,7 +2388,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        /* Get MCI capabilities and set operations according to it */
        atmci_get_cap(host);
-       if (host->caps.has_dma && atmci_configure_dma(host)) {
+       if (atmci_configure_dma(host)) {
                host->prepare_data = &atmci_prepare_data_dma;
                host->submit_data = &atmci_submit_data_dma;
                host->stop_transfer = &atmci_stop_transfer_dma;
@@ -2487,6 +2567,7 @@ static struct platform_driver atmci_driver = {
        .driver         = {
                .name           = "atmel_mci",
                .pm             = ATMCI_PM_OPS,
+               .of_match_table = of_match_ptr(atmci_dt_ids),
        },
 };