audio: port the non upstreamed changes
authorRamesh Babu K V <ramesh.babu@intel.com>
Mon, 24 Oct 2011 09:46:29 +0000 (15:16 +0530)
committerbuildbot <buildbot@intel.com>
Tue, 29 Nov 2011 20:38:21 +0000 (12:38 -0800)
BZ: 15246

move staging sst to sound/
port sn95031 changes
port sst_platform and mfld_machine drv
port the intel-mid-dma driver
port the intel-sst driver
asoc:add ignore_pmdown_time flag to dai_link
(backport for k3.2)

Orignal commit log for asoc backport patch:
ASoC framework delays playback widget power down sequence
by 5 seconds.  This delay is applicable for all the playback
streams.  This delay is not required for voice dai's.

This patch adds ignore_pmdown_time flag to snd_soc_dai_link
structure.  Each dai_link can choose to ignore the pmdown_time
based on board configuration.

commit ID in upstream asoc tree:
e50fad4f029c36ed85a71fe7413684cfd3c7d78c

Change-Id: I50c665d842730cdb5bb54fd1d39680ba3b1fcd5c
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Reviewed-on: http://android.intel.com:8080/25532
Reviewed-by: Suet, NicolasX <nicolasx.suet@intel.com>
Reviewed-by: Seibel, Eric <eric.seibel@intel.com>
Tested-by: Seibel, Eric <eric.seibel@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
29 files changed:
drivers/dma/intel_mid_dma.c
drivers/dma/intel_mid_dma_regs.h
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/intel_sst/Kconfig [deleted file]
drivers/staging/intel_sst/Makefile [deleted file]
drivers/staging/intel_sst/TODO [deleted file]
include/sound/intel_sst.h [moved from drivers/staging/intel_sst/intel_sst.h with 97% similarity]
include/sound/intel_sst_ioctl.h [moved from drivers/staging/intel_sst/intel_sst_ioctl.h with 99% similarity]
include/sound/soc.h
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/sst/Makefile [new file with mode: 0644]
sound/pci/sst/intel_sst.c [moved from drivers/staging/intel_sst/intel_sst.c with 94% similarity]
sound/pci/sst/intel_sst_app_interface.c [moved from drivers/staging/intel_sst/intel_sst_app_interface.c with 98% similarity]
sound/pci/sst/intel_sst_common.h [moved from drivers/staging/intel_sst/intel_sst_common.h with 94% similarity]
sound/pci/sst/intel_sst_drv_interface.c [moved from drivers/staging/intel_sst/intel_sst_drv_interface.c with 86% similarity]
sound/pci/sst/intel_sst_dsp.c [moved from drivers/staging/intel_sst/intel_sst_dsp.c with 62% similarity]
sound/pci/sst/intel_sst_fw_ipc.h [moved from drivers/staging/intel_sst/intel_sst_fw_ipc.h with 100% similarity]
sound/pci/sst/intel_sst_ipc.c [moved from drivers/staging/intel_sst/intel_sst_ipc.c with 95% similarity]
sound/pci/sst/intel_sst_pvt.c [moved from drivers/staging/intel_sst/intel_sst_pvt.c with 99% similarity]
sound/pci/sst/intel_sst_stream.c [moved from drivers/staging/intel_sst/intel_sst_stream.c with 96% similarity]
sound/pci/sst/intel_sst_stream_encoded.c [moved from drivers/staging/intel_sst/intel_sst_stream_encoded.c with 99% similarity]
sound/soc/codecs/sn95031.c
sound/soc/codecs/sn95031.h
sound/soc/mid-x86/mfld_machine.c
sound/soc/mid-x86/sst_platform.c
sound/soc/mid-x86/sst_platform.h
sound/soc/soc-core.c

index 0ddc40b..8a0fc17 100644 (file)
@@ -110,21 +110,51 @@ static int get_block_ts(int len, int tx_width, int block_size)
        return block_ts;
 }
 
+/**
+ * get_reg_width       -       computes the DMA sample width
+ * @kernel_width: Kernel DMA slave bus width
+ *
+ * converts the DMA kernel slave bus width in the Intel DMA
+ * bus width
+ */
+static int get_reg_width(enum dma_slave_buswidth kernel_width)
+{
+       int reg_width = -1;
+
+       switch (kernel_width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               reg_width = 0;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               reg_width = 1;
+               break;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               reg_width = 2;
+               break;
+       case DMA_SLAVE_BUSWIDTH_UNDEFINED:
+       case DMA_SLAVE_BUSWIDTH_8_BYTES:
+       default:
+               pr_err("ERR_MDMA: get_reg_width unsupported reg width\n");
+               break;
+       }
+       return reg_width;
+}
+
+
 /*****************************************************************************
 DMAC1 interrupt Functions*/
 
 /**
  * dmac1_mask_periphral_intr - mask the periphral interrupt
- * @midc: dma channel for which masking is required
+ * @mid: dma device for which masking is required
  *
  * Masks the DMA periphral interrupt
  * this is valid for DMAC1 family controllers only
  * This controller should have periphral mask registers already mapped
  */
-static void dmac1_mask_periphral_intr(struct intel_mid_dma_chan *midc)
+static void dmac1_mask_periphral_intr(struct middma_device *mid)
 {
        u32 pimr;
-       struct middma_device *mid = to_middma_device(midc->chan.device);
 
        if (mid->pimr_mask) {
                pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
@@ -184,7 +214,6 @@ static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
 static void disable_dma_interrupt(struct intel_mid_dma_chan *midc)
 {
        /*Check LPE PISR, make sure fwd is disabled*/
-       dmac1_mask_periphral_intr(midc);
        iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK);
        iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
        iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
@@ -242,7 +271,7 @@ static void midc_desc_put(struct intel_mid_dma_chan *midc,
  * Load a transaction into the engine. This must be called with midc->lock
  * held and bh disabled.
  */
-static void midc_dostart(struct intel_mid_dma_chan *midc,
+static int midc_dostart(struct intel_mid_dma_chan *midc,
                        struct intel_mid_dma_desc *first)
 {
        struct middma_device *mid = to_middma_device(midc->chan.device);
@@ -252,7 +281,7 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
                /*error*/
                pr_err("ERR_MDMA: channel is busy in start\n");
                /* The tasklet will hopefully advance the queue... */
-               return;
+               return -EBUSY;
        }
        midc->busy = true;
        /*write registers and en*/
@@ -269,6 +298,7 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
        first->status = DMA_IN_PROGRESS;
 
        iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
+       return 0;
 }
 
 /**
@@ -302,13 +332,9 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
                        desc->current_lli = 0;
        }
        spin_unlock_bh(&midc->lock);
-       if (callback_txd) {
-               pr_debug("MDMA: TXD callback set ... calling\n");
-               callback_txd(param_txd);
-       }
        if (midc->raw_tfr) {
                desc->status = DMA_SUCCESS;
-               if (desc->lli != NULL) {
+               if (desc->lli != NULL && desc->lli->llp != NULL) {
                        pci_pool_free(desc->lli_pool, desc->lli,
                                                desc->lli_phys);
                        pci_pool_destroy(desc->lli_pool);
@@ -316,8 +342,18 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
                list_move(&desc->desc_node, &midc->free_list);
                midc->busy = false;
        }
+       if (callback_txd) {
+               pr_debug("MDMA: TXD callback set ... calling\n");
+               callback_txd(param_txd);
+       }
+
        spin_lock_bh(&midc->lock);
+}
 
+static struct
+intel_mid_dma_desc *midc_first_queued(struct intel_mid_dma_chan *midc)
+{
+       return list_entry(midc->queue.next, struct intel_mid_dma_desc, desc_node);
 }
 /**
  * midc_scan_descriptors -             check the descriptors in channel
@@ -338,8 +374,16 @@ static void midc_scan_descriptors(struct middma_device *mid,
                if (desc->status == DMA_IN_PROGRESS)
                        midc_descriptor_complete(midc, desc);
        }
-       return;
+
+       if (!list_empty(&midc->queue)) {
+               pr_debug("MDMA: submitting txn in queue\n");
+               if (0 == midc_dostart(midc, midc_first_queued(midc)))
+                       list_splice_init(&midc->queue, &midc->active_list);
+               else
+                       pr_warn("Submit failed as ch is busy\n");
        }
+       return;
+}
 /**
  * midc_lli_fill_sg -          Helper function to convert
  *                             SG list to Linked List Items.
@@ -491,7 +535,9 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
 
        ret = dma_async_is_complete(cookie, last_complete, last_used);
        if (ret != DMA_SUCCESS) {
+               spin_lock_bh(&midc->lock);
                midc_scan_descriptors(to_middma_device(chan->device), midc);
+               spin_unlock_bh(&midc->lock);
 
                last_complete = midc->completed;
                last_used = chan->cookie;
@@ -598,6 +644,8 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
        union intel_mid_dma_cfg_lo cfg_lo;
        union intel_mid_dma_cfg_hi cfg_hi;
        enum dma_slave_buswidth width;
+       int dst_reg_width = 0;
+       int src_reg_width = 0;
 
        pr_debug("MDMA: Prep for memcpy\n");
        BUG_ON(!chan);
@@ -639,7 +687,8 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
                                        cfg_hi.cfgx.dst_per = 3;
                                if (mids->device_instance == 1)
                                        cfg_hi.cfgx.dst_per = 1;
-                       } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
+                       } else if (mids->dma_slave.direction ==
+                                                       DMA_FROM_DEVICE) {
                                if (mids->device_instance == 0)
                                        cfg_hi.cfgx.src_per = 2;
                                if (mids->device_instance == 1)
@@ -664,20 +713,27 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
        /*calculate CTL_LO*/
        ctl_lo.ctl_lo = 0;
        ctl_lo.ctlx.int_en = 1;
+
+       dst_reg_width = get_reg_width(mids->dma_slave.dst_addr_width);
+       if (dst_reg_width < 0) {
+               pr_err("ERR_MDMA: Failed to get DST reg width\n");
+               return NULL;
+
+       }
+       ctl_lo.ctlx.dst_tr_width = dst_reg_width;
+
+       src_reg_width = get_reg_width(mids->dma_slave.src_addr_width);
+       if (src_reg_width < 0) {
+               pr_err("ERR_MDMA: Failed to get SRC reg width\n");
+                               return NULL;
+       }
+       ctl_lo.ctlx.src_tr_width = src_reg_width;
+
+
+
        ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
        ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
 
-       /*
-        * Here we need some translation from "enum dma_slave_buswidth"
-        * to the format for our dma controller
-        *              standard        intel_mid_dmac's format
-        *               1 Byte                 0b000
-        *               2 Bytes                0b001
-        *               4 Bytes                0b010
-        */
-       ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
-       ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
-
        if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
                ctl_lo.ctlx.tt_fc = 0;
                ctl_lo.ctlx.sinc = 0;
@@ -755,18 +811,8 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
        BUG_ON(!mids);
 
        if (!midc->dma->pimr_mask) {
-               /* We can still handle sg list with only one item */
-               if (sg_len == 1) {
-                       txd = intel_mid_dma_prep_memcpy(chan,
-                                               mids->dma_slave.dst_addr,
-                                               mids->dma_slave.src_addr,
-                                               sgl->length,
-                                               flags);
-                       return txd;
-               } else {
-                       pr_warn("MDMA: SG list is not supported by this controller\n");
-                       return  NULL;
-               }
+               pr_debug("MDMA: SG list is not supported by this controller\n");
+               return  NULL;
        }
 
        pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
@@ -824,11 +870,11 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
        struct middma_device    *mid = to_middma_device(chan->device);
        struct intel_mid_dma_desc       *desc, *_desc;
 
+       pr_debug("entry:%s\n", __func__);
        if (true == midc->busy) {
                /*trying to free ch in use!!!!!*/
                pr_err("ERR_MDMA: trying to free ch in use\n");
        }
-       pm_runtime_put(&mid->pdev->dev);
        spin_lock_bh(&midc->lock);
        midc->descs_allocated = 0;
        list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
@@ -849,10 +895,9 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
        /* Disable CH interrupts */
        iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
        iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
+       pm_runtime_put(&mid->pdev->dev);
 }
 
-static int dma_resume(struct device *dev);
-
 /**
  * intel_mid_dma_alloc_chan_resources -        Allocate dma resources
  * @chan: chan requiring attention
@@ -870,13 +915,6 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
 
        pm_runtime_get_sync(&mid->pdev->dev);
 
-       if (mid->state == SUSPENDED) {
-               if (dma_resume(&mid->pdev->dev)) {
-                       pr_err("ERR_MDMA: resume failed");
-                       return -EFAULT;
-               }
-       }
-
        /* ASSERT:  channel is idle */
        if (test_ch_en(mid->dma_base, midc->ch_id)) {
                /*ch is not idle*/
@@ -1036,19 +1074,26 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
        u32 tfr_status, err_status;
        int call_tasklet = 0;
 
+       /*DMA Interrupt*/
+       pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
+       if (!mid) {
+               pr_err("ERR_MDMA:null pointer mid\n");
+               return -EINVAL;
+       }
+
        tfr_status = ioread32(mid->dma_base + RAW_TFR);
        err_status = ioread32(mid->dma_base + RAW_ERR);
        if (!tfr_status && !err_status)
                return IRQ_NONE;
 
-       /*DMA Interrupt*/
-       pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
        pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
        tfr_status &= mid->intr_mask;
        if (tfr_status) {
                /*need to disable intr*/
-               iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
-               iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
+               iowrite32((tfr_status << INT_MASK_WE),
+                                               mid->dma_base + MASK_TFR);
+               iowrite32((tfr_status << INT_MASK_WE),
+                                               mid->dma_base + MASK_BLOCK);
                pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
                call_tasklet = 1;
        }
@@ -1092,6 +1137,7 @@ static int mid_setup_dma(struct pci_dev *pdev)
        if (NULL == dma->dma_pool) {
                pr_err("ERR_MDMA:pci_pool_create failed\n");
                err = -ENOMEM;
+               kfree(dma);
                goto err_dma_pool;
        }
 
@@ -1101,7 +1147,7 @@ static int mid_setup_dma(struct pci_dev *pdev)
                dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
                                        LNW_PERIPHRAL_MASK_SIZE);
                if (dma->mask_reg == NULL) {
-                       pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
+                       pr_err("ERR_MDMA:Cant map periphral intr space !!\n");
                        return -ENOMEM;
                }
        } else
@@ -1202,6 +1248,8 @@ err_engine:
        free_irq(pdev->irq, dma);
 err_irq:
        pci_pool_destroy(dma->dma_pool);
+       iounmap(dma->mask_reg);
+       kfree(dma);
 err_dma_pool:
        pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
        return err;
@@ -1335,82 +1383,58 @@ static void __devexit intel_mid_dma_remove(struct pci_dev *pdev)
 
 /* Power Management */
 /*
-* dma_suspend - PCI suspend function
+* dma_suspend - suspend function
 *
-* @pci: PCI device structure
-* @state: PM message
+* @dev: device structure
 *
 * This function is called by OS when a power event occurs
 */
-static int dma_suspend(struct device *dev)
+int dma_suspend(struct device *dev)
 {
        int i;
-       struct pci_dev *pci = to_pci_dev(dev);
-       struct middma_device *device = pci_get_drvdata(pci);
+       struct middma_device *device = dev_get_drvdata(dev);
        pr_debug("MDMA: dma_suspend called\n");
 
        for (i = 0; i < device->max_chan; i++) {
                if (device->ch[i].in_use)
                        return -EAGAIN;
        }
+       dmac1_mask_periphral_intr(device);
        device->state = SUSPENDED;
-       pci_set_drvdata(pci, device);
-       pci_save_state(pci);
-       pci_disable_device(pci);
-       pci_set_power_state(pci, PCI_D3hot);
+
        return 0;
 }
 
 /**
-* dma_resume - PCI resume function
+* dma_resume - resume function
 *
-* @pci:        PCI device structure
+* @dev:        device structure
 *
 * This function is called by OS when a power event occurs
 */
-static int dma_resume(struct device *dev)
+int dma_resume(struct device *dev)
 {
-       int ret;
-       struct pci_dev *pci = to_pci_dev(dev);
-       struct middma_device *device = pci_get_drvdata(pci);
+       struct middma_device *device = dev_get_drvdata(dev);
 
        pr_debug("MDMA: dma_resume called\n");
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       ret = pci_enable_device(pci);
-       if (ret) {
-               pr_err("MDMA: device can't be enabled for %x\n", pci->device);
-               return ret;
-       }
        device->state = RUNNING;
        iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-       pci_set_drvdata(pci, device);
        return 0;
 }
 
 static int dma_runtime_suspend(struct device *dev)
 {
-       struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct middma_device *device = pci_get_drvdata(pci_dev);
-
-       device->state = SUSPENDED;
-       return 0;
+       return dma_suspend(dev);
 }
 
 static int dma_runtime_resume(struct device *dev)
 {
-       struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct middma_device *device = pci_get_drvdata(pci_dev);
-
-       device->state = RUNNING;
-       iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-       return 0;
+       return dma_resume(dev);
 }
 
 static int dma_runtime_idle(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct middma_device *device = pci_get_drvdata(pdev);
+       struct middma_device *device = dev_get_drvdata(dev);
        int i;
 
        for (i = 0; i < device->max_chan; i++) {
@@ -1425,20 +1449,24 @@ static int dma_runtime_idle(struct device *dev)
 * PCI stuff
 */
 static struct pci_device_id intel_mid_dma_ids[] = {
-       { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID),       INFO(2, 6, 4095, 0x200020)},
-       { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID),       INFO(2, 0, 2047, 0)},
-       { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID),    INFO(2, 0, 2047, 0)},
-       { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID),      INFO(4, 0, 4095, 0x400040)},
+       { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID),
+                                       INFO(2, 6, 4095, 0x200020)},
+       { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID),
+                                       INFO(2, 0, 2047, 0)},
+       { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID),
+                                       INFO(2, 0, 2047, 0)},
+       { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID),
+                                       INFO(4, 0, 4095, 0x400040)},
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
 
 static const struct dev_pm_ops intel_mid_dma_pm = {
-       .suspend = dma_suspend,
-       .resume = dma_resume,
-       .runtime_suspend = dma_runtime_suspend,
-       .runtime_resume = dma_runtime_resume,
-       .runtime_idle = dma_runtime_idle,
+       SET_SYSTEM_SLEEP_PM_OPS(dma_suspend,
+                       dma_resume)
+       SET_RUNTIME_PM_OPS(dma_runtime_suspend,
+                       dma_runtime_resume,
+                       dma_runtime_idle)
 };
 
 static struct pci_driver intel_mid_dma_pci_driver = {
index 22acc64..02db4bd 100644 (file)
@@ -45,7 +45,7 @@
 #define DISABLE_CHANNEL(chan_num) \
        (REG_BIT8 << chan_num)
 
-#define DESCS_PER_CHANNEL      16
+#define DESCS_PER_CHANNEL      128
 /*DMA Registers*/
 /*registers associated with channel programming*/
 #define DMA_REG_SIZE           0x400
@@ -295,4 +295,7 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
        return container_of(slave, struct intel_mid_dma_slave, dma_slave);
 }
 
