]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 25 Jul 2012 00:12:54 +0000 (17:12 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 25 Jul 2012 00:12:54 +0000 (17:12 -0700)
Pull slave-dmaengine update from Vinod Koul:
 "This time we have a new dmaengine driver from the tegra folks.  Also
  we have Guennadi's cleanup of sh drivers which incudes a library for
  sh drivers.  And the usual odd fixes in bunch of drivers and some nice
  cleanup of dw_dmac from Andy."

Fix up conflicts in drivers/mmc/host/sh_mmcif.c

* 'next' of git://git.infradead.org/users/vkoul/slave-dma: (46 commits)
  dmaengine: Cleanup logging messages
  mmc: sh_mmcif: switch to the new DMA channel allocation and configuration
  dma: sh: provide a migration path for slave drivers to stop using .private
  dma: sh: use an integer slave ID to improve API compatibility
  dmaengine: shdma: prepare to stop using struct dma_chan::private
  sh: remove unused DMA device pointer from SIU platform data
  ASoC: siu: don't use DMA device for channel filtering
  dmaengine: shdma: (cosmetic) simplify a static function
  dmaengine: at_hdmac: add a few const qualifiers
  dw_dmac: use 'u32' for LLI structure members, not dma_addr_t
  dw_dmac: mark dwc_dump_lli inline
  dma: mxs-dma: Export missing symbols from mxs-dma.c
  dma: shdma: convert to the shdma base library
  ASoC: fsi: prepare for conversion to the shdma base library
  usb: renesas_usbhs: prepare for conversion to the shdma base library
  ASoC: siu: prepare for conversion to the shdma base library
  serial: sh-sci: prepare for conversion to the shdma base library
  mmc: sh_mobile_sdhi: prepare for conversion to the shdma base library
  mmc: sh_mmcif: remove unneeded struct sh_mmcif_dma, prepare to shdma conversion
  dma: shdma: prepare for conversion to the shdma base library
  ...

1  2 
drivers/dma/dw_dmac.c
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/tty/serial/sh-sci.c
drivers/usb/renesas_usbhs/fifo.c
include/linux/mmc/sh_mmcif.h
sound/soc/sh/fsi.c

diff --combined drivers/dma/dw_dmac.c
index 7212961575770df8c17d00d666bd11a79553a0b2,57beb5c8e3fd2bf15eda13c7464525398534fc07..d3c5a5a88f1e9af91b97848f6d9c107ac2010da5
@@@ -105,13 -105,13 +105,13 @@@ static struct dw_desc *dwc_desc_get(str
  
        spin_lock_irqsave(&dwc->lock, flags);
        list_for_each_entry_safe(desc, _desc, &dwc->free_list, desc_node) {
+               i++;
                if (async_tx_test_ack(&desc->txd)) {
                        list_del(&desc->desc_node);
                        ret = desc;
                        break;
                }
                dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc);
-               i++;
        }
        spin_unlock_irqrestore(&dwc->lock, flags);
  
@@@ -191,6 -191,42 +191,42 @@@ static void dwc_initialize(struct dw_dm
  
  /*----------------------------------------------------------------------*/
  
+ static inline unsigned int dwc_fast_fls(unsigned long long v)
+ {
+       /*
+        * We can be a lot more clever here, but this should take care
+        * of the most common optimization.
+        */
+       if (!(v & 7))
+               return 3;
+       else if (!(v & 3))
+               return 2;
+       else if (!(v & 1))
+               return 1;
+       return 0;
+ }
+ static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+ {
+       dev_err(chan2dev(&dwc->chan),
+               "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
+               channel_readl(dwc, SAR),
+               channel_readl(dwc, DAR),
+               channel_readl(dwc, LLP),
+               channel_readl(dwc, CTL_HI),
+               channel_readl(dwc, CTL_LO));
+ }
+ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
+ {
+       channel_clear_bit(dw, CH_EN, dwc->mask);
+       while (dma_readl(dw, CH_EN) & dwc->mask)
+               cpu_relax();
+ }
+ /*----------------------------------------------------------------------*/
  /* Called with dwc->lock held and bh disabled */
  static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
  {
        if (dma_readl(dw, CH_EN) & dwc->mask) {
                dev_err(chan2dev(&dwc->chan),
                        "BUG: Attempted to start non-idle channel\n");
-               dev_err(chan2dev(&dwc->chan),
-                       "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-                       channel_readl(dwc, SAR),
-                       channel_readl(dwc, DAR),
-                       channel_readl(dwc, LLP),
-                       channel_readl(dwc, CTL_HI),
-                       channel_readl(dwc, CTL_LO));
+               dwc_dump_chan_regs(dwc);
  
                /* The tasklet will hopefully advance the queue... */
                return;
@@@ -290,9 -320,7 +320,7 @@@ static void dwc_complete_all(struct dw_
                        "BUG: XFER bit set, but channel not idle!\n");
  
                /* Try to continue after resetting the channel... */
-               channel_clear_bit(dw, CH_EN, dwc->mask);
-               while (dma_readl(dw, CH_EN) & dwc->mask)
-                       cpu_relax();
+               dwc_chan_disable(dw, dwc);
        }
  
        /*
@@@ -337,7 -365,8 +365,8 @@@ static void dwc_scan_descriptors(struc
                return;
        }
  
-       dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
+       dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
+                       (unsigned long long)llp);
  
        list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
                /* check first descriptors addr */
                "BUG: All descriptors done, but channel not idle!\n");
  
        /* Try to continue after resetting the channel... */
-       channel_clear_bit(dw, CH_EN, dwc->mask);
-       while (dma_readl(dw, CH_EN) & dwc->mask)
-               cpu_relax();
+       dwc_chan_disable(dw, dwc);
  
        if (!list_empty(&dwc->queue)) {
                list_move(dwc->queue.next, &dwc->active_list);
        spin_unlock_irqrestore(&dwc->lock, flags);
  }
  
- static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
+ static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
  {
        dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
                        "  desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
-                       lli->sar, lli->dar, lli->llp,
-                       lli->ctlhi, lli->ctllo);
+                       lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo);
  }
  
  static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
