From: Linus Torvalds Date: Wed, 25 Jul 2012 00:12:54 +0000 (-0700) Subject: Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma X-Git-Tag: master-2012-08-06~92 X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=c511dc1fb6bee58363eb203d53393784f2589d02;hp=-c;p=~andy%2Flinux Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma 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 ... --- c511dc1fb6bee58363eb203d53393784f2589d02 diff --combined drivers/dma/dw_dmac.c index 72129615757,57beb5c8e3f..d3c5a5a88f1 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@@ -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) { @@@ -200,13 -236,7 +236,7 @@@ 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 */ @@@ -373,9 -402,7 +402,7 @@@ "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); @@@ -384,12 -411,11 +411,11 @@@ 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; @@@ -746,14 -755,7 +755,7 @@@ 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); @@@ -813,14 -815,7 +815,7 @@@ 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) { @@@ -1057,8 -1050,7 +1050,7 @@@ 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 */ @@@ -1097,7 -1089,7 +1089,7 @@@ 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; @@@ -1432,9 -1414,15 +1414,15 @@@ } 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; @@@ -1443,8 -1431,6 +1431,6 @@@ 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]; @@@ -1474,17 -1460,13 +1460,13 @@@ 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 "); +MODULE_AUTHOR("Viresh Kumar "); diff --combined drivers/mmc/host/sh_mmcif.c index b2af7136cd2,0f07d2878c4..5d8142773fa --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@@ -54,8 -54,6 +54,8 @@@ #include #include #include +#include +#include #include #include #include @@@ -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; + if (!pdata) + return; + - /* 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->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) @@@ -449,14 -452,13 +457,14 @@@ 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; } @@@ -916,35 -924,10 +924,35 @@@ 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); @@@ -962,7 -945,6 +970,7 @@@ 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); @@@ -974,10 -956,9 +982,10 @@@ } 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; @@@ -985,7 -966,8 +993,7 @@@ 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]; @@@ -1314,26 -1276,42 +1322,26 @@@ 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; @@@ -1341,52 -1319,34 +1349,52 @@@ 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); @@@ -1395,42 -1355,33 +1403,42 @@@ 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); @@@ -1452,9 -1403,9 +1460,9 @@@ 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; @@@ -1463,18 -1414,24 +1471,18 @@@ #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); } @@@ -1483,12 -1440,6 +1491,12 @@@ #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, }, }; diff --combined drivers/mmc/host/sh_mobile_sdhi.c index a842939e465,b8d7004cf04..0bdc146178d --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@@ -21,7 -21,6 +21,7 @@@ #include #include #include +#include #include #include #include @@@ -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); @@@ -152,8 -132,9 +152,8 @@@ 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; @@@ -161,18 -142,13 +161,18 @@@ 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); @@@ -301,7 -276,7 +301,7 @@@ 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), diff --combined drivers/tty/serial/sh-sci.c index 1bd9163bc11,21f7e53f798..d4d8c9453cd --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@@ -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 = ¶m->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); @@@ -1684,7 -1684,7 +1684,7 @@@ 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) @@@ -2425,22 -2413,24 +2425,22 @@@ 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) diff --combined drivers/usb/renesas_usbhs/fifo.c index 08313574aac,fc597a49ac2..30b757a3f59 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@@ -17,8 -17,8 +17,8 @@@ #include #include #include -#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); @@@ -1182,8 -1182,8 +1182,8 @@@ 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; } diff --combined include/linux/mmc/sh_mmcif.h index c2f73cbb4d5,c37956ccf02..e7d5dd67bb7 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@@ -32,20 -32,12 +32,14 @@@ * 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 53486ff9c2a,3edf3bdf536..0540408a9fa --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@@ -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; @@@ -1101,6 -1104,7 +1101,6 @@@ 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); @@@ -1108,8 -1112,14 +1108,8 @@@ 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; @@@ -1118,12 -1128,13 +1118,12 @@@ 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; @@@ -1181,19 -1192,8 +1181,19 @@@ 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; @@@ -1694,7 -1694,7 +1694,7 @@@ 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;