+
+int dma_resume(struct device *dev);
+
 #endif /*__INTEL_MID_DMAC_REGS_H__*/
index 24ff5d6..4141282 100644 (file)
@@ -146,8 +146,6 @@ source "drivers/staging/bcm/Kconfig"
 
 source "drivers/staging/ft1000/Kconfig"
 
-source "drivers/staging/intel_sst/Kconfig"
-
 source "drivers/staging/speakup/Kconfig"
 
 source "drivers/staging/cptm1217/Kconfig"
index e420855..b55d2a9 100644 (file)
@@ -64,7 +64,6 @@ obj-$(CONFIG_ATH6K_LEGACY)    += ath6kl/
 obj-$(CONFIG_USB_ENESTORAGE)   += keucr/
 obj-$(CONFIG_BCM_WIMAX)                += bcm/
 obj-$(CONFIG_FT1000)           += ft1000/
-obj-$(CONFIG_SND_INTEL_SST)    += intel_sst/
 obj-$(CONFIG_SPEAKUP)          += speakup/
 obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
 obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += cptm1217/
diff --git a/drivers/staging/intel_sst/Kconfig b/drivers/staging/intel_sst/Kconfig
deleted file mode 100644 (file)
index 0df320f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-config SND_INTEL_SST
-       tristate "Intel SST (LPE) Driver"
-       depends on X86 && INTEL_SCU_IPC
-       default n
-       help
-         Say Y here to include support for the Intel(R) MID SST DSP driver
-         On other PC platforms if you are unsure answer 'N'
diff --git a/drivers/staging/intel_sst/Makefile b/drivers/staging/intel_sst/Makefile
deleted file mode 100644 (file)
index 275809c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for Intel MID Audio drivers
-#
-snd-intel-sst-y := intel_sst.o intel_sst_ipc.o intel_sst_stream.o intel_sst_drv_interface.o intel_sst_dsp.o intel_sst_pvt.o intel_sst_stream_encoded.o intel_sst_app_interface.o
-obj-$(CONFIG_SND_INTEL_SST) += snd-intel-sst.o
diff --git a/drivers/staging/intel_sst/TODO b/drivers/staging/intel_sst/TODO
deleted file mode 100644 (file)
index c733d70..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-TODO
-----
-
-Get the memrar driver cleaned up and upstream (dependency blocking SST)
-Replace long/short press with two virtual buttons
-Review the printks and kill off any left over ST_ERR: messages
-Review the misc device ioctls for 32/64bit safety and sanity
-Review the misc device ioctls for size safety depending on config and decide
-       if space/unused areas should be left
-What the sound folks turn up on full review
-Using the ALSA frameworks properly
-
-
similarity index 97%
rename from drivers/staging/intel_sst/intel_sst.h
rename to include/sound/intel_sst.h
index 9a189f8..72e0066 100644 (file)
@@ -29,7 +29,7 @@
  *     and middleware.
  *  This file is shared between the SST and MAD drivers
  */
-#include "intel_sst_ioctl.h"
+#include <sound/intel_sst_ioctl.h>
 #include <sound/jack.h>
 
 #define SST_CARD_NAMES "intel_mid_card"
@@ -93,20 +93,17 @@ struct snd_pmic_ops {
        int pb_on, pbhs_on;
        int cap_on;
        int output_dev_id;
-       int lineout_dev_id, line_out_names_cnt;
+       int lineout_dev_id, lineout_names_cnt;
        int prev_lineout_dev_id;
        bool jack_interrupt_status;
        void (*pmic_irq_cb) (void *cb_data, u8 value);
        void (*pmic_irq_enable)(void *data);
-       int (*pmic_jack_enable) (void);
        int (*pmic_get_mic_bias)(void *intelmaddata);
        int (*pmic_set_headset_state)(int state);
 
        unsigned int hw_dmic_map[MFLD_MAX_HW_CH];
        unsigned int available_dmics;
        int (*set_hw_dmic_route) (u8 index);
-
-       int gpio_amp;
 };
 
 extern void sst_mad_send_jack_report(struct snd_jack *jack,
@@ -145,6 +142,7 @@ enum intel_sst_pll_mode {
        SST_PLL_AUDIENCE = 0x4,
        SST_PLL_VIBRA1 = 0x8,
        SST_PLL_VIBRA2 = 0x10,
+       SST_PLL_MSIC = 0x20,
 };
 
 int register_sst_card(struct intel_sst_card_ops *card);
similarity index 99%
rename from drivers/staging/intel_sst/intel_sst_ioctl.h
rename to include/sound/intel_sst_ioctl.h
index 34cd6cd..f7a7c6a 100644 (file)
@@ -414,7 +414,7 @@ struct snd_sst_tuning_params {
 } __attribute__ ((packed));
 /*IOCTL defined here */
 /*SST MMF IOCTLS only */
-#define SNDRV_SST_STREAM_SET_PARAMS _IOR('L', 0x00, \
+#define SNDRV_SST_STREAM_SET_PARAMS _IOWR('L', 0x00, \
                                        struct snd_sst_stream_params *)
 #define SNDRV_SST_STREAM_GET_PARAMS _IOWR('L', 0x01, \
                                        struct snd_sst_get_stream_params *)
index a55a7c3..861c9c5 100644 (file)
@@ -669,6 +669,9 @@ struct snd_soc_dai_link {
        /* Symmetry requirements */
        unsigned int symmetric_rates:1;
 
+       /* ignore dapm power down delay */
+       unsigned int ignore_pmdown_time:1;
+
        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_pcm_runtime *rtd);
 
index e90d103..9900bd9 100644 (file)
@@ -9,6 +9,14 @@ menuconfig SND_PCI
 
 if SND_PCI
 
+config SND_INTEL_SST
+       tristate "Intel SST (LPE) Driver"
+       depends on X86 && INTEL_SCU_IPC
+       default n
+       help
+         Say Y here to include support for the Intel(R) MID SST DSP driver
+         On other PC platforms if you are unsure answer 'N'
+
 config SND_AD1889
        tristate "Analog Devices AD1889"
        select SND_AC97_CODEC
index 54fe325..4687a65 100644 (file)
@@ -77,6 +77,7 @@ obj-$(CONFIG_SND) += \
        pcxhr/ \
        riptide/ \
        rme9652/ \
+       sst/ \
        trident/ \
        ymfpci/ \
        vx222/
diff --git a/sound/pci/sst/Makefile b/sound/pci/sst/Makefile
new file mode 100644 (file)
index 0000000..94b15ef
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for Intel MID Audio drivers
+#
+snd-intel-sst-objs := intel_sst.o intel_sst_ipc.o intel_sst_stream.o intel_sst_drv_interface.o  intel_sst_dsp.o intel_sst_pvt.o intel_sst_stream_encoded.o intel_sst_app_interface.o
+obj-$(CONFIG_SND_INTEL_SST) += snd-intel-sst.o
similarity index 94%
rename from drivers/staging/intel_sst/intel_sst.c
rename to sound/pci/sst/intel_sst.c
index 3936906..7792c78 100644 (file)
 #include <linux/firmware.h>
 #include <linux/miscdevice.h>
 #include <linux/pm_runtime.h>
+#include <linux/async.h>
 #include <asm/mrst.h>
 #include <asm/intel_scu_ipc.h>
-#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -55,6 +56,7 @@ MODULE_VERSION(SST_DRIVER_VERSION);
 
 struct intel_sst_drv *sst_drv_ctx;
 static struct mutex drv_ctx_lock;
+struct class *sst_class;
 
 /* fops Routines */
 static const struct file_operations intel_sst_fops = {
@@ -110,6 +112,7 @@ static irqreturn_t intel_sst_interrupt(int irq, void *context)
        /* Do not handle interrupt in suspended state */
        if (drv->sst_state == SST_SUSPENDED)
                return IRQ_NONE;
+
        /* Interrupt arrived, check src */
        isr.full = sst_shim_read(drv->shim, SST_ISRX);
 
@@ -123,6 +126,7 @@ static irqreturn_t intel_sst_interrupt(int irq, void *context)
                                stream->period_elapsed(stream->pcm_substream);
                        return IRQ_HANDLED;
                }
+               pr_err("recieved IPC %x\n", header.full);
                if (header.part.large)
                        size = header.part.data;
                if (header.part.msg_id & REPLY_MSG) {
@@ -204,8 +208,10 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        sst_drv_ctx->unique_id = 0;
        sst_drv_ctx->pmic_port_instance = SST_DEFAULT_PMIC_PORT;
        sst_drv_ctx->fw = NULL;
+       sst_drv_ctx->fw_in_mem = NULL;
 
        INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_list);
+       INIT_LIST_HEAD(&sst_drv_ctx->fw_list);
        INIT_WORK(&sst_drv_ctx->ipc_post_msg.wq, sst_post_message);
        INIT_WORK(&sst_drv_ctx->ipc_process_msg.wq, sst_process_message);
        INIT_WORK(&sst_drv_ctx->ipc_process_reply.wq, sst_process_reply);
@@ -288,12 +294,14 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        pr_debug("SRAM Ptr %p\n", sst_drv_ctx->mailbox);
 
        /* IRAM */
+       sst_drv_ctx->iram_base = pci_resource_start(pci, 3);
        sst_drv_ctx->iram = pci_ioremap_bar(pci, 3);
        if (!sst_drv_ctx->iram)
                goto do_unmap_sram;
        pr_debug("IRAM Ptr %p\n", sst_drv_ctx->iram);
 
        /* DRAM */
+       sst_drv_ctx->dram_base = pci_resource_start(pci, 4);
        sst_drv_ctx->dram = pci_ioremap_bar(pci, 4);
        if (!sst_drv_ctx->dram)
                goto do_unmap_iram;
@@ -425,11 +433,11 @@ static void __devexit intel_sst_remove(struct pci_dev *pci)
        destroy_workqueue(sst_drv_ctx->process_msg_wq);
        destroy_workqueue(sst_drv_ctx->post_msg_wq);
        destroy_workqueue(sst_drv_ctx->mad_wq);
-       kfree(pci_get_drvdata(pci));
-       if (sst_drv_ctx->fw) {
-               release_firmware(sst_drv_ctx->fw);
-               sst_drv_ctx->fw = NULL;
-       }
+       release_firmware(sst_drv_ctx->fw);
+       sst_drv_ctx->fw = NULL;
+       kfree(sst_drv_ctx->fw_in_mem);
+       sst_drv_ctx->fw_in_mem = NULL;
+       kfree(sst_drv_ctx);
        sst_drv_ctx = NULL;
        pci_release_regions(pci);
        pci_disable_device(pci);
@@ -439,7 +447,7 @@ static void __devexit intel_sst_remove(struct pci_dev *pci)
 static void sst_save_dsp_context(void)
 {
        struct snd_sst_ctxt_params fw_context;
-       unsigned int pvt_id, i;
+       unsigned int pvt_id;
        struct ipc_post *msg = NULL;
 
        /*check cpu type*/
@@ -455,8 +463,7 @@ static void sst_save_dsp_context(void)
        if (sst_create_large_msg(&msg))
                return;
        pvt_id = sst_assign_pvt_id(sst_drv_ctx);
-       i = sst_get_block_stream(sst_drv_ctx);
-       sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
+       sst_drv_ctx->alloc_block[0].sst_id = pvt_id;
        sst_fill_header(&msg->header, IPC_IA_GET_FW_CTXT, 1, pvt_id);
        msg->header.part.data = sizeof(fw_context) + sizeof(u32);
        fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx);