@@@ -487,17 -513,9 +513,9 @@@ static void dwc_handle_cyclic(struct dw
  
                spin_lock_irqsave(&dwc->lock, flags);
  
-               dev_err(chan2dev(&dwc->chan),
-                       "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-                       channel_readl(dwc, SAR),
-                       channel_readl(dwc, DAR),
-                       channel_readl(dwc, LLP),
-                       channel_readl(dwc, CTL_HI),
-                       channel_readl(dwc, CTL_LO));
+               dwc_dump_chan_regs(dwc);
  
-               channel_clear_bit(dw, CH_EN, dwc->mask);
-               while (dma_readl(dw, CH_EN) & dwc->mask)
-                       cpu_relax();
+               dwc_chan_disable(dw, dwc);
  
                /* make sure DMA does not restart by loading a new list */
                channel_writel(dwc, LLP, 0);
@@@ -527,7 -545,7 +545,7 @@@ static void dw_dma_tasklet(unsigned lon
        status_xfer = dma_readl(dw, RAW.XFER);
        status_err = dma_readl(dw, RAW.ERROR);
  
-       dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err);
+       dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err);
  
        for (i = 0; i < dw->dma.chancnt; i++) {
                dwc = &dw->chan[i];
@@@ -551,7 -569,7 +569,7 @@@ static irqreturn_t dw_dma_interrupt(in
        struct dw_dma *dw = dev_id;
        u32 status;
  
-       dev_vdbg(dw->dma.dev, "interrupt: status=0x%x\n",
+       dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__,
                        dma_readl(dw, STATUS_INT));
  
        /*
@@@ -597,12 -615,12 +615,12 @@@ static dma_cookie_t dwc_tx_submit(struc
         * for DMA. But this is hard to do in a race-free manner.
         */
        if (list_empty(&dwc->active_list)) {
-               dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
+               dev_vdbg(chan2dev(tx->chan), "%s: started %u\n", __func__,
                                desc->txd.cookie);
                list_add_tail(&desc->desc_node, &dwc->active_list);
                dwc_dostart(dwc, dwc_first_active(dwc));
        } else {
-               dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+               dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__,
                                desc->txd.cookie);
  
                list_add_tail(&desc->desc_node, &dwc->queue);
@@@ -627,26 -645,17 +645,17 @@@ dwc_prep_dma_memcpy(struct dma_chan *ch
        unsigned int            dst_width;
        u32                     ctllo;
  
-       dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n",
-                       dest, src, len, flags);
+       dev_vdbg(chan2dev(chan),
+                       "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
+                       (unsigned long long)dest, (unsigned long long)src,
+                       len, flags);
  
        if (unlikely(!len)) {
-               dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+               dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
                return NULL;
        }
  
-       /*
-        * We can be a lot more clever here, but this should take care
-        * of the most common optimization.
-        */
-       if (!((src | dest  | len) & 7))
-               src_width = dst_width = 3;
-       else if (!((src | dest  | len) & 3))
-               src_width = dst_width = 2;
-       else if (!((src | dest | len) & 1))
-               src_width = dst_width = 1;
-       else
-               src_width = dst_width = 0;
+       src_width = dst_width = dwc_fast_fls(src | dest | len);
  
        ctllo = DWC_DEFAULT_CTLLO(chan)
                        | DWC_CTLL_DST_WIDTH(dst_width)
@@@ -720,7 -729,7 +729,7 @@@ dwc_prep_slave_sg(struct dma_chan *chan
        struct scatterlist      *sg;
        size_t                  total_len = 0;
  
-       dev_vdbg(chan2dev(chan), "prep_dma_slave\n");
+       dev_vdbg(chan2dev(chan), "%s\n", __func__);
  
        if (unlikely(!dws || !sg_len))
                return NULL;
                        mem = sg_dma_address(sg);
                        len = sg_dma_len(sg);
  
-                       if (!((mem | len) & 7))
-                               mem_width = 3;
-                       else if (!((mem | len) & 3))
-                               mem_width = 2;
-                       else if (!((mem | len) & 1))
-                               mem_width = 1;
-                       else
-                               mem_width = 0;
+                       mem_width = dwc_fast_fls(mem | len);
  
  slave_sg_todev_fill_desc:
                        desc = dwc_desc_get(dwc);
                        mem = sg_dma_address(sg);
                        len = sg_dma_len(sg);
  
-                       if (!((mem | len) & 7))
-                               mem_width = 3;
-                       else if (!((mem | len) & 3))
-                               mem_width = 2;
-                       else if (!((mem | len) & 1))
-                               mem_width = 1;
-                       else
-                               mem_width = 0;
+                       mem_width = dwc_fast_fls(mem | len);
  
  slave_sg_fromdev_fill_desc:
                        desc = dwc_desc_get(dwc);
@@@ -950,9 -945,7 +945,7 @@@ static int dwc_control(struct dma_chan 
        } else if (cmd == DMA_TERMINATE_ALL) {
                spin_lock_irqsave(&dwc->lock, flags);
  
-               channel_clear_bit(dw, CH_EN, dwc->mask);
-               while (dma_readl(dw, CH_EN) & dwc->mask)
-                       cpu_relax();
+               dwc_chan_disable(dw, dwc);
  
                dwc->paused = false;
  
@@@ -1014,7 -1007,7 +1007,7 @@@ static int dwc_alloc_chan_resources(str
        int                     i;
        unsigned long           flags;
  
-       dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
+       dev_vdbg(chan2dev(chan), "%s\n", __func__);
  
        /* ASSERT:  channel is idle */
        if (dma_readl(dw, CH_EN) & dwc->mask) {
  
        spin_unlock_irqrestore(&dwc->lock, flags);
  
-       dev_dbg(chan2dev(chan),
-               "alloc_chan_resources allocated %d descriptors\n", i);
+       dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);
  
        return i;
  }
@@@ -1071,7 -1063,7 +1063,7 @@@ static void dwc_free_chan_resources(str
        unsigned long           flags;
        LIST_HEAD(list);
  
-       dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
+       dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
                        dwc->descs_allocated);
  
        /* ASSERT:  channel is idle */
                kfree(desc);
        }
  
-       dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
+       dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
  }
  
  /* --------------------- Cyclic DMA API extensions -------------------- */
@@@ -1126,13 -1118,7 +1118,7 @@@ int dw_dma_cyclic_start(struct dma_cha
        if (dma_readl(dw, CH_EN) & dwc->mask) {
                dev_err(chan2dev(&dwc->chan),
                        "BUG: Attempted to start non-idle channel\n");
-               dev_err(chan2dev(&dwc->chan),
-                       "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-                       channel_readl(dwc, SAR),
-                       channel_readl(dwc, DAR),
-                       channel_readl(dwc, LLP),
-                       channel_readl(dwc, CTL_HI),
-                       channel_readl(dwc, CTL_LO));
+               dwc_dump_chan_regs(dwc);
                spin_unlock_irqrestore(&dwc->lock, flags);
                return -EBUSY;
        }
@@@ -1167,9 -1153,7 +1153,7 @@@ void dw_dma_cyclic_stop(struct dma_cha
  
        spin_lock_irqsave(&dwc->lock, flags);
  
-       channel_clear_bit(dw, CH_EN, dwc->mask);
-       while (dma_readl(dw, CH_EN) & dwc->mask)
-               cpu_relax();
+       dwc_chan_disable(dw, dwc);
  
        spin_unlock_irqrestore(&dwc->lock, flags);
  }
@@@ -1308,9 -1292,9 +1292,9 @@@ struct dw_cyclic_desc *dw_dma_cyclic_pr
        dma_sync_single_for_device(chan2parent(chan), last->txd.phys,
                        sizeof(last->lli), DMA_TO_DEVICE);
  
-       dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%08x len %zu "
-                       "period %zu periods %d\n", buf_addr, buf_len,
-                       period_len, periods);
+       dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu "
+                       "period %zu periods %d\n", (unsigned long long)buf_addr,
+                       buf_len, period_len, periods);
  
        cdesc->periods = periods;
        dwc->cdesc = cdesc;
@@@ -1340,16 -1324,14 +1324,14 @@@ void dw_dma_cyclic_free(struct dma_cha
        int                     i;
        unsigned long           flags;
  
-       dev_dbg(chan2dev(&dwc->chan), "cyclic free\n");
+       dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);
  
        if (!cdesc)
                return;
  
        spin_lock_irqsave(&dwc->lock, flags);
  
-       channel_clear_bit(dw, CH_EN, dwc->mask);
-       while (dma_readl(dw, CH_EN) & dwc->mask)
-               cpu_relax();
+       dwc_chan_disable(dw, dwc);
  
        dma_writel(dw, CLEAR.ERROR, dwc->mask);
        dma_writel(dw, CLEAR.XFER, dwc->mask);
@@@ -1386,7 -1368,7 +1368,7 @@@ static void dw_dma_off(struct dw_dma *d
                dw->chan[i].initialized = false;
  }
  
- static int __init dw_probe(struct platform_device *pdev)
+ static int __devinit dw_probe(struct platform_device *pdev)
  {
        struct dw_dma_platform_data *pdata;
        struct resource         *io;
        }
        clk_prepare_enable(dw->clk);
  
+       /* Calculate all channel mask before DMA setup */
+       dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
        /* force dma off, just in case */
        dw_dma_off(dw);
  
+       /* disable BLOCK interrupts as well */
+       channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
        err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw);
        if (err)
                goto err_irq;
  
        tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
  
