From 8818fdb3e7d193fdd2d99c06bee71768a5caa3f1 Mon Sep 17 00:00:00 2001 From: Ramesh Babu K V Date: Mon, 24 Oct 2011 15:16:29 +0530 Subject: [PATCH] audio: port the non upstreamed changes 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 Reviewed-on: http://android.intel.com:8080/25532 Reviewed-by: Suet, NicolasX Reviewed-by: Seibel, Eric Tested-by: Seibel, Eric Reviewed-by: buildbot Tested-by: buildbot --- drivers/dma/intel_mid_dma.c | 222 ++++++++------- drivers/dma/intel_mid_dma_regs.h | 5 +- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/intel_sst/Kconfig | 7 - drivers/staging/intel_sst/Makefile | 5 - drivers/staging/intel_sst/TODO | 13 - .../intel_sst => include/sound}/intel_sst.h | 8 +- .../intel_sst => include/sound}/intel_sst_ioctl.h | 2 +- include/sound/soc.h | 3 + sound/pci/Kconfig | 8 + sound/pci/Makefile | 1 + sound/pci/sst/Makefile | 5 + .../intel_sst => sound/pci/sst}/intel_sst.c | 56 ++-- .../pci/sst}/intel_sst_app_interface.c | 21 +- .../intel_sst => sound/pci/sst}/intel_sst_common.h | 52 +++- .../pci/sst}/intel_sst_drv_interface.c | 141 +++++----- .../intel_sst => sound/pci/sst}/intel_sst_dsp.c | 310 ++++++++++++++++++--- .../intel_sst => sound/pci/sst}/intel_sst_fw_ipc.h | 0 .../intel_sst => sound/pci/sst}/intel_sst_ipc.c | 49 ++-- .../intel_sst => sound/pci/sst}/intel_sst_pvt.c | 5 +- .../intel_sst => sound/pci/sst}/intel_sst_stream.c | 35 ++- .../pci/sst}/intel_sst_stream_encoded.c | 13 +- sound/soc/codecs/sn95031.c | 294 ++++++++++--------- sound/soc/codecs/sn95031.h | 5 + sound/soc/mid-x86/mfld_machine.c | 110 ++++++-- sound/soc/mid-x86/sst_platform.c | 56 ++-- sound/soc/mid-x86/sst_platform.h | 8 +- sound/soc/soc-core.c | 15 +- 29 files changed, 940 insertions(+), 512 deletions(-) delete mode 100644 drivers/staging/intel_sst/Kconfig delete mode 100644 drivers/staging/intel_sst/Makefile delete mode 100644 drivers/staging/intel_sst/TODO rename {drivers/staging/intel_sst => include/sound}/intel_sst.h (97%) rename {drivers/staging/intel_sst => include/sound}/intel_sst_ioctl.h (99%) create mode 100644 sound/pci/sst/Makefile rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst.c (94%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_app_interface.c (98%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_common.h (94%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_drv_interface.c (86%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_dsp.c (62%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_fw_ipc.h (100%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_ipc.c (95%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_pvt.c (99%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_stream.c (96%) rename {drivers/staging/intel_sst => sound/pci/sst}/intel_sst_stream_encoded.c (99%) diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 0ddc40b..8a0fc17 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -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 = { diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h index 22acc64..02db4bd 100644 --- a/drivers/dma/intel_mid_dma_regs.h +++ b/drivers/dma/intel_mid_dma_regs.h @@ -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__*/ diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 24ff5d6..4141282 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -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" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index e420855..b55d2a9 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -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 index 0df320f..0000000 --- a/drivers/staging/intel_sst/Kconfig +++ /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 index 275809c..0000000 --- a/drivers/staging/intel_sst/Makefile +++ /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 index c733d70..0000000 --- a/drivers/staging/intel_sst/TODO +++ /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 - - diff --git a/drivers/staging/intel_sst/intel_sst.h b/include/sound/intel_sst.h similarity index 97% rename from drivers/staging/intel_sst/intel_sst.h rename to include/sound/intel_sst.h index 9a189f8..72e0066 100644 --- a/drivers/staging/intel_sst/intel_sst.h +++ b/include/sound/intel_sst.h @@ -29,7 +29,7 @@ * and middleware. * This file is shared between the SST and MAD drivers */ -#include "intel_sst_ioctl.h" +#include #include #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); diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/include/sound/intel_sst_ioctl.h 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 --- a/drivers/staging/intel_sst/intel_sst_ioctl.h +++ b/include/sound/intel_sst_ioctl.h @@ -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 *) diff --git a/include/sound/soc.h b/include/sound/soc.h index a55a7c3..861c9c5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -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); diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e90d103..9900bd9 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -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 diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 54fe325..4687a65 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -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 index 0000000..94b15ef --- /dev/null +++ b/sound/pci/sst/Makefile @@ -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 diff --git a/drivers/staging/intel_sst/intel_sst.c b/sound/pci/sst/intel_sst.c similarity index 94% rename from drivers/staging/intel_sst/intel_sst.c rename to sound/pci/sst/intel_sst.c index 3936906..7792c78 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/sound/pci/sst/intel_sst.c @@ -37,10 +37,11 @@ #include #include #include +#include #include #include -#include "intel_sst.h" -#include "intel_sst_ioctl.h" +#include +#include #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); diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/sound/pci/sst/intel_sst_app_interface.c similarity index 98% rename from drivers/staging/intel_sst/intel_sst_app_interface.c rename to sound/pci/sst/intel_sst_app_interface.c index 35f788a..3ab69a3 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/sound/pci/sst/intel_sst_app_interface.c @@ -41,8 +41,8 @@ #include #include "../../../drivers/staging/memrar/memrar.h" #endif -#include "intel_sst.h" -#include "intel_sst_ioctl.h" +#include +#include #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(¶ms, (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), ¶ms, 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; } diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h 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 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ b/sound/pci/sst/intel_sst_common.h @@ -28,6 +28,9 @@ * Common private declarations for SST */ +#include +#include + #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__ */ diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/sound/pci/sst/intel_sst_drv_interface.c similarity index 86% rename from drivers/staging/intel_sst/intel_sst_drv_interface.c rename to sound/pci/sst/intel_sst_drv_interface.c index ff6288c..8854060 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/sound/pci/sst/intel_sst_drv_interface.c @@ -33,8 +33,8 @@ #include #include #include -#include "intel_sst.h" -#include "intel_sst_ioctl.h" +#include +#include #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; diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/sound/pci/sst/intel_sst_dsp.c 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 --- a/drivers/staging/intel_sst/intel_sst_dsp.c +++ b/sound/pci/sst/intel_sst_dsp.c @@ -33,10 +33,13 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include -#include "intel_sst.h" -#include "intel_sst_ioctl.h" +#include +#include +#include +#include #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 diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/sound/pci/sst/intel_sst_fw_ipc.h similarity index 100% rename from drivers/staging/intel_sst/intel_sst_fw_ipc.h rename to sound/pci/sst/intel_sst_fw_ipc.h diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/sound/pci/sst/intel_sst_ipc.c 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 --- a/drivers/staging/intel_sst/intel_sst_ipc.c +++ b/sound/pci/sst/intel_sst_ipc.c @@ -31,8 +31,8 @@ #include #include #include -#include "intel_sst.h" -#include "intel_sst_ioctl.h" +#include +#include #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; } diff --git a/drivers/staging/intel_sst/intel_sst_pvt.c b/sound/pci/sst/intel_sst_pvt.c 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 --- a/drivers/staging/intel_sst/intel_sst_pvt.c +++ b/sound/pci/sst/intel_sst_pvt.c @@ -35,8 +35,8 @@ #include #include #include -#include "intel_sst.h" -#include "intel_sst_ioctl.h" +#include +#include #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; } - diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/sound/pci/sst/intel_sst_stream.c 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 --- a/drivers/staging/intel_sst/intel_sst_stream.c +++ b/sound/pci/sst/intel_sst_stream.c @@ -33,8 +33,8 @@ #include #include #include -#include "intel_sst_ioctl.h" -#include "intel_sst.h" +#include +#include #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; diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/sound/pci/sst/intel_sst_stream_encoded.c similarity index 99% rename from drivers/staging/intel_sst/intel_sst_stream_encoded.c rename to sound/pci/sst/intel_sst_stream_encoded.c index 612c535..884a58a 100644 --- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c +++ b/sound/pci/sst/intel_sst_stream_encoded.c @@ -36,8 +36,8 @@ #include #include "../memrar/memrar.h" #endif -#include "intel_sst_ioctl.h" -#include "intel_sst.h" +#include +#include #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; diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 8850383..626d7a3 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -28,7 +28,6 @@ #include #include #include - #include #include #include @@ -38,24 +37,33 @@ #include #include #include -#include "../../../drivers/staging/intel_sst/intel_sst.h" +#include #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, diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h index e474358..3e08147 100644 --- a/sound/soc/codecs/sn95031.h +++ b/sound/soc/codecs/sn95031.h @@ -102,6 +102,11 @@ #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 diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index a3ecc99..c9071a8 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index 93b7862..32dcf4a 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -31,8 +31,8 @@ #include #include #include -#include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h" -#include "../../../drivers/staging/intel_sst/intel_sst.h" +#include +#include #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; diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h index 627cf12..1bb8901 100644 --- a/sound/soc/mid-x86/sst_platform.h +++ b/sound/soc/mid-x86/sst_platform.h @@ -35,15 +35,15 @@ #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; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e59850c..92aaa20 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -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, -- 2.7.4