@@ -469,9 +476,9 @@ static void sst_save_dsp_context(void)
        spin_unlock(&sst_drv_ctx->list_spin_lock);
        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
        /*wait for reply*/
-       if (sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]))
+       if (sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]))
                pr_debug("err fw context save timeout  ...\n");
-       sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+       sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
        pr_debug("fw context saved  ...\n");
        return;
 }
@@ -525,11 +532,10 @@ static int intel_sst_runtime_suspend(struct device *dev)
 {
        union config_status_reg csr;
 
-       pr_debug("sst: runtime_suspend called\n");
-
-       if (sst_drv_ctx->stream_cnt) {
-               pr_err("active streams,not able to suspend\n");
-               return -EBUSY;
+       pr_debug("runtime_suspend called\n");
+       if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
+               pr_err("System already in Suspended state");
+               return 0;
        }
        /*save fw context*/
        sst_save_dsp_context();
@@ -551,7 +557,7 @@ static int intel_sst_runtime_resume(struct device *dev)
 {
        u32 csr;
 
-       pr_debug("sst: runtime_resume called\n");
+       pr_debug("runtime_resume called\n");
        if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
                pr_err("SST is not in suspended state\n");
                return 0;
@@ -565,6 +571,7 @@ static int intel_sst_runtime_resume(struct device *dev)
         * CSR - Configuration and Status Register.
         */
        csr |= (sst_drv_ctx->csr_value | 0x30000);
+       sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr);
 
        intel_sst_set_pll(true, SST_PLL_AUDIO);
        mutex_lock(&sst_drv_ctx->sst_lock);
@@ -576,9 +583,12 @@ static int intel_sst_runtime_resume(struct device *dev)
 static int intel_sst_runtime_idle(struct device *dev)
 {
        pr_debug("runtime_idle called\n");
-       if (sst_drv_ctx->stream_cnt == 0 && sst_drv_ctx->am_cnt == 0)
+       if (!sst_drv_ctx->am_cnt && sst_drv_ctx->sst_state != SST_UN_INIT) {
                pm_schedule_suspend(dev, SST_SUSPEND_DELAY);
-       return -EBUSY;
+               return -EBUSY;
+       } else {
+               return 0;
+       }
 }
 
 static const struct dev_pm_ops intel_sst_pm = {
@@ -643,13 +653,9 @@ static void __exit intel_sst_exit(void)
        pci_unregister_driver(&driver);
 
        pr_debug("driver unloaded\n");
-       if (sst_drv_ctx->fw) {
-               release_firmware(sst_drv_ctx->fw);
-               sst_drv_ctx->fw = NULL;
-       }
        sst_drv_ctx = NULL;
        return;
 }
 
-module_init(intel_sst_init);
+module_init_async(intel_sst_init);
 module_exit(intel_sst_exit);
@@ -41,8 +41,8 @@
 #include <linux/rar_register.h>
 #include "../../../drivers/staging/memrar/memrar.h"
 #endif
-#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -62,6 +62,7 @@ static int intel_sst_check_device(void)
        int retval = 0;
 
        if (sst_drv_ctx->sst_state == SST_UN_INIT) {
+               sst_drv_ctx->sst_state = SST_START_INIT;
                /* FW is not downloaded */
                retval = sst_download_fw();
                if (retval)
@@ -95,6 +96,7 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr)
        retval = intel_sst_check_device();
        if (retval) {
                pm_runtime_put(&sst_drv_ctx->pci->dev);
+               sst_drv_ctx->sst_state = SST_UN_INIT;
                mutex_unlock(&sst_drv_ctx->stream_lock);
                return retval;
        }
@@ -918,7 +920,6 @@ static long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg)
                retval = sst_create_algo_ipc(&algo_params, &msg);
                if (retval < 0)
                        break;
-               algo_params.reserved = 1;
                if (copy_from_user(msg->mailbox_data + retval,
                                algo_params.params, algo_params.size))  {
                        kfree(msg);
@@ -974,13 +975,17 @@ static int sst_ioctl_tuning_params(unsigned int cmd, unsigned long arg)
 {
        struct snd_sst_tuning_params params;
        struct ipc_post *msg;
+       unsigned long address;
 
        if (copy_from_user(&params, (void __user *)arg, sizeof(params)))
                return -EFAULT;
+       if (params.size > SST_MAILBOX_SIZE)
+               return -ENOMEM;
        pr_debug("Parameter %d, Stream %d, Size %d\n", params.type,
                        params.str_id, params.size);
        if (sst_create_large_msg(&msg))
                return -ENOMEM;
+       address = (unsigned long)params.addr;
 
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_SST_TUNING_PARAMS):
@@ -995,8 +1000,7 @@ static int sst_ioctl_tuning_params(unsigned int cmd, unsigned long arg)
        memcpy(msg->mailbox_data + sizeof(u32), &params, sizeof(params));
        /* driver doesn't need to send address, so overwrite addr with data */
        if (copy_from_user(msg->mailbox_data + sizeof(u32) + sizeof(params) - sizeof(params.addr),
-                       (void __user *)(unsigned long)params.addr,
-                       params.size)) {
+                       (void __user *)address, params.size)) {
                kfree(msg->mailbox_data);
                kfree(msg);
                return -EFAULT;
@@ -1085,6 +1089,13 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        pr_debug("SET_STREAM_PARAMS received!\n");
                        /* allocated set params only */
                        retval = sst_set_stream_param(str_id, &str_param);
+                       /* Block the call for reply */
+                       if (!retval) {
+                               int sfreq = 0, word_size = 0, num_channel = 0;
+                               sfreq = str_param.sparams.uc.pcm_params.sfreq;
+                               word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz;
+                               num_channel = str_param.sparams.uc.pcm_params.num_chan;
+                       }
                }
                break;
        }
similarity index 94%
rename from drivers/staging/intel_sst/intel_sst_common.h
rename to sound/pci/sst/intel_sst_common.h
index e1783a6..9459dab 100644 (file)
@@ -28,6 +28,9 @@
  *  Common private declarations for SST
  */
 
+#include <linux/dmaengine.h>
+#include <linux/intel_mid_dma.h>
+
 #define SST_DRIVER_VERSION "2.0.04"
 #define SST_VERSION_NUM 0x2004
 
@@ -42,6 +45,7 @@
 enum sst_states {
        SST_FW_LOADED = 1,
        SST_FW_RUNNING,
+       SST_START_INIT,
        SST_UN_INIT,
        SST_ERROR,
        SST_SUSPENDED,
@@ -317,6 +321,35 @@ struct mad_ops_wq {
 #define SST_MMAP_PAGES (640*1024 / PAGE_SIZE)
 #define SST_MMAP_STEP  (40*1024 / PAGE_SIZE)
 
+/* FIXME optimze this */
+enum sst_dma_desc {
+       SST_DESC_NULL = 0,
+       SST_DESC_PREPARED,
+       SST_DESC_SUBMITTED,
+       SST_DESC_DONE,
+};
+
+struct sst_firmware_list {
+       unsigned long src;
+       unsigned long dstn;
+       unsigned int len;
+       struct list_head node;
+       struct dma_async_tx_descriptor *desc;
+       enum sst_dma_desc trf_status;
+       bool is_last;
+       wait_queue_t *wait;
+       wait_queue_head_t *queue;
+};
+
+struct sst_dma {
+       struct dma_chan *ch;
+       struct intel_mid_dma_slave slave;
+       struct pci_dev *dmac;
+};
+
+#define PCI_DMAC_ID 0x0830
+#define SST_MAX_DMA_LEN (4095*4)
+#define SST_DMA_DELAY 2000
 /***
  * struct intel_sst_drv - driver ops
  *
@@ -373,6 +406,8 @@ struct intel_sst_drv {
        void __iomem            *mailbox;
        void __iomem            *iram;
        void __iomem            *dram;
+       unsigned int            iram_base;
+       unsigned int            dram_base;
        unsigned int            shim_phy_add;
        struct list_head        ipc_dispatch_list;
        struct work_struct      ipc_post_msg_wq;
@@ -386,7 +421,7 @@ struct intel_sst_drv {
        struct workqueue_struct *process_msg_wq;
        struct workqueue_struct *process_reply_wq;
 
-       struct stream_info      streams[MAX_NUM_STREAMS];
+       struct stream_info streams[MAX_NUM_STREAMS+1]; /*str_id 0 is not used*/
        struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM];
        struct sst_block        tgt_dev_blk, fw_info_blk, ppp_params_blk,
                                vol_info_blk, mute_info_blk, hs_info_blk;
@@ -419,7 +454,9 @@ struct intel_sst_drv {
        unsigned int            pll_mode;
        const struct firmware *fw;
 
-       unsigned int            fw_downloaded;
+       struct list_head        fw_list;
+       struct sst_dma          dma;
+       void                    *fw_in_mem;
 };
 
 extern struct intel_sst_drv *sst_drv_ctx;
@@ -490,7 +527,8 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
 ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
                        unsigned long nr_segs, loff_t offset);
 
-int sst_load_fw(const struct firmware *fw, void *context);
+int sst_request_fw(void);
+int sst_load_fw(const void *fw_in_mem, void *context);
 int sst_load_library(struct snd_sst_lib_download *lib, u8 ops);
 int sst_spi_mode_enable(void);
 int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
@@ -617,4 +655,12 @@ static inline int sst_shim_read(void __iomem *addr, int offset)
 {
        return readl(addr + offset);
 }
+
+static inline void
+sst_set_fw_state_locked(struct intel_sst_drv *sst_drv_ctx, int sst_state)
+{
+       mutex_lock(&sst_drv_ctx->sst_lock);
+       sst_drv_ctx->sst_state = sst_state;
+       mutex_unlock(&sst_drv_ctx->sst_lock);
+}
 #endif /* __INTEL_SST_COMMON_H__ */
@@ -33,8 +33,8 @@
 #include <linux/fs.h>
 #include <linux/firmware.h>
 #include <linux/pm_runtime.h>
-#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -44,7 +44,7 @@ static void sst_restore_fw_context(void)
        struct ipc_post *msg = NULL;
        int retval = 0;
 
-       pr_debug("sst: restore_fw_context\n");
+       pr_debug("restore_fw_context\n");
        /*check cpu type*/
        if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
                return;
@@ -52,13 +52,11 @@ static void sst_restore_fw_context(void)
        if (!sst_drv_ctx->fw_cntx_size)
                return;
                /*nothing to restore*/
-       pr_debug("sst: restoring context......\n");
+       pr_debug("restoring context......\n");
        /*send msg to fw*/
        if (sst_create_large_msg(&msg))
                return;
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       sst_drv_ctx->sst_state = SST_FW_CTXT_RESTORE;
-       mutex_unlock(&sst_drv_ctx->sst_lock);
+       sst_set_fw_state_locked(sst_drv_ctx, SST_FW_CTXT_RESTORE);
        sst_fill_header(&msg->header, IPC_IA_SET_FW_CTXT, 1, 0);
        sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID;
        sst_drv_ctx->alloc_block[0].ops_block.condition = false;
@@ -76,8 +74,9 @@ static void sst_restore_fw_context(void)
        spin_unlock(&sst_drv_ctx->list_spin_lock);
        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
        retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]);
+       sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
        if (retval)
-               pr_err("sst: sst_restore_fw_context..timeout!\n");
+               pr_err("sst_restore_fw_context..timeout!\n");
        return;
 }
 
@@ -90,46 +89,25 @@ int sst_download_fw(void)
 {
        int retval;
 
-       char name[20];
-
-       if (sst_drv_ctx->sst_state != SST_UN_INIT)
-               return -EPERM;
-
-       /* Reload firmware is not needed for MRST */
-       if ( (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) && sst_drv_ctx->fw_downloaded) {
-               pr_debug("FW already downloaded, skip for MRST platform\n");
-               sst_drv_ctx->sst_state = SST_FW_RUNNING;
-               return 0;
-       }
-
-       snprintf(name, sizeof(name), "%s%04x%s", "fw_sst_",
-                                       sst_drv_ctx->pci_id, ".bin");
+       if (sst_drv_ctx->sst_state != SST_START_INIT)
+               return -EAGAIN;
 
-       pr_debug("Downloading %s FW now...\n", name);
-       if (!sst_drv_ctx->fw) {
-               retval = request_firmware(&sst_drv_ctx->fw, name,
-                                &sst_drv_ctx->pci->dev);
-               if (retval) {
-                       pr_err("sst: request fw failed %d\n", retval);
-                       return retval;
-               }
-       }
+       retval = sst_request_fw();
+       if (retval)
+               return retval;
        sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID;
        sst_drv_ctx->alloc_block[0].ops_block.condition = false;
-       retval = sst_load_fw(sst_drv_ctx->fw, NULL);
+       retval = sst_load_fw(sst_drv_ctx->fw_in_mem, NULL);
        if (retval) {
-               release_firmware(sst_drv_ctx->fw);
-               sst_drv_ctx->fw = NULL;
                goto end_restore;
        }
 
        retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]);
        if (retval) {
                pr_err("fw download failed %d\n" , retval);
-               release_firmware(sst_drv_ctx->fw);
-               sst_drv_ctx->fw = NULL;
-       } else
-               sst_drv_ctx->fw_downloaded = 1;
+               /* assume FW d/l failed due to timeout*/
+               retval = -EBUSY;
+       }
 
 end_restore:
        sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
@@ -137,9 +115,7 @@ end_restore:
                return retval;
 
        sst_restore_fw_context();
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       sst_drv_ctx->sst_state = SST_FW_RUNNING;
-       mutex_unlock(&sst_drv_ctx->sst_lock);
+       sst_set_fw_state_locked(sst_drv_ctx, SST_FW_RUNNING);
 
        return retval;
 }
@@ -205,8 +181,6 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param,
        pr_debug("Stream allocated %d\n", retval);
        str_id = retval;
        str_info = &sst_drv_ctx->streams[str_id];
-       if (str_id == 0)
-               str_id = -SST_IPC_ERR_STREAM_ALLOC_FAILED;
        /* Block the call for reply */
        retval = sst_wait_interruptible_timeout(sst_drv_ctx,
                        &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
@@ -214,6 +188,8 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param,
                pr_debug("FW alloc failed retval %d, ret_code %d\n",
                                retval, str_info->ctrl_blk.ret_code);
                str_id = -str_info->ctrl_blk.ret_code; /*return error*/
+               if (str_id == 0)
+                       str_id = retval; /*FW timed out*/
                *lib_dnld = str_info->ctrl_blk.data;
                sst_clean_stream(str_info);
        } else
@@ -242,6 +218,23 @@ static int sst_get_sfreq(struct snd_sst_params *str_param)
        }
 }
 
