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.

Attachment: 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

Reply via email to