-       dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
        INIT_LIST_HEAD(&dw->dma.channels);
        for (i = 0; i < pdata->nr_channels; i++) {
                struct dw_dma_chan      *dwc = &dw->chan[i];
                channel_clear_bit(dw, CH_EN, dwc->mask);
        }
  
-       /* Clear/disable all interrupts on all channels. */
+       /* Clear all interrupts on all channels. */
        dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
+       dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
        dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
        dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
        dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
  
-       channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
-       channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
-       channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
-       channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
        dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
        dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
        if (pdata->is_private)
@@@ -1523,7 -1505,7 +1505,7 @@@ err_kfree
        return err;
  }
  
- static int __exit dw_remove(struct platform_device *pdev)
+ static int __devexit dw_remove(struct platform_device *pdev)
  {
        struct dw_dma           *dw = platform_get_drvdata(pdev);
        struct dw_dma_chan      *dwc, *_dwc;
@@@ -1602,7 -1584,7 +1584,7 @@@ MODULE_DEVICE_TABLE(of, dw_dma_id_table
  #endif
  
  static struct platform_driver dw_driver = {
-       .remove         = __exit_p(dw_remove),
+       .remove         = __devexit_p(dw_remove),
        .shutdown       = dw_shutdown,
        .driver = {
                .name   = "dw_dmac",
@@@ -1626,4 -1608,4 +1608,4 @@@ module_exit(dw_exit)
  MODULE_LICENSE("GPL v2");
  MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
  MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
 -MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
 +MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
index b2af7136cd27445d33225e36d5314005dcfb39b6,0f07d2878c4919e0f0c30decb0d11d54a162a5f3..5d8142773fac073b75cf56db111ecde2d398717d
@@@ -54,8 -54,6 +54,8 @@@
  #include <linux/mmc/mmc.h>
  #include <linux/mmc/sdio.h>
  #include <linux/mmc/sh_mmcif.h>
 +#include <linux/mmc/slot-gpio.h>
 +#include <linux/mod_devicetable.h>
  #include <linux/pagemap.h>
  #include <linux/platform_device.h>
  #include <linux/pm_qos.h>
@@@ -213,8 -211,6 +213,6 @@@ struct sh_mmcif_host 
        struct mmc_host *mmc;
        struct mmc_request *mrq;
        struct platform_device *pd;
-       struct sh_dmae_slave dma_slave_tx;
-       struct sh_dmae_slave dma_slave_rx;
        struct clk *hclk;
        unsigned int clk;
        int bus_width;
@@@ -373,59 -369,66 +371,69 @@@ static void sh_mmcif_start_dma_tx(struc
                desc, cookie);
  }
  
- static bool sh_mmcif_filter(struct dma_chan *chan, void *arg)
- {
-       dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
-       chan->private = arg;
-       return true;
- }
  static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
                                 struct sh_mmcif_plat_data *pdata)
  {
-       struct sh_dmae_slave *tx, *rx;
+       struct resource *res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
+       struct dma_slave_config cfg;
+       dma_cap_mask_t mask;
+       int ret;
        host->dma_active = false;
  
-       /* We can only either use DMA for both Tx and Rx or not use it at all */
-       if (pdata->dma) {
-               dev_warn(&host->pd->dev,
-                        "Update your platform to use embedded DMA slave IDs\n");
-               tx = &pdata->dma->chan_priv_tx;
-               rx = &pdata->dma->chan_priv_rx;
-       } else {
-               tx = &host->dma_slave_tx;
-               tx->slave_id = pdata->slave_id_tx;
-               rx = &host->dma_slave_rx;
-               rx->slave_id = pdata->slave_id_rx;
-       }
-       if (tx->slave_id > 0 && rx->slave_id > 0) {
-               dma_cap_mask_t mask;
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
-               host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, tx);
-               dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__,
-                       host->chan_tx);
 +      if (!pdata)
 +              return;
 +
+       if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
+               return;
  
-               if (!host->chan_tx)
-                       return;
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
  
-               host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, rx);
-               dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__,
-                       host->chan_rx);
+       host->chan_tx = dma_request_channel(mask, shdma_chan_filter,
+                                           (void *)pdata->slave_id_tx);
+       dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__,
+               host->chan_tx);
  