+static int sst_get_wdsize(struct snd_sst_params *str_param)
+{
+       switch (str_param->codec) {
+       case SST_CODEC_TYPE_PCM:
+               return str_param->sparams.uc.pcm_params.pcm_wd_sz;
+       case SST_CODEC_TYPE_MP3:
+               return str_param->sparams.uc.mp3_params.pcm_wd_sz;
+       case SST_CODEC_TYPE_AAC:
+               return str_param->sparams.uc.aac_params.pcm_wd_sz;
+       case SST_CODEC_TYPE_WMA9:
+               return str_param->sparams.uc.wma_params.pcm_wd_sz;
+       default:
+               return 0;
+       }
+}
+
+
 /*
  * sst_get_stream - this function prepares for stream allocation
  *
@@ -257,6 +250,8 @@ int sst_get_stream(struct snd_sst_params *str_param)
        retval = sst_get_stream_allocated(str_param, &lib_dnld);
        if (retval == -(SST_LIB_ERR_LIB_DNLD_REQUIRED)) {
                /* codec download is required */
+               struct snd_sst_alloc_response *response;
+
                pr_debug("Codec is required.... trying that\n");
                if (lib_dnld == NULL) {
                        pr_err("lib download null!!! abort\n");
@@ -264,14 +259,13 @@ int sst_get_stream(struct snd_sst_params *str_param)
                }
                i = sst_get_block_stream(sst_drv_ctx);
                if (i < 0) {
-                       pr_err("sst: invalid value for number of stream\n ");
-                       return -EINVAL;
-               }
-               pr_debug("alloc block allocated = %d\n", i);
-               if (i < 0) {
+                       pr_err("invalid value for number of stream\n ");
                        kfree(lib_dnld);
-                       return -ENOMEM;
+                       return i;
                }
+               response = sst_drv_ctx->alloc_block[i].ops_block.data;
+               pr_debug("alloc block allocated = %d\n", i);
+
                retval = sst_load_library(lib_dnld, str_param->ops);
                kfree(lib_dnld);
 
@@ -280,8 +274,10 @@ int sst_get_stream(struct snd_sst_params *str_param)
                        pr_debug("codec was downloaded successfully\n");
 
                        retval = sst_get_stream_allocated(str_param, &lib_dnld);
-                       if (retval <= 0)
+                       if (retval <= 0) {
+                               retval = -EIO;
                                goto err;
+                       }
 
                        pr_debug("Alloc done stream id %d\n", retval);
                } else {
@@ -289,8 +285,10 @@ int sst_get_stream(struct snd_sst_params *str_param)
                        retval = -EIO;
                        goto err;
                }
-       } else if  (retval <= 0)
+       } else if  (retval <= 0) {
+               retval = -EIO;
                goto err;
+       }
        /*else
                set_port_params(str_param, str_param->ops);*/
 
@@ -313,19 +311,25 @@ err:
        return retval;
 }
 
-static void sst_prepare_fw(void)
+void sst_prepare_fw(void)
 {
        int retval;
 
+       mutex_lock(&sst_drv_ctx->sst_lock);
        if (sst_drv_ctx->sst_state == SST_UN_INIT) {
+               sst_drv_ctx->sst_state = SST_START_INIT;
+               mutex_unlock(&sst_drv_ctx->sst_lock);
                /* FW is not downloaded */
-               pr_debug("sst: DSP Downloading FW now...\n");
+               pr_debug("DSP Downloading FW now...\n");
                retval = sst_download_fw();
                if (retval) {
-                       pr_err("sst: FW download fail %x\n", retval);
-                       pr_debug("sst: doing rtpm_put\n");
+                       pr_err("FW download fail %x\n", retval);
+                       pr_debug("doing rtpm_put\n");
+                       sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
                        pm_runtime_put(&sst_drv_ctx->pci->dev);
                }
+       } else {
+               mutex_unlock(&sst_drv_ctx->sst_lock);
        }
 }
 
@@ -344,7 +348,7 @@ void sst_process_mad_ops(struct work_struct *work)
                retval = sst_resume_stream(mad_ops->stream_id);
                break;
        case SST_SND_DROP:
-               pr_debug("SST Debug: in mad_ops drop stream\n");
+               pr_debug("in mad_ops drop stream\n");
                retval = sst_drop_stream(mad_ops->stream_id);
                break;
        case SST_SND_START:
@@ -355,7 +359,7 @@ void sst_process_mad_ops(struct work_struct *work)
                pr_debug("play/capt frames...\n");
                break;
        case SST_SND_DEVICE_RESUME:
-               pr_debug("sst: SST_SND_DEVICE_RESUME\n");
+               pr_debug("SST_SND_DEVICE_RESUME\n");
                pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
                sst_prepare_fw();
                break;
@@ -391,23 +395,30 @@ static int sst_open_pcm_stream(struct snd_sst_params *str_param)
        struct stream_info *str_info;
        int retval;
 
-       pr_debug("sst: open_pcm, doing rtpm_get\n");
+       pr_debug("open_pcm, doing rtpm_get\n");
        pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
 
+       mutex_lock(&sst_drv_ctx->sst_lock);
        if (sst_drv_ctx->sst_state == SST_UN_INIT) {
+               sst_drv_ctx->sst_state = SST_START_INIT;
+               mutex_unlock(&sst_drv_ctx->sst_lock);
                /* FW is not downloaded */
                pr_debug("DSP Downloading FW now...\n");
                retval = sst_download_fw();
                if (retval) {
                        pr_err("FW download fail %x, abort\n", retval);
+                       pr_debug("open_pcm, doing rtpm_put\n");
+                       sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
                        pm_runtime_put(&sst_drv_ctx->pci->dev);
                        return retval;
                }
                send_intial_rx_timeslot();
+       } else {
+               mutex_unlock(&sst_drv_ctx->sst_lock);
        }
 
        if (!str_param) {
-               pr_debug("sst: open_pcm, doing rtpm_put\n");
+               pr_debug("open_pcm, doing rtpm_put\n");
                pm_runtime_put(&sst_drv_ctx->pci->dev);
                return -EINVAL;
        }
@@ -434,7 +445,7 @@ static int sst_close_pcm_stream(unsigned int str_id)
 {
        struct stream_info *stream;
 
-       pr_debug("sst: stream free called\n");
+       pr_debug("stream free called\n");
        if (sst_validate_strid(str_id))
                return -EINVAL;
        stream = &sst_drv_ctx->streams[str_id];
@@ -443,7 +454,7 @@ static int sst_close_pcm_stream(unsigned int str_id)
        stream->status = STREAM_UN_INIT;
        stream->period_elapsed = NULL;
        sst_drv_ctx->stream_cnt--;
-       pr_debug("sst: will call runtime put now\n");
+       pr_debug("will call runtime put now\n");
        pm_runtime_put(&sst_drv_ctx->pci->dev);
        return 0;
 }
@@ -469,6 +480,8 @@ static int sst_device_control(int cmd, void *arg)
        case SST_SND_START:
        case SST_SND_DEVICE_RESUME: {
                struct mad_ops_wq *work = kzalloc(sizeof(*work), GFP_ATOMIC);
+               if (!work)
+                       return -ENOMEM;
                INIT_WORK(&work->wq, sst_process_mad_ops);
                work->control_op = cmd;
                work->stream_id = *(int *)arg;
@@ -476,12 +489,12 @@ static int sst_device_control(int cmd, void *arg)
                break;
        }
        case SST_SND_DEVICE_RESUME_SYNC:
-               pr_debug("sst: SST_SND_DEVICE_RESUME_SYNC\n");
+               pr_debug("SST_SND_DEVICE_RESUME_SYNC\n");
                pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
                sst_prepare_fw();
                break;
        case SST_SND_DEVICE_SUSPEND:
