static void bcm2835_dma_release(struct spi_master *master) { if (master->dma_tx) { dmaengine_terminate_sync(master->dma_tx); dma_release_channel(master->dma_tx); master->dma_tx = NULL; } if (master->dma_rx) { dmaengine_terminate_sync(master->dma_rx); dma_release_channel(master->dma_rx); master->dma_rx = NULL; } }
static void bcm2835_spi_handle_err(struct spi_master *master, struct spi_message *msg) { struct bcm2835_spi *bs = spi_master_get_devdata(master); /* if an error occurred and we have an active dma, then terminate */ if (cmpxchg(&bs->dma_pending, true, false)) { dmaengine_terminate_sync(master->dma_tx); dmaengine_terminate_sync(master->dma_rx); bcm2835_spi_undo_prologue(bs); } /* and reset */ bcm2835_spi_reset_hw(master); }
void pxa2xx_spi_dma_release(struct driver_data *drv_data) { struct spi_master *master = drv_data->master; if (master->dma_rx) { dmaengine_terminate_sync(master->dma_rx); dma_release_channel(master->dma_rx); master->dma_rx = NULL; } if (master->dma_tx) { dmaengine_terminate_sync(master->dma_tx); dma_release_channel(master->dma_tx); master->dma_tx = NULL; } }
static int bcm2835_spi_transfer_one_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr, u32 cs) { struct bcm2835_spi *bs = spi_master_get_devdata(master); int ret; /* * Transfer first few bytes without DMA if length of first TX or RX * sglist entry is not a multiple of 4 bytes (hardware limitation). */ bcm2835_spi_transfer_prologue(master, tfr, bs, cs); /* setup tx-DMA */ ret = bcm2835_spi_prepare_sg(master, tfr, true); if (ret) goto err_reset_hw; /* start TX early */ dma_async_issue_pending(master->dma_tx); /* mark as dma pending */ bs->dma_pending = 1; /* set the DMA length */ bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len); /* start the HW */ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA | BCM2835_SPI_CS_DMAEN); /* setup rx-DMA late - to run transfers while * mapping of the rx buffers still takes place * this saves 10us or more. */ ret = bcm2835_spi_prepare_sg(master, tfr, false); if (ret) { /* need to reset on errors */ dmaengine_terminate_sync(master->dma_tx); bs->dma_pending = false; goto err_reset_hw; } /* start rx dma late */ dma_async_issue_pending(master->dma_rx); /* wait for wakeup in framework */ return 1; err_reset_hw: bcm2835_spi_reset_hw(master); bcm2835_spi_undo_prologue(bs); return ret; }
void serial8250_release_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; if (!dma) return; /* Release RX resources */ dmaengine_terminate_sync(dma->rxchan); dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf, dma->rx_addr); dma_release_channel(dma->rxchan); dma->rxchan = NULL; /* Release TX resources */ dmaengine_terminate_sync(dma->txchan); dma_unmap_single(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); dma_release_channel(dma->txchan); dma->txchan = NULL; dma->tx_running = 0; dev_dbg_ratelimited(p->port.dev, "dma channels released\n"); }
static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) { unsigned long flags; struct dma_slave_config rxconf, txconf; struct dma_async_tx_descriptor *rxdesc, *txdesc; spin_lock_irqsave(&rs->lock, flags); rs->state &= ~RXBUSY; rs->state &= ~TXBUSY; spin_unlock_irqrestore(&rs->lock, flags); rxdesc = NULL; if (rs->rx) { rxconf.direction = rs->dma_rx.direction; rxconf.src_addr = rs->dma_rx.addr; rxconf.src_addr_width = rs->n_bytes; if (rs->dma_caps.max_burst > 4) rxconf.src_maxburst = 4; else rxconf.src_maxburst = 1; dmaengine_slave_config(rs->dma_rx.ch, &rxconf); rxdesc = dmaengine_prep_slave_sg( rs->dma_rx.ch, rs->rx_sg.sgl, rs->rx_sg.nents, rs->dma_rx.direction, DMA_PREP_INTERRUPT); if (!rxdesc) return -EINVAL; rxdesc->callback = rockchip_spi_dma_rxcb; rxdesc->callback_param = rs; } txdesc = NULL; if (rs->tx) { txconf.direction = rs->dma_tx.direction; txconf.dst_addr = rs->dma_tx.addr; txconf.dst_addr_width = rs->n_bytes; if (rs->dma_caps.max_burst > 4) txconf.dst_maxburst = 4; else txconf.dst_maxburst = 1; dmaengine_slave_config(rs->dma_tx.ch, &txconf); txdesc = dmaengine_prep_slave_sg( rs->dma_tx.ch, rs->tx_sg.sgl, rs->tx_sg.nents, rs->dma_tx.direction, DMA_PREP_INTERRUPT); if (!txdesc) { if (rxdesc) dmaengine_terminate_sync(rs->dma_rx.ch); return -EINVAL; } txdesc->callback = rockchip_spi_dma_txcb; txdesc->callback_param = rs; } /* rx must be started before tx due to spi instinct */ if (rxdesc) { spin_lock_irqsave(&rs->lock, flags); rs->state |= RXBUSY; spin_unlock_irqrestore(&rs->lock, flags); dmaengine_submit(rxdesc); dma_async_issue_pending(rs->dma_rx.ch); } if (txdesc) { spin_lock_irqsave(&rs->lock, flags); rs->state |= TXBUSY; spin_unlock_irqrestore(&rs->lock, flags); dmaengine_submit(txdesc); dma_async_issue_pending(rs->dma_tx.ch); } return 0; }