-               if (!host->chan_rx) {
-                       dma_release_channel(host->chan_tx);
-                       host->chan_tx = NULL;
-                       return;
-               }
+       if (!host->chan_tx)
+               return;
  
-               init_completion(&host->dma_complete);
-       }
+       cfg.slave_id = pdata->slave_id_tx;
+       cfg.direction = DMA_MEM_TO_DEV;
+       cfg.dst_addr = res->start + MMCIF_CE_DATA;
+       cfg.src_addr = 0;
+       ret = dmaengine_slave_config(host->chan_tx, &cfg);
+       if (ret < 0)
+               goto ecfgtx;
+       host->chan_rx = dma_request_channel(mask, shdma_chan_filter,
+                                           (void *)pdata->slave_id_rx);
+       dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__,
+               host->chan_rx);
+       if (!host->chan_rx)
+               goto erqrx;
+       cfg.slave_id = pdata->slave_id_rx;
+       cfg.direction = DMA_DEV_TO_MEM;
+       cfg.dst_addr = 0;
+       cfg.src_addr = res->start + MMCIF_CE_DATA;
+       ret = dmaengine_slave_config(host->chan_rx, &cfg);
+       if (ret < 0)
+               goto ecfgrx;
+       init_completion(&host->dma_complete);
+       return;
+ ecfgrx:
+       dma_release_channel(host->chan_rx);
+       host->chan_rx = NULL;
+ erqrx:
+ ecfgtx:
+       dma_release_channel(host->chan_tx);
+       host->chan_tx = NULL;
  }
  
  static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
  static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
  {
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
 +      bool sup_pclk = p ? p->sup_pclk : false;
  
        sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
        sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
  
        if (!clk)
                return;
 -      if (p->sup_pclk && clk == host->clk)
 +      if (sup_pclk && clk == host->clk)
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
        else
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
@@@ -898,15 -900,21 +906,15 @@@ static void sh_mmcif_request(struct mmc
  
        switch (mrq->cmd->opcode) {
        /* MMCIF does not support SD/SDIO command */
 -      case SD_IO_SEND_OP_COND:
 +      case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */
 +      case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
 +              if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR)
 +                      break;
        case MMC_APP_CMD:
                host->state = STATE_IDLE;
                mrq->cmd->error = -ETIMEDOUT;
                mmc_request_done(mmc, mrq);
                return;
 -      case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
 -              if (!mrq->data) {
 -                      /* send_if_cond cmd (not support) */
 -                      host->state = STATE_IDLE;
 -                      mrq->cmd->error = -ETIMEDOUT;
 -                      mmc_request_done(mmc, mrq);
 -                      return;
 -              }
 -              break;
        default:
                break;
        }
        sh_mmcif_start_cmd(host, mrq);
  }
  
 +static int sh_mmcif_clk_update(struct sh_mmcif_host *host)
 +{
 +      int ret = clk_enable(host->hclk);
 +
 +      if (!ret) {
 +              host->clk = clk_get_rate(host->hclk);
 +              host->mmc->f_max = host->clk / 2;
 +              host->mmc->f_min = host->clk / 512;
 +      }
 +
 +      return ret;
 +}
 +
 +static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)
 +{
 +      struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
 +      struct mmc_host *mmc = host->mmc;
 +
 +      if (pd && pd->set_pwr)
 +              pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF);
 +      if (!IS_ERR(mmc->supply.vmmc))
 +              /* Errors ignored... */
 +              mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
 +                                    ios->power_mode ? ios->vdd : 0);
 +}
 +
  static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
  {
        struct sh_mmcif_host *host = mmc_priv(mmc);
 -      struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
        unsigned long flags;
  
        spin_lock_irqsave(&host->lock, flags);
                        sh_mmcif_request_dma(host, host->pd->dev.platform_data);
                        host->card_present = true;
                }
 +              sh_mmcif_set_power(host, ios);
        } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* clock stop */
                sh_mmcif_clock_control(host, 0);
                }
                if (host->power) {
                        pm_runtime_put(&host->pd->dev);
 +                      clk_disable(host->hclk);
                        host->power = false;
 -                      if (p->down_pwr && ios->power_mode == MMC_POWER_OFF)
 -                              p->down_pwr(host->pd);
 +                      if (ios->power_mode == MMC_POWER_OFF)
 +                              sh_mmcif_set_power(host, ios);
                }
                host->state = STATE_IDLE;
                return;
  
        if (ios->clock) {
                if (!host->power) {
 -                      if (p->set_pwr)
 -                              p->set_pwr(host->pd, ios->power_mode);
 +                      sh_mmcif_clk_update(host);
                        pm_runtime_get_sync(&host->pd->dev);
                        host->power = true;
                        sh_mmcif_sync_reset(host);
@@@ -1001,12 -983,8 +1009,12 @@@ static int sh_mmcif_get_cd(struct mmc_h
  {
        struct sh_mmcif_host *host = mmc_priv(mmc);
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
 +      int ret = mmc_gpio_get_cd(mmc);
 +
 +      if (ret >= 0)
 +              return ret;
  
 -      if (!p->get_cd)
 +      if (!p || !p->get_cd)
                return -ENOSYS;
        else
                return p->get_cd(host->pd);
@@@ -1272,28 -1250,12 +1280,28 @@@ static void mmcif_timeout_work(struct w
        mmc_request_done(host->mmc, mrq);
  }
  
 +static void sh_mmcif_init_ocr(struct sh_mmcif_host *host)
 +{
 +      struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
 +      struct mmc_host *mmc = host->mmc;
 +
 +      mmc_regulator_get_supply(mmc);
 +
 +      if (!pd)
 +              return;
 +
 +      if (!mmc->ocr_avail)
 +              mmc->ocr_avail = pd->ocr;
 +      else if (pd->ocr)
 +              dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
 +}
 +
  static int __devinit sh_mmcif_probe(struct platform_device *pdev)
  {
        int ret = 0, irq[2];
        struct mmc_host *mmc;
        struct sh_mmcif_host *host;
 -      struct sh_mmcif_plat_data *pd;
 +      struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
        struct resource *res;
        void __iomem *reg;
        char clk_name[8];
                dev_err(&pdev->dev, "ioremap error.\n");
                return -ENOMEM;
        }
 -      pd = pdev->dev.platform_data;
 -      if (!pd) {
 -              dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
 -              ret = -ENXIO;
 -              goto clean_up;
 -      }
 +
        mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
        if (!mmc) {
                ret = -ENOMEM;
 -              goto clean_up;
 +              goto ealloch;
        }
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->addr      = reg;
        host->timeout   = 1000;
  
 -      snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
 -      host->hclk = clk_get(&pdev->dev, clk_name);
 -      if (IS_ERR(host->hclk)) {
 -              dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
 -              ret = PTR_ERR(host->hclk);
 -              goto clean_up1;
 -      }
 -      clk_enable(host->hclk);
 -      host->clk = clk_get_rate(host->hclk);
        host->pd = pdev;
  
        spin_lock_init(&host->lock);
  
        mmc->ops = &sh_mmcif_ops;
 -      mmc->f_max = host->clk / 2;
 -      mmc->f_min = host->clk / 512;
 -      if (pd->ocr)
 -              mmc->ocr_avail = pd->ocr;
 +      sh_mmcif_init_ocr(host);
 +
        mmc->caps = MMC_CAP_MMC_HIGHSPEED;
 -      if (pd->caps)
 +      if (pd && pd->caps)
                mmc->caps |= pd->caps;
        mmc->max_segs = 32;
        mmc->max_blk_size = 512;
        mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
        mmc->max_seg_size = mmc->max_req_size;
  
 -      sh_mmcif_sync_reset(host);
        platform_set_drvdata(pdev, host);
  
        pm_runtime_enable(&pdev->dev);
        host->power = false;
  
 +      snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
 +      host->hclk = clk_get(&pdev->dev, clk_name);
 +      if (IS_ERR(host->hclk)) {
 +              ret = PTR_ERR(host->hclk);
 +              dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
 +              goto eclkget;
 +      }
 +      ret = sh_mmcif_clk_update(host);
 +      if (ret < 0)
 +              goto eclkupdate;
 +
        ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
 -              goto clean_up2;
 +              goto eresume;
  
        INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
  
 +      sh_mmcif_sync_reset(host);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
  
        ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
 -              goto clean_up3;
 +              goto ereqirq0;
        }
        ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
 -              goto clean_up4;
 +              goto ereqirq1;
 +      }
 +
 +      if (pd && pd->use_cd_gpio) {
 +              ret = mmc_gpio_request_cd(mmc, pd->cd_gpio);
 +              if (ret < 0)
 +                      goto erqcd;
        }
  
 +      clk_disable(host->hclk);
        ret = mmc_add_host(mmc);
        if (ret < 0)
 -              goto clean_up5;
 +              goto emmcaddh;
  
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
  
                sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
        return ret;
  
 -clean_up5:
 +emmcaddh:
 +      if (pd && pd->use_cd_gpio)
 +              mmc_gpio_free_cd(mmc);
 +erqcd:
        free_irq(irq[1], host);
 -clean_up4:
 +ereqirq1:
        free_irq(irq[0], host);
 -clean_up3:
 +ereqirq0:
        pm_runtime_suspend(&pdev->dev);
 -clean_up2:
 -      pm_runtime_disable(&pdev->dev);
 +eresume:
        clk_disable(host->hclk);
 -clean_up1:
 +eclkupdate:
 +      clk_put(host->hclk);
 +eclkget:
 +      pm_runtime_disable(&pdev->dev);
        mmc_free_host(mmc);
 -clean_up:
 -      if (reg)
 -              iounmap(reg);
 +ealloch:
 +      iounmap(reg);
        return ret;
  }
  
  static int __devexit sh_mmcif_remove(struct platform_device *pdev)
  {
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
 +      struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
        int irq[2];
  
        host->dying = true;
 +      clk_enable(host->hclk);
        pm_runtime_get_sync(&pdev->dev);
  
        dev_pm_qos_hide_latency_limit(&pdev->dev);
  
 +      if (pd && pd->use_cd_gpio)
 +              mmc_gpio_free_cd(host->mmc);
 +
        mmc_remove_host(host->mmc);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
  
  
        platform_set_drvdata(pdev, NULL);
  
 -      clk_disable(host->hclk);
        mmc_free_host(host->mmc);
        pm_runtime_put_sync(&pdev->dev);
 +      clk_disable(host->hclk);
        pm_runtime_disable(&pdev->dev);
  
        return 0;
  #ifdef CONFIG_PM
  static int sh_mmcif_suspend(struct device *dev)
  {
 -      struct platform_device *pdev = to_platform_device(dev);
 -      struct sh_mmcif_host *host = platform_get_drvdata(pdev);
 +      struct sh_mmcif_host *host = dev_get_drvdata(dev);
        int ret = mmc_suspend_host(host->mmc);
  
 -      if (!ret) {
 +      if (!ret)
                sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 -              clk_disable(host->hclk);
 -      }
  
        return ret;
  }
  
  static int sh_mmcif_resume(struct device *dev)
  {
 -      struct platform_device *pdev = to_platform_device(dev);
 -      struct sh_mmcif_host *host = platform_get_drvdata(pdev);
 -
 -      clk_enable(host->hclk);
 +      struct sh_mmcif_host *host = dev_get_drvdata(dev);
  
        return mmc_resume_host(host->mmc);
  }
  #define sh_mmcif_resume               NULL
  #endif        /* CONFIG_PM */
  
 +static const struct of_device_id mmcif_of_match[] = {
 +      { .compatible = "renesas,sh-mmcif" },
 +      { }
 +};
 +MODULE_DEVICE_TABLE(of, mmcif_of_match);
 +
  static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
        .suspend = sh_mmcif_suspend,
        .resume = sh_mmcif_resume,
@@@ -1500,8 -1451,6 +1508,8 @@@ static struct platform_driver sh_mmcif_
        .driver         = {
                .name   = DRIVER_NAME,
                .pm     = &sh_mmcif_dev_pm_ops,
 +              .owner  = THIS_MODULE,
 +              .of_match_table = mmcif_of_match,
        },
  };
  
index a842939e46555295f32418ac05f96c495d734ea2,b8d7004cf04a35bb71e39ecf5847746435ba01e5..0bdc146178dbcee41aa55c1f27754bb36c256d37
@@@ -21,7 -21,6 +21,7 @@@
  #include <linux/kernel.h>
  #include <linux/clk.h>
  #include <linux/slab.h>
 +#include <linux/mod_devicetable.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/mmc/host.h>
@@@ -40,39 -39,22 +40,39 @@@ struct sh_mobile_sdhi 
        struct tmio_mmc_dma dma_priv;
  };
  
 +static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
 +{
 +      struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
 +      struct tmio_mmc_host *host = mmc_priv(mmc);
 +      struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
 +      int ret = clk_enable(priv->clk);
 +      if (ret < 0)
 +              return ret;
 +
 +      *f = clk_get_rate(priv->clk);
 +      return 0;
 +}
 +
 +static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
 +{
 +      struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
 +      struct tmio_mmc_host *host = mmc_priv(mmc);
 +      struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
 +      clk_disable(priv->clk);
 +}
 +
  static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
  {
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
  
 -      if (p && p->set_pwr)
 -              p->set_pwr(pdev, state);
 +      p->set_pwr(pdev, state);
  }
  
  static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
  {
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
  
 -      if (p && p->get_cd)
 -              return p->get_cd(pdev);
 -      else
 -              return -ENOSYS;
 +      return p->get_cd(pdev);
  }
  
  static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