-               pr_debug("sst: SST_SND_DEVICE_SUSPEND doing rtpm_put\n");
+               pr_debug("SST_SND_DEVICE_SUSPEND doing rtpm_put\n");
                pm_runtime_put(&sst_drv_ctx->pci->dev);
                break;
        case SST_SND_STREAM_INIT: {
@@ -572,7 +585,7 @@ static struct intel_sst_card_ops sst_pmic_ops = {
  */
 int register_sst_card(struct intel_sst_card_ops *card)
 {
-       pr_debug("sst: driver register card %p\n", sst_drv_ctx);
+       pr_debug("driver register card %p\n", sst_drv_ctx);
        if (!sst_drv_ctx) {
                pr_err("No SST driver register card reject\n");
                return -ENODEV;
similarity index 62%
rename from drivers/staging/intel_sst/intel_sst_dsp.c
rename to sound/pci/sst/intel_sst_dsp.c
index 25685fb..b0faa11 100644 (file)
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/firmware.h>
-#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <linux/dmaengine.h>
+#include <linux/intel_mid_dma.h>
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -133,13 +136,15 @@ static int sst_start_medfield(void)
  * @module: FW module header
  *
  * Parses modules that need to be placed in SST IRAM and DRAM
+ * and stores them in a list for transfer
  * returns error or 0 if module sizes are proper
  */
 static int sst_parse_module(struct fw_module_header *module)
 {
        struct dma_block_info *block;
-       u32 count;
-       void __iomem *ram;
+       struct sst_firmware_list *node;
+       u32 count, offset;
+       unsigned long ram;
 
        pr_debug("module sign %s size %x blocks %x type %x\n",
                        module->signature, module->mod_size,
@@ -155,53 +160,162 @@ static int sst_parse_module(struct fw_module_header *module)
                }
                switch (block->type) {
                case SST_IRAM:
-                       ram = sst_drv_ctx->iram;
+                       ram = sst_drv_ctx->iram_base;
                        break;
                case SST_DRAM:
-                       ram = sst_drv_ctx->dram;
+                       ram = sst_drv_ctx->dram_base;
                        break;
                default:
                        pr_err("wrong ram type0x%x in block0x%x\n",
                                        block->type, count);
                        return -EINVAL;
                }
-               memcpy_toio(ram + block->ram_offset,
-                               (void *)block + sizeof(*block), block->size);
+               offset = 0;
+               do {
+                       node = kmalloc(sizeof(*node), GFP_KERNEL);
+                       if (!node) {
+                               pr_err("mem alloc failed\n");
+                               return -ENOMEM;
+                       }
+                       node->dstn = ram + block->ram_offset + offset;
+                       node->src = virt_to_phys((void *)block + sizeof(*block) + offset);
+                       node->len = block->size - offset;
+                       node->is_last = false;
+                       node->trf_status = SST_DESC_NULL;
+                       pr_debug("DMA block src %lx, dstn %lx, size %d, offset %d\n",
+                               node->src, node->dstn, node->len, offset);
+                       if (node->len > SST_MAX_DMA_LEN) {
+                               pr_debug("block size exceeds %d\n", SST_MAX_DMA_LEN);
+                               node->len = SST_MAX_DMA_LEN;
+                               offset += node->len;
+                       } else {
+                               offset = 0;
+                               pr_debug("Node length less that %d\n", SST_MAX_DMA_LEN);
+                       }
+                       list_add_tail(&node->node, &sst_drv_ctx->fw_list);
+               } while (offset > 0);
                block = (void *)block + sizeof(*block) + block->size;
        }
+       if (node)
+               node->is_last = true;
        return 0;
 }
 
+static bool chan_filter(struct dma_chan *chan, void *param)
+{
+       struct sst_dma *dma = (struct sst_dma *)param;
+       bool ret = false;
+
+       /* we only need MID_DMAC1 as that can access DSP RAMs*/
+       if (chan->device->dev == &dma->dmac->dev)
+               ret = true;
+
+       return ret;
+}
+
+static int sst_alloc_dma_chan(struct sst_dma *dma)
+{
+       dma_cap_mask_t mask;
+       struct intel_mid_dma_slave *slave = &dma->slave;
+       int retval;
+
+       pr_debug("%s\n", __func__);
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_MEMCPY, mask);
+
+       dma->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DMAC_ID, NULL);
+       if (!dma->dmac) {
+               pr_err("Can't find DMAC %x\n", PCI_DMAC_ID);
+               return -ENODEV;
+       }
+       dma->ch = dma_request_channel(mask, chan_filter, dma);
+
+       slave->dma_slave.direction = DMA_FROM_DEVICE;
+       slave->hs_mode = 0;
+       slave->cfg_mode = LNW_DMA_MEM_TO_MEM;
+       slave->dma_slave.src_addr_width = slave->dma_slave.dst_addr_width =
+                                               DMA_SLAVE_BUSWIDTH_4_BYTES;
+       slave->dma_slave.src_maxburst = slave->dma_slave.dst_maxburst =
+                                                       LNW_DMA_MSIZE_16;
+
+       retval = dmaengine_slave_config(dma->ch, &slave->dma_slave);
+       if (retval) {
+               pr_err("unable to set slave config, err %d\n", retval);
+               return -EIO;
+       }
+       return retval;
+}
+
+static void sst_dma_transfer_complete(void *arg)
+{
+       struct sst_firmware_list *block = arg;
+       static unsigned int count;
+
+       pr_debug("%s, dma callback for %d\n", __func__, count);
+       count++;
+
+       pr_debug("current desc status %d\n", block->trf_status);
+       if (block->trf_status != SST_DESC_SUBMITTED)
+               pr_warn("desc status is showing wrongly\n");
+       block->trf_status = SST_DESC_DONE;
+       pr_debug("new desc status %d\n", block->trf_status);
+       if (block->is_last == true) {
+               count = 0;
+               pr_debug("end of list callback, waking up...\n");
+       }
+}
+
+static int
+sst_get_dma_desc(struct list_head *head, struct sst_dma *dma)
+{
+       struct sst_firmware_list *block;
+       enum dma_ctrl_flags flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+       int i = 0;
+
+       pr_debug("%s\n", __func__);
+       list_for_each_entry(block, head, node) {
+               pr_debug("prep for block %d\n", i); i++;
+               block->desc = dma->ch->device->device_prep_dma_memcpy(
+                       dma->ch, block->dstn, block->src, block->len, flag);
+               if (block->desc) {
+                       block->trf_status = SST_DESC_PREPARED;
+                       block->desc->callback = sst_dma_transfer_complete;
+                       block->desc->callback_param = block;
+                       pr_debug("set block ptrs\n");
+               }
+       }
+       return 0;
+}
 /**
  * sst_parse_fw_image - parse and load FW
  *
  * @sst_fw: pointer to audio fw
  *
- * This function is called to parse and download the FW image
+ * This function is called to verify and parse the FW image and save the parsed
+ * image in a list for DMA
  */
-static int sst_parse_fw_image(const struct firmware *sst_fw)
+static int sst_parse_fw_image(const void *sst_fw_in_mem, unsigned long size)
 {
        struct fw_header *header;
        u32 count;
        int ret_val;
        struct fw_module_header *module;
 
-       BUG_ON(!sst_fw);
-
+       pr_debug("%s\n", __func__);
        /* Read the header information from the data pointer */
-       header = (struct fw_header *)sst_fw->data;
-
+       header = (struct fw_header *)sst_fw_in_mem;
+       pr_debug("header sign=%s size=%x modules=%x fmt=%x size=%x\n",
+                       header->signature, header->file_size, header->modules,
+                       header->file_format, sizeof(*header));
        /* verify FW */
        if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
-                       (sst_fw->size != header->file_size + sizeof(*header))) {
+               (size != header->file_size + sizeof(*header))) {
                /* Invalid FW signature */
-               pr_err("Invalid FW sign/filesize mismatch\n");
+               pr_err("InvalidFW sign/filesize mismatch\n");
                return -EINVAL;
        }
-       pr_debug("header sign=%s size=%x modules=%x fmt=%x size=%x\n",
-                       header->signature, header->file_size, header->modules,
-                       header->file_format, sizeof(*header));
-       module = (void *)sst_fw->data + sizeof(*header);
+
+       module = (void *)sst_fw_in_mem + sizeof(*header);
        for (count = 0; count < header->modules; count++) {
                /* module */
                ret_val = sst_parse_module(module);
@@ -213,20 +327,123 @@ static int sst_parse_fw_image(const struct firmware *sst_fw)
        return 0;
 }
 
+/*
+ * sst_request_fw - requests audio fw from kernel and saves a copy
+ *
+ * This function requests the SST FW from the kernel, parses it and
+ * saves a copy in the driver context
+ */
+int sst_request_fw(void)
+{
+       int retval = 0;
+       char name[20];
+
+       snprintf(name, sizeof(name), "%s%04x%s", "fw_sst_",
+                                       sst_drv_ctx->pci_id, ".bin");
+
+       pr_debug("Requesting %s FW now...\n", name);
+       retval = request_firmware(&sst_drv_ctx->fw, name,
+                                &sst_drv_ctx->pci->dev);
+       if (retval) {
+               pr_err("request fw failed %d\n", retval);
+               return retval;
+       }
+
+       if (!sst_drv_ctx->fw_in_mem) {
+               pr_debug("firmware not in memory\n");
+               sst_drv_ctx->fw_in_mem = kzalloc(sst_drv_ctx->fw->size, GFP_KERNEL);
+               if (!sst_drv_ctx->fw_in_mem) {
+                       pr_err("%s unable to allocate memory\n", __func__);
+                       retval = -ENOMEM;
+                       goto end_release;
+               }
+               memcpy(sst_drv_ctx->fw_in_mem, sst_drv_ctx->fw->data,
+                               sst_drv_ctx->fw->size);
+       }
+
+       retval = sst_parse_fw_image(sst_drv_ctx->fw_in_mem,
+                                       sst_drv_ctx->fw->size);
+       if (retval) {
+               kfree(sst_drv_ctx->fw_in_mem);
+               goto end_release;
+       }
+
+end_release:
+       release_firmware(sst_drv_ctx->fw);
+       sst_drv_ctx->fw = NULL;
+       return retval;
+}
+
+int sst_dma_firmware(struct list_head *head)
+{
+       /* submit the descriptors */
+       struct sst_firmware_list *block;
+       int i = 0;
+       int cnt = 0;
+       pr_debug("%s\n", __func__);
+
+       list_for_each_entry(block, head, node) {
+               pr_debug("submitting desc %d\n", i); i++;
+               pr_debug("before submit desc status %d\n", block->trf_status);
+               block->trf_status = SST_DESC_SUBMITTED;
+               block->desc->tx_submit(block->desc);
+               /* wait for dma completion
+                * since this is memcpy, max block length should get completed
+                * within 2ms, since we are waiting for dma compleetion here and
+                * dont want to yeild, just poll
+                * this is required till multiblock memcpy support API is added
+                * in the dma driver
+                */
+               udelay(SST_DMA_DELAY);
+               pr_debug("after submit desc status %d\n", block->trf_status);
+               cnt = 0;
+               /* wait in loop with counter */
+               while (1) {
+                       pr_debug("while desc status %d\n", block->trf_status);
+                       if (block->trf_status == SST_DESC_DONE) {
+                               pr_debug("desc done %d\n", (i-1));
+                               break;
+                       }
+                       udelay(SST_DMA_DELAY);
+                       cnt++;
+                       if (cnt >= 10) {
+                               pr_err("dma for block %d failed\n", (i-1));
+                               break;
+                       }
+               }
+               pr_debug("wait done\n");
+       }
+       pr_debug("submitted all desc, waiting now...\n");
+       return 0;
+}
+
+void sst_dma_free_resources(struct list_head *head, struct sst_dma *dma)
+{
+       struct sst_firmware_list *block, *__block;
+
+       pr_debug("entry:%s\n", __func__);
+
+       list_for_each_entry_safe(block, __block, head, node) {
+               list_del(&block->node);
+               kfree(block);
+       }
+       dma_release_channel(dma->ch);
+}
+
 /**
  * sst_load_fw - function to load FW into DSP
  *
  * @fw: Pointer to driver loaded FW
  * @context: driver context
  *
- * This function is called by OS when the FW is loaded into kernel
+ * Transfers the FW to DSP using DMA
  */
-int sst_load_fw(const struct firmware *fw, void *context)
+int sst_load_fw(const void *fw_in_mem, void *context)
 {
        int ret_val;
 
        pr_debug("load_fw called\n");
-       BUG_ON(!fw);
+       BUG_ON(!fw_in_mem);
 
        if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
                ret_val = intel_sst_reset_dsp_mrst();
@@ -235,22 +452,25 @@ int sst_load_fw(const struct firmware *fw, void *context)
        if (ret_val)
                return ret_val;
 
-       ret_val = sst_parse_fw_image(fw);
+       /* get a dmac channel */
+       sst_alloc_dma_chan(&sst_drv_ctx->dma);
+       /* allocate desc for transfer */
+       sst_get_dma_desc(&sst_drv_ctx->fw_list, &sst_drv_ctx->dma);
+       ret_val = sst_dma_firmware(&sst_drv_ctx->fw_list);
        if (ret_val)
-               return ret_val;
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       sst_drv_ctx->sst_state = SST_FW_LOADED;
-       mutex_unlock(&sst_drv_ctx->sst_lock);
-       /*  7. ask scu to reset the bypass bits */
-       /*  8.bring sst out of reset  */
+               goto free_dma;
+       sst_set_fw_state_locked(sst_drv_ctx, SST_FW_LOADED);
+       /* bring sst out of reset */
        if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
                ret_val = sst_start_mrst();
        else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
                ret_val = sst_start_medfield();
        if (ret_val)
-               return ret_val;
+               goto free_dma;
 
        pr_debug("fw loaded successful!!!\n");
+free_dma:
+       sst_dma_free_resources(&sst_drv_ctx->fw_list, &sst_drv_ctx->dma);
        return ret_val;
 }
 
@@ -266,6 +486,7 @@ static int sst_download_library(const struct firmware *fw_lib,
        union config_status_reg csr;
        struct snd_sst_str_type str_type = {0};
        int retval = 0;
+       void *codec_fw;
 
        if (sst_create_large_msg(&msg))
                return -ENOMEM;
@@ -298,9 +519,7 @@ static int sst_download_library(const struct firmware *fw_lib,
        }
        pr_debug("FW responded, ready for download now...\n");
        /* downloading on success */
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       sst_drv_ctx->sst_state = SST_FW_LOADED;
-       mutex_unlock(&sst_drv_ctx->sst_lock);
+       sst_set_fw_state_locked(sst_drv_ctx, SST_FW_LOADED);
        csr.full = readl(sst_drv_ctx->shim + SST_CSR);
        csr.part.run_stall = 1;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
@@ -309,7 +528,19 @@ static int sst_download_library(const struct firmware *fw_lib,
        csr.part.bypass = 0x7;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
 
-       sst_parse_fw_image(fw_lib);
+       codec_fw = kzalloc(fw_lib->size, GFP_KERNEL);
+       if (!codec_fw)
+               return -ENOMEM;
+       memcpy(codec_fw, fw_lib->data, fw_lib->size);
+       retval = sst_parse_fw_image(codec_fw, fw_lib->size);
+       sst_alloc_dma_chan(&sst_drv_ctx->dma);
+       sst_get_dma_desc(&sst_drv_ctx->fw_list, &sst_drv_ctx->dma);
+       retval = sst_dma_firmware(&sst_drv_ctx->fw_list);
+
+       sst_dma_free_resources(&sst_drv_ctx->fw_list, &sst_drv_ctx->dma);
+       kfree(codec_fw);
+       if (retval)
+               return retval;
 
        /* set the FW to running again */
        csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
@@ -341,20 +572,15 @@ static int sst_download_library(const struct firmware *fw_lib,
        retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
        if (retval) {
                /* error */
-               mutex_lock(&sst_drv_ctx->sst_lock);
-               sst_drv_ctx->sst_state = SST_UN_INIT;
-               mutex_unlock(&sst_drv_ctx->sst_lock);
+               sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
                sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
                return -EIO;
        }
 
        pr_debug("FW success on Download complete\n");
        sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       sst_drv_ctx->sst_state = SST_FW_RUNNING;
-       mutex_unlock(&sst_drv_ctx->sst_lock);
+       sst_set_fw_state_locked(sst_drv_ctx, SST_FW_RUNNING);
        return 0;
-
 }
 
 /* This function is called before downloading the codec/postprocessing
similarity index 95%
rename from drivers/staging/intel_sst/intel_sst_ipc.c
rename to sound/pci/sst/intel_sst_ipc.c
index e58b01b..085d7ee 100644 (file)
@@ -31,8 +31,8 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
-#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -54,7 +54,6 @@ static void sst_send_sound_card_type(void)
        list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
        spin_unlock(&sst_drv_ctx->list_spin_lock);
        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
-       return;
 }
 
 /**
@@ -123,7 +122,6 @@ void sst_post_message(struct work_struct *work)
 
        kfree(msg->mailbox_data);
        kfree(msg);
-       return;
 }
 
 /*
@@ -170,9 +168,7 @@ static int process_fw_init(struct sst_ipc_msg_wq *msg)
 
        pr_debug("*** FW Init msg came***\n");
        if (init->result) {
-               mutex_lock(&sst_drv_ctx->sst_lock);
-               sst_drv_ctx->sst_state = SST_ERROR;
-               mutex_unlock(&sst_drv_ctx->sst_lock);
+               sst_set_fw_state_locked(sst_drv_ctx, SST_ERROR);
                pr_debug("FW Init failed, Error %x\n", init->result);
                pr_err("FW Init failed, Error %x\n", init->result);
                retval = -init->result;
@@ -222,11 +218,14 @@ void sst_process_message(struct work_struct *work)
 
        case IPC_SST_GET_PLAY_FRAMES:
                if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+                       struct stream_info *stream ;
+
                        if (sst_validate_strid(str_id)) {
                                pr_err("strid %d invalid\n", str_id);
                                break;
                        }
                        /* call sst_play_frame */
+                       stream = &sst_drv_ctx->streams[str_id];
                        pr_debug("sst_play_frames for %d\n",
                                        msg->header.part.str_id);
                        mutex_lock(&sst_drv_ctx->streams[str_id].lock);
@@ -332,16 +331,16 @@ void sst_process_reply(struct work_struct *work)
                }
                break;
        case IPC_IA_ALG_PARAMS: {
-               pr_debug("sst:IPC_ALG_PARAMS response %x\n", msg->header.full);
-               pr_debug("sst: data value %x\n", msg->header.part.data);
-               pr_debug("sst: large value %x\n", msg->header.part.large);
+               pr_debug("IPC_ALG_PARAMS response %x\n", msg->header.full);
+               pr_debug("data value %x\n", msg->header.part.data);
+               pr_debug("large value %x\n", msg->header.part.large);
 
                if (!msg->header.part.large) {
                        if (!msg->header.part.data) {
-                               pr_debug("sst: alg set success\n");
+                               pr_debug("alg set success\n");
                                sst_drv_ctx->ppp_params_blk.ret_code = 0;
                        } else {
-                               pr_debug("sst: alg set failed\n");
+                               pr_debug("alg set failed\n");
                                sst_drv_ctx->ppp_params_blk.ret_code =
                                                        -msg->header.part.data;
                        }
@@ -350,20 +349,21 @@ void sst_process_reply(struct work_struct *work)
                        struct snd_ppp_params *mailbox_params, *get_params;
                        char *params;
 
-                       pr_debug("sst: alg get success\n");
+                       pr_debug("alg get success\n");
                        mailbox_params = (struct snd_ppp_params *)msg->mailbox;
                        get_params = kzalloc(sizeof(*get_params), GFP_KERNEL);
-                       if (get_params == NULL) {
-                               pr_err("sst: out of memory for ALG PARAMS");
+                       if (!get_params) {
+                               pr_debug("mem alloc failed\n");
                                break;
                        }
                        memcpy_fromio(get_params, mailbox_params,
                                                        sizeof(*get_params));
                        get_params->params = kzalloc(mailbox_params->size,
                                                        GFP_KERNEL);
-                       if (get_params->params == NULL) {
+                       if (!get_params->params) {
+                               pr_debug("mem alloc failed\n");
                                kfree(get_params);
-                               pr_err("sst: out of memory for ALG PARAMS block");
+                               pr_err("out of memory for ALG PARAMS block");
                                break;
                        }
                        params = msg->mailbox;
@@ -383,7 +383,7 @@ void sst_process_reply(struct work_struct *work)
 
        case IPC_IA_TUNING_PARAMS:
        case IPC_IA_SET_RUNTIME_PARAMS: {
-               pr_debug("sst:IPC_TUNING_PARAMS resp: %x\n", msg->header.full);
+               pr_debug("IPC_TUNING_PARAMS resp: %x\n", msg->header.full);
                pr_debug("data value %x\n", msg->header.part.data);
                if (msg->header.part.large) {
                        pr_debug("alg set failed\n");
@@ -397,6 +397,7 @@ void sst_process_reply(struct work_struct *work)
                        sst_drv_ctx->ppp_params_blk.condition = true;
                        wake_up(&sst_drv_ctx->wait_queue);
                }
+               break;
        }
 
        case IPC_IA_GET_FW_INFO: {
@@ -602,6 +603,7 @@ void sst_process_reply(struct work_struct *work)
                        wake_up(&sst_drv_ctx->wait_queue);
                }
                break;
+
        case IPC_IA_PAUSE_STREAM:
        case IPC_IA_RESUME_STREAM:
        case IPC_IA_SET_STREAM_PARAMS:
@@ -697,16 +699,15 @@ void sst_process_reply(struct work_struct *work)
                break;
        }
        case IPC_IA_SET_FW_CTXT: {
-               int retval;
+               int retval = msg->header.part.data;
 
                if (!msg->header.part.data) {
-                       pr_debug("sst: Msg IPC_IA_SET_FW_CTXT succedded %x\n",
-                                msg->header.part.msg_id);
+                       pr_debug("Msg IPC_IA_SET_FW_CTXT succedded %x\n",
+                                      msg->header.part.msg_id);
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
-                              msg->header.part.msg_id, msg->header.part.data);
+                       pr_err("Msg %x reply error %x\n",
+                       msg->header.part.msg_id, msg->header.part.data);
                }
-               retval = msg->header.part.data;
                sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
                break;
        }
similarity index 99%
rename from drivers/staging/intel_sst/intel_sst_pvt.c
rename to sound/pci/sst/intel_sst_pvt.c
index e034bea..9a0eb05 100644 (file)
@@ -35,8 +35,8 @@
 #include <linux/fs.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
-#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -310,4 +310,3 @@ int sst_enable_rx_timeslot(int status)
                                &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT);
        return retval;
 }
-
similarity index 96%
rename from drivers/staging/intel_sst/intel_sst_stream.c
rename to sound/pci/sst/intel_sst_stream.c
index 5199553..fc81861 100644 (file)
@@ -33,8 +33,8 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
-#include "intel_sst_ioctl.h"
-#include "intel_sst.h"
+#include <sound/intel_sst_ioctl.h>
+#include <sound/intel_sst.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 
@@ -203,9 +203,15 @@ int sst_alloc_stream_response(unsigned int str_id,
        str_info = &sst_drv_ctx->streams[str_id];
        if (resp->str_type.result == SST_LIB_ERR_LIB_DNLD_REQUIRED) {
                lib_dnld = kzalloc(sizeof(*lib_dnld), GFP_KERNEL);
-               memcpy(lib_dnld, &resp->lib_dnld, sizeof(*lib_dnld));
-       } else
+               if (!lib_dnld) {
+                       pr_debug("SST DBG: mem alloc failed\n");
+                       retval = -ENOMEM;
+               } else {
+                       memcpy(lib_dnld, &resp->lib_dnld, sizeof(*lib_dnld));
+               }
+       } else {
                lib_dnld = NULL;
+       }
        if (str_info->ctrl_blk.on == true) {
                str_info->ctrl_blk.on = false;
                str_info->ctrl_blk.data = lib_dnld;
@@ -213,6 +219,10 @@ int sst_alloc_stream_response(unsigned int str_id,
                str_info->ctrl_blk.ret_code = resp->str_type.result;
                pr_debug("SST DEBUG: sst_alloc_stream_response: waking up.\n");
                wake_up(&sst_drv_ctx->wait_queue);
+       } else {
+               kfree(lib_dnld);
+               pr_debug("SST DEBUG: sst_alloc_stream_response: ctrl block not on\n");
+               retval = -EIO;
        }
        return retval;
 }
@@ -311,7 +321,7 @@ int sst_pause_stream(int str_id)
                if (str_info->prev == STREAM_UN_INIT)
                        return -EBADRQC;
                if (str_info->ctrl_blk.on == true) {
-                       pr_err("SST ERR: control path is in use\n");
+                       pr_err("control path is in use\n");
                        return -EINVAL;
                }
                if (sst_create_short_msg(&msg))
@@ -339,7 +349,7 @@ int sst_pause_stream(int str_id)
                }
        } else {
                retval = -EBADRQC;
-               pr_err("SST ERR: BADQRC for stream\n");
+               pr_err("BADQRC for stream\n");
        }
 
        return retval;
