ALSA: opl4 - Fix a wrong argument in proc write callback
[safe/jmp/linux-2.6] / drivers / mmc / host / atmel-mci.c
index 02529af..88be37d 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/seq_file.h>
+#include <linux/slab.h>
 #include <linux/stat.h>
 
 #include <linux/mmc/host.h>
 
-#include <asm/atmel-mci.h>
+#include <mach/atmel-mci.h>
+#include <linux/atmel-mci.h>
+
 #include <asm/io.h>
 #include <asm/unaligned.h>
 
+#include <mach/cpu.h>
 #include <mach/board.h>
 
 #include "atmel-mci-regs.h"
@@ -55,7 +59,6 @@ enum atmel_mci_state {
 
 struct atmel_mci_dma {
 #ifdef CONFIG_MMC_ATMELMCI_DMA
-       struct dma_client               client;
        struct dma_chan                 *chan;
        struct dma_async_tx_descriptor  *data_desc;
 #endif
@@ -92,6 +95,7 @@ struct atmel_mci_dma {
  * @need_clock_update: Update the clock rate before the next request.
  * @need_reset: Reset controller before next request.
  * @mode_reg: Value of the MR register.
+ * @cfg_reg: Value of the CFG register.
  * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
  *     rate and timeout calculations.
  * @mapbase: Physical address of the MMIO registers.
@@ -155,6 +159,7 @@ struct atmel_mci {
        bool                    need_clock_update;
        bool                    need_reset;
        u32                     mode_reg;
+       u32                     cfg_reg;
        unsigned long           bus_hz;
        unsigned long           mapbase;
        struct clk              *mck;
@@ -178,6 +183,7 @@ struct atmel_mci {
  *     available.
  * @wp_pin: GPIO pin used for card write protect sending, or negative
  *     if not available.
+ * @detect_is_active_high: The state of the detect pin when it is active.
  * @detect_timer: Timer used for debouncing @detect_pin interrupts.
  */
 struct atmel_mci_slot {
@@ -197,6 +203,7 @@ struct atmel_mci_slot {
 
        int                     detect_pin;
        int                     wp_pin;
+       bool                    detect_is_active_high;
 
        struct timer_list       detect_timer;
 };
@@ -209,6 +216,31 @@ struct atmel_mci_slot {
        set_bit(event, &host->pending_events)
 
 /*
+ * Enable or disable features/registers based on
+ * whether the processor supports them
+ */
+static bool mci_has_rwproof(void)
+{
+       if (cpu_is_at91sam9261() || cpu_is_at91rm9200())
+               return false;
+       else
+               return true;
+}
+
+/*
+ * The new MCI2 module isn't 100% compatible with the old MCI module,
+ * and it has a few nice features which we want to use...
+ */
+static inline bool atmci_is_mci2(void)
+{
+       if (cpu_is_at91sam9g45())
+               return true;
+
+       return false;
+}
+
+
+/*
  * The debugfs stuff below is mostly optimized away when
  * CONFIG_DEBUG_FS is not set.
  */
@@ -275,8 +307,13 @@ static void atmci_show_status_reg(struct seq_file *s,
                [3]     = "BLKE",
                [4]     = "DTIP",
                [5]     = "NOTBUSY",
+               [6]     = "ENDRX",
+               [7]     = "ENDTX",
                [8]     = "SDIOIRQA",
                [9]     = "SDIOIRQB",
+               [12]    = "SDIOWAIT",
+               [14]    = "RXBUFF",
+               [15]    = "TXBUFE",
                [16]    = "RINDE",
                [17]    = "RDIRE",
                [18]    = "RCRCE",
@@ -284,6 +321,11 @@ static void atmci_show_status_reg(struct seq_file *s,
                [20]    = "RTOE",
                [21]    = "DCRCE",
                [22]    = "DTOE",
+               [23]    = "CSTOE",
+               [24]    = "BLKOVRE",
+               [25]    = "DMADONE",
+               [26]    = "FIFOEMPTY",
+               [27]    = "XFRDONE",
                [30]    = "OVRE",
                [31]    = "UNRE",
        };
@@ -333,12 +375,33 @@ static int atmci_regs_show(struct seq_file *s, void *v)
                        buf[MCI_BLKR / 4],
                        buf[MCI_BLKR / 4] & 0xffff,
                        (buf[MCI_BLKR / 4] >> 16) & 0xffff);
+       if (atmci_is_mci2())
+               seq_printf(s, "CSTOR:\t0x%08x\n", buf[MCI_CSTOR / 4]);
 
        /* Don't read RSPR and RDR; it will consume the data there */
 
        atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]);
        atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]);
 
+       if (atmci_is_mci2()) {
+               u32 val;
+
+               val = buf[MCI_DMA / 4];
+               seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n",
+                               val, val & 3,
+                               ((val >> 4) & 3) ?
+                                       1 << (((val >> 4) & 3) + 1) : 1,
+                               val & MCI_DMAEN ? " DMAEN" : "");
+
+               val = buf[MCI_CFG / 4];
+               seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n",
+                               val,
+                               val & MCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "",
+                               val & MCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "",
+                               val & MCI_CFG_HSMODE ? " HSMODE" : "",
+                               val & MCI_CFG_LSYNC ? " LSYNC" : "");
+       }
+
        kfree(buf);
 
        return 0;
@@ -533,6 +596,10 @@ static void atmci_dma_complete(void *arg)
 
        dev_vdbg(&host->pdev->dev, "DMA complete\n");
 
+       if (atmci_is_mci2())
+               /* Disable DMA hardware handshaking on MCI */
+               mci_writel(host, DMA, mci_readl(host, DMA) & ~MCI_DMAEN);
+
        atmci_dma_cleanup(host);
 
        /*
@@ -568,13 +635,14 @@ static void atmci_dma_complete(void *arg)
 }
 
 static int
-atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
 {
        struct dma_chan                 *chan;
        struct dma_async_tx_descriptor  *desc;
        struct scatterlist              *sg;
        unsigned int                    i;
        enum dma_data_direction         direction;
+       unsigned int                    sglen;
 
        /*
         * We don't do DMA on "complex" transfers, i.e. with
@@ -593,43 +661,59 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
 
        /* If we don't have a channel, we can't do DMA */
        chan = host->dma.chan;
-       if (chan) {
-               dma_chan_get(chan);
+       if (chan)
                host->data_chan = chan;
-       }
 
        if (!chan)
                return -ENODEV;
 
+       if (atmci_is_mci2())
+               mci_writel(host, DMA, MCI_DMA_CHKSIZE(3) | MCI_DMAEN);
+
        if (data->flags & MMC_DATA_READ)
                direction = DMA_FROM_DEVICE;
        else
                direction = DMA_TO_DEVICE;
 
+       sglen = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, direction);
+       if (sglen != data->sg_len)
+               goto unmap_exit;
        desc = chan->device->device_prep_slave_sg(chan,
                        data->sg, data->sg_len, direction,
                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc)
