Hi, Please find attached a patch for Intel MID I2S driver. This patch fix the Mobile release voice call issue, by calling the DMA Teminate All interface.
Thanks, Selma. >From 4a28c1a4ae44de728087b4cbe2e56880f1029a9c Mon Sep 17 00:00:00 2001 From: Selma Bensaid <[email protected]> Date: Wed, 10 Nov 2010 10:31:38 +0100 Subject: [PATCH] Call the DMA Terminate All interface when closing intel_mid_i2s for immediate close (i.e do not wait any more for end of ongoing DMA transaction). This patch will allow Pulse Audio to unload the voice module even after hanging up the signaling call (no more I2S CLK and FRMSYN coming from the modem), this corresponds to the mobile release a voice call use case. Signed-off-by: Selma Bensaid <[email protected]> --- sound/pci/intel_mid_i2s/intel_mid_i2s.c | 221 ++++++++++++++++++++++++------- 1 files changed, 171 insertions(+), 50 deletions(-) diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.c b/sound/pci/intel_mid_i2s/intel_mid_i2s.c index 121faf6..65b2193 100644 --- a/sound/pci/intel_mid_i2s/intel_mid_i2s.c +++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.c @@ -531,6 +531,7 @@ struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage usage, } pdev = to_pci_dev(found_device); drv_data = pci_get_drvdata(pdev); + drv_data->current_settings = *ps_settings; if (!drv_data) { dev_err(found_device, "no drv_data in open pdev=%p\n", pdev); @@ -547,7 +548,6 @@ struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage usage, goto open_error; } /* if we restart after stop without suspend, we start ssp faster */ - drv_data->current_settings = *ps_settings; set_ssp_i2s_hw(drv_data, ps_settings); drv_data->mask_sr = ((SSSR_BCE_MASK << SSSR_BCE_SHIFT) | @@ -585,6 +585,10 @@ EXPORT_SYMBOL_GPL(intel_mid_i2s_open); void intel_mid_i2s_close(struct intel_mid_i2s_hdl *drv_data) { void __iomem *reg; + struct intel_mid_i2s_settings *ssp_settings = &(drv_data->current_settings); + int s; + struct dma_chan *channel; + WARN(!drv_data, "Driver data=NULL\n"); if (!drv_data) return; @@ -594,20 +598,27 @@ void intel_mid_i2s_close(struct intel_mid_i2s_hdl *drv_data) mutex_unlock(&drv_data->mutex); return; } - /* to be modified to wait_event_interruptible_timeout */ + set_bit(I2S_PORT_CLOSING, &drv_data->flags); - dev_dbg(&drv_data->pdev->dev, "Status bit pending write=%d read=%d\n", + dev_info(&drv_data->pdev->dev, "Status bit pending write=%d read=%d\n", test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags), test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)); if (test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags) || test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) { - dev_dbg(&drv_data->pdev->dev, "Pending callback in close...\n"); + dev_info(&drv_data->pdev->dev, "Pending callback in close...\n"); + } + + if (ssp_settings->ssp_active_tx_slots_map) { + channel = drv_data->txchan; + s = channel->device->device_control(channel, DMA_TERMINATE_ALL, 0); + dev_info(&drv_data->pdev->dev, "DMA_TERMINATE tx=%d\n", s); + } + if (ssp_settings->ssp_active_rx_slots_map) { + channel = drv_data->rxchan; + s = channel->device->device_control(channel, DMA_TERMINATE_ALL, 0); + dev_info(&drv_data->pdev->dev, "DMA_TERMINATE rx=%d\n", s); } - /* waiting below. To be replaced when "DMA_TERMINATE_ALL" fix available */ - wait_event(drv_data->wq_chan_closing, - ((!test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) && - (!test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)))); /* release DMA Channel.. */ i2s_dma_stop(drv_data); reg = drv_data->ioaddr; @@ -615,6 +626,7 @@ void intel_mid_i2s_close(struct intel_mid_i2s_hdl *drv_data) i2s_ssp_stop(drv_data); put_device(&drv_data->pdev->dev); write_SSCR0(0, reg); + /* pm runtime */ pm_runtime_put(&drv_data->pdev->dev); dev_dbg(&(drv_data->pdev->dev), "SSP Stopped.\n"); @@ -764,6 +776,48 @@ static bool chan_filter(struct dma_chan *chan, void *param) out: return ret; } +static int i2s_compute_dma_width(u16 ssp_data_size, enum intel_mid_dma_width *dma_width) +{ + if (ssp_data_size <= 8) + *dma_width = LNW_DMA_WIDTH_8BIT; + else if (ssp_data_size <= 16) + *dma_width = LNW_DMA_WIDTH_16BIT; + else if (ssp_data_size <= 32) + *dma_width = LNW_DMA_WIDTH_32BIT; + else + return -EINVAL; + + + return 0; +} +static int i2s_compute_dma_msize(u8 ssp_threshold, enum intel_mid_dma_msize *dma_msize) +{ + + switch (ssp_threshold) { + case 1: + *dma_msize = LNW_DMA_MSIZE_1; + break; + case 4: + *dma_msize = LNW_DMA_MSIZE_4; + break; + case 8: + *dma_msize = LNW_DMA_MSIZE_8; + break; + case 16: + *dma_msize = LNW_DMA_MSIZE_16; + break; + case 32: + *dma_msize = LNW_DMA_MSIZE_32; + break; + case 64: + *dma_msize = LNW_DMA_MSIZE_64; + break; + default: + return -EINVAL; + break; + } + return 0; +} /** * i2s_dma_start - prepare and reserve dma channels @@ -777,55 +831,117 @@ out: static int i2s_dma_start(struct intel_mid_i2s_hdl *drv_data) { struct intel_mid_dma_slave *rxs, *txs; + struct pci_dev *l_pdev; + struct intel_mid_i2s_settings *ssp_settings = &(drv_data->current_settings); dma_cap_mask_t mask; int retval = 0; - struct pci_dev *l_pdev; + int temp = 0; dev_dbg(&drv_data->pdev->dev, "DMAC1 start\n"); drv_data->txchan = NULL; drv_data->rxchan = NULL; l_pdev = drv_data->pdev; - /* 1. init rx channel */ - rxs = &drv_data->dmas_rx; - rxs->dirn = DMA_FROM_DEVICE; - rxs->hs_mode = LNW_DMA_HW_HS; - rxs->cfg_mode = LNW_DMA_PER_TO_MEM; - rxs->src_width = LNW_DMA_WIDTH_16BIT; - rxs->dst_width = LNW_DMA_WIDTH_32BIT; - rxs->src_msize = LNW_DMA_MSIZE_8; - rxs->dst_msize = LNW_DMA_MSIZE_8; - rxs->device_instance = drv_data->device_instance; - dma_cap_zero(mask); - dma_cap_set(DMA_MEMCPY, mask); - dma_cap_set(DMA_SLAVE, mask); - drv_data->rxchan = dma_request_channel(mask, chan_filter, drv_data); - if (!drv_data->rxchan) { - dev_err(&(drv_data->pdev->dev), - "Could not get Rx channel\n"); - retval = -2; - goto err_exit; + + if (ssp_settings->ssp_active_rx_slots_map) { + /* 1. init rx channel */ + rxs = &drv_data->dmas_rx; + rxs->dirn = DMA_FROM_DEVICE; + rxs->hs_mode = LNW_DMA_HW_HS; + rxs->cfg_mode = LNW_DMA_PER_TO_MEM; + temp = i2s_compute_dma_width(ssp_settings->data_size, &rxs->src_width); + + if (temp != 0) { + dev_err(&(drv_data->pdev->dev), + "RX DMA Channel Bad data_size = %d\n", + ssp_settings->data_size); + retval = -1; + goto err_exit; + + } + rxs->dst_width = LNW_DMA_WIDTH_32BIT; + + temp = i2s_compute_dma_msize(ssp_settings->ssp_rx_fifo_threshold, &rxs->src_msize); + if (temp != 0) { + dev_err(&(drv_data->pdev->dev), + "RX DMA Channel Bad RX FIFO Threshold\n"); + retval = -2; + goto err_exit; + + } + + temp = i2s_compute_dma_msize(ssp_settings->ssp_rx_fifo_threshold, &rxs->dst_msize); + if (temp != 0) { + dev_err(&(drv_data->pdev->dev), + "RX DMA Channel Bad RX FIFO Threshold\n"); + retval = -3; + goto err_exit; + + } + + rxs->device_instance = drv_data->device_instance; + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_SLAVE, mask); + drv_data->rxchan = dma_request_channel(mask, chan_filter, drv_data); + if (!drv_data->rxchan) { + dev_err(&(drv_data->pdev->dev), + "Could not get Rx channel\n"); + retval = 4; + goto err_exit; + } + drv_data->rxchan->private = rxs; } - drv_data->rxchan->private = rxs; - /* 2. init tx channel */ - txs = &drv_data->dmas_tx; - txs->dirn = DMA_TO_DEVICE; - txs->hs_mode = LNW_DMA_HW_HS; - txs->cfg_mode = LNW_DMA_MEM_TO_PER; - txs->src_width = LNW_DMA_WIDTH_32BIT; - txs->dst_width = LNW_DMA_WIDTH_16BIT; - txs->src_msize = LNW_DMA_MSIZE_8; - txs->dst_msize = LNW_DMA_MSIZE_8; - txs->device_instance = drv_data->device_instance; - dma_cap_set(DMA_SLAVE, mask); - dma_cap_set(DMA_MEMCPY, mask); - drv_data->txchan = dma_request_channel(mask, chan_filter, drv_data); - if (!drv_data->txchan) { - dev_err(&(drv_data->pdev->dev), - "Could not get Tx channel\n"); - retval = -3; - goto free_rxchan; + + if (ssp_settings->ssp_active_tx_slots_map) { + /* 2. init tx channel */ + txs = &drv_data->dmas_tx; + txs->dirn = DMA_TO_DEVICE; + txs->hs_mode = LNW_DMA_HW_HS; + txs->cfg_mode = LNW_DMA_MEM_TO_PER; + txs->src_width = LNW_DMA_WIDTH_32BIT; + temp = i2s_compute_dma_width(ssp_settings->data_size, &txs->dst_width); + if (temp != 0) { + dev_err(&(drv_data->pdev->dev), + "TX DMA Channel Bad data_size = %d\n", + ssp_settings->data_size); + retval = -5; + goto err_exit; + + } + + temp = i2s_compute_dma_msize(ssp_settings->ssp_tx_fifo_threshold+1, &txs->src_msize); + if (temp != 0) { + dev_err(&(drv_data->pdev->dev), + "TX DMA Channel Bad TX FIFO Threshold = %d\n", + ssp_settings->ssp_tx_fifo_threshold); + retval = -6; + goto err_exit; + + } + + temp = i2s_compute_dma_msize(ssp_settings->ssp_tx_fifo_threshold+1, &txs->dst_msize); + if (temp != 0) { + dev_err(&(drv_data->pdev->dev), + "TX DMA Channel Bad TX FIFO Threshold = %d\n", + ssp_settings->ssp_tx_fifo_threshold); + retval = -7; + goto err_exit; + + } + + txs->device_instance = drv_data->device_instance; + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_MEMCPY, mask); + drv_data->txchan = dma_request_channel(mask, chan_filter, drv_data); + if (!drv_data->txchan) { + dev_err(&(drv_data->pdev->dev), + "Could not get Tx channel\n"); + retval = -8; + goto free_rxchan; + } + drv_data->txchan->private = txs; } - drv_data->txchan->private = txs; + return retval; free_rxchan: dma_release_channel(drv_data->rxchan); @@ -844,9 +960,14 @@ err_exit: */ static void i2s_dma_stop(struct intel_mid_i2s_hdl *drv_data) { + struct intel_mid_i2s_settings *ssp_settings = &(drv_data->current_settings); + dev_dbg(&drv_data->pdev->dev, "DMAC1 stop\n"); - dma_release_channel(drv_data->txchan); - dma_release_channel(drv_data->rxchan); + if (ssp_settings->ssp_active_rx_slots_map) + dma_release_channel(drv_data->rxchan); + if (ssp_settings->ssp_active_tx_slots_map) + dma_release_channel(drv_data->txchan); + } static void i2s_ssp_stop(struct intel_mid_i2s_hdl *drv_data) -- 1.7.2.3 --------------------------------------------------------------------- Intel Corporation SAS (French simplified joint stock company) Registered headquarters: "Les Montalets"- 2, rue de Paris, 92196 Meudon Cedex, France Registration Number: 302 456 199 R.C.S. NANTERRE Capital: 4,572,000 Euros This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
0001-Call-the-DMA-Terminate-All-interface-when-closing-in.patch
Description: 0001-Call-the-DMA-Terminate-All-interface-when-closing-in.patch
_______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