@@ -474,8 +484,7 @@ int sst_drop_stream(int str_id)
                }
        } else {
                retval = -EBADRQC;
-               pr_debug("SST ERR:BADQRC for stream, state %x\n",
-                        str_info->status);
+               pr_debug("BADQRC for stream, state %x\n", str_info->status);
        }
        return retval;
 }
@@ -541,16 +550,6 @@ int sst_free_stream(int str_id)
        struct stream_info *str_info;
 
        pr_debug("SST DBG:sst_free_stream for %d\n", str_id);
-       if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
-               pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
-               pr_debug("sst: DSP Downloading FW now...\n");
-               retval = sst_download_fw();
-               if (retval) {
-                       pr_err("sst: FW download fail %x, abort\n", retval);
-                       pm_runtime_put(&sst_drv_ctx->pci->dev);
-                       return retval;
-               }
-       }
        retval = sst_validate_strid(str_id);
        if (retval)
                return retval;
@@ -36,8 +36,8 @@
 #include <linux/rar_register.h>
 #include "../memrar/memrar.h"
 #endif
-#include "intel_sst_ioctl.h"
-#include "intel_sst.h"
+#include <sound/intel_sst_ioctl.h>
+#include <sound/intel_sst.h>
 #include "intel_sst_fw_ipc.h"
 #include "intel_sst_common.h"
 /**
@@ -384,7 +384,7 @@ static int sst_send_target(struct snd_sst_target_device *target)
 static int sst_target_device_validate(struct snd_sst_target_device *target)
 {
        int retval = 0;
-       int i;
+       int i;
 
        for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) {
                if (target->devices[i].device_type == SND_SST_DEVICE_PCM) {
@@ -435,7 +435,7 @@ int sst_target_device_select(struct snd_sst_target_device *target)
 
        pr_debug("Target Device Select\n");
 
-       if (target->device_route > 2) {
+       if (target->device_route < 0 || target->device_route > 2) {
                pr_err("device route is invalid\n");
                return -EINVAL;
        }
@@ -790,7 +790,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
        struct ipc_post *msg = NULL;
        int retval = 0;
 
-       pr_debug("SST DBG:sst_set_mute:called\n");
+       pr_debug("sst_set_mute:called\n");
 
        if (str_info->decode_ibuf_type == SST_BUF_RAR) {
 #ifdef CONFIG_MRST_RAR_HANDLER
@@ -891,6 +891,7 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
        return retval;
 }
 #endif
+
 /*This function is used to prepare the kernel input buffers with contents
 before sending for decode*/
 static int sst_prepare_input_buffers(struct stream_info *str_info,
@@ -1136,7 +1137,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
 
                retval = sst_send_decode_mess(str_id, str_info, &dec_info);
                if (retval || dec_info.input_bytes_consumed == 0) {
-                       pr_err("SST ERR: mess failed or no input consumed\n");
+                       pr_err("messg failed or no input consumed\n");
                        goto finish;
                }
                input_bytes = dec_info.input_bytes_consumed;
index 8850383..626d7a3 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-
 #include <asm/intel_scu_ipc.h>
 #include <asm/intel_mid_gpadc.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
 #include <sound/jack.h>
-#include "../../../drivers/staging/intel_sst/intel_sst.h"
+#include <sound/intel_sst.h>
 #include "sn95031.h"
 
 #define SN95031_RATES (SNDRV_PCM_RATE_8000_96000)
 #define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+#define SN95031_SW_DBNC 250
 
 struct sn95031_work {
        struct delayed_work work;
        struct snd_soc_codec *codec;
 };
+
+struct sn95031_jack_work {
+       unsigned int intr_id;
+       struct delayed_work work;
+       struct snd_soc_jack *jack;
+};
+
 /* codec private data */
 struct sn95031_priv {
        uint8_t clk_src;
        enum sn95031_pll_status  pll_state;
-       struct sn95031_work oc_work;
+       struct sn95031_jack_work jack_work;
 };
-static void *audio_adc_handle;
-static unsigned int sn95031_lp_flag;
+
+void *audio_adc_handle;
+unsigned int sn95031_lp_flag;
 
 /* This Function reads the voltage level from the ADC Driver*/
 static unsigned int sn95031_read_voltage(void)
@@ -64,10 +72,10 @@ static unsigned int sn95031_read_voltage(void)
 
        /* Reads the mic bias value */
        if (!sn95031_lp_flag)
-               /* GPADC MIC BIAS takes around a 1000ms to settle down and
+               /* GPADC MIC BIAS takes around a 50ms to settle down and
                * get sampled porperly, reading earlier than this causes to
                * read incorrect values */
-               msleep(1000);
+               msleep(50);
        intel_mid_gpadc_sample(audio_adc_handle, SN95031_ADC_SAMPLE_COUNT,
                                                                &mic_bias);
        mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000;
@@ -78,16 +86,24 @@ static unsigned int sn95031_read_voltage(void)
 /* enables mic bias voltage */
 static void sn95031_enable_mic_bias(struct snd_soc_codec *codec)
 {
-       snd_soc_write(codec, SN95031_VAUD, 0x2D);
-       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2));
+       pr_debug("enable mic bias\n");
+       pr_debug("codec %p\n", codec);
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "AMIC1Bias");
+       snd_soc_dapm_sync(&codec->dapm);
 }
 
+/* disables mic bias voltage */
+static void sn95031_disable_mic_bias(struct snd_soc_codec *codec)
+{
+       pr_debug("disable mic bias\n");
+       snd_soc_dapm_disable_pin(&codec->dapm, "AMIC1Bias");
+       snd_soc_dapm_sync(&codec->dapm);
+}
 /* reads the ADC registers and gets the mic bias value in mV. */
 static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
 {
        unsigned int mic_bias;
 
-       sn95031_enable_mic_bias(codec);
        mic_bias = sn95031_read_voltage();
        return mic_bias;
 }
@@ -163,6 +179,7 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        pr_debug("vaud_bias power up rail\n");
+                       intel_sst_set_pll(true, SST_PLL_MSIC);
                        /* power up the rail, on in normal and aoac mode */
                        snd_soc_write(codec, SN95031_VAUD, 0x2D);
                        msleep(1);
@@ -181,6 +198,8 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
                 * so 100100b ie 24
                 */
                snd_soc_write(codec, SN95031_VAUD, 0x24);
+               sn95031_configure_pll(codec, DISABLE_PLL);
+               intel_sst_set_pll(false, SST_PLL_MSIC);
                break;
        }
 
@@ -193,14 +212,18 @@ static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
 {
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
-               /* power up the rail */
-               snd_soc_write(w->codec, SN95031_VHSP, 0x2D);
+               /* power up the rail- 1.8v, powersave mode */
+               snd_soc_write(w->codec, SN95031_VHSP, 0xED);
                snd_soc_write(w->codec, SN95031_VHSN, 0x2D);
                msleep(1);
        } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
                pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-               snd_soc_write(w->codec, SN95031_VHSP, 0x24);
+               /* First disable VHSN and then followed by VHSP rail.
+               Need to have minimum of 5ms delay between the rail shutdowns
+               to avoid any glitches due to transients. */
                snd_soc_write(w->codec, SN95031_VHSN, 0x24);
+               usleep_range(5000, 6000);
+               snd_soc_write(w->codec, SN95031_VHSP, 0x24);
        }
        return 0;
 }