-               return -ENOMEM;
+               goto unmap_exit;
 
        host->dma.data_desc = desc;
        desc->callback = atmci_dma_complete;
        desc->callback_param = host;
-       desc->tx_submit(desc);
-
-       /* Go! */
-       chan->device->device_issue_pending(chan);
 
        return 0;
+unmap_exit:
+       dma_unmap_sg(&host->pdev->dev, data->sg, sglen, direction);
+       return -ENOMEM;
+}
+
+static void atmci_submit_data(struct atmel_mci *host)
+{
+       struct dma_chan                 *chan = host->data_chan;
+       struct dma_async_tx_descriptor  *desc = host->dma.data_desc;
+
+       if (chan) {
+               desc->tx_submit(desc);
+               chan->device->device_issue_pending(chan);
+       }
 }
 
 #else /* CONFIG_MMC_ATMELMCI_DMA */
 
-static int atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+static int atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
 {
        return -ENOSYS;
 }
 
+static void atmci_submit_data(struct atmel_mci *host) {}
+
 static void atmci_stop_dma(struct atmel_mci *host)
 {
        /* Data transfer was stopped by the interrupt handler */
@@ -643,7 +727,7 @@ static void atmci_stop_dma(struct atmel_mci *host)
  * Returns a mask of interrupt flags to be enabled after the whole
  * request has been prepared.
  */
-static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
+static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
 {
        u32 iflags;
 
@@ -654,7 +738,7 @@ static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
        host->data = data;
 
        iflags = ATMCI_DATA_ERROR_FLAGS;
-       if (atmci_submit_data_dma(host, data)) {
+       if (atmci_prepare_data_dma(host, data)) {
                host->data_chan = NULL;
 
                /*
@@ -700,6 +784,8 @@ static void atmci_start_request(struct atmel_mci *host,
                mci_writel(host, CR, MCI_CR_SWRST);
                mci_writel(host, CR, MCI_CR_MCIEN);
                mci_writel(host, MR, host->mode_reg);
+               if (atmci_is_mci2())
+                       mci_writel(host, CFG, host->cfg_reg);
                host->need_reset = false;
        }
        mci_writel(host, SDCR, slot->sdc_reg);
@@ -715,6 +801,7 @@ static void atmci_start_request(struct atmel_mci *host,
                while (!(mci_readl(host, SR) & MCI_CMDRDY))
                        cpu_relax();
        }
+       iflags = 0;
        data = mrq->data;
        if (data) {
                atmci_set_timeout(host, slot, data);
@@ -724,15 +811,17 @@ static void atmci_start_request(struct atmel_mci *host,
                                | MCI_BLKLEN(data->blksz));
                dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
                        MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
+
+               iflags |= atmci_prepare_data(host, data);
        }
 
-       iflags = MCI_CMDRDY;
+       iflags |= MCI_CMDRDY;
        cmd = mrq->cmd;
        cmdflags = atmci_prepare_command(slot->mmc, cmd);
        atmci_start_command(host, cmd, cmdflags);
 
        if (data)
-               iflags |= atmci_submit_data(host, data);
+               atmci_submit_data(host);
 
        if (mrq->stop) {
                host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
@@ -815,7 +904,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                slot->sdc_reg |= MCI_SDCBUS_1BIT;
                break;
        case MMC_BUS_WIDTH_4:
-               slot->sdc_reg = MCI_SDCBUS_4BIT;
+               slot->sdc_reg |= MCI_SDCBUS_4BIT;
                break;
        }
 
@@ -828,6 +917,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        clk_enable(host->mck);
                        mci_writel(host, CR, MCI_CR_SWRST);
                        mci_writel(host, CR, MCI_CR_MCIEN);
+                       if (atmci_is_mci2())
+                               mci_writel(host, CFG, host->cfg_reg);
                }
 
                /*
@@ -850,13 +941,15 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        clkdiv = 255;
                }
 
+               host->mode_reg = MCI_MR_CLKDIV(clkdiv);
+
                /*
                 * WRPROOF and RDPROOF prevent overruns/underruns by
                 * stopping the clock when the FIFO is full/empty.
                 * This state is not expected to last for long.
                 */
-               host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
-                                       | MCI_MR_RDPROOF;
+               if (mci_has_rwproof())
+                       host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);
 
                if (list_empty(&host->queue))
                        mci_writel(host, MR, host->mode_reg);
@@ -927,7 +1020,8 @@ static int atmci_get_cd(struct mmc_host *mmc)
        struct atmel_mci_slot   *slot = mmc_priv(mmc);
 
        if (gpio_is_valid(slot->detect_pin)) {
-               present = !gpio_get_value(slot->detect_pin);
+               present = !(gpio_get_value(slot->detect_pin) ^
+                           slot->detect_is_active_high);
                dev_dbg(&mmc->class_dev, "card is %spresent\n",
                                present ? "" : "not ");
        }
@@ -1031,7 +1125,8 @@ static void atmci_detect_change(unsigned long data)
                return;
 
        enable_irq(gpio_to_irq(slot->detect_pin));
-       present = !gpio_get_value(slot->detect_pin);
+       present = !(gpio_get_value(slot->detect_pin) ^
+                   slot->detect_is_active_high);
        present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
        dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
@@ -1062,6 +1157,8 @@ static void atmci_detect_change(unsigned long data)
                                mci_writel(host, CR, MCI_CR_SWRST);
                                mci_writel(host, CR, MCI_CR_MCIEN);
                                mci_writel(host, MR, host->mode_reg);
+                               if (atmci_is_mci2())
+                                       mci_writel(host, CFG, host->cfg_reg);
 
                                host->data = NULL;
                                host->cmd = NULL;
@@ -1253,6 +1350,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                        nbytes += 4;
 
                        if (offset == sg->length) {
+                               flush_dcache_page(sg_page(sg));
                                host->sg = sg = sg_next(sg);
                                if (!sg)
                                        goto done;
@@ -1442,60 +1540,6 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_MMC_ATMELMCI_DMA
-
-static inline struct atmel_mci *
-dma_client_to_atmel_mci(struct dma_client *client)
-{
-       return container_of(client, struct atmel_mci, dma.client);
-}
-
-static enum dma_state_client atmci_dma_event(struct dma_client *client,
-               struct dma_chan *chan, enum dma_state state)
-{
-       struct atmel_mci        *host;
-       enum dma_state_client   ret = DMA_NAK;
-
-       host = dma_client_to_atmel_mci(client);
-
-       switch (state) {
-       case DMA_RESOURCE_AVAILABLE:
-               spin_lock_bh(&host->lock);
-               if (!host->dma.chan) {
-                       host->dma.chan = chan;
-                       ret = DMA_ACK;
-               }
-               spin_unlock_bh(&host->lock);
-
-               if (ret == DMA_ACK)
-                       dev_info(&host->pdev->dev,
-                                       "Using %s for DMA transfers\n",
-                                       chan->dev.bus_id);
-               break;
-
-       case DMA_RESOURCE_REMOVED:
-               spin_lock_bh(&host->lock);
-               if (host->dma.chan == chan) {
-                       host->dma.chan = NULL;
-                       ret = DMA_ACK;
-               }
-               spin_unlock_bh(&host->lock);
-
-               if (ret == DMA_ACK)
-                       dev_info(&host->pdev->dev,
-                                       "Lost %s, falling back to PIO\n",
-                                       chan->dev.bus_id);
-               break;
-
-       default:
-               break;
-       }
-
-
-       return ret;
-}
-#endif /* CONFIG_MMC_ATMELMCI_DMA */
-
 static int __init atmci_init_slot(struct atmel_mci *host,
                struct mci_slot_pdata *slot_data, unsigned int id,
                u32 sdc_reg)
@@ -1512,6 +1556,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        slot->host = host;
        slot->detect_pin = slot_data->detect_pin;
        slot->wp_pin = slot_data->wp_pin;
+       slot->detect_is_active_high = slot_data->detect_is_active_high;
        slot->sdc_reg = sdc_reg;
 
        mmc->ops = &atmci_ops;
@@ -1533,7 +1578,8 @@ static int __init atmci_init_slot(struct atmel_mci *host,
                if (gpio_request(slot->detect_pin, "mmc_detect")) {
                        dev_dbg(&mmc->class_dev, "no detect pin available\n");
                        slot->detect_pin = -EBUSY;
-               } else if (gpio_get_value(slot->detect_pin)) {
+               } else if (gpio_get_value(slot->detect_pin) ^
+                               slot->detect_is_active_high) {
                        clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
                }
        }
@@ -1599,6 +1645,52 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
        mmc_free_host(slot->mmc);
 }
 
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct mci_dma_data     *sl = slave;
+
+       if (sl && find_slave_dev(sl) == chan->device->dev) {
+               chan->private = slave_data_ptr(sl);
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static void atmci_configure_dma(struct atmel_mci *host)
+{
+       struct mci_platform_data        *pdata;
+
+       if (host == NULL)
+               return;
+
+       pdata = host->pdev->dev.platform_data;
+
+       if (pdata && find_slave_dev(pdata->dma_slave)) {
+               dma_cap_mask_t mask;
+
+               setup_dma_addr(pdata->dma_slave,
+                              host->mapbase + MCI_TDR,
+                              host->mapbase + MCI_RDR);
+
+               /* Try to grab a DMA channel */
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               host->dma.chan =
+                       dma_request_channel(mask, filter, pdata->dma_slave);
+       }
+       if (!host->dma.chan)
+               dev_notice(&host->pdev->dev, "DMA not available, using PIO\n");
+       else
+               dev_info(&host->pdev->dev,
+                                       "Using %s for DMA transfers\n",
+                                       dma_chan_name(host->dma.chan));
+}
+#else
+static void atmci_configure_dma(struct atmel_mci *host) {}
+#endif
+
 static int __init atmci_probe(struct platform_device *pdev)
 {
        struct mci_platform_data        *pdata;
@@ -1646,28 +1738,11 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
 
-       ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
+       ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
        if (ret)
                goto err_request_irq;
 
-#ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (pdata->dma_slave) {
-               struct dma_slave *slave = pdata->dma_slave;
-
-               slave->tx_reg = regs->start + MCI_TDR;
-               slave->rx_reg = regs->start + MCI_RDR;
-
-               /* Try to grab a DMA channel */
-               host->dma.client.event_callback = atmci_dma_event;
-               dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
-               host->dma.client.slave = slave;
-
-               dma_async_client_register(&host->dma.client);
-               dma_async_client_chan_request(&host->dma.client);
-       } else {
-               dev_notice(&pdev->dev, "DMA not available, using PIO\n");
-       }
-#endif /* CONFIG_MMC_ATMELMCI_DMA */
+       atmci_configure_dma(host);
 
        platform_set_drvdata(pdev, host);
 
@@ -1687,8 +1762,10 @@ static int __init atmci_probe(struct platform_device *pdev)
                        nr_slots++;
        }
 
-       if (!nr_slots)
+       if (!nr_slots) {
+               dev_err(&pdev->dev, "init failed: no slot defined\n");
                goto err_init_slot;
+       }
 
        dev_info(&pdev->dev,
                        "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
@@ -1698,8 +1775,8 @@ static int __init atmci_probe(struct platform_device *pdev)
 
 err_init_slot:
 #ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (pdata->dma_slave)
-               dma_async_client_unregister(&host->dma.client);
+       if (host->dma.chan)
+               dma_release_channel(host->dma.chan);
 #endif
        free_irq(irq, host);
 err_request_irq:
@@ -1730,8 +1807,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
        clk_disable(host->mck);
 
 #ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (host->dma.client.slave)
-               dma_async_client_unregister(&host->dma.client);
+       if (host->dma.chan)
+               dma_release_channel(host->dma.chan);
 #endif
 
        free_irq(platform_get_irq(pdev, 0), host);
@@ -1760,7 +1837,7 @@ static void __exit atmci_exit(void)
        platform_driver_unregister(&atmci_driver);
 }
 
-module_init(atmci_init);
+late_initcall(atmci_init); /* try to load after dma driver when built-in */
 module_exit(atmci_exit);
 
 MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");