@@@ -134,14 -116,12 +134,14 @@@ static int __devinit sh_mobile_sdhi_pro
        }
  
        mmc_data = &priv->mmc_data;
 -      p->pdata = mmc_data;
  
 -      if (p->init) {
 -              ret = p->init(pdev, &sdhi_ops);
 -              if (ret)
 -                      goto einit;
 +      if (p) {
 +              p->pdata = mmc_data;
 +              if (p->init) {
 +                      ret = p->init(pdev, &sdhi_ops);
 +                      if (ret)
 +                              goto einit;
 +              }
        }
  
        snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
                goto eclkget;
        }
  
 -      mmc_data->hclk = clk_get_rate(priv->clk);
 -      mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
 -      mmc_data->get_cd = sh_mobile_sdhi_get_cd;
 +      mmc_data->clk_enable = sh_mobile_sdhi_clk_enable;
 +      mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
        mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
        if (p) {
                mmc_data->flags = p->tmio_flags;
                        mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
                mmc_data->ocr_mask = p->tmio_ocr_mask;
                mmc_data->capabilities |= p->tmio_caps;
 +              mmc_data->capabilities2 |= p->tmio_caps2;
                mmc_data->cd_gpio = p->cd_gpio;
 +              if (p->set_pwr)
 +                      mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
 +              if (p->get_cd)
 +                      mmc_data->get_cd = sh_mobile_sdhi_get_cd;
  
                if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
-                       priv->param_tx.slave_id = p->dma_slave_tx;
-                       priv->param_rx.slave_id = p->dma_slave_rx;
-                       priv->dma_priv.chan_priv_tx = &priv->param_tx;
-                       priv->dma_priv.chan_priv_rx = &priv->param_rx;
+                       priv->param_tx.shdma_slave.slave_id = p->dma_slave_tx;
+                       priv->param_rx.shdma_slave.slave_id = p->dma_slave_rx;
+                       priv->dma_priv.chan_priv_tx = &priv->param_tx.shdma_slave;
+                       priv->dma_priv.chan_priv_rx = &priv->param_rx.shdma_slave;
                        priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
                        mmc_data->dma = &priv->dma_priv;
                }