@@ -227,7 +250,7 @@ static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
 
        pr_debug("sn95031_dmic12_event\n");
        if (SND_SOC_DAPM_EVENT_ON(event)) {
-               pr_debug("sn95031_dmic12_eventi ON\n");
+               pr_debug("sn95031_dmic12_event ON\n");
                ldo = BIT(5)|BIT(4);
                clk_dir = BIT(0);
                data_dir = BIT(7);
@@ -448,6 +471,13 @@ static const struct soc_enum sn95031_vibra1_brake_enum =
 static const struct soc_enum sn95031_vibra2_brake_enum =
        SOC_ENUM_SINGLE(SN95031_VIB2C1, 1, 2, sn95031_vibra_start_text);
 
+static const  char *sn95031_jack_debounce_text[] = {"61us", "122us", "244us",
+                                       "488us", "976us", "1.952ms",
+                                       "3.904ms", "7.8125ms", "15.625ms",
+                                       "31.25ms", "62.5ms", "125ms"};
+static const struct soc_enum sn95031_jack_debounce_enum =
+       SOC_ENUM_SINGLE(SN95031_BTNCTRL1, 4, 12, sn95031_jack_debounce_text);
+
 static const struct snd_kcontrol_new sn95031_snd_controls[] = {
        SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum),
        SOC_ENUM("Mic2Mode Capture Route", sn95031_micmode2_enum),
@@ -485,6 +515,7 @@ static const struct snd_kcontrol_new sn95031_snd_controls[] = {
        SOC_ENUM("Vibra2 Off Time", sn95031_vibra2_off_enum),
        SOC_ENUM("Vibra2 Start", sn95031_vibra2_start_enum),
        SOC_ENUM("Vibra2 Brake", sn95031_vibra2_brake_enum),
+       SOC_ENUM("Jack Debounce Time", sn95031_jack_debounce_enum),
 };
 
 /* DAPM widgets */
@@ -533,9 +564,9 @@ static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
                        SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PCM2_IN", "Headset", 0,
                        SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_AIF_IN("PCM1_IN", "Voice-Playback", 0,
+       SND_SOC_DAPM_AIF_IN("PCM1_IN", "Downlink", 0,
                        SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("PCM1_Out", "Voice-Capture", 0,
+       SND_SOC_DAPM_AIF_OUT("PCM1_Out", "Uplink", 0,
                        SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0,
                        sn95031_vhs_event,
@@ -551,9 +582,9 @@ static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
                        SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* playback path driver enables */
-       SND_SOC_DAPM_PGA("Headset Left Playback",
+       SND_SOC_DAPM_OUT_DRV("Headset Left Playback",
                        SN95031_DRIVEREN, 0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Headset Right Playback",
+       SND_SOC_DAPM_OUT_DRV("Headset Right Playback",
                        SN95031_DRIVEREN, 1, 0, NULL, 0),
        SND_SOC_DAPM_PGA("Speaker Left Playback",
                        SN95031_DRIVEREN, 2, 0, NULL, 0),
@@ -661,8 +692,6 @@ static const struct snd_soc_dapm_route sn95031_audio_map[] = {
        /* Voice Playback path*/
        { "Mode Playback Route", "Voice", "PCM1_IN"},
        /* speaker map */
-       { "IHFOUTL", NULL, "Speaker Rail"},
-       { "IHFOUTR", NULL, "Speaker Rail"},
        { "IHFOUTL", "NULL", "Speaker Left Playback"},
        { "IHFOUTR", "NULL", "Speaker Right Playback"},
        { "Speaker Left Playback", "Music", "Speaker Mux Playback Route"},
@@ -805,6 +834,7 @@ static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
 static int sn95031_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
                int source, unsigned int freq_in, unsigned int freq_out)
 {
+       int mode;
        struct snd_soc_codec *codec = codec_dai->codec;
        struct sn95031_priv *sn95031_ctx;
        sn95031_ctx = snd_soc_codec_get_drvdata(codec_dai->codec);
@@ -824,7 +854,14 @@ static int sn95031_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
                mutex_unlock(&codec->mutex);
                return 0;
        }
-       sn95031_ctx->clk_src = source;
+       mode = snd_soc_read(codec, SN95031_PCM1C3) >> 7;
+       if (!mode && (!strcmp(codec_dai->name, "SN95031 Voice"))) {
+               sn95031_ctx->clk_src = SN95031_PCM1BCLK;
+               snd_soc_write(codec, SN95031_PCM1C2, 0x04);
+       } else {
+               sn95031_ctx->clk_src = SN95031_PLLIN;
+               snd_soc_write(codec, SN95031_PCM1C2, 0x00);
+       }
        if (codec->dapm.bias_level >= SND_SOC_BIAS_PREPARE) {
                pr_debug("bias_level is active, enabling pll\n");
                sn95031_configure_pll(codec, ENABLE_PLL);
@@ -962,8 +999,6 @@ static int sn95031_voice_hw_params(struct snd_pcm_substream *substream,
        snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate);
        snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(6)|BIT(5)|BIT(4),
                                                pcm1fs);
-       /* configure the PCM1 in I2S mode */
-       snd_soc_write(dai->codec, SN95031_PCM1C2, 0x04);
        /* enable pcm 1 */
        snd_soc_update_bits(dai->codec, SN95031_PCM1C3, BIT(0), BIT(0));
        return 0;
@@ -1066,14 +1101,14 @@ static struct snd_soc_dai_driver sn95031_dais[] = {
 {
        .name = "SN95031 Voice",
        .playback = {
-               .stream_name = "Voice-Playback",
+               .stream_name = "Downlink",
                .channels_min = 1,
                .channels_max = 2,
                .rates = SN95031_RATES,
                .formats = SN95031_FORMATS,
        },
        .capture = {
-               .stream_name = "Voice-Capture",
+               .stream_name = "Uplink",
                .channels_min = 1,
                .channels_max = 2,
                .rates = SN95031_RATES,
@@ -1090,40 +1125,44 @@ static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec)
 
 static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
 {
-       snd_soc_write(codec, SN95031_BTNCTRL1, 0x77);
        snd_soc_update_bits(codec, SN95031_BTNCTRL2, BIT(0), BIT(0));
 }
 
 static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack)
 {
-       int micbias = sn95031_get_mic_bias(mfld_jack->codec);
+       int micbias, jack_type;
 
-       int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
+       sn95031_enable_mic_bias(mfld_jack->codec);
+       micbias = sn95031_get_mic_bias(mfld_jack->codec);
 
-       pr_debug("jack type detected = %d\n", jack_type);
+       jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
+
+       pr_debug("jack type detected = %d, micbias = %d\n", jack_type, micbias);
        if (jack_type == SND_JACK_HEADSET)
                sn95031_enable_jack_btn(mfld_jack->codec);
+       else
+               sn95031_disable_mic_bias(mfld_jack->codec);
+
        return jack_type;
 }
-static void sn95031_jack_report(struct mfld_jack_data *jack_data,
-               unsigned int status)
+static void sn95031_jack_report(struct snd_soc_jack *jack, unsigned int status)
 {
        unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
 
+       pr_debug("jack reported of type: %d\n", status);
        if ((status == SND_JACK_HEADSET) | (status == SND_JACK_HEADPHONE)) {
                pr_debug("detected headset or headphone, disabling JACKDET\n");
-               snd_soc_update_bits(jack_data->mfld_jack->codec,
-                                       SN95031_ACCDETMASK, BIT(2), BIT(2));
+               snd_soc_update_bits(jack->codec, SN95031_ACCDETMASK,
+                                                               BIT(2), BIT(2));
+
                /* if we detected valid headset then disable headset ground.
                 * Otherwise enable it in else condition
                 * this is required for jack detect to work well */
-               snd_soc_update_bits(jack_data->mfld_jack->codec,
-                                       SN95031_BTNCTRL2, BIT(1), 0);
+               snd_soc_update_bits(jack->codec, SN95031_BTNCTRL2, BIT(1), 0);
        } else
-               snd_soc_update_bits(jack_data->mfld_jack->codec,
+               snd_soc_update_bits(jack->codec,
                                        SN95031_BTNCTRL2, BIT(1), BIT(1));
-
-       snd_soc_jack_report(jack_data->mfld_jack, status, mask);
+       snd_soc_jack_report(jack, status, mask);
 #ifdef CONFIG_SWITCH_MID
        if (status) {
                if (status == SND_JACK_HEADPHONE)
@@ -1131,41 +1170,50 @@ static void sn95031_jack_report(struct mfld_jack_data *jack_data,
                else if (status == SND_JACK_HEADSET)
                        mid_headset_report(1);
        } else {
-                       mid_headset_report(0);
+               mid_headset_report(0);
        }
 #endif
        /*button pressed and released so we send explicit button release */
        if (status & SND_JACK_BTN_0)
-               snd_soc_jack_report(jack_data->mfld_jack,
-                               SND_JACK_HEADSET, mask);
+               snd_soc_jack_report(jack, SND_JACK_HEADSET, mask);
 }
 
-void sn95031_jack_detection(struct mfld_jack_data *jack_data)
+void sn95031_jack_wq(struct work_struct *work)
 {
-       unsigned int status, voltage;
        unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
-
-       pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id);
-       if (jack_data->intr_id & 0x1) {
-               pr_debug("short_push detected\n");
+       struct sn95031_priv *sn95031_ctx =
+               container_of(work, struct sn95031_priv, jack_work.work.work);
+       struct sn95031_jack_work *jack_wq = &sn95031_ctx->jack_work;
+       struct snd_soc_jack *jack = jack_wq->jack;
+       unsigned int voltage, status = 0;
+
+       pr_debug("jack status in wq:%d\n", jack_wq->intr_id);
+       if (jack_wq->intr_id & SN95031_JACK_INSERTED) {
+               status = sn95031_get_headset_state(jack);
+               jack_wq->intr_id &= ~SN95031_JACK_INSERTED;
+       } else if (jack_wq->intr_id & SN95031_JACK_REMOVED) {
+               pr_debug("reporting jack as removed\n");
+               sn95031_disable_jack_btn(jack->codec);
+               snd_soc_update_bits(jack->codec, SN95031_ACCDETMASK, BIT(2), 0);
+               sn95031_disable_mic_bias(jack->codec);
+               jack_wq->intr_id &= ~SN95031_JACK_REMOVED;
+       } else if (jack_wq->intr_id & SN95031_JACK_BTN0) {
                if (sn95031_lp_flag) {
-                       snd_soc_jack_report(jack_data->mfld_jack,
-                                               SND_JACK_HEADSET, mask);
+                       snd_soc_jack_report(jack, SND_JACK_HEADSET, mask);
                        sn95031_lp_flag = 0;
                        return;
-               } else
+               } else {
                        status = SND_JACK_HEADSET | SND_JACK_BTN_0;
-               sn95031_jack_report(jack_data, status);
-       }
-       if (jack_data->intr_id & 0x2) {
-               pr_debug("long_push detected\n");
+               }
+               jack_wq->intr_id &= ~SN95031_JACK_BTN0;
+       } else if (jack_wq->intr_id & SN95031_JACK_BTN1) {
                /* we get spurious intterupts if jack key is held down
                * so we ignore them untill key is released by
                * checking the voltage level */
                if (sn95031_lp_flag) {
                        voltage = sn95031_read_voltage();
                        if (voltage > 400) {
-                               snd_soc_jack_report(jack_data->mfld_jack,
+                               snd_soc_jack_report(jack,
                                                        SND_JACK_HEADSET, mask);
                                sn95031_lp_flag = 0; /* button released */
                        }
@@ -1173,102 +1221,68 @@ void sn95031_jack_detection(struct mfld_jack_data *jack_data)
                }
                status = SND_JACK_HEADSET | SND_JACK_BTN_1;
                sn95031_lp_flag = 1;
-               sn95031_jack_report(jack_data, status);
-       }
-       if (jack_data->intr_id & 0x4) {
-               pr_debug("headset or headphones inserted\n");
-               status = sn95031_get_headset_state(jack_data->mfld_jack);
-               sn95031_jack_report(jack_data, status);
-       }
-       if (jack_data->intr_id & 0x8) {
-               pr_debug("headset or headphones removed, disabling btn and enabling JACKDET\n");
-               status = 0;
-               sn95031_disable_jack_btn(jack_data->mfld_jack->codec);
-               snd_soc_update_bits(jack_data->mfld_jack->codec,
-                                               SN95031_ACCDETMASK, BIT(2), 0);
-               sn95031_jack_report(jack_data, status);
+               jack_wq->intr_id &= ~SN95031_JACK_BTN1;
        }
+       sn95031_jack_report(jack, status);
 }
-EXPORT_SYMBOL_GPL(sn95031_jack_detection);
 
-static void sn95031_ocvol_int_mask(struct snd_soc_codec *codec, int status)
+static int sn95031_schedule_jack_wq(struct mfld_jack_data *jack_data)
 {
-       snd_soc_update_bits(codec, SN95031_OCAUDIOMASK, BIT(0), status);
-
-}
-static void sn95031_restore_ihf_vol(struct snd_soc_codec *codec,
-                               unsigned int vol_addr, int crush_volume)
-{
-       u8 ihf_volume;
-
-       pr_debug("In %s\n", __func__);
-       ihf_volume = SN95031_IHF_VOLUME_MASK & snd_soc_read(codec, vol_addr);
-
-       if (!crush_volume)
-               ihf_volume -= SN95031_BCU_VOLUME_RECOVERY_3DB;
-       else
-               ihf_volume -= SN95031_BCU_VOLUME_RECOVERY_6DB;
-
-       snd_soc_update_bits(codec, vol_addr,
-                               SN95031_IHF_VOLUME_MASK, ihf_volume);
-
-       ihf_volume = snd_soc_read(codec, vol_addr);
-       pr_debug("IHF Volume: %x : %x\n", vol_addr, ihf_volume);
+       int retval = 0;
+       struct sn95031_priv *sn95031 = snd_soc_codec_get_drvdata(
+                       jack_data->mfld_jack->codec);
+
+       sn95031->jack_work.jack = jack_data->mfld_jack;
+       retval = schedule_delayed_work(&sn95031->jack_work.work,
+                       msecs_to_jiffies(SN95031_SW_DBNC));
+       return retval;
 }
 
-
-static void sn95031_oc_workqueue(struct work_struct *work)
+void sn95031_jack_detection(struct mfld_jack_data *jack_data)
 {
-       int crush_volume;
-       struct sn95031_work *oc_wq =
-               container_of(work, struct sn95031_work, work.work);
-       struct snd_soc_codec *codec = oc_wq->codec;
-
-       pr_debug("In %s\n", __func__);
-       if (!codec) {
-               pr_debug("codec value null");
-               return;
-       }
-       crush_volume =
-               SN95031_BCU_CRUSH_VOL & snd_soc_read(codec, SN95031_IHFRXCTRL);
+       int retval = 0;
+       struct sn95031_priv *sn95031 = snd_soc_codec_get_drvdata(
+                       jack_data->mfld_jack->codec);
 
-       sn95031_restore_ihf_vol(codec, SN95031_IHFLVOLCTRL, crush_volume);
-       sn95031_restore_ihf_vol(codec, SN95031_IHFRVOLCTRL, crush_volume);
-       sn95031_ocvol_int_mask(codec, false);
-
-}
+       pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id);
 
-void sn95031_oc_handler(struct snd_soc_codec *codec, int oc_interrupt_value)
-{
-       int value;
-       struct sn95031_priv *sn95031_ctx;
+       if (jack_data->intr_id & SN95031_JACK_INSERTED ||
+                               jack_data->intr_id & SN95031_JACK_REMOVED) {
 
-       pr_debug("In %s\n", __func__);
-       if (!codec) {
-               pr_debug("codec value null\n");
+               retval = sn95031_schedule_jack_wq(jack_data);
+               if (!retval) {
+                       pr_debug("jack inserted/removed, intr already queued \n");
+                       sn95031->jack_work.intr_id = jack_data->intr_id;
+               } else {
+                       sn95031->jack_work.intr_id |= jack_data->intr_id;
+               }
                return;
        }
-       sn95031_ocvol_int_mask(codec, true);
-       if (oc_interrupt_value & 0x01) {
-               sn95031_ctx = snd_soc_codec_get_drvdata(codec);
-
-               value = snd_soc_read(codec, SN95031_BURST_CNTRL);
-               if (value & BIT(5))
-                       pr_debug("TXPACTEN set to'1'<5 percent BCU setting\n");
 
-               schedule_delayed_work(&sn95031_ctx->oc_work.work,
-                                       msecs_to_jiffies(SN95031_BCU_DELAY));
-       } else {
-               pr_debug("unhandled interrupt: %x..\n", oc_interrupt_value);
-               sn95031_ocvol_int_mask(codec, false);
+       if (jack_data->intr_id & SN95031_JACK_BTN0 ||
+                               jack_data->intr_id & SN95031_JACK_BTN1) {
+               if (jack_data->mfld_jack->status == SND_JACK_HEADSET) {
+                       retval = sn95031_schedule_jack_wq(jack_data);
+                       if (!retval) {
+                               pr_debug("spurious button press detected\n");
+                               sn95031->jack_work.intr_id = jack_data->intr_id;
+                               return;
+                       } else {
+                               sn95031->jack_work.intr_id |= jack_data->intr_id;
+                       }
+                       pr_debug("BTN_Press detected\n");
+               } else {
+                       pr_debug("BTN_press received, but jack is removed\n");
+               }
        }
 }
-EXPORT_SYMBOL_GPL(sn95031_oc_handler);
+EXPORT_SYMBOL_GPL(sn95031_jack_detection);
 
 /* codec registration */
 static int sn95031_codec_probe(struct snd_soc_codec *codec)
 {
        struct sn95031_priv *sn95031_ctx;
+
        pr_debug("codec_probe called\n");
 
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
@@ -1282,8 +1296,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
        sn95031_ctx->clk_src = SN95031_INVALID;
        sn95031_ctx->pll_state = PLL_DISABLED;
 
-       INIT_DELAYED_WORK(&sn95031_ctx->oc_work.work, sn95031_oc_workqueue);
-       sn95031_ctx->oc_work.codec = codec;
+       INIT_DELAYED_WORK(&sn95031_ctx->jack_work.work, sn95031_jack_wq);
 
        /* PCM1 slot configurations*/
        snd_soc_write(codec, SN95031_NOISEMUX, 0x0);
@@ -1328,6 +1341,8 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
        snd_soc_write(codec, SN95031_AUDIOMUX34, 0x32);
        /* voice related stuff */
        snd_soc_write(codec, SN95031_VOICETXVOL, 0x89);
+       /* debounce time and long press duration */
+       snd_soc_write(codec, SN95031_BTNCTRL1, 0xA7);
 
        /* soft mute ramp time */
        snd_soc_write(codec, SN95031_SOFTMUTE, 0x3);
@@ -1350,6 +1365,13 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
        snd_soc_write(codec, SN95031_VHSN, 0x24);
        snd_soc_write(codec, SN95031_VHSP, 0x24);
 
+       /* mask the OCVOLSTSMASK bit, so that driver will not receive
+        * any overcurrent interrupt. Overcurent scenario will be
+        * handled from the application space through alsa_amixer
+        * volume control.
+        */
+       snd_soc_update_bits(codec, SN95031_OCAUDIOMASK, BIT(0), BIT(0));
+
        snd_soc_add_controls(codec, sn95031_snd_controls,
                             ARRAY_SIZE(sn95031_snd_controls));
 
@@ -1377,12 +1399,12 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec)
 
        /*Free the adc handle*/
        intel_mid_gpadc_free(audio_adc_handle);
-
+       cancel_delayed_work(&sn95031_ctx->jack_work.work);
        kfree(sn95031_ctx);
+
        return 0;
 }
-
-static struct snd_soc_codec_driver sn95031_codec = {
+struct snd_soc_codec_driver sn95031_codec = {
        .probe          = sn95031_codec_probe,
        .remove         = sn95031_codec_remove,
        .read           = sn95031_read,
index e474358..3e08147 100644 (file)
 #define SN95031_SSR5                   0x384
 #define SN95031_SSR6                   0x385
 
+#define SN95031_JACK_INSERTED          0x04
+#define SN95031_JACK_REMOVED           0x08
+#define SN95031_JACK_BTN1              0x02
+#define SN95031_JACK_BTN0              0x01
+
 /* ADC registers */
 
 #define SN95031_ADC1CNTL1 0x1C0
index a3ecc99..c9071a8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/async.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -64,6 +65,18 @@ struct mfld_mc_private {
 
 static struct snd_soc_jack mfld_jack;
 
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin mfld_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "AMIC1",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 /* jack detection voltage zones */
 static struct snd_soc_jack_zone mfld_zones[] = {
        {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
@@ -81,6 +94,12 @@ static const struct soc_enum headset_enum =
 static const struct soc_enum lo_enum =
        SOC_ENUM_SINGLE_EXT(4, lo_text);
 
+static const char *sn95031_pcm1_mode_text[] = {"Slave", "Master"};
+
+static const struct soc_enum SN95031_pcm1_mode_config_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sn95031_pcm1_mode_text),
+                                                       sn95031_pcm1_mode_text);
+
 static int headset_get_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -180,12 +199,48 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
        lo_dac = ucontrol->value.integer.value[0];
        return 0;
 }
+static int sn95031_get_pcm1_mode(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       int mode;
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+       mode = snd_soc_read(codec, SN95031_PCM1C3) >> 7;
+       pr_debug("mode: %d\n", mode);
+       ucontrol->value.integer.value[0] = mode;
+       return 0;
+}
+static int sn95031_set_pcm1_mode(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       u8 mode = ucontrol->value.integer.value[0];
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+       if (mode) {
+               pr_debug("can we set the master mode settings\n");
+               snd_soc_update_bits(codec, SN95031_PCM1C3,
+                               BIT(1)|BIT(2)|BIT(3)|BIT(7), BIT(7)|BIT(1));
+               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1),
+                                                               BIT(0)|BIT(1));
+               snd_soc_update_bits(codec, SN95031_PCM1C2,
+                                               BIT(0)|BIT(1)|BIT(2), 0);
+       } else {
+               pr_debug("setting the slave mode settings\n");
+               snd_soc_update_bits(codec, SN95031_PCM1C3, BIT(7), 0);
+               snd_soc_update_bits(codec, SN95031_PCM1C1, BIT(0)|BIT(1), 0);
+               snd_soc_update_bits(codec, SN95031_PCM1C2, BIT(2), BIT(2));
+
+       }
+       return 0;
+}
 
 static const struct snd_kcontrol_new mfld_snd_controls[] = {
        SOC_ENUM_EXT("Playback Switch", headset_enum,
                        headset_get_switch, headset_set_switch),
        SOC_ENUM_EXT("Lineout Mux", lo_enum,
                        lo_get_switch, lo_set_switch),
+       SOC_ENUM_EXT("PCM1 Mode", SN95031_pcm1_mode_config_enum,
+                       sn95031_get_pcm1_mode, sn95031_set_pcm1_mode),
 };
 
 static const struct snd_soc_dapm_widget mfld_widgets[] = {
@@ -210,6 +265,14 @@ static void mfld_jack_check(unsigned int intr_status)
        /* TODO: add american headset detection post gpiolib support */
 }
 
+static unsigned int async_param;
+static LIST_HEAD(mfld_jack_async_list);
+static void mfld_jack_check_async(void *ptr, async_cookie_t cookie)
+{
+       mfld_jack_check(*(unsigned int *)ptr);
+       return;
+}
+
 static int mfld_init(struct snd_soc_pcm_runtime *runtime)
 {
        struct snd_soc_codec *codec = runtime->codec;
@@ -248,15 +311,19 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        snd_soc_dapm_disable_pin(dapm, "DMIC6");
        snd_soc_dapm_disable_pin(dapm, "AMIC2");
 
+       /* Keep the voice call paths active during
+       suspend. Mark the end points ignore_suspend */
        snd_soc_dapm_ignore_suspend(dapm, "PCM1_IN");
        snd_soc_dapm_ignore_suspend(dapm, "PCM1_Out");
-       snd_soc_dapm_ignore_suspend(dapm, "PCM2_IN");
-       snd_soc_dapm_ignore_suspend(dapm, "PCM2_Out");
-       snd_soc_dapm_ignore_suspend(dapm, "IHFDAC Right");
-       snd_soc_dapm_ignore_suspend(dapm, "IHFDAC Left");
-       snd_soc_dapm_ignore_suspend(dapm, "HSDAC Right");
-       snd_soc_dapm_ignore_suspend(dapm, "HSDAC Left");
-
+       snd_soc_dapm_ignore_suspend(dapm, "EPOUT");
+       snd_soc_dapm_ignore_suspend(dapm, "HPOUTL");
+       snd_soc_dapm_ignore_suspend(dapm, "HPOUTR");
+       snd_soc_dapm_ignore_suspend(dapm, "IHFOUTL");
+       snd_soc_dapm_ignore_suspend(dapm, "IHFOUTR");
+       snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+       snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+       snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
+       snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
        snd_soc_dapm_sync(dapm);
        /* Headset and button jack detection */
        ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
@@ -277,7 +344,9 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        /* we want to check if anything is inserted at boot,
         * so send a fake event to codec and it will read adc
         * to find if anything is there or not */
-       mfld_jack_check(MFLD_JACK_INSERT);
+       async_param = MFLD_JACK_INSERT;
+       async_schedule_domain(mfld_jack_check_async,
+                       &async_param, &mfld_jack_async_list);
        return ret_val;
 }
 
@@ -336,6 +405,7 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .platform_name = "sst-platform",
                .init = NULL,
                .ignore_suspend = 1,
+               .ignore_pmdown_time = 1,
        },
 };
 
@@ -395,7 +465,7 @@ static irqreturn_t snd_mfld_codec_intr_detection(int irq, void *data)
 {
        struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
        unsigned long flags;
-       u8 oc_int_value = 0, jack_int_value = 0;
+       u8 jack_int_value = 0;
 
        if (mfld_jack.codec == NULL) {
                pr_debug("codec NULL returning..");
@@ -413,7 +483,7 @@ static irqreturn_t snd_mfld_codec_intr_detection(int irq, void *data)
                goto ret;
        }
        if (mc_drv_ctx->oc_interrupt_status) {
-               oc_int_value = mc_drv_ctx->oc_interrupt_status;
+               pr_info("OC int value: %d\n", mc_drv_ctx->oc_interrupt_status);
                mc_drv_ctx->oc_interrupt_status = 0;
        }
        if (mc_drv_ctx->jack_interrupt_status) {
@@ -422,10 +492,6 @@ static irqreturn_t snd_mfld_codec_intr_detection(int irq, void *data)
        }
        spin_unlock_irqrestore(&mc_drv_ctx->lock, flags);
 
-       if (oc_int_value) {
-               mc_drv_ctx->codec = mfld_jack.codec;
-               sn95031_oc_handler(mc_drv_ctx->codec, oc_int_value);
-       }
        if (jack_int_value)
                mfld_jack_check(jack_int_value);
 
@@ -470,7 +536,8 @@ static int __devinit snd_mfld_mc_probe(struct platform_device *pdev)
        /* register for interrupt */
        ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler,
                        snd_mfld_codec_intr_detection,
-                       IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
+                       IRQF_SHARED | IRQF_NO_SUSPEND,
+                       pdev->dev.driver->name, mc_drv_ctx);
        if (ret_val) {
                pr_err("cannot register IRQ\n");
                goto unalloc;
@@ -483,8 +550,8 @@ static int __devinit snd_mfld_mc_probe(struct platform_device *pdev)
                pr_debug("snd_soc_register_card failed %d\n", ret_val);
                goto freeirq;
        }
-       platform_set_drvdata(pdev, mc_drv_ctx);
-       dev_set_drvdata(&pdev->dev, &snd_soc_card_mfld);
+       platform_set_drvdata(pdev, &snd_soc_card_mfld);
+       snd_soc_card_set_drvdata(&snd_soc_card_mfld, mc_drv_ctx);
        pr_debug("successfully exited probe\n");
        return ret_val;
 
@@ -497,11 +564,13 @@ unalloc:
 
 static int __devexit snd_mfld_mc_remove(struct platform_device *pdev)
 {
-       struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev);
+       struct snd_soc_card *soc_card = platform_get_drvdata(pdev);
+       struct mfld_mc_private *mc_drv_ctx = snd_soc_card_get_drvdata(soc_card);
        pr_debug("snd_mfld_mc_remove called\n");
        free_irq(platform_get_irq(pdev, 0), mc_drv_ctx);
-       snd_soc_unregister_card(&snd_soc_card_mfld);
        kfree(mc_drv_ctx);
+       snd_soc_card_set_drvdata(soc_card, NULL);
+       snd_soc_unregister_card(soc_card);
        platform_set_drvdata(pdev, NULL);
        return 0;
 }
@@ -526,11 +595,12 @@ static int __init snd_mfld_driver_init(void)
        pr_debug("snd_mfld_driver_init called\n");
        return platform_driver_register(&snd_mfld_mc_driver);
 }
-module_init(snd_mfld_driver_init);
+module_init_async(snd_mfld_driver_init);
 
 static void __exit snd_mfld_driver_exit(void)
 {
        pr_debug("snd_mfld_driver_exit called\n");
+       async_synchronize_full_domain(&mfld_jack_async_list);
        platform_driver_unregister(&snd_mfld_mc_driver);
 }
 module_exit(snd_mfld_driver_exit);
index 93b7862..32dcf4a 100644 (file)
@@ -31,8 +31,8 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h"
-#include "../../../drivers/staging/intel_sst/intel_sst.h"
+#include <sound/intel_sst_ioctl.h>
+#include <sound/intel_sst.h>
 #include "../codecs/sn95031.h"
 #include "sst_platform.h"
 
@@ -79,7 +79,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
        },
        .capture = {
                .channels_min = 1,
-               .channels_max = 5,
+               .channels_max = 2,
                .rates = SNDRV_PCM_RATE_44100,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
@@ -106,7 +106,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
        .name = "Vibra2-cpu-dai",
        .playback = {
                .channels_min = SST_MONO,
-               .channels_max = SST_STEREO,
+               .channels_max = SST_MONO,
                .rates = SNDRV_PCM_RATE_44100,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
@@ -209,14 +209,20 @@ static void sst_period_elapsed(void *mad_substream)
        struct sst_runtime_stream *stream;
        int status;
 
-       if (!substream || !substream->runtime)
+       if (!substream || !substream->runtime) {
+               pr_debug("In %s : Null Substream pointer\n", __func__);
                return;
+       }
        stream = substream->runtime->private_data;
-       if (!stream)
+       if (!stream) {
+               pr_debug("In %s : Null Stream pointer\n", __func__);
                return;
+       }
        status = sst_get_stream_status(stream);
-       if (status != SST_PLATFORM_RUNNING)
+       if (status != SST_PLATFORM_RUNNING) {
+               pr_debug("In %s : Stream Status=%d\n", __func__, status);
                return;
+       }
        snd_pcm_period_elapsed(substream);
 }
 
@@ -298,6 +304,11 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
        }
        runtime->private_data = stream;
        sst_cpu_ctx->active_nonvoice_cnt++;
+
+       /* Make sure, that the period size is always even */
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                          SNDRV_PCM_HW_PARAM_PERIODS, 2);
+
        return snd_pcm_hw_constraint_integer(runtime,
                         SNDRV_PCM_HW_PARAM_PERIODS);
 
@@ -342,16 +353,13 @@ static int sst_platform_close(struct snd_pcm_substream *substream)
 func_exit:
        if (!sst_cpu_ctx->active_nonvoice_cnt)
                snd_soc_dai_set_tristate(codec_dai, 1);
-       /*if all CPU dais are inactive, disable PLL*/
-       if (!sst_cpu_ctx->active_voice_cnt && !sst_cpu_ctx->active_nonvoice_cnt)
-               snd_soc_dai_set_pll(codec_dai, 0, 0, 0, 0);
        return ret_val;
 }
 
 static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct sst_runtime_stream *stream;
-       int ret_val = 0;
+       int ret_val = 0, str_id;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai_link *dai_link = rtd->dai_link;
 
@@ -362,6 +370,7 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
                return ret_val;
        }
        stream = substream->runtime->private_data;
+       str_id = stream->stream_info.str_id;
        if (stream->stream_info.str_id)
                return ret_val;
 
@@ -472,26 +481,21 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
 static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params)
 {
-       int ret, clk_src;
+       int ret;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dai_link *dai_link = rtd->dai_link;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
-       if (!strcmp(dai_link->cpu_dai_name, SST_VOICE_DAI))
-               clk_src = SN95031_PCM1BCLK;
-       else {
-               clk_src = SN95031_PLLIN;
-               /* Force the data width to 24 bit in MSIC. Post Processing
-               algorithms in DSP enabled with 24 bit precision */
-               ret = snd_soc_codec_set_params(codec, SNDRV_PCM_FORMAT_S24_LE);
-               if (ret < 0) {
-                       pr_debug("codec set_params returned error\n");
-                       return ret;
-               }
+       /* Force the data width to 24 bit in MSIC. Post Processing
+       algorithms in DSP enabled with 24 bit precision */
+       ret = snd_soc_codec_set_params(codec, SNDRV_PCM_FORMAT_S24_LE);
+       if (ret < 0) {
+               pr_debug("codec set_params returned error\n");
+               return ret;
        }
        /*last two parameters have to non-zero, otherwise pll gets disabled*/
-       snd_soc_dai_set_pll(codec_dai, 0, clk_src, 1, params_rate(params));
+       snd_soc_dai_set_pll(codec_dai, 0, SST_CLK_UNINIT, 1,
+                                                       params_rate(params));
        snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
        memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
 
@@ -532,7 +536,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
                retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
                        SNDRV_DMA_TYPE_CONTINUOUS,
                        snd_dma_continuous_data(GFP_KERNEL),
-                       SST_MIN_BUFFER, SST_MAX_BUFFER);
+                       SST_MAX_BUFFER, SST_MAX_BUFFER);
                if (retval) {
                        pr_err("dma buffer allocationf fail\n");
                        return retval;
index 627cf12..1bb8901 100644 (file)
 #define SST_MAX_RATE           48000
 #define SST_MIN_CHANNEL                1
 #define SST_MAX_CHANNEL                2
-#define SST_MAX_BUFFER         22050 /*500ms*/
-#define SST_MIN_BUFFER         22050
-#define SST_MIN_PERIOD_BYTES   441   /*10ms */
-#define SST_MAX_PERIOD_BYTES   ((SST_MAX_BUFFER) / (SST_MIN_PERIODS))
+#define SST_MAX_BUFFER         88200 /*500ms*/
+#define SST_MIN_PERIOD_BYTES   1764  /*10ms@44.1,16bit,2ch*/
+#define SST_MAX_PERIOD_BYTES   44100 /*250ms*/
 #define SST_MIN_PERIODS                2
 #define SST_MAX_PERIODS                50
 #define SST_FIFO_SIZE          0
 #define SST_CARD_NAMES         "intel_mid_card"
 #define MSIC_VENDOR_ID         3
+#define SST_CLK_UNINIT         0x03
 
 struct sst_runtime_stream {
        int     stream_status;
index e59850c..92aaa20 100644 (file)
@@ -762,10 +762,17 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        cpu_dai->runtime = NULL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* start delayed pop wq here for playback streams */
-               codec_dai->pop_wait = 1;
-               schedule_delayed_work(&rtd->delayed_work,
-                       msecs_to_jiffies(rtd->pmdown_time));
+               if (unlikely(rtd->dai_link->ignore_pmdown_time)) {
+                       /* powered down playback stream now */
+                       snd_soc_dapm_stream_event(rtd,
+                               codec_dai->driver->playback.stream_name,
+                               SND_SOC_DAPM_STREAM_STOP);
+               } else {
+                       /* start delayed pop wq here for playback streams */
+                       codec_dai->pop_wait = 1;
+                       schedule_delayed_work(&rtd->delayed_work,
+                               msecs_to_jiffies(rtd->pmdown_time));
+               }
        } else {
                /* capture streams can be powered down now */
                snd_soc_dapm_stream_event(rtd,