static void tegra_uart_shutdown(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); tegra_uart_hw_deinit(tup); tup->rx_in_progress = 0; tup->tx_in_progress = 0; tegra_uart_dma_channel_free(tup, true); tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); }
static int tegra_uart_startup(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); int ret; ret = tegra_uart_dma_channel_allocate(tup, false); if (ret < 0) { dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", ret); return ret; } if (!tup->use_rx_pio) { ret = tegra_uart_dma_channel_allocate(tup, true); if (ret < 0) { dev_err(u->dev, "Rx Dma allocation failed, err = %d\n", ret); goto fail_rx_dma; } } ret = tegra_uart_hw_init(tup); if (ret < 0) { dev_err(u->dev, "Uart HW init failed, err = %d\n", ret); goto fail_hw_init; } ret = request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED, dev_name(u->dev), tup); if (ret < 0) { dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); goto fail_hw_init; } return 0; fail_hw_init: if (!tup->use_rx_pio) tegra_uart_dma_channel_free(tup, true); fail_rx_dma: tegra_uart_dma_channel_free(tup, false); return ret; }
static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, bool dma_to_memory) { struct dma_chan *dma_chan; unsigned char *dma_buf; dma_addr_t dma_phys; int ret; struct dma_slave_config dma_sconfig; dma_chan = dma_request_slave_channel_reason(tup->uport.dev, dma_to_memory ? "rx" : "tx"); if (IS_ERR(dma_chan)) { ret = PTR_ERR(dma_chan); dev_err(tup->uport.dev, "DMA channel alloc failed: %d\n", ret); return ret; } if (dma_to_memory) { dma_buf = dma_alloc_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, &dma_phys, GFP_KERNEL); if (!dma_buf) { dev_err(tup->uport.dev, "Not able to allocate the dma buffer\n"); dma_release_channel(dma_chan); return -ENOMEM; } dma_sconfig.src_addr = tup->uport.mapbase; dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.src_maxburst = 4; tup->rx_dma_chan = dma_chan; tup->rx_dma_buf_virt = dma_buf; tup->rx_dma_buf_phys = dma_phys; } else { dma_phys = dma_map_single(tup->uport.dev, tup->uport.state->xmit.buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(tup->uport.dev, dma_phys)) { dev_err(tup->uport.dev, "dma_map_single tx failed\n"); dma_release_channel(dma_chan); return -ENOMEM; } dma_buf = tup->uport.state->xmit.buf; dma_sconfig.dst_addr = tup->uport.mapbase; dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.dst_maxburst = 16; tup->tx_dma_chan = dma_chan; tup->tx_dma_buf_virt = dma_buf; tup->tx_dma_buf_phys = dma_phys; } ret = dmaengine_slave_config(dma_chan, &dma_sconfig); if (ret < 0) { dev_err(tup->uport.dev, "Dma slave config failed, err = %d\n", ret); tegra_uart_dma_channel_free(tup, dma_to_memory); return ret; } return 0; }