@@@ -272,7 -248,7 +272,7 @@@ eirq_card_detect
  eprobe:
        clk_put(priv->clk);
  eclkget:
 -      if (p->cleanup)
 +      if (p && p->cleanup)
                p->cleanup(pdev);
  einit:
        kfree(priv);
@@@ -287,8 -263,7 +287,8 @@@ static int sh_mobile_sdhi_remove(struc
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
        int i = 0, irq;
  
 -      p->pdata = NULL;
 +      if (p)
 +              p->pdata = NULL;
  
        tmio_mmc_host_remove(host);
  
  
        clk_put(priv->clk);
  
 -      if (p->cleanup)
 +      if (p && p->cleanup)
                p->cleanup(pdev);
  
        kfree(priv);
@@@ -316,18 -291,11 +316,18 @@@ static const struct dev_pm_ops tmio_mmc
        .runtime_resume = tmio_mmc_host_runtime_resume,
  };
  
 +static const struct of_device_id sh_mobile_sdhi_of_match[] = {
 +      { .compatible = "renesas,shmobile-sdhi" },
 +      { }
 +};
 +MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
 +
  static struct platform_driver sh_mobile_sdhi_driver = {
        .driver         = {
                .name   = "sh_mobile_sdhi",
                .owner  = THIS_MODULE,
                .pm     = &tmio_mmc_dev_pm_ops,
 +              .of_match_table = sh_mobile_sdhi_of_match,
        },
        .probe          = sh_mobile_sdhi_probe,
        .remove         = __devexit_p(sh_mobile_sdhi_remove),
index 1bd9163bc1181eb0aaeae952acfaf910911b3720,21f7e53f798360f5d1d13de42089057df346788f..d4d8c9453cd8c8b3e01a056f2ce3a2e20926412d
@@@ -1615,9 -1615,9 +1615,9 @@@ static bool filter(struct dma_chan *cha
        struct sh_dmae_slave *param = slave;
  
        dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
-               param->slave_id);
+               param->shdma_slave.slave_id);
  
-       chan->private = param;
+       chan->private = &param->shdma_slave;
        return true;
  }
  
@@@ -1656,7 -1656,7 +1656,7 @@@ static void sci_request_dma(struct uart
        param = &s->param_tx;
  
        /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
-       param->slave_id = s->cfg->dma_slave_tx;
+       param->shdma_slave.slave_id = s->cfg->dma_slave_tx;
  
        s->cookie_tx = -EINVAL;
        chan = dma_request_channel(mask, filter, param);
        param = &s->param_rx;
  
        /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
-       param->slave_id = s->cfg->dma_slave_rx;
+       param->shdma_slave.slave_id = s->cfg->dma_slave_rx;
  
        chan = dma_request_channel(mask, filter, param);
        dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
@@@ -2179,16 -2179,6 +2179,16 @@@ static int __devinit sci_init_single(st
        return 0;
  }
  
 +static void sci_cleanup_single(struct sci_port *port)
 +{
 +      sci_free_gpios(port);
 +
 +      clk_put(port->iclk);
 +      clk_put(port->fclk);
 +
 +      pm_runtime_disable(port->port.dev);
 +}
 +
  #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
  static void serial_console_putchar(struct uart_port *port, int ch)
  {
@@@ -2370,10 -2360,14 +2370,10 @@@ static int sci_remove(struct platform_d
        cpufreq_unregister_notifier(&port->freq_transition,
                                    CPUFREQ_TRANSITION_NOTIFIER);
  
 -      sci_free_gpios(port);
 -
        uart_remove_one_port(&sci_uart_driver, &port->port);
  
 -      clk_put(port->iclk);
 -      clk_put(port->fclk);
 +      sci_cleanup_single(port);
  
 -      pm_runtime_disable(&dev->dev);
        return 0;
  }
  
@@@ -2391,20 -2385,14 +2391,20 @@@ static int __devinit sci_probe_single(s
                           index+1, SCI_NPORTS);
                dev_notice(&dev->dev, "Consider bumping "
                           "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
 -              return 0;
 +              return -EINVAL;
        }
  
        ret = sci_init_single(dev, sciport, index, p);
        if (ret)
                return ret;
  
 -      return uart_add_one_port(&sci_uart_driver, &sciport->port);
 +      ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
 +      if (ret) {
 +              sci_cleanup_single(sciport);
 +              return ret;
 +      }
 +
 +      return 0;
  }
  
  static int __devinit sci_probe(struct platform_device *dev)
  
        ret = sci_probe_single(dev, dev->id, p, sp);
        if (ret)
 -              goto err_unreg;
 +              return ret;
  
        sp->freq_transition.notifier_call = sci_notifier;
  
        ret = cpufreq_register_notifier(&sp->freq_transition,
                                        CPUFREQ_TRANSITION_NOTIFIER);
 -      if (unlikely(ret < 0))
 -              goto err_unreg;
 +      if (unlikely(ret < 0)) {
 +              sci_cleanup_single(sp);
 +              return ret;
 +      }
  
  #ifdef CONFIG_SH_STANDARD_BIOS
        sh_bios_gdb_detach();
  #endif
  
        return 0;
 -
 -err_unreg:
 -      sci_remove(dev);
 -      return ret;
  }
  
  static int sci_suspend(struct device *dev)
index 08313574aac8719aaf1f1b85b1c339cd25f23123,fc597a49ac2752a02027ef20801d93d925a46ce0..30b757a3f59e1e70c9a1478687e66f15267510b3
@@@ -17,8 -17,8 +17,8 @@@
  #include <linux/delay.h>
  #include <linux/io.h>
  #include <linux/scatterlist.h>
 -#include "./common.h"
 -#include "./pipe.h"
 +#include "common.h"
 +#include "pipe.h"
  
  #define usbhsf_get_cfifo(p)   (&((p)->fifo_info.cfifo))
  #define usbhsf_get_d0fifo(p)  (&((p)->fifo_info.d0fifo))
@@@ -994,7 -994,7 +994,7 @@@ static bool usbhsf_dma_filter(struct dm
         *
         * usbhs doesn't recognize id = 0 as valid DMA
         */
-       if (0 == slave->slave_id)
+       if (0 == slave->shdma_slave.slave_id)
                return false;
  
        chan->private = slave;
@@@ -1173,8 -1173,8 +1173,8 @@@ int usbhs_fifo_probe(struct usbhs_priv 
        fifo->port      = D0FIFO;
        fifo->sel       = D0FIFOSEL;
        fifo->ctr       = D0FIFOCTR;
-       fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id);
-       fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id);
+       fifo->tx_slave.shdma_slave.slave_id     = usbhs_get_dparam(priv, d0_tx_id);
+       fifo->rx_slave.shdma_slave.slave_id     = usbhs_get_dparam(priv, d0_rx_id);
  
        /* D1FIFO */
        fifo = usbhsf_get_d1fifo(priv);
        fifo->port      = D1FIFO;
        fifo->sel       = D1FIFOSEL;
        fifo->ctr       = D1FIFOCTR;
-       fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id);
-       fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id);
+       fifo->tx_slave.shdma_slave.slave_id     = usbhs_get_dparam(priv, d1_tx_id);
+       fifo->rx_slave.shdma_slave.slave_id     = usbhs_get_dparam(priv, d1_rx_id);
  
        return 0;
  }
index c2f73cbb4d5cb14912a01efa59983b21e5ff081a,c37956ccf02e408ed447be4cbfff3c3e5cf8a37a..e7d5dd67bb74fa42fbac10a67840667bc6c8e062
   * 1111 : Peripheral clock (sup_pclk set '1')
   */
  
- struct sh_mmcif_dma {
-       struct sh_dmae_slave chan_priv_tx;
-       struct sh_dmae_slave chan_priv_rx;
- };
  struct sh_mmcif_plat_data {
        void (*set_pwr)(struct platform_device *pdev, int state);
        void (*down_pwr)(struct platform_device *pdev);
        int (*get_cd)(struct platform_device *pdef);
-       struct sh_mmcif_dma     *dma;           /* Deprecated. Instead */
-       unsigned int            slave_id_tx;    /* use embedded slave_id_[tr]x */
+       unsigned int            slave_id_tx;    /* embedded slave_id_[tr]x */
        unsigned int            slave_id_rx;
 +      bool                    use_cd_gpio : 1;
 +      unsigned int            cd_gpio;
        u8                      sup_pclk;       /* 1 :SH7757, 0: SH7724/SH7372 */
        unsigned long           caps;
        u32                     ocr;
diff --combined sound/soc/sh/fsi.c
index 53486ff9c2afab75064de91599a2e1297a744359,3edf3bdf536af814bcb2a684fa5d9007fb251014..0540408a9fa9ab706c28e7ef6ed60a329bec027c
@@@ -247,7 -247,7 +247,7 @@@ struct fsi_priv 
  struct fsi_stream_handler {
        int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
 -      int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io);
 +      int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
        int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
        void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
@@@ -571,16 -571,16 +571,16 @@@ static int fsi_stream_transfer(struct f
  #define fsi_stream_stop(fsi, io)\
        fsi_stream_handler_call(io, start_stop, fsi, io, 0)
  
 -static int fsi_stream_probe(struct fsi_priv *fsi)
 +static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
  {
        struct fsi_stream *io;
        int ret1, ret2;
  
        io = &fsi->playback;
 -      ret1 = fsi_stream_handler_call(io, probe, fsi, io);
 +      ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
  
        io = &fsi->capture;
 -      ret2 = fsi_stream_handler_call(io, probe, fsi, io);
 +      ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
  
        if (ret1 < 0)
                return ret1;
@@@ -1089,10 -1089,13 +1089,10 @@@ static void fsi_dma_do_tasklet(unsigne
  {
        struct fsi_stream *io = (struct fsi_stream *)data;
        struct fsi_priv *fsi = fsi_stream_to_priv(io);
 -      struct dma_chan *chan;
        struct snd_soc_dai *dai;
        struct dma_async_tx_descriptor *desc;
 -      struct scatterlist sg;
        struct snd_pcm_runtime *runtime;
        enum dma_data_direction dir;
 -      dma_cookie_t cookie;
        int is_play = fsi_stream_is_play(fsi, io);
        int len;
        dma_addr_t buf;
                return;
  
        dai     = fsi_get_dai(io->substream);
 -      chan    = io->chan;
        runtime = io->substream->runtime;
        dir     = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        len     = samples_to_bytes(runtime, io->period_samples);
  
        dma_sync_single_for_device(dai->dev, buf, len, dir);
  
 -      sg_init_table(&sg, 1);
 -      sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
 -                  len , offset_in_page(buf));
 -      sg_dma_address(&sg) = buf;
 -      sg_dma_len(&sg) = len;
 -
 -      desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
 -                                     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 +      desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
 +                                         DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
                return;
        desc->callback          = fsi_dma_complete;
        desc->callback_param    = io;
  
 -      cookie = desc->tx_submit(desc);
 -      if (cookie < 0) {
 +      if (dmaengine_submit(desc) < 0) {
                dev_err(dai->dev, "tx_submit() fail\n");
                return;
        }
  
 -      dma_async_issue_pending(chan);
 +      dma_async_issue_pending(io->chan);
  
        /*
         * FIXME
@@@ -1173,7 -1184,7 +1173,7 @@@ static void fsi_dma_push_start_stop(str
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
  }
  
 -static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
 +static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
  {
        dma_cap_mask_t mask;
  
        dma_cap_set(DMA_SLAVE, mask);
  
        io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
 -      if (!io->chan)
 -              return -EIO;
 +      if (!io->chan) {
 +
 +              /* switch to PIO handler */
 +              if (fsi_stream_is_play(fsi, io))
 +                      fsi->playback.handler   = &fsi_pio_push_handler;
 +              else
 +                      fsi->capture.handler    = &fsi_pio_pop_handler;
 +
 +              dev_info(dev, "switch handler (dma => pio)\n");
 +
 +              /* probe again */
 +              return fsi_stream_probe(fsi, dev);
 +      }
  
        tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
  
@@@ -1631,8 -1631,8 +1631,8 @@@ static void fsi_handler_init(struct fsi
        fsi->capture.priv       = fsi;
  
        if (fsi->info->tx_id) {
-               fsi->playback.slave.slave_id    = fsi->info->tx_id;
-               fsi->playback.handler           = &fsi_dma_push_handler;
+               fsi->playback.slave.shdma_slave.slave_id = fsi->info->tx_id;
+               fsi->playback.handler = &fsi_dma_push_handler;
        }
  }
  
@@@ -1683,7 -1683,7 +1683,7 @@@ static int fsi_probe(struct platform_de
        master->fsia.master     = master;
        master->fsia.info       = &info->port_a;
        fsi_handler_init(&master->fsia);
 -      ret = fsi_stream_probe(&master->fsia);
 +      ret = fsi_stream_probe(&master->fsia, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIA stream probe failed\n");
                goto exit_iounmap;
        master->fsib.master     = master;
        master->fsib.info       = &info->port_b;
        fsi_handler_init(&master->fsib);
 -      ret = fsi_stream_probe(&master->fsib);
 +      ret = fsi_stream_probe(&master->fsib, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIB stream probe failed\n");
                goto exit_fsia;