提交 03cf1526 编写于 作者: G Greg Kroah-Hartman

staging: remove intel_sst driver

Intel has asked that this driver now be removed from the tree, and I am
happy to oblige.

Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 4588d6d4
......@@ -116,8 +116,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"
......
......@@ -50,7 +50,6 @@ obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/
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_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
......
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_INTELMID
tristate "Intel MID sound card driver"
depends on SOUND && SND
select SND_PCM
select SND_SEQUENCER
select SND_JACK
depends on SND_INTEL_SST
default n
help
Say Y here to include support for the Intel(R) MID sound card driver
On other PC platforms if you are unsure answer 'N'
#
# 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
snd-intelmid-y := intelmid.o intelmid_msic_control.o intelmid_ctrl.o intelmid_pvt.o intelmid_v0_control.o intelmid_v1_control.o intelmid_v2_control.o
obj-$(CONFIG_SND_INTEL_SST) += snd-intel-sst.o
obj-$(CONFIG_SND_INTELMID) += snd-intelmid.o
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
/*
* intel_sst.c - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corp
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This driver exposes the audio engine functionalities to the ALSA
* and middleware.
*
* This file contains all init functions
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/miscdevice.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
#include <asm/mrst.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intel_sst_fw_ipc.h"
#include "intel_sst_common.h"
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver");
MODULE_LICENSE("GPL v2");
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 = {
.owner = THIS_MODULE,
.open = intel_sst_open,
.release = intel_sst_release,
.read = intel_sst_read,
.write = intel_sst_write,
.unlocked_ioctl = intel_sst_ioctl,
.mmap = intel_sst_mmap,
.aio_read = intel_sst_aio_read,
.aio_write = intel_sst_aio_write,
};
static const struct file_operations intel_sst_fops_cntrl = {
.owner = THIS_MODULE,
.open = intel_sst_open_cntrl,
.release = intel_sst_release_cntrl,
.unlocked_ioctl = intel_sst_ioctl,
};
static struct miscdevice lpe_dev = {
.minor = MISC_DYNAMIC_MINOR,/* dynamic allocation */
.name = "intel_sst",/* /dev/intel_sst */
.fops = &intel_sst_fops
};
static struct miscdevice lpe_ctrl = {
.minor = MISC_DYNAMIC_MINOR,/* dynamic allocation */
.name = "intel_sst_ctrl",/* /dev/intel_sst_ctrl */
.fops = &intel_sst_fops_cntrl
};
/**
* intel_sst_interrupt - Interrupt service routine for SST
*
* @irq: irq number of interrupt
* @context: pointer to device structre
*
* This function is called by OS when SST device raises
* an interrupt. This will be result of write in IPC register
* Source can be busy or done interrupt
*/
static irqreturn_t intel_sst_interrupt(int irq, void *context)
{
union interrupt_reg isr;
union ipc_header header;
union interrupt_reg imr;
struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
unsigned int size = 0, str_id;
struct stream_info *stream ;
/* 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);
if (isr.part.busy_interrupt) {
header.full = sst_shim_read(drv->shim, SST_IPCD);
if (header.part.msg_id == IPC_SST_PERIOD_ELAPSED) {
sst_clear_interrupt();
str_id = header.part.str_id;
stream = &sst_drv_ctx->streams[str_id];
if (stream->period_elapsed)
stream->period_elapsed(stream->pcm_substream);
return IRQ_HANDLED;
}
if (header.part.large)
size = header.part.data;
if (header.part.msg_id & REPLY_MSG) {
sst_drv_ctx->ipc_process_msg.header = header;
memcpy_fromio(sst_drv_ctx->ipc_process_msg.mailbox,
drv->mailbox + SST_MAILBOX_RCV, size);
queue_work(sst_drv_ctx->process_msg_wq,
&sst_drv_ctx->ipc_process_msg.wq);
} else {
sst_drv_ctx->ipc_process_reply.header = header;
memcpy_fromio(sst_drv_ctx->ipc_process_reply.mailbox,
drv->mailbox + SST_MAILBOX_RCV, size);
queue_work(sst_drv_ctx->process_reply_wq,
&sst_drv_ctx->ipc_process_reply.wq);
}
/* mask busy inetrrupt */
imr.full = sst_shim_read(drv->shim, SST_IMRX);
imr.part.busy_interrupt = 1;
sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
return IRQ_HANDLED;
} else if (isr.part.done_interrupt) {
/* Clear done bit */
header.full = sst_shim_read(drv->shim, SST_IPCX);
header.part.done = 0;
sst_shim_write(sst_drv_ctx->shim, SST_IPCX, header.full);
/* write 1 to clear status register */;
isr.part.done_interrupt = 1;
/* dummy register for shim workaround */
sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full);
queue_work(sst_drv_ctx->post_msg_wq,
&sst_drv_ctx->ipc_post_msg.wq);
return IRQ_HANDLED;
} else
return IRQ_NONE;
}
/*
* intel_sst_probe - PCI probe function
*
* @pci: PCI device structure
* @pci_id: PCI device ID structure
*
* This function is called by OS when a device is found
* This enables the device, interrupt etc
*/
static int __devinit intel_sst_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
int i, ret = 0;
pr_debug("Probe for DID %x\n", pci->device);
mutex_lock(&drv_ctx_lock);
if (sst_drv_ctx) {
pr_err("Only one sst handle is supported\n");
mutex_unlock(&drv_ctx_lock);
return -EBUSY;
}
sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL);
if (!sst_drv_ctx) {
pr_err("malloc fail\n");
mutex_unlock(&drv_ctx_lock);
return -ENOMEM;
}
mutex_unlock(&drv_ctx_lock);
sst_drv_ctx->pci_id = pci->device;
mutex_init(&sst_drv_ctx->stream_lock);
mutex_init(&sst_drv_ctx->sst_lock);
sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
sst_drv_ctx->stream_cnt = 0;
sst_drv_ctx->encoded_cnt = 0;
sst_drv_ctx->am_cnt = 0;
sst_drv_ctx->pb_streams = 0;
sst_drv_ctx->cp_streams = 0;
sst_drv_ctx->unique_id = 0;
sst_drv_ctx->pmic_port_instance = SST_DEFAULT_PMIC_PORT;
INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_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);
INIT_WORK(&sst_drv_ctx->mad_ops.wq, sst_process_mad_ops);
init_waitqueue_head(&sst_drv_ctx->wait_queue);
sst_drv_ctx->mad_wq = create_workqueue("sst_mad_wq");
if (!sst_drv_ctx->mad_wq)
goto do_free_drv_ctx;
sst_drv_ctx->post_msg_wq = create_workqueue("sst_post_msg_wq");
if (!sst_drv_ctx->post_msg_wq)
goto free_mad_wq;
sst_drv_ctx->process_msg_wq = create_workqueue("sst_process_msg_wqq");
if (!sst_drv_ctx->process_msg_wq)
goto free_post_msg_wq;
sst_drv_ctx->process_reply_wq = create_workqueue("sst_proces_reply_wq");
if (!sst_drv_ctx->process_reply_wq)
goto free_process_msg_wq;
for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
sst_drv_ctx->alloc_block[i].ops_block.condition = false;
}
spin_lock_init(&sst_drv_ctx->list_spin_lock);
sst_drv_ctx->max_streams = pci_id->driver_data;
pr_debug("Got drv data max stream %d\n",
sst_drv_ctx->max_streams);
for (i = 1; i <= sst_drv_ctx->max_streams; i++) {
struct stream_info *stream = &sst_drv_ctx->streams[i];
INIT_LIST_HEAD(&stream->bufs);
mutex_init(&stream->lock);
spin_lock_init(&stream->pcm_lock);
}
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
sst_drv_ctx->mmap_mem = NULL;
sst_drv_ctx->mmap_len = SST_MMAP_PAGES * PAGE_SIZE;
while (sst_drv_ctx->mmap_len > 0) {
sst_drv_ctx->mmap_mem =
kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL);
if (sst_drv_ctx->mmap_mem) {
pr_debug("Got memory %p size 0x%x\n",
sst_drv_ctx->mmap_mem,
sst_drv_ctx->mmap_len);
break;
}
if (sst_drv_ctx->mmap_len < (SST_MMAP_STEP*PAGE_SIZE)) {
pr_err("mem alloc fail...abort!!\n");
ret = -ENOMEM;
goto free_process_reply_wq;
}
sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
pr_debug("mem alloc failed...trying %d\n",
sst_drv_ctx->mmap_len);
}
}
/* Init the device */
ret = pci_enable_device(pci);
if (ret) {
pr_err("device can't be enabled\n");
goto do_free_mem;
}
sst_drv_ctx->pci = pci_dev_get(pci);
ret = pci_request_regions(pci, SST_DRV_NAME);
if (ret)
goto do_disable_device;
/* map registers */
/* SST Shim */
sst_drv_ctx->shim_phy_add = pci_resource_start(pci, 1);
sst_drv_ctx->shim = pci_ioremap_bar(pci, 1);
if (!sst_drv_ctx->shim)
goto do_release_regions;
pr_debug("SST Shim Ptr %p\n", sst_drv_ctx->shim);
/* Shared SRAM */
sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2);
if (!sst_drv_ctx->mailbox)
goto do_unmap_shim;
pr_debug("SRAM Ptr %p\n", sst_drv_ctx->mailbox);
/* IRAM */
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 = pci_ioremap_bar(pci, 4);
if (!sst_drv_ctx->dram)
goto do_unmap_iram;
pr_debug("DRAM Ptr %p\n", sst_drv_ctx->dram);
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
/* Register the ISR */
ret = request_irq(pci->irq, intel_sst_interrupt,
IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx);
if (ret)
goto do_unmap_dram;
pr_debug("Registered IRQ 0x%x\n", pci->irq);
/*Register LPE Control as misc driver*/
ret = misc_register(&lpe_ctrl);
if (ret) {
pr_err("couldn't register control device\n");
goto do_free_irq;
}
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
ret = misc_register(&lpe_dev);
if (ret) {
pr_err("couldn't register LPE device\n");
goto do_free_misc;
}
} else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) {
u32 csr;
/*allocate mem for fw context save during suspend*/
sst_drv_ctx->fw_cntx = kzalloc(FW_CONTEXT_MEM, GFP_KERNEL);
if (!sst_drv_ctx->fw_cntx) {
ret = -ENOMEM;
goto do_free_misc;
}
/*setting zero as that is valid mem to restore*/
sst_drv_ctx->fw_cntx_size = 0;
/*set lpe start clock and ram size*/
csr = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr |= 0x30060; /*remove the clock ratio after fw fix*/
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr);
}
sst_drv_ctx->lpe_stalled = 0;
pci_set_drvdata(pci, sst_drv_ctx);
pm_runtime_allow(&pci->dev);
pm_runtime_put_noidle(&pci->dev);
pr_debug("...successfully done!!!\n");
return ret;
do_free_misc:
misc_deregister(&lpe_ctrl);
do_free_irq:
free_irq(pci->irq, sst_drv_ctx);
do_unmap_dram:
iounmap(sst_drv_ctx->dram);
do_unmap_iram:
iounmap(sst_drv_ctx->iram);
do_unmap_sram:
iounmap(sst_drv_ctx->mailbox);
do_unmap_shim:
iounmap(sst_drv_ctx->shim);
do_release_regions:
pci_release_regions(pci);
do_disable_device:
pci_disable_device(pci);
do_free_mem:
kfree(sst_drv_ctx->mmap_mem);
free_process_reply_wq:
destroy_workqueue(sst_drv_ctx->process_reply_wq);
free_process_msg_wq:
destroy_workqueue(sst_drv_ctx->process_msg_wq);
free_post_msg_wq:
destroy_workqueue(sst_drv_ctx->post_msg_wq);
free_mad_wq:
destroy_workqueue(sst_drv_ctx->mad_wq);
do_free_drv_ctx:
kfree(sst_drv_ctx);
sst_drv_ctx = NULL;
pr_err("Probe failed with %d\n", ret);
return ret;
}
/**
* intel_sst_remove - PCI remove function
*
* @pci: PCI device structure
*
* This function is called by OS when a device is unloaded
* This frees the interrupt etc
*/
static void __devexit intel_sst_remove(struct pci_dev *pci)
{
pm_runtime_get_noresume(&pci->dev);
pm_runtime_forbid(&pci->dev);
pci_dev_put(sst_drv_ctx->pci);
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
misc_deregister(&lpe_ctrl);
free_irq(pci->irq, sst_drv_ctx);
iounmap(sst_drv_ctx->dram);
iounmap(sst_drv_ctx->iram);
iounmap(sst_drv_ctx->mailbox);
iounmap(sst_drv_ctx->shim);
sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
misc_deregister(&lpe_dev);
kfree(sst_drv_ctx->mmap_mem);
} else
kfree(sst_drv_ctx->fw_cntx);
flush_scheduled_work();
destroy_workqueue(sst_drv_ctx->process_reply_wq);
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));
sst_drv_ctx = NULL;
pci_release_regions(pci);
pci_disable_device(pci);
pci_set_drvdata(pci, NULL);
}
void sst_save_dsp_context(void)
{
struct snd_sst_ctxt_params fw_context;
unsigned int pvt_id, i;
struct ipc_post *msg = NULL;
/*check cpu type*/
if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
return;
/*not supported for rest*/
if (sst_drv_ctx->sst_state != SST_FW_RUNNING) {
pr_debug("fw not running no context save ...\n");
return;
}
/*send msg to fw*/
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_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);
fw_context.size = FW_CONTEXT_MEM;
memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
memcpy(msg->mailbox_data + sizeof(u32),
&fw_context, sizeof(fw_context));
spin_lock(&sst_drv_ctx->list_spin_lock);
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);
/*wait for reply*/
if (sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]))
pr_debug("err fw context save timeout ...\n");
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
pr_debug("fw context saved ...\n");
return;
}
/* Power Management */
/*
* intel_sst_suspend - PCI suspend function
*
* @pci: PCI device structure
* @state: PM message
*
* This function is called by OS when a power event occurs
*/
int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
{
union config_status_reg csr;
pr_debug("intel_sst_suspend called\n");
if (sst_drv_ctx->stream_cnt) {
pr_err("active streams,not able to suspend\n");
return -EBUSY;
}
/*save fw context*/
sst_save_dsp_context();
/*Assert RESET on LPE Processor*/
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full = csr.full | 0x2;
/* Move the SST state to Suspended */
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_SUSPENDED;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
mutex_unlock(&sst_drv_ctx->sst_lock);
pci_set_drvdata(pci, sst_drv_ctx);
pci_save_state(pci);
pci_disable_device(pci);
pci_set_power_state(pci, PCI_D3hot);
return 0;
}
/**
* intel_sst_resume - PCI resume function
*
* @pci: PCI device structure
*
* This function is called by OS when a power event occurs
*/
int intel_sst_resume(struct pci_dev *pci)
{
int ret = 0;
pr_debug("intel_sst_resume called\n");
if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
pr_err("SST is not in suspended state\n");
return 0;
}
sst_drv_ctx = pci_get_drvdata(pci);
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
ret = pci_enable_device(pci);
if (ret)
pr_err("device can't be enabled\n");
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
return 0;
}
/* The runtime_suspend/resume is pretty much similar to the legacy
* suspend/resume with the noted exception below:
* The PCI core takes care of taking the system through D3hot and
* restoring it back to D0 and so there is no need to duplicate
* that here.
*/
static int intel_sst_runtime_suspend(struct device *dev)
{
union config_status_reg csr;
pr_debug("intel_sst_runtime_suspend called\n");
if (sst_drv_ctx->stream_cnt) {
pr_err("active streams,not able to suspend\n");
return -EBUSY;
}
/*save fw context*/
sst_save_dsp_context();
/*Assert RESET on LPE Processor*/
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full = csr.full | 0x2;
/* Move the SST state to Suspended */
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_SUSPENDED;
/* Only needed by Medfield */
if (sst_drv_ctx->pci_id != SST_MRST_PCI_ID)
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
mutex_unlock(&sst_drv_ctx->sst_lock);
return 0;
}
static int intel_sst_runtime_resume(struct device *dev)
{
pr_debug("intel_sst_runtime_resume called\n");
if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
pr_err("SST is not in suspended state\n");
return 0;
}
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
return 0;
}
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)
pm_schedule_suspend(dev, SST_SUSPEND_DELAY);
return -EBUSY;
}
static const struct dev_pm_ops intel_sst_pm = {
.runtime_suspend = intel_sst_runtime_suspend,
.runtime_resume = intel_sst_runtime_resume,
.runtime_idle = intel_sst_runtime_idle,
};
/* PCI Routines */
static struct pci_device_id intel_sst_ids[] = {
{ PCI_VDEVICE(INTEL, SST_MRST_PCI_ID), 3},
{ PCI_VDEVICE(INTEL, SST_MFLD_PCI_ID), 6},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, intel_sst_ids);
static struct pci_driver driver = {
.name = SST_DRV_NAME,
.id_table = intel_sst_ids,
.probe = intel_sst_probe,
.remove = __devexit_p(intel_sst_remove),
#ifdef CONFIG_PM
.suspend = intel_sst_suspend,
.resume = intel_sst_resume,
.driver = {
.pm = &intel_sst_pm,
},
#endif
};
/**
* intel_sst_init - Module init function
*
* Registers with PCI
* Registers with /dev
* Init all data strutures
*/
static int __init intel_sst_init(void)
{
/* Init all variables, data structure etc....*/
int ret = 0;
pr_debug("INFO: ******** SST DRIVER loading.. Ver: %s\n",
SST_DRIVER_VERSION);
mutex_init(&drv_ctx_lock);
/* Register with PCI */
ret = pci_register_driver(&driver);
if (ret)
pr_err("PCI register failed\n");
return ret;
}
/**
* intel_sst_exit - Module exit function
*
* Unregisters with PCI
* Unregisters with /dev
* Frees all data strutures
*/
static void __exit intel_sst_exit(void)
{
pci_unregister_driver(&driver);
pr_debug("driver unloaded\n");
sst_drv_ctx = NULL;
return;
}
module_init(intel_sst_init);
module_exit(intel_sst_exit);
#ifndef __INTEL_SST_H__
#define __INTEL_SST_H__
/*
* intel_sst.h - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corporation
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This driver exposes the audio engine functionalities to the ALSA
* and middleware.
* This file is shared between the SST and MAD drivers
*/
#include "intel_sst_ioctl.h"
#include <sound/jack.h>
#define SST_CARD_NAMES "intel_mid_card"
#define MFLD_MAX_HW_CH 4
/* control list Pmic & Lpe */
/* Input controls */
enum port_status {
ACTIVATE = 1,
DEACTIVATE,
};
/* Card states */
enum sst_card_states {
SND_CARD_UN_INIT = 0,
SND_CARD_INIT_DONE,
};
enum sst_controls {
SST_SND_ALLOC = 0x1000,
SST_SND_PAUSE = 0x1001,
SST_SND_RESUME = 0x1002,
SST_SND_DROP = 0x1003,
SST_SND_FREE = 0x1004,
SST_SND_BUFFER_POINTER = 0x1005,
SST_SND_STREAM_INIT = 0x1006,
SST_SND_START = 0x1007,
SST_SND_STREAM_PROCESS = 0x1008,
SST_MAX_CONTROLS = 0x1008,
SST_CONTROL_BASE = 0x1000,
SST_ENABLE_RX_TIME_SLOT = 0x1009,
};
enum SND_CARDS {
SND_FS = 0,
SND_MX,
SND_NC,
SND_MSIC
};
struct pcm_stream_info {
int str_id;
void *mad_substream;
void (*period_elapsed) (void *mad_substream);
unsigned long long buffer_ptr;
int sfreq;
};
struct snd_pmic_ops {
int card_status;
int master_mute;
int num_channel;
int input_dev_id;
int mute_status;
struct mutex lock;
int pb_on, pbhs_on;
int cap_on;
int output_dev_id;
int lineout_dev_id, line_out_names_cnt;
int prev_lineout_dev_id;
bool jack_interrupt_status;
int (*set_input_dev) (u8 value);
int (*set_output_dev) (u8 value);
int (*set_lineout_dev) (u8 value);
int (*set_mute) (int dev_id, u8 value);
int (*get_mute) (int dev_id, u8 *value);
int (*set_vol) (int dev_id, int value);
int (*get_vol) (int dev_id, int *value);
int (*init_card) (void);
int (*set_pcm_audio_params)
(int sfreq, int word_size , int num_channel);
int (*set_pcm_voice_params) (void);
int (*set_voice_port) (int status);
int (*set_audio_port) (int status);
int (*power_up_pmic_pb) (unsigned int port);
int (*power_up_pmic_cp) (unsigned int port);
int (*power_down_pmic_pb) (unsigned int device);
int (*power_down_pmic_cp) (unsigned int device);
int (*power_down_pmic) (void);
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,
int buttonpressevent,
int status);
int intemad_set_headset_state(int state);
int intelmad_get_mic_bias(void);
struct intel_sst_pcm_control {
int (*open) (struct snd_sst_params *str_param);
int (*device_control) (int cmd, void *arg);
int (*close) (unsigned int str_id);
};
struct intel_sst_card_ops {
char *module_name;
unsigned int vendor_id;
struct intel_sst_pcm_control *pcm_control;
struct snd_pmic_ops *scard_ops;
};
/* modified for generic access */
struct sc_reg_access {
u16 reg_addr;
u8 value;
u8 mask;
};
enum sc_reg_access_type {
PMIC_READ = 0,
PMIC_WRITE,
PMIC_READ_MODIFY,
};
int register_sst_card(struct intel_sst_card_ops *card);
void unregister_sst_card(struct intel_sst_card_ops *card);
#endif /* __INTEL_SST_H__ */
#ifndef __INTEL_SST_COMMON_H__
#define __INTEL_SST_COMMON_H__
/*
* intel_sst_common.h - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corporation
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Common private declarations for SST
*/
#define SST_DRIVER_VERSION "1.2.17"
#define SST_VERSION_NUM 0x1217
/* driver names */
#define SST_DRV_NAME "intel_sst_driver"
#define SST_MRST_PCI_ID 0x080A
#define SST_MFLD_PCI_ID 0x082F
#define PCI_ID_LENGTH 4
#define SST_SUSPEND_DELAY 2000
#define FW_CONTEXT_MEM (64*1024)
enum sst_states {
SST_FW_LOADED = 1,
SST_FW_RUNNING,
SST_UN_INIT,
SST_ERROR,
SST_SUSPENDED
};
#define MAX_ACTIVE_STREAM 3
#define MAX_ENC_STREAM 1
#define MAX_AM_HANDLES 1
#define ALLOC_TIMEOUT 5000
/* SST numbers */
#define SST_BLOCK_TIMEOUT 5000
#define TARGET_DEV_BLOCK_TIMEOUT 5000
#define BLOCK_UNINIT -1
#define RX_TIMESLOT_UNINIT -1
/* SST register map */
#define SST_CSR 0x00
#define SST_PISR 0x08
#define SST_PIMR 0x10
#define SST_ISRX 0x18
#define SST_IMRX 0x28
#define SST_IPCX 0x38 /* IPC IA-SST */
#define SST_IPCD 0x40 /* IPC SST-IA */
#define SST_ISRD 0x20 /* dummy register for shim workaround */
#define SST_SHIM_SIZE 0X44
#define SPI_MODE_ENABLE_BASE_ADDR 0xffae4000
#define FW_SIGNATURE_SIZE 4
/* PMIC and SST hardware states */
enum sst_mad_states {
SND_MAD_UN_INIT = 0,
SND_MAD_INIT_DONE,
};
/* stream states */
enum sst_stream_states {
STREAM_UN_INIT = 0, /* Freed/Not used stream */
STREAM_RUNNING = 1, /* Running */
STREAM_PAUSED = 2, /* Paused stream */
STREAM_DECODE = 3, /* stream is in decoding only state */
STREAM_INIT = 4, /* stream init, waiting for data */
};
enum sst_ram_type {
SST_IRAM = 1,
SST_DRAM = 2,
};
/* SST shim registers to structure mapping */
union config_status_reg {
struct {
u32 mfld_strb:1;
u32 sst_reset:1;
u32 hw_rsvd:3;
u32 sst_clk:2;
u32 bypass:3;
u32 run_stall:1;
u32 rsvd1:2;
u32 strb_cntr_rst:1;
u32 rsvd:18;
} part;
u32 full;
};
union interrupt_reg {
struct {
u32 done_interrupt:1;
u32 busy_interrupt:1;
u32 rsvd:30;
} part;
u32 full;
};
union sst_pisr_reg {
struct {
u32 pssp0:1;
u32 pssp1:1;
u32 rsvd0:3;
u32 dmac:1;
u32 rsvd1:26;
} part;
u32 full;
};
union sst_pimr_reg {
struct {
u32 ssp0:1;
u32 ssp1:1;
u32 rsvd0:3;
u32 dmac:1;
u32 rsvd1:10;
u32 ssp0_sc:1;
u32 ssp1_sc:1;
u32 rsvd2:3;
u32 dmac_sc:1;
u32 rsvd3:10;
} part;
u32 full;
};
struct sst_stream_bufs {
struct list_head node;
u32 size;
const char *addr;
u32 data_copied;
bool in_use;
u32 offset;
};
struct snd_sst_user_cap_list {
unsigned int iov_index; /* index of iov */
unsigned long iov_offset; /* offset in iov */
unsigned long offset; /* offset in kmem */
unsigned long size; /* size copied */
struct list_head node;
};
/*
This structure is used to block a user/fw data call to another
fw/user call
*/
struct sst_block {
bool condition; /* condition for blocking check */
int ret_code; /* ret code when block is released */
void *data; /* data to be appsed for block if any */
bool on;
};
enum snd_sst_buf_type {
SST_BUF_USER_STATIC = 1,
SST_BUF_USER_DYNAMIC,
SST_BUF_MMAP_STATIC,
SST_BUF_MMAP_DYNAMIC,
};
enum snd_src {
SST_DRV = 1,
MAD_DRV = 2
};
/**
* struct stream_info - structure that holds the stream information
*
* @status : stream current state
* @prev : stream prev state
* @codec : stream codec
* @sst_id : stream id
* @ops : stream operation pb/cp/drm...
* @bufs: stream buffer list
* @lock : stream mutex for protecting state
* @pcm_lock : spinlock for pcm path only
* @mmapped : is stream mmapped
* @sg_index : current stream user buffer index
* @cur_ptr : stream user buffer pointer
* @buf_entry : current user buffer
* @data_blk : stream block for data operations
* @ctrl_blk : stream block for ctrl operations
* @buf_type : stream user buffer type
* @pcm_substream : PCM substream
* @period_elapsed : PCM period elapsed callback
* @sfreq : stream sampling freq
* @decode_ibuf : Decoded i/p buffers pointer
* @decode_obuf : Decoded o/p buffers pointer
* @decode_isize : Decoded i/p buffers size
* @decode_osize : Decoded o/p buffers size
* @decode_ibuf_type : Decoded i/p buffer type
* @decode_obuf_type : Decoded o/p buffer type
* @idecode_alloc : Decode alloc index
* @need_draining : stream set for drain
* @str_type : stream type
* @curr_bytes : current bytes decoded
* @cumm_bytes : cummulative bytes decoded
* @str_type : stream type
* @src : stream source
* @device : output device type (medfield only)
* @pcm_slot : pcm slot value
*/
struct stream_info {
unsigned int status;
unsigned int prev;
u8 codec;
unsigned int sst_id;
unsigned int ops;
struct list_head bufs;
struct mutex lock; /* mutex */
spinlock_t pcm_lock;
bool mmapped;
unsigned int sg_index; /* current buf Index */
unsigned char __user *cur_ptr; /* Current static bufs */
struct snd_sst_buf_entry __user *buf_entry;
struct sst_block data_blk; /* stream ops block */
struct sst_block ctrl_blk; /* stream control cmd block */
enum snd_sst_buf_type buf_type;
void *pcm_substream;
void (*period_elapsed) (void *pcm_substream);
unsigned int sfreq;
void *decode_ibuf, *decode_obuf;
unsigned int decode_isize, decode_osize;
u8 decode_ibuf_type, decode_obuf_type;
unsigned int idecode_alloc;
unsigned int need_draining;
unsigned int str_type;
u32 curr_bytes;
u32 cumm_bytes;
u32 src;
enum snd_sst_audio_device_type device;
u8 pcm_slot;
};
/*
* struct stream_alloc_bloc - this structure is used for blocking the user's
* alloc calls to fw's response to alloc calls
*
* @sst_id : session id of blocked stream
* @ops_block : ops block struture
*/
struct stream_alloc_block {
int sst_id; /* session id of blocked stream */
struct sst_block ops_block; /* ops block struture */
};
#define SST_FW_SIGN "$SST"
#define SST_FW_LIB_SIGN "$LIB"
/*
* struct fw_header - FW file headers
*
* @signature : FW signature
* @modules : # of modules
* @file_format : version of header format
* @reserved : reserved fields
*/
struct fw_header {
unsigned char signature[FW_SIGNATURE_SIZE]; /* FW signature */
u32 file_size; /* size of fw minus this header */
u32 modules; /* # of modules */
u32 file_format; /* version of header format */
u32 reserved[4];
};
struct fw_module_header {
unsigned char signature[FW_SIGNATURE_SIZE]; /* module signature */
u32 mod_size; /* size of module */
u32 blocks; /* # of blocks */
u32 type; /* codec type, pp lib */
u32 entry_point;
};
struct dma_block_info {
enum sst_ram_type type; /* IRAM/DRAM */
u32 size; /* Bytes */
u32 ram_offset; /* Offset in I/DRAM */
u32 rsvd; /* Reserved field */
};
struct ioctl_pvt_data {
int str_id;
int pvt_id;
};
struct sst_ipc_msg_wq {
union ipc_header header;
char mailbox[SST_MAILBOX_SIZE];
struct work_struct wq;
};
struct mad_ops_wq {
int stream_id;
enum sst_controls control_op;
struct work_struct wq;
};
#define SST_MMAP_PAGES (640*1024 / PAGE_SIZE)
#define SST_MMAP_STEP (40*1024 / PAGE_SIZE)
/***
* struct intel_sst_drv - driver ops
*
* @pmic_state : pmic state
* @pmic_vendor : pmic vendor detected
* @sst_state : current sst device state
* @pci_id : PCI device id loaded
* @shim : SST shim pointer
* @mailbox : SST mailbox pointer
* @iram : SST IRAM pointer
* @dram : SST DRAM pointer
* @shim_phy_add : SST shim phy addr
* @ipc_dispatch_list : ipc messages dispatched
* @ipc_post_msg_wq : wq to post IPC messages context
* @ipc_process_msg : wq to process msgs from FW context
* @ipc_process_reply : wq to process reply from FW context
* @ipc_post_msg : wq to post reply from FW context
* @mad_ops : MAD driver operations registered
* @mad_wq : MAD driver wq
* @post_msg_wq : wq to post IPC messages
* @process_msg_wq : wq to process msgs from FW
* @process_reply_wq : wq to process reply from FW
* @streams : sst stream contexts
* @alloc_block : block structure for alloc
* @tgt_dev_blk : block structure for target device
* @fw_info_blk : block structure for fw info block
* @vol_info_blk : block structure for vol info block
* @mute_info_blk : block structure for mute info block
* @hs_info_blk : block structure for hs info block
* @list_lock : sst driver list lock (deprecated)
* @list_spin_lock : sst driver spin lock block
* @scard_ops : sst card ops
* @pci : sst pci device struture
* @active_streams : sst active streams
* @sst_lock : sst device lock
* @stream_lock : sst stream lock
* @unique_id : sst unique id
* @stream_cnt : total sst active stream count
* @pb_streams : total active pb streams
* @cp_streams : total active cp streams
* @lpe_stalled : lpe stall status
* @pmic_port_instance : active pmic port instance
* @rx_time_slot_status : active rx slot
* @lpaudio_start : lpaudio status
* @audio_start : audio status
* @devt_d : pointer to /dev/lpe node
* @devt_c : pointer to /dev/lpe_ctrl node
* @max_streams : max streams allowed
*/
struct intel_sst_drv {
bool pmic_state;
int pmic_vendor;
int sst_state;
unsigned int pci_id;
void __iomem *shim;
void __iomem *mailbox;
void __iomem *iram;
void __iomem *dram;
unsigned int shim_phy_add;
struct list_head ipc_dispatch_list;
struct work_struct ipc_post_msg_wq;
struct sst_ipc_msg_wq ipc_process_msg;
struct sst_ipc_msg_wq ipc_process_reply;
struct sst_ipc_msg_wq ipc_post_msg;
struct mad_ops_wq mad_ops;
wait_queue_head_t wait_queue;
struct workqueue_struct *mad_wq;
struct workqueue_struct *post_msg_wq;
struct workqueue_struct *process_msg_wq;
struct workqueue_struct *process_reply_wq;
struct stream_info streams[MAX_NUM_STREAMS];
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;
struct mutex list_lock;/* mutex for IPC list locking */
spinlock_t list_spin_lock; /* mutex for IPC list locking */
struct snd_pmic_ops *scard_ops;
struct pci_dev *pci;
int active_streams[MAX_NUM_STREAMS];
void *mmap_mem;
struct mutex sst_lock;
struct mutex stream_lock;
unsigned int mmap_len;
unsigned int unique_id;
unsigned int stream_cnt; /* total streams */
unsigned int encoded_cnt; /* enocded streams only */
unsigned int am_cnt;
unsigned int pb_streams; /* pb streams active */
unsigned int cp_streams; /* cp streams active */
unsigned int lpe_stalled; /* LPE is stalled or not */
unsigned int pmic_port_instance; /*pmic port instance*/
int rx_time_slot_status;
unsigned int lpaudio_start;
/* 1 - LPA stream(MP3 pb) in progress*/
unsigned int audio_start;
dev_t devt_d, devt_c;
unsigned int max_streams;
unsigned int *fw_cntx;
unsigned int fw_cntx_size;
unsigned int fw_downloaded;
};
extern struct intel_sst_drv *sst_drv_ctx;
#define CHIP_REV_REG 0xff108000
#define CHIP_REV_ADDR 0x78
/* misc definitions */
#define FW_DWNL_ID 0xFF
#define LOOP1 0x11111111
#define LOOP2 0x22222222
#define LOOP3 0x33333333
#define LOOP4 0x44444444
#define SST_DEFAULT_PMIC_PORT 1 /*audio port*/
/* NOTE: status will have +ve for good cases and -ve for error ones */
#define MAX_STREAM_FIELD 255
int sst_alloc_stream(char *params, unsigned int stream_ops, u8 codec,
unsigned int session_id);
int sst_alloc_stream_response(unsigned int str_id,
struct snd_sst_alloc_response *response);
int sst_stalled(void);
int sst_pause_stream(int id);
int sst_resume_stream(int id);
int sst_enable_rx_timeslot(int status);
int sst_drop_stream(int id);
int sst_free_stream(int id);
int sst_start_stream(int streamID);
int sst_play_frame(int streamID);
int sst_pcm_play_frame(int str_id, struct sst_stream_bufs *sst_buf);
int sst_capture_frame(int streamID);
int sst_set_stream_param(int streamID, struct snd_sst_params *str_param);
int sst_target_device_select(struct snd_sst_target_device *target_device);
int sst_decode(int str_id, struct snd_sst_dbufs *dbufs);
int sst_get_decoded_bytes(int str_id, unsigned long long *bytes);
int sst_get_fw_info(struct snd_sst_fw_info *info);
int sst_get_stream_params(int str_id,
struct snd_sst_get_stream_params *get_params);
int sst_get_stream(struct snd_sst_params *str_param);
int sst_get_stream_allocated(struct snd_sst_params *str_param,
struct snd_sst_lib_download **lib_dnld);
int sst_drain_stream(int str_id);
int sst_get_vol(struct snd_sst_vol *set_vol);
int sst_set_vol(struct snd_sst_vol *set_vol);
int sst_set_mute(struct snd_sst_mute *set_mute);
void sst_post_message(struct work_struct *work);
void sst_process_message(struct work_struct *work);
void sst_process_reply(struct work_struct *work);
void sst_process_mad_ops(struct work_struct *work);
void sst_process_mad_jack_detection(struct work_struct *work);
long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd,
unsigned long arg);
int intel_sst_open(struct inode *i_node, struct file *file_ptr);
int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr);
int intel_sst_release(struct inode *i_node, struct file *file_ptr);
int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr);
int intel_sst_read(struct file *file_ptr, char __user *buf,
size_t count, loff_t *ppos);
int intel_sst_write(struct file *file_ptr, const char __user *buf,
size_t count, loff_t *ppos);
int intel_sst_mmap(struct file *fp, struct vm_area_struct *vma);
ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
unsigned long nr_segs, loff_t offset);
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_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);
int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
struct sst_block *block);
int sst_wait_interruptible_timeout(struct intel_sst_drv *sst_drv_ctx,
struct sst_block *block, int timeout);
int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
struct stream_alloc_block *block);
int sst_create_large_msg(struct ipc_post **arg);
int sst_create_short_msg(struct ipc_post **arg);
void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
u8 sst_id, int status, void *data);
void sst_clear_interrupt(void);
int intel_sst_resume(struct pci_dev *pci);
int sst_download_fw(void);
void free_stream_context(unsigned int str_id);
void sst_clean_stream(struct stream_info *stream);
/*
* sst_fill_header - inline to fill sst header
*
* @header : ipc header
* @msg : IPC message to be sent
* @large : is ipc large msg
* @str_id : stream id
*
* this function is an inline function that sets the headers before
* sending a message
*/
static inline void sst_fill_header(union ipc_header *header,
int msg, int large, int str_id)
{
header->part.msg_id = msg;
header->part.str_id = str_id;
header->part.large = large;
header->part.done = 0;
header->part.busy = 1;
header->part.data = 0;
}
/*
* sst_assign_pvt_id - assign a pvt id for stream
*
* @sst_drv_ctx : driver context
*
* this inline function assigns a private id for calls that dont have stream
* context yet, should be called with lock held
*/
static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx)
{
sst_drv_ctx->unique_id++;
if (sst_drv_ctx->unique_id >= MAX_NUM_STREAMS)
sst_drv_ctx->unique_id = 1;
return sst_drv_ctx->unique_id;
}
/*
* sst_init_stream - this function initialzes stream context
*
* @stream : stream struture
* @codec : codec for stream
* @sst_id : stream id
* @ops : stream operation
* @slot : stream pcm slot
* @device : device type
*
* this inline function initialzes stream context for allocated stream
*/
static inline void sst_init_stream(struct stream_info *stream,
int codec, int sst_id, int ops, u8 slot,
enum snd_sst_audio_device_type device)
{
stream->status = STREAM_INIT;
stream->prev = STREAM_UN_INIT;
stream->codec = codec;
stream->sst_id = sst_id;
stream->str_type = 0;
stream->ops = ops;
stream->data_blk.on = false;
stream->data_blk.condition = false;
stream->data_blk.ret_code = 0;
stream->data_blk.data = NULL;
stream->ctrl_blk.on = false;
stream->ctrl_blk.condition = false;
stream->ctrl_blk.ret_code = 0;
stream->ctrl_blk.data = NULL;
stream->need_draining = false;
stream->decode_ibuf = NULL;
stream->decode_isize = 0;
stream->mmapped = false;
stream->pcm_slot = slot;
stream->device = device;
}
/*
* sst_validate_strid - this function validates the stream id
*
* @str_id : stream id to be validated
*
* returns 0 if valid stream
*/
static inline int sst_validate_strid(int str_id)
{
if (str_id <= 0 || str_id > sst_drv_ctx->max_streams) {
pr_err("SST ERR: invalid stream id : %d MAX_STREAMS:%d\n",
str_id, sst_drv_ctx->max_streams);
return -EINVAL;
} else
return 0;
}
static inline int sst_shim_write(void __iomem *addr, int offset, int value)
{
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
writel(value, addr + SST_ISRD); /*dummy*/
writel(value, addr + offset);
return 0;
}
static inline int sst_shim_read(void __iomem *addr, int offset)
{
return readl(addr + offset);
}
#endif /* __INTEL_SST_COMMON_H__ */
/*
* intel_sst_interface.c - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corp
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This driver exposes the audio engine functionalities to the ALSA
* and middleware.
* Upper layer interfaces (MAD driver, MMF) to SST driver
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/firmware.h>
#include <linux/pm_runtime.h>
#include <linux/export.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intel_sst_fw_ipc.h"
#include "intel_sst_common.h"
/*
* sst_download_fw - download the audio firmware to DSP
*
* This function is called when the FW needs to be downloaded to SST DSP engine
*/
int sst_download_fw(void)
{
int retval;
const struct firmware *fw_sst;
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");
pr_debug("Downloading %s FW now...\n", name);
retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev);
if (retval) {
pr_err("request fw failed %d\n", 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(fw_sst, NULL);
if (retval)
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);
else
sst_drv_ctx->fw_downloaded = 1;
end_restore:
release_firmware(fw_sst);
sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
return retval;
}
/*
* sst_stalled - this function checks if the lpe is in stalled state
*/
int sst_stalled(void)
{
int retry = 1000;
int retval = -1;
while (retry) {
if (!sst_drv_ctx->lpe_stalled)
return 0;
/*wait for time and re-check*/
msleep(1);
retry--;
}
pr_debug("in Stalled State\n");
return retval;
}
void free_stream_context(unsigned int str_id)
{
struct stream_info *stream;
if (!sst_validate_strid(str_id)) {
/* str_id is valid, so stream is alloacted */
stream = &sst_drv_ctx->streams[str_id];
if (sst_free_stream(str_id))
sst_clean_stream(&sst_drv_ctx->streams[str_id]);
if (stream->ops == STREAM_OPS_PLAYBACK ||
stream->ops == STREAM_OPS_PLAYBACK_DRM) {
sst_drv_ctx->pb_streams--;
if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
sst_drv_ctx->scard_ops->power_down_pmic_pb(
stream->device);
else {
if (sst_drv_ctx->pb_streams == 0)
sst_drv_ctx->scard_ops->
power_down_pmic_pb(stream->device);
}
} else if (stream->ops == STREAM_OPS_CAPTURE) {
sst_drv_ctx->cp_streams--;
if (sst_drv_ctx->cp_streams == 0)
sst_drv_ctx->scard_ops->power_down_pmic_cp(
stream->device);
}
if (sst_drv_ctx->pb_streams == 0
&& sst_drv_ctx->cp_streams == 0)
sst_drv_ctx->scard_ops->power_down_pmic();
}
}
/*
* sst_get_stream_allocated - this function gets a stream allocated with
* the given params
*
* @str_param : stream params
* @lib_dnld : pointer to pointer of lib downlaod struct
*
* This creates new stream id for a stream, in case lib is to be downloaded to
* DSP, it downloads that
*/
int sst_get_stream_allocated(struct snd_sst_params *str_param,
struct snd_sst_lib_download **lib_dnld)
{
int retval, str_id;
struct stream_info *str_info;
retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops,
str_param->codec, str_param->device_type);
if (retval < 0) {
pr_err("sst_alloc_stream failed %d\n", retval);
return retval;
}
pr_debug("Stream allocated %d\n", retval);
str_id = retval;
str_info = &sst_drv_ctx->streams[str_id];
/* Block the call for reply */
retval = sst_wait_interruptible_timeout(sst_drv_ctx,
&str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) {
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*/
*lib_dnld = str_info->ctrl_blk.data;
sst_clean_stream(str_info);
} else
pr_debug("FW Stream allocated success\n");
return str_id; /*will ret either error (in above if) or correct str id*/
}
/*
* sst_get_sfreq - this function returns the frequency of the stream
*
* @str_param : stream params
*/
static int sst_get_sfreq(struct snd_sst_params *str_param)
{
switch (str_param->codec) {
case SST_CODEC_TYPE_PCM:
return 48000; /*str_param->sparams.uc.pcm_params.sfreq;*/
case SST_CODEC_TYPE_MP3:
return str_param->sparams.uc.mp3_params.sfreq;
case SST_CODEC_TYPE_AAC:
return str_param->sparams.uc.aac_params.sfreq;
case SST_CODEC_TYPE_WMA9:
return str_param->sparams.uc.wma_params.sfreq;
default:
return 0;
}
}
/*
* sst_get_stream - this function prepares for stream allocation
*
* @str_param : stream param
*/
int sst_get_stream(struct snd_sst_params *str_param)
{
int i, retval;
struct stream_info *str_info;
struct snd_sst_lib_download *lib_dnld;
/* stream is not allocated, we are allocating */
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");
return -EIO;
}
i = sst_get_block_stream(sst_drv_ctx);
response = sst_drv_ctx->alloc_block[i].ops_block.data;
pr_debug("alloc block allocated = %d\n", i);
if (i < 0) {
kfree(lib_dnld);
return -ENOMEM;
}
retval = sst_load_library(lib_dnld, str_param->ops);
kfree(lib_dnld);
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
if (!retval) {
pr_debug("codec was downloaded successfully\n");
retval = sst_get_stream_allocated(str_param, &lib_dnld);
if (retval <= 0)
goto err;
pr_debug("Alloc done stream id %d\n", retval);
} else {
pr_debug("codec download failed\n");
retval = -EIO;
goto err;
}
} else if (retval <= 0)
goto err;
/*else
set_port_params(str_param, str_param->ops);*/
/* store sampling freq */
str_info = &sst_drv_ctx->streams[retval];
str_info->sfreq = sst_get_sfreq(str_param);
/* power on the analog, if reqd */
if (str_param->ops == STREAM_OPS_PLAYBACK ||
str_param->ops == STREAM_OPS_PLAYBACK_DRM) {
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
sst_drv_ctx->scard_ops->power_up_pmic_pb(
sst_drv_ctx->pmic_port_instance);
else
sst_drv_ctx->scard_ops->power_up_pmic_pb(
str_info->device);
/*Only if the playback is MP3 - Send a message*/
sst_drv_ctx->pb_streams++;
} else if (str_param->ops == STREAM_OPS_CAPTURE) {
sst_drv_ctx->scard_ops->power_up_pmic_cp(
sst_drv_ctx->pmic_port_instance);
/*Send a messageif not sent already*/
sst_drv_ctx->cp_streams++;
}
err:
return retval;
}
void sst_process_mad_ops(struct work_struct *work)
{
struct mad_ops_wq *mad_ops =
container_of(work, struct mad_ops_wq, wq);
int retval = 0;
switch (mad_ops->control_op) {
case SST_SND_PAUSE:
retval = sst_pause_stream(mad_ops->stream_id);
break;
case SST_SND_RESUME:
retval = sst_resume_stream(mad_ops->stream_id);
break;
case SST_SND_DROP:
retval = sst_drop_stream(mad_ops->stream_id);
break;
case SST_SND_START:
pr_debug("SST Debug: start stream\n");
retval = sst_start_stream(mad_ops->stream_id);
break;
case SST_SND_STREAM_PROCESS:
pr_debug("play/capt frames...\n");
break;
default:
pr_err(" wrong control_ops reported\n");
}
return;
}
void send_intial_rx_timeslot(void)
{
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID &&
sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT
&& sst_drv_ctx->pmic_vendor != SND_NC)
sst_enable_rx_timeslot(sst_drv_ctx->rx_time_slot_status);
}
/*
* sst_open_pcm_stream - Open PCM interface
*
* @str_param: parameters of pcm stream
*
* This function is called by MID sound card driver to open
* a new pcm interface
*/
int sst_open_pcm_stream(struct snd_sst_params *str_param)
{
struct stream_info *str_info;
int retval;
pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
/* LPE is suspended, resume it before proceeding*/
pr_debug("Resuming from Suspended state\n");
retval = intel_sst_resume(sst_drv_ctx->pci);
if (retval) {
pr_err("Resume Failed = %#x, abort\n", retval);
pm_runtime_put(&sst_drv_ctx->pci->dev);
return retval;
}
}
if (sst_drv_ctx->sst_state == SST_UN_INIT) {
/* 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);
pm_runtime_put(&sst_drv_ctx->pci->dev);
return retval;
}
send_intial_rx_timeslot();
}
if (!str_param) {
pm_runtime_put(&sst_drv_ctx->pci->dev);
return -EINVAL;
}
retval = sst_get_stream(str_param);
if (retval > 0) {
sst_drv_ctx->stream_cnt++;
str_info = &sst_drv_ctx->streams[retval];
str_info->src = MAD_DRV;
} else
pm_runtime_put(&sst_drv_ctx->pci->dev);
return retval;
}
/*
* sst_close_pcm_stream - Close PCM interface
*
* @str_id: stream id to be closed
*
* This function is called by MID sound card driver to close
* an existing pcm interface
*/
int sst_close_pcm_stream(unsigned int str_id)
{
struct stream_info *stream;
pr_debug("sst: stream free called\n");
if (sst_validate_strid(str_id))
return -EINVAL;
stream = &sst_drv_ctx->streams[str_id];
free_stream_context(str_id);
stream->pcm_substream = NULL;
stream->status = STREAM_UN_INIT;
stream->period_elapsed = NULL;
sst_drv_ctx->stream_cnt--;
pr_debug("sst: will call runtime put now\n");
pm_runtime_put(&sst_drv_ctx->pci->dev);
return 0;
}
/*
* sst_device_control - Set Control params
*
* @cmd: control cmd to be set
* @arg: command argument
*
* This function is called by MID sound card driver to set
* SST/Sound card controls for an opened stream.
* This is registered with MID driver
*/
int sst_device_control(int cmd, void *arg)
{
int retval = 0, str_id = 0;
switch (cmd) {
case SST_SND_PAUSE:
case SST_SND_RESUME:
case SST_SND_DROP:
case SST_SND_START:
sst_drv_ctx->mad_ops.control_op = cmd;
sst_drv_ctx->mad_ops.stream_id = *(int *)arg;
queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq);
break;
case SST_SND_STREAM_INIT: {
struct pcm_stream_info *str_info;
struct stream_info *stream;
pr_debug("stream init called\n");
str_info = (struct pcm_stream_info *)arg;
str_id = str_info->str_id;
retval = sst_validate_strid(str_id);
if (retval)
break;
stream = &sst_drv_ctx->streams[str_id];
pr_debug("setting the period ptrs\n");
stream->pcm_substream = str_info->mad_substream;
stream->period_elapsed = str_info->period_elapsed;
stream->sfreq = str_info->sfreq;
stream->prev = stream->status;
stream->status = STREAM_INIT;
break;
}
case SST_SND_BUFFER_POINTER: {
struct pcm_stream_info *stream_info;
struct snd_sst_tstamp fw_tstamp = {0,};
struct stream_info *stream;
stream_info = (struct pcm_stream_info *)arg;
str_id = stream_info->str_id;
retval = sst_validate_strid(str_id);
if (retval)
break;
stream = &sst_drv_ctx->streams[str_id];
if (!stream->pcm_substream)
break;
memcpy_fromio(&fw_tstamp,
((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
+(str_id * sizeof(fw_tstamp))),
sizeof(fw_tstamp));
pr_debug("Pointer Query on strid = %d ops %d\n",
str_id, stream->ops);
if (stream->ops == STREAM_OPS_PLAYBACK)
stream_info->buffer_ptr = fw_tstamp.samples_rendered;
else
stream_info->buffer_ptr = fw_tstamp.samples_processed;
pr_debug("Samples rendered = %llu, buffer ptr %llu\n",
fw_tstamp.samples_rendered, stream_info->buffer_ptr);
break;
}
case SST_ENABLE_RX_TIME_SLOT: {
int status = *(int *)arg;
sst_drv_ctx->rx_time_slot_status = status ;
sst_enable_rx_timeslot(status);
break;
}
default:
/* Illegal case */
pr_warn("illegal req\n");
return -EINVAL;
}
return retval;
}
struct intel_sst_pcm_control pcm_ops = {
.open = sst_open_pcm_stream,
.device_control = sst_device_control,
.close = sst_close_pcm_stream,
};
struct intel_sst_card_ops sst_pmic_ops = {
.pcm_control = &pcm_ops,
};
/*
* register_sst_card - function for sound card to register
*
* @card: pointer to structure of operations
*
* This function is called card driver loads and is ready for registration
*/
int register_sst_card(struct intel_sst_card_ops *card)
{
if (!sst_drv_ctx) {
pr_err("No SST driver register card reject\n");
return -ENODEV;
}
if (!card || !card->module_name) {
pr_err("Null Pointer Passed\n");
return -EINVAL;
}
if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) {
/* register this driver */
if ((strncmp(SST_CARD_NAMES, card->module_name,
strlen(SST_CARD_NAMES))) == 0) {
sst_drv_ctx->pmic_vendor = card->vendor_id;
sst_drv_ctx->scard_ops = card->scard_ops;
sst_pmic_ops.module_name = card->module_name;
sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
card->pcm_control = sst_pmic_ops.pcm_control;
return 0;
} else {
pr_err("strcmp fail %s\n", card->module_name);
return -EINVAL;
}
} else {
/* already registered a driver */
pr_err("Repeat for registration..denied\n");
return -EBADRQC;
}
/* The ASoC code doesn't set scard_ops */
if (sst_drv_ctx->scard_ops)
sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
return 0;
}
EXPORT_SYMBOL_GPL(register_sst_card);
/*
* unregister_sst_card- function for sound card to un-register
*
* @card: pointer to structure of operations
*
* This function is called when card driver unloads
*/
void unregister_sst_card(struct intel_sst_card_ops *card)
{
if (sst_pmic_ops.pcm_control == card->pcm_control) {
/* unreg */
sst_pmic_ops.module_name = "";
sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
pr_debug("Unregistered %s\n", card->module_name);
}
return;
}
EXPORT_SYMBOL_GPL(unregister_sst_card);
/*
* intel_sst_dsp.c - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corp
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This driver exposes the audio engine functionalities to the ALSA
* and middleware.
*
* This file contains all dsp controlling functions like firmware download,
* setting/resetting dsp cores, etc
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/firmware.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intel_sst_fw_ipc.h"
#include "intel_sst_common.h"
/**
* intel_sst_reset_dsp_mrst - Resetting SST DSP
*
* This resets DSP in case of MRST platfroms
*/
static int intel_sst_reset_dsp_mrst(void)
{
union config_status_reg csr;
pr_debug("Resetting the DSP in mrst\n");
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full |= 0x382;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.strb_cntr_rst = 0;
csr.part.run_stall = 0x1;
csr.part.bypass = 0x7;
csr.part.sst_reset = 0x1;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
return 0;
}
/**
* intel_sst_reset_dsp_medfield - Resetting SST DSP
*
* This resets DSP in case of Medfield platfroms
*/
static int intel_sst_reset_dsp_medfield(void)
{
union config_status_reg csr;
pr_debug("Resetting the DSP in medfield\n");
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full |= 0x382;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
return 0;
}
/**
* sst_start_mrst - Start the SST DSP processor
*
* This starts the DSP in MRST platfroms
*/
static int sst_start_mrst(void)
{
union config_status_reg csr;
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.bypass = 0;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.part.run_stall = 0;
csr.part.sst_reset = 0;
csr.part.strb_cntr_rst = 1;
pr_debug("Setting SST to execute_mrst 0x%x\n", csr.full);
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
return 0;
}
/**
* sst_start_medfield - Start the SST DSP processor
*
* This starts the DSP in Medfield platfroms
*/
static int sst_start_medfield(void)
{
union config_status_reg csr;
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.bypass = 0;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.mfld_strb = 1;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.run_stall = 0;
csr.part.sst_reset = 0;
pr_debug("Starting the DSP_medfld %x\n", csr.full);
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
pr_debug("Starting the DSP_medfld\n");
return 0;
}
/**
* sst_parse_module - Parse audio FW modules
*
* @module: FW module header
*
* Parses modules that need to be placed in SST IRAM and DRAM
* 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;
pr_debug("module sign %s size %x blocks %x type %x\n",
module->signature, module->mod_size,
module->blocks, module->type);
pr_debug("module entrypoint 0x%x\n", module->entry_point);
block = (void *)module + sizeof(*module);
for (count = 0; count < module->blocks; count++) {
if (block->size <= 0) {
pr_err("block size invalid\n");
return -EINVAL;
}
switch (block->type) {
case SST_IRAM:
ram = sst_drv_ctx->iram;
break;
case SST_DRAM:
ram = sst_drv_ctx->dram;
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);
block = (void *)block + sizeof(*block) + block->size;
}
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
*/
static int sst_parse_fw_image(const struct firmware *sst_fw)
{
struct fw_header *header;
u32 count;
int ret_val;
struct fw_module_header *module;
BUG_ON(!sst_fw);
/* Read the header information from the data pointer */
header = (struct fw_header *)sst_fw->data;
/* verify FW */
if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
(sst_fw->size != header->file_size + sizeof(*header))) {
/* Invalid FW signature */
pr_err("Invalid FW 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);
for (count = 0; count < header->modules; count++) {
/* module */
ret_val = sst_parse_module(module);
if (ret_val)
return ret_val;
module = (void *)module + sizeof(*module) + module->mod_size ;
}
return 0;
}
/**
* 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
*/
int sst_load_fw(const struct firmware *fw, void *context)
{
int ret_val;
pr_debug("load_fw called\n");
BUG_ON(!fw);
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
ret_val = intel_sst_reset_dsp_mrst();
else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
ret_val = intel_sst_reset_dsp_medfield();
if (ret_val)
return ret_val;
ret_val = sst_parse_fw_image(fw);
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 */
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;
pr_debug("fw loaded successful!!!\n");
return ret_val;
}
/*This function is called when any codec/post processing library
needs to be downloaded*/
static int sst_download_library(const struct firmware *fw_lib,
struct snd_sst_lib_download_info *lib)
{
/* send IPC message and wait */
int i;
u8 pvt_id;
struct ipc_post *msg = NULL;
union config_status_reg csr;
struct snd_sst_str_type str_type = {0};
int retval = 0;
if (sst_create_large_msg(&msg))
return -ENOMEM;
pvt_id = sst_assign_pvt_id(sst_drv_ctx);
i = sst_get_block_stream(sst_drv_ctx);
pr_debug("alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
if (i < 0) {
kfree(msg);
return -ENOMEM;
}
sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
sst_fill_header(&msg->header, IPC_IA_PREP_LIB_DNLD, 1, pvt_id);
msg->header.part.data = sizeof(u32) + sizeof(str_type);
str_type.codec_type = lib->dload_lib.lib_info.lib_type;
/*str_type.pvt_id = pvt_id;*/
memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
memcpy(msg->mailbox_data + sizeof(u32), &str_type, sizeof(str_type));
spin_lock(&sst_drv_ctx->list_spin_lock);
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);
retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
if (retval) {
/* error */
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
pr_err("Prep codec downloaded failed %d\n",
retval);
return -EIO;
}
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);
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);
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.bypass = 0x7;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
sst_parse_fw_image(fw_lib);
/* set the FW to running again */
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.bypass = 0x0;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.run_stall = 0;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
/* send download complete and wait */
if (sst_create_large_msg(&msg)) {
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
return -ENOMEM;
}
sst_fill_header(&msg->header, IPC_IA_LIB_DNLD_CMPLT, 1, pvt_id);
sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
msg->header.part.data = sizeof(u32) + sizeof(*lib);
lib->pvt_id = pvt_id;
memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
memcpy(msg->mailbox_data + sizeof(u32), lib, sizeof(*lib));
spin_lock(&sst_drv_ctx->list_spin_lock);
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);
pr_debug("Waiting for FW response Download complete\n");
sst_drv_ctx->alloc_block[i].ops_block.condition = false;
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_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);
return 0;
}
/* This function is called before downloading the codec/postprocessing
library is set for download to SST DSP*/
static int sst_validate_library(const struct firmware *fw_lib,
struct lib_slot_info *slot,
u32 *entry_point)
{
struct fw_header *header;
struct fw_module_header *module;
struct dma_block_info *block;
unsigned int n_blk, isize = 0, dsize = 0;
int err = 0;
header = (struct fw_header *)fw_lib->data;
if (header->modules != 1) {
pr_err("Module no mismatch found\n");
err = -EINVAL;
goto exit;
}
module = (void *)fw_lib->data + sizeof(*header);
*entry_point = module->entry_point;
pr_debug("Module entry point 0x%x\n", *entry_point);
pr_debug("Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
module->signature, module->mod_size,
module->blocks, module->type);
block = (void *)module + sizeof(*module);
for (n_blk = 0; n_blk < module->blocks; n_blk++) {
switch (block->type) {
case SST_IRAM:
isize += block->size;
break;
case SST_DRAM:
dsize += block->size;
break;
default:
pr_err("Invalid block type for 0x%x\n", n_blk);
err = -EINVAL;
goto exit;
}
block = (void *)block + sizeof(*block) + block->size;
}
if (isize > slot->iram_size || dsize > slot->dram_size) {
pr_err("library exceeds size allocated\n");
err = -EINVAL;
goto exit;
} else
pr_debug("Library is safe for download...\n");
pr_debug("iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
isize, dsize, slot->iram_size, slot->dram_size);
exit:
return err;
}
/* This function is called when FW requests for a particular library download
This function prepares the library to download*/
int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
{
char buf[20];
const char *type, *dir;
int len = 0, error = 0;
u32 entry_point;
const struct firmware *fw_lib;
struct snd_sst_lib_download_info dload_info = {{{0},},};
memset(buf, 0, sizeof(buf));
pr_debug("Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
pr_debug("Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
lib->lib_info.lib_version, lib->lib_info.lib_name,
lib->lib_info.lib_caps, lib->lib_info.media_type);
pr_debug("IRAM Size 0x%x, offset 0x%x\n",
lib->slot_info.iram_size, lib->slot_info.iram_offset);
pr_debug("DRAM Size 0x%x, offset 0x%x\n",
lib->slot_info.dram_size, lib->slot_info.dram_offset);
switch (lib->lib_info.lib_type) {
case SST_CODEC_TYPE_MP3:
type = "mp3_";
break;
case SST_CODEC_TYPE_AAC:
type = "aac_";
break;
case SST_CODEC_TYPE_AACP:
type = "aac_v1_";
break;
case SST_CODEC_TYPE_eAACP:
type = "aac_v2_";
break;
case SST_CODEC_TYPE_WMA9:
type = "wma9_";
break;
default:
pr_err("Invalid codec type\n");
error = -EINVAL;
goto wake;
}
if (ops == STREAM_OPS_CAPTURE)
dir = "enc_";
else
dir = "dec_";
len = strlen(type) + strlen(dir);
strncpy(buf, type, sizeof(buf)-1);
strncpy(buf + strlen(type), dir, sizeof(buf)-strlen(type)-1);
len += snprintf(buf + len, sizeof(buf) - len, "%d",
lib->slot_info.slot_num);
len += snprintf(buf + len, sizeof(buf) - len, ".bin");
pr_debug("Requesting %s\n", buf);
error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
if (error) {
pr_err("library load failed %d\n", error);
goto wake;
}
error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
if (error)
goto wake_free;
lib->mod_entry_pt = entry_point;
memcpy(&dload_info.dload_lib, lib, sizeof(*lib));
error = sst_download_library(fw_lib, &dload_info);
if (error)
goto wake_free;
/* lib is downloaded and init send alloc again */
pr_debug("Library is downloaded now...\n");
wake_free:
/* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */
release_firmware(fw_lib);
wake:
return error;
}
#ifndef __INTEL_SST_FW_IPC_H__
#define __INTEL_SST_FW_IPC_H__
/*
* intel_sst_fw_ipc.h - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corporation
* Author: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This driver exposes the audio engine functionalities to the ALSA
* and middleware.
* This file has definitions shared between the firmware and driver
*/
#define MAX_NUM_STREAMS_MRST 3
#define MAX_NUM_STREAMS_MFLD 6
#define MAX_NUM_STREAMS 6
#define MAX_DBG_RW_BYTES 80
#define MAX_NUM_SCATTER_BUFFERS 8
#define MAX_LOOP_BACK_DWORDS 8
/* IPC base address and mailbox, timestamp offsets */
#define SST_MAILBOX_SIZE 0x0400
#define SST_MAILBOX_SEND 0x0000
#define SST_MAILBOX_RCV 0x0804
#define SST_TIME_STAMP 0x1800
#define SST_RESERVED_OFFSET 0x1A00
#define SST_CHEKPOINT_OFFSET 0x1C00
#define REPLY_MSG 0x80
/* Message ID's for IPC messages */
/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */
/* I2L Firmware/Codec Download msgs */
#define IPC_IA_PREP_LIB_DNLD 0x01
#define IPC_IA_LIB_DNLD_CMPLT 0x02
#define IPC_IA_SET_PMIC_TYPE 0x03
#define IPC_IA_GET_FW_VERSION 0x04
#define IPC_IA_GET_FW_BUILD_INF 0x05
#define IPC_IA_GET_FW_INFO 0x06
#define IPC_IA_GET_FW_CTXT 0x07
#define IPC_IA_SET_FW_CTXT 0x08
/* I2L Codec Config/control msgs */
#define IPC_IA_SET_CODEC_PARAMS 0x10
#define IPC_IA_GET_CODEC_PARAMS 0x11
#define IPC_IA_SET_PPP_PARAMS 0x12
#define IPC_IA_GET_PPP_PARAMS 0x13
#define IPC_IA_PLAY_FRAMES 0x14
#define IPC_IA_CAPT_FRAMES 0x15
#define IPC_IA_PLAY_VOICE 0x16
#define IPC_IA_CAPT_VOICE 0x17
#define IPC_IA_DECODE_FRAMES 0x18
#define IPC_IA_ALG_PARAMS 0x1A
#define IPC_IA_TUNING_PARAMS 0x1B
/* I2L Stream config/control msgs */
#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */
#define IPC_IA_SET_STREAM_PARAMS 0x22
#define IPC_IA_GET_STREAM_PARAMS 0x23
#define IPC_IA_PAUSE_STREAM 0x24
#define IPC_IA_RESUME_STREAM 0x25
#define IPC_IA_DROP_STREAM 0x26
#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */
#define IPC_IA_TARGET_DEV_SELECT 0x28
#define IPC_IA_CONTROL_ROUTING 0x29
#define IPC_IA_SET_STREAM_VOL 0x2A /*Vol for stream, pre mixer */
#define IPC_IA_GET_STREAM_VOL 0x2B
#define IPC_IA_SET_STREAM_MUTE 0x2C
#define IPC_IA_GET_STREAM_MUTE 0x2D
#define IPC_IA_ENABLE_RX_TIME_SLOT 0x2E /* Enable Rx time slot 0 or 1 */
#define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */
/* Debug msgs */
#define IPC_IA_DBG_MEM_READ 0x40
#define IPC_IA_DBG_MEM_WRITE 0x41
#define IPC_IA_DBG_LOOP_BACK 0x42
/* L2I Firmware/Codec Download msgs */
#define IPC_IA_FW_INIT_CMPLT 0x81
#define IPC_IA_LPE_GETTING_STALLED 0x82
#define IPC_IA_LPE_UNSTALLED 0x83
/* L2I Codec Config/control msgs */
#define IPC_SST_GET_PLAY_FRAMES 0x90 /* Request IA more data */
#define IPC_SST_GET_CAPT_FRAMES 0x91 /* Request IA more data */
#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */
#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */
#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */
#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */
#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */
#define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */
#define IPC_IA_TARGET_DEV_CHNGD 0x98 /* error in processing a stream */
#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */
/* L2S messages */
#define IPC_SC_DDR_LINK_UP 0xC0
#define IPC_SC_DDR_LINK_DOWN 0xC1
#define IPC_SC_SET_LPECLK_REQ 0xC2
#define IPC_SC_SSP_BIT_BANG 0xC3
/* L2I Error reporting msgs */
#define IPC_IA_MEM_ALLOC_FAIL 0xE0
#define IPC_IA_PROC_ERR 0xE1 /* error in processing a
stream can be used by playback and
capture modules */
/* L2I Debug msgs */
#define IPC_IA_PRINT_STRING 0xF0
/* Command Response or Acknowledge message to any IPC message will have
* same message ID and stream ID information which is sent.
* There is no specific Ack message ID. The data field is used as response
* meaning.
*/
enum ackData {
IPC_ACK_SUCCESS = 0,
IPC_ACK_FAILURE
};
enum sst_error_codes {
/* Error code,response to msgId: Description */
/* Common error codes */
SST_SUCCESS = 0, /* Success */
SST_ERR_INVALID_STREAM_ID = 1,
SST_ERR_INVALID_MSG_ID = 2,
SST_ERR_INVALID_STREAM_OP = 3,
SST_ERR_INVALID_PARAMS = 4,
SST_ERR_INVALID_CODEC = 5,
SST_ERR_INVALID_MEDIA_TYPE = 6,
SST_ERR_STREAM_ERR = 7,
/* IPC specific error codes */
SST_IPC_ERR_CALL_BACK_NOT_REGD = 8,
SST_IPC_ERR_STREAM_NOT_ALLOCATED = 9,
SST_IPC_ERR_STREAM_ALLOC_FAILED = 10,
SST_IPC_ERR_GET_STREAM_FAILED = 11,
SST_ERR_MOD_NOT_AVAIL = 12,
SST_ERR_MOD_DNLD_RQD = 13,
SST_ERR_STREAM_STOPPED = 14,
SST_ERR_STREAM_IN_USE = 15,
/* Capture specific error codes */
SST_CAP_ERR_INCMPLTE_CAPTURE_MSG = 16,
SST_CAP_ERR_CAPTURE_FAIL = 17,
SST_CAP_ERR_GET_DDR_NEW_SGLIST = 18,
SST_CAP_ERR_UNDER_RUN = 19,
SST_CAP_ERR_OVERFLOW = 20,
/* Playback specific error codes*/
SST_PB_ERR_INCMPLTE_PLAY_MSG = 21,
SST_PB_ERR_PLAY_FAIL = 22,
SST_PB_ERR_GET_DDR_NEW_SGLIST = 23,
/* Codec manager specific error codes */
SST_LIB_ERR_LIB_DNLD_REQUIRED = 24,
SST_LIB_ERR_LIB_NOT_SUPPORTED = 25,
/* Library manager specific error codes */
SST_SCC_ERR_PREP_DNLD_FAILED = 26,
SST_SCC_ERR_LIB_DNLD_RES_FAILED = 27,
/* Scheduler specific error codes */
SST_SCH_ERR_FAIL = 28,
/* DMA specific error codes */
SST_DMA_ERR_NO_CHNL_AVAILABLE = 29,
SST_DMA_ERR_INVALID_INPUT_PARAMS = 30,
SST_DMA_ERR_CHNL_ALREADY_SUSPENDED = 31,
SST_DMA_ERR_CHNL_ALREADY_STARTED = 32,
SST_DMA_ERR_CHNL_NOT_ENABLED = 33,
SST_DMA_ERR_TRANSFER_FAILED = 34,
SST_SSP_ERR_ALREADY_ENABLED = 35,
SST_SSP_ERR_ALREADY_DISABLED = 36,
SST_SSP_ERR_NOT_INITIALIZED = 37,
SST_SSP_ERR_SRAM_NO_DMA_DATA = 38,
/* Other error codes */
SST_ERR_MOD_INIT_FAIL = 39,
/* FW init error codes */
SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED = 40,
SST_RDR_ERR_ROUTE_ALREADY_STARTED = 41,
SST_RDR_ERR_IO_DEV_SEL_FAILED = 42,
SST_RDR_PREP_CODEC_DNLD_FAILED = 43,
/* Memory debug error codes */
SST_ERR_DBG_MEM_READ_FAIL = 44,
SST_ERR_DBG_MEM_WRITE_FAIL = 45,
SST_ERR_INSUFFICIENT_INPUT_SG_LIST = 46,
SST_ERR_INSUFFICIENT_OUTPUT_SG_LIST = 47,
SST_ERR_BUFFER_NOT_AVAILABLE = 48,
SST_ERR_BUFFER_NOT_ALLOCATED = 49,
SST_ERR_INVALID_REGION_TYPE = 50,
SST_ERR_NULL_PTR = 51,
SST_ERR_INVALID_BUFFER_SIZE = 52,
SST_ERR_INVALID_BUFFER_INDEX = 53,
/*IIPC specific error codes */
SST_IIPC_QUEUE_FULL = 54,
SST_IIPC_ERR_MSG_SND_FAILED = 55,
SST_PB_ERR_UNDERRUN_OCCURED = 56,
SST_RDR_INSUFFICIENT_MIXER_BUFFER = 57,
SST_INVALID_TIME_SLOTS = 58,
};
enum dbg_mem_data_type {
/* Data type of debug read/write */
DATA_TYPE_U32,
DATA_TYPE_U16,
DATA_TYPE_U8,
};
/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/
/* IPC Header */
union ipc_header {
struct {
u32 msg_id:8; /* Message ID - Max 256 Message Types */
u32 str_id:5;
u32 large:1; /* Large Message if large = 1 */
u32 reserved:2; /* Reserved for future use */
u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */
u32 done:1; /* bit 30 */
u32 busy:1; /* bit 31 */
} part;
u32 full;
} __attribute__ ((packed));
/* Firmware build info */
struct sst_fw_build_info {
unsigned char date[16]; /* Firmware build date */
unsigned char time[16]; /* Firmware build time */
} __attribute__ ((packed));
struct ipc_header_fw_init {
struct snd_sst_fw_version fw_version;/* Firmware version details */
struct sst_fw_build_info build_info;
u16 result; /* Fw init result */
u8 module_id; /* Module ID in case of error */
u8 debug_info; /* Debug info from Module ID in case of fail */
} __attribute__ ((packed));
/* Address and size info of a frame buffer in DDR */
struct sst_address_info {
u32 addr; /* Address at IA */
u32 size; /* Size of the buffer */
} __attribute__ ((packed));
/* Time stamp */
struct snd_sst_tstamp {
u64 samples_processed;/* capture - data in DDR */
u64 samples_rendered;/* playback - data rendered */
u64 bytes_processed;/* bytes decoded or encoded */
u32 sampling_frequency;/* eg: 48000, 44100 */
u32 dma_base_address;/* DMA base address */
u16 dma_channel_no;/* DMA Channel used for the data transfer*/
u16 reserved;/* 32 bit alignment */
};
/* Frame info to play or capture */
struct sst_frame_info {
u16 num_entries; /* number of entries to follow */
u16 rsrvd;
struct sst_address_info addr[MAX_NUM_SCATTER_BUFFERS];
} __attribute__ ((packed));
/* Frames info for decode */
struct snd_sst_decode_info {
unsigned long long input_bytes_consumed;
unsigned long long output_bytes_produced;
struct sst_frame_info frames_in;
struct sst_frame_info frames_out;
} __attribute__ ((packed));
/* SST to IA print debug message*/
struct ipc_sst_ia_print_params {
u32 string_size;/* Max value is 160 */
u8 prt_string[160];/* Null terminated Char string */
} __attribute__ ((packed));
/* Voice data message */
struct snd_sst_voice_data {
u16 num_bytes;/* Number of valid voice data bytes */
u8 pcm_wd_size;/* 0=8 bit, 1=16 bit 2=32 bit */
u8 reserved;/* Reserved */
u8 voice_data_buf[0];/* Voice data buffer in bytes, little endian */
} __attribute__ ((packed));
/* SST to IA memory read debug message */
struct ipc_sst_ia_dbg_mem_rw {
u16 num_bytes;/* Maximum of MAX_DBG_RW_BYTES */
u16 data_type;/* enum: dbg_mem_data_type */
u32 address; /* Memory address of data memory of data_type */
u8 rw_bytes[MAX_DBG_RW_BYTES];/* Maximum of 64 bytes can be RW */
} __attribute__ ((packed));
struct ipc_sst_ia_dbg_loop_back {
u16 num_dwords; /* Maximum of MAX_DBG_RW_BYTES */
u16 increment_val;/* Increments dwords by this value, 0- no increment */
u32 lpbk_dwords[MAX_LOOP_BACK_DWORDS];/* Maximum of 8 dwords loopback */
} __attribute__ ((packed));
/* Stream type params struture for Alloc stream */
struct snd_sst_str_type {
u8 codec_type; /* Codec type */
u8 str_type; /* 1 = voice 2 = music */
u8 operation; /* Playback or Capture */
u8 protected_str; /* 0=Non DRM, 1=DRM */
u8 time_slots;
u8 reserved; /* Reserved */
u16 result; /* Result used for acknowledgment */
} __attribute__ ((packed));
/* Library info structure */
struct module_info {
u32 lib_version;
u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/
u32 media_type;
u8 lib_name[12];
u32 lib_caps;
unsigned char b_date[16]; /* Lib build date */
unsigned char b_time[16]; /* Lib build time */
} __attribute__ ((packed));
/* Library slot info */
struct lib_slot_info {
u8 slot_num; /* 1 or 2 */
u8 reserved1;
u16 reserved2;
u32 iram_size; /* slot size in IRAM */
u32 dram_size; /* slot size in DRAM */
u32 iram_offset; /* starting offset of slot in IRAM */
u32 dram_offset; /* starting offset of slot in DRAM */
} __attribute__ ((packed));
struct snd_sst_lib_download {
struct module_info lib_info; /* library info type, capabilities etc */
struct lib_slot_info slot_info; /* slot info to be downloaded */
u32 mod_entry_pt;
};
struct snd_sst_lib_download_info {
struct snd_sst_lib_download dload_lib;
u16 result; /* Result used for acknowledgment */
u8 pvt_id; /* Private ID */
u8 reserved; /* for alignment */
};
/* Alloc stream params structure */
struct snd_sst_alloc_params {
struct snd_sst_str_type str_type;
struct snd_sst_stream_params stream_params;
};
struct snd_sst_fw_get_stream_params {
struct snd_sst_stream_params codec_params;
struct snd_sst_pmic_config pcm_params;
};
/* Alloc stream response message */
struct snd_sst_alloc_response {
struct snd_sst_str_type str_type; /* Stream type for allocation */
struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */
};
/* Drop response */
struct snd_sst_drop_response {
u32 result;
u32 bytes;
};
/* CSV Voice call routing structure */
struct snd_sst_control_routing {
u8 control; /* 0=start, 1=Stop */
u8 reserved[3]; /* Reserved- for 32 bit alignment */
};
struct ipc_post {
struct list_head node;
union ipc_header header; /* driver specific */
char *mailbox_data;
};
struct snd_sst_ctxt_params {
u32 address; /* Physical Address in DDR where the context is stored */
u32 size; /* size of the context */
};
#endif /* __INTEL_SST_FW_IPC_H__ */
#ifndef __INTEL_SST_IOCTL_H__
#define __INTEL_SST_IOCTL_H__
/*
* intel_sst_ioctl.h - Intel SST Driver for audio engine
*
* Copyright (C) 2008-10 Intel Corporation
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This file defines all sst ioctls
*/
/* codec and post/pre processing related info */
#include <linux/types.h>
enum sst_codec_types {
/* AUDIO/MUSIC CODEC Type Definitions */
SST_CODEC_TYPE_UNKNOWN = 0,
SST_CODEC_TYPE_PCM, /* Pass through Audio codec */
SST_CODEC_TYPE_MP3,
SST_CODEC_TYPE_MP24,
SST_CODEC_TYPE_AAC,
SST_CODEC_TYPE_AACP,
SST_CODEC_TYPE_eAACP,
SST_CODEC_TYPE_WMA9,
SST_CODEC_TYPE_WMA10,
SST_CODEC_TYPE_WMA10P,
SST_CODEC_TYPE_RA,
SST_CODEC_TYPE_DDAC3,
SST_CODEC_TYPE_STEREO_TRUE_HD,
SST_CODEC_TYPE_STEREO_HD_PLUS,
/* VOICE CODEC Type Definitions */
SST_CODEC_TYPE_VOICE_PCM = 0x21, /* Pass through voice codec */
};
enum sst_algo_types {
SST_CODEC_SRC = 0x64,
SST_CODEC_MIXER = 0x65,
SST_CODEC_DOWN_MIXER = 0x66,
SST_CODEC_VOLUME_CONTROL = 0x67,
SST_CODEC_OEM1 = 0xC8,
SST_CODEC_OEM2 = 0xC9,
};
enum snd_sst_stream_ops {
STREAM_OPS_PLAYBACK = 0, /* Decode */
STREAM_OPS_CAPTURE, /* Encode */
STREAM_OPS_PLAYBACK_DRM, /* Play Audio/Voice */
STREAM_OPS_PLAYBACK_ALERT, /* Play Audio/Voice */
STREAM_OPS_CAPTURE_VOICE_CALL, /* CSV Voice recording */
};
enum stream_mode {
SST_STREAM_MODE_NONE = 0,
SST_STREAM_MODE_DNR = 1,
SST_STREAM_MODE_FNF = 2,
SST_STREAM_MODE_CAPTURE = 3
};
enum stream_type {
SST_STREAM_TYPE_NONE = 0,
SST_STREAM_TYPE_MUSIC = 1,
SST_STREAM_TYPE_NORMAL = 2,
SST_STREAM_TYPE_LONG_PB = 3,
SST_STREAM_TYPE_LOW_LATENCY = 4,
};
enum snd_sst_audio_device_type {
SND_SST_DEVICE_HEADSET = 1,
SND_SST_DEVICE_IHF,
SND_SST_DEVICE_VIBRA,
SND_SST_DEVICE_HAPTIC,
SND_SST_DEVICE_CAPTURE,
};
/* Firmware Version info */
struct snd_sst_fw_version {
__u8 build; /* build number*/
__u8 minor; /* minor number*/
__u8 major; /* major number*/
__u8 type; /* build type */
};
/* Port info structure */
struct snd_sst_port_info {
__u16 port_type;
__u16 reserved;
};
/* Mixer info structure */
struct snd_sst_mix_info {
__u16 max_streams;
__u16 reserved;
};
/* PCM Parameters */
struct snd_pcm_params {
__u16 codec; /* codec type */
__u8 num_chan; /* 1=Mono, 2=Stereo */
__u8 pcm_wd_sz; /* 16/24 - bit*/
__u32 reserved; /* Bitrate in bits per second */
__u32 sfreq; /* Sampling rate in Hz */
__u32 ring_buffer_size;
__u32 period_count; /* period elapsed in samples*/
__u32 ring_buffer_addr;
};
/* MP3 Music Parameters Message */
struct snd_mp3_params {
__u16 codec;
__u8 num_chan; /* 1=Mono, 2=Stereo */
__u8 pcm_wd_sz; /* 16/24 - bit*/
__u32 brate; /* Use the hard coded value. */
__u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
__u8 crc_check; /* crc_check - disable (0) or enable (1) */
__u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB*/
__u16 reserved; /* Unused */
};
#define AAC_BIT_STREAM_ADTS 0
#define AAC_BIT_STREAM_ADIF 1
#define AAC_BIT_STREAM_RAW 2
/* AAC Music Parameters Message */
struct snd_aac_params {
__u16 codec;
__u8 num_chan; /* 1=Mono, 2=Stereo*/
__u8 pcm_wd_sz; /* 16/24 - bit*/
__u32 brate;
__u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
__u32 aac_srate; /* Plain AAC decoder operating sample rate */
__u8 mpg_id; /* 0=MPEG-2, 1=MPEG-4 */
__u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
__u8 aac_profile; /* 0=Main Profile, 1=LC profile, 3=SSR profile */
__u8 ext_chl; /* No.of external channels */
__u8 aot; /* Audio object type. 1=Main , 2=LC , 3=SSR, 4=SBR*/
__u8 op_align; /* output alignment 0=16 bit , 1=MSB, 2= LSB align */
__u8 brate_type; /* 0=CBR, 1=VBR */
__u8 crc_check; /* crc check 0= disable, 1=enable */
__s8 bit_stream_format[8]; /* input bit stream format adts/adif/raw */
__u8 jstereo; /* Joint stereo Flag */
__u8 sbr_present; /* 1 = SBR Present, 0 = SBR absent, for RAW */
__u8 downsample; /* 1 = Downsampling ON, 0 = Downsampling OFF */
__u8 num_syntc_elems; /* 1- Mono/stereo, 0 - Dual Mono, 0 - for raw */
__s8 syntc_id[2]; /* 0 for ID_SCE(Dula Mono), -1 for raw */
__s8 syntc_tag[2]; /* raw - -1 and 0 -16 for rest of the streams */
__u8 pce_present; /* Flag. 1- present 0 - not present, for RAW */
__u8 sbr_type; /* sbr_type: 0-plain aac, 1-aac-v1, 2-aac-v2 */
__u8 outchmode; /*0- mono, 1-stereo, 2-dual mono 3-Parametric stereo */
__u8 ps_present;
};
/* WMA Music Parameters Message */
struct snd_wma_params {
__u16 codec;
__u8 num_chan; /* 1=Mono, 2=Stereo */
__u8 pcm_wd_sz; /* 16/24 - bit*/
__u32 brate; /* Use the hard coded value. */
__u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
__u32 channel_mask; /* Channel Mask */
__u16 format_tag; /* Format Tag */
__u16 block_align; /* packet size */
__u16 wma_encode_opt;/* Encoder option */
__u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB */
__u8 pcm_src; /* input pcm bit width */
};
/* Pre processing param structure */
struct snd_prp_params {
__u32 reserved; /* No pre-processing defined yet */
};
/* Pre and post processing params structure */
struct snd_ppp_params {
__u8 algo_id;/* Post/Pre processing algorithm ID */
__u8 str_id; /*Only 5 bits used 0 - 31 are valid*/
__u8 enable; /* 0= disable, 1= enable*/
__u8 reserved;
__u32 size; /*Size of parameters for all blocks*/
void *params;
} __attribute__ ((packed));
struct snd_sst_postproc_info {
__u32 src_min; /* Supported SRC Min sampling freq */
__u32 src_max; /* Supported SRC Max sampling freq */
__u8 src; /* 0=Not supported, 1=Supported */
__u8 bass_boost; /* 0=Not Supported, 1=Supported */
__u8 stereo_widening; /* 0=Not Supported, 1=Supported */
__u8 volume_control; /* 0=Not Supported, 1=Supported */
__s16 min_vol; /* Minimum value of Volume in dB */
__s16 max_vol; /* Maximum value of Volume in dB */
__u8 mute_control; /* 0=No Mute, 1=Mute */
__u8 reserved1;
__u16 reserved2;
};
/* pre processing Capability info structure */
struct snd_sst_prp_info {
__s16 min_vol; /* Minimum value of Volume in dB */
__s16 max_vol; /* Maximum value of Volume in dB */
__u8 volume_control; /* 0=Not Supported, 1=Supported */
__u8 reserved1; /* for 32 bit alignment */
__u16 reserved2; /* for 32 bit alignment */
} __attribute__ ((packed));
/*Pre / Post processing algorithms support*/
struct snd_sst_ppp_info {
__u32 src:1; /* 0=Not supported, 1=Supported */
__u32 mixer:1; /* 0=Not supported, 1=Supported */
__u32 volume_control:1; /* 0=Not Supported, 1=Supported */
__u32 mute_control:1; /* 0=Not Supported, 1=Supported */
__u32 anc:1; /* 0=Not Supported, 1=Supported */
__u32 side_tone:1; /* 0=Not Supported, 1=Supported */
__u32 dc_removal:1; /* 0=Not Supported, 1=Supported */
__u32 equalizer:1; /* 0=Not Supported, 1=Supported */
__u32 spkr_prot:1; /* 0=Not Supported, 1=Supported */
__u32 bass_boost:1; /* 0=Not Supported, 1=Supported */
__u32 stereo_widening:1;/* 0=Not Supported, 1=Supported */
__u32 rsvd1:21;
__u32 rsvd2;
};
/* Firmware capabilities info */
struct snd_sst_fw_info {
struct snd_sst_fw_version fw_version; /* Firmware version */
__u8 audio_codecs_supported[8]; /* Codecs supported by FW */
__u32 recommend_min_duration; /* Min duration for Lowpower Playback */
__u8 max_pcm_streams_supported; /* Max num of PCM streams supported */
__u8 max_enc_streams_supported; /* Max number of Encoded streams */
__u16 reserved; /* 32 bit alignment*/
struct snd_sst_ppp_info ppp_info; /* pre_processing mod cap info */
struct snd_sst_postproc_info pop_info; /* Post processing cap info*/
struct snd_sst_port_info port_info[3]; /* Port info */
struct snd_sst_mix_info mix_info;/* Mixer info */
__u32 min_input_buf; /* minmum i/p buffer for decode */
};
/* Codec params struture */
union snd_sst_codec_params {
struct snd_pcm_params pcm_params;
struct snd_mp3_params mp3_params;
struct snd_aac_params aac_params;
struct snd_wma_params wma_params;
};
struct snd_sst_stream_params {
union snd_sst_codec_params uc;
} __attribute__ ((packed));
struct snd_sst_params {
__u32 result;
__u32 stream_id;
__u8 codec;
__u8 ops;
__u8 stream_type;
__u8 device_type;
struct snd_sst_stream_params sparams;
};
struct snd_sst_vol {
__u32 stream_id;
__s32 volume;
__u32 ramp_duration;
__u32 ramp_type; /* Ramp type, default=0 */
};
struct snd_sst_mute {
__u32 stream_id;
__u32 mute;
};
/* ioctl related stuff here */
struct snd_sst_pmic_config {
__u32 sfreq; /* Sampling rate in Hz */
__u16 num_chan; /* Mono =1 or Stereo =2 */
__u16 pcm_wd_sz; /* Number of bits per sample */
} __attribute__ ((packed));
struct snd_sst_get_stream_params {
struct snd_sst_params codec_params;
struct snd_sst_pmic_config pcm_params;
};
enum snd_sst_target_type {
SND_SST_TARGET_PMIC = 1,
SND_SST_TARGET_LPE,
SND_SST_TARGET_MODEM,
SND_SST_TARGET_BT,
SND_SST_TARGET_FM,
SND_SST_TARGET_NONE,
};
enum snd_sst_device_type {
SND_SST_DEVICE_SSP = 1,
SND_SST_DEVICE_PCM,
SND_SST_DEVICE_OTHER,
};
enum snd_sst_device_mode {
SND_SST_DEV_MODE_PCM_MODE1 = 1, /*(16-bit word, bit-length frame sync)*/
SND_SST_DEV_MODE_PCM_MODE2,
SND_SST_DEV_MODE_PCM_MODE3,
SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED,
SND_SST_DEV_MODE_PCM_MODE4_LEFT_JUSTIFIED,
SND_SST_DEV_MODE_PCM_MODE4_I2S, /*(I2S mode, 16-bit words)*/
SND_SST_DEV_MODE_PCM_MODE5,
SND_SST_DEV_MODE_PCM_MODE6,
};
enum snd_sst_port_action {
SND_SST_PORT_PREPARE = 1,
SND_SST_PORT_ACTIVATE,
};
/* Target selection per device structure */
struct snd_sst_slot_info {
__u8 mix_enable; /* Mixer enable or disable */
__u8 device_type;
__u8 device_instance; /* 0, 1, 2 */
__u8 target_device;
__u16 target_sink;
__u8 slot[2];
__u8 master;
__u8 action;
__u8 device_mode;
__u8 reserved;
struct snd_sst_pmic_config pcm_params;
} __attribute__ ((packed));
#define SST_MAX_TARGET_DEVICES 3
/* Target device list structure */
struct snd_sst_target_device {
__u32 device_route;
struct snd_sst_slot_info devices[SST_MAX_TARGET_DEVICES];
} __attribute__ ((packed));
struct snd_sst_driver_info {
__u32 version; /* Version of the driver */
__u32 active_pcm_streams;
__u32 active_enc_streams;
__u32 max_pcm_streams;
__u32 max_enc_streams;
__u32 buf_per_stream;
};
enum snd_sst_buff_type {
SST_BUF_USER = 1,
SST_BUF_MMAP,
SST_BUF_RAR,
};
struct snd_sst_mmap_buff_entry {
unsigned int offset;
unsigned int size;
};
struct snd_sst_mmap_buffs {
unsigned int entries;
enum snd_sst_buff_type type;
struct snd_sst_mmap_buff_entry *buff;
};
struct snd_sst_buff_entry {
void *buffer;
unsigned int size;
};
struct snd_sst_buffs {
unsigned int entries;
__u8 type;
struct snd_sst_buff_entry *buff_entry;
};
struct snd_sst_dbufs {
unsigned long long input_bytes_consumed;
unsigned long long output_bytes_produced;
struct snd_sst_buffs *ibufs;
struct snd_sst_buffs *obufs;
};
struct snd_sst_tuning_params {
__u8 type;
__u8 str_id;
__u8 size;
__u8 rsvd;
__aligned_u64 addr;
} __attribute__ ((packed));
/*IOCTL defined here */
/*SST MMF IOCTLS only */
#define SNDRV_SST_STREAM_SET_PARAMS _IOR('L', 0x00, \
struct snd_sst_stream_params *)
#define SNDRV_SST_STREAM_GET_PARAMS _IOWR('L', 0x01, \
struct snd_sst_get_stream_params *)
#define SNDRV_SST_STREAM_GET_TSTAMP _IOWR('L', 0x02, __u64 *)
#define SNDRV_SST_STREAM_DECODE _IOWR('L', 0x03, struct snd_sst_dbufs *)
#define SNDRV_SST_STREAM_BYTES_DECODED _IOWR('L', 0x04, __u64 *)
#define SNDRV_SST_STREAM_START _IO('A', 0x42)
#define SNDRV_SST_STREAM_DROP _IO('A', 0x43)
#define SNDRV_SST_STREAM_DRAIN _IO('A', 0x44)
#define SNDRV_SST_STREAM_PAUSE _IOW('A', 0x45, int)
#define SNDRV_SST_STREAM_RESUME _IO('A', 0x47)
#define SNDRV_SST_MMAP_PLAY _IOW('L', 0x05, struct snd_sst_mmap_buffs *)
#define SNDRV_SST_MMAP_CAPTURE _IOW('L', 0x06, struct snd_sst_mmap_buffs *)
/*SST common ioctls */
#define SNDRV_SST_DRIVER_INFO _IOR('L', 0x10, struct snd_sst_driver_info *)
#define SNDRV_SST_SET_VOL _IOW('L', 0x11, struct snd_sst_vol *)
#define SNDRV_SST_GET_VOL _IOW('L', 0x12, struct snd_sst_vol *)
#define SNDRV_SST_MUTE _IOW('L', 0x13, struct snd_sst_mute *)
/*AM Ioctly only */
#define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *)
#define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \
struct snd_sst_target_device *)
/*DSP Ioctls on /dev/intel_sst_ctrl only*/
#define SNDRV_SST_SET_ALGO _IOW('L', 0x30, struct snd_ppp_params *)
#define SNDRV_SST_GET_ALGO _IOWR('L', 0x31, struct snd_ppp_params *)
#define SNDRV_SST_TUNING_PARAMS _IOW('L', 0x32, struct snd_sst_tuning_params *)
#endif /* __INTEL_SST_IOCTL_H__ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
#ifndef __INTELMID_SND_CTRL_H__
#define __INTELMID_SND_CTRL_H__
/*
* intelmid_snd_control.h - Intel Sound card driver for MID
*
* Copyright (C) 2008-10 Intel Corporation
* Authors: Vinod Koul <vinod.koul@intel.com>
* Harsha Priya <priya.harsha@intel.com>
* Dharageswari R <dharageswari.r@intel.com>
* KP Jeeja <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This file defines all snd control functions
*/
/*
Mask bits
*/
#define MASK0 0x01 /* 0000 0001 */
#define MASK1 0x02 /* 0000 0010 */
#define MASK2 0x04 /* 0000 0100 */
#define MASK3 0x08 /* 0000 1000 */
#define MASK4 0x10 /* 0001 0000 */
#define MASK5 0x20 /* 0010 0000 */
#define MASK6 0x40 /* 0100 0000 */
#define MASK7 0x80 /* 1000 0000 */
/*
value bits
*/
#define VALUE0 0x01 /* 0000 0001 */
#define VALUE1 0x02 /* 0000 0010 */
#define VALUE2 0x04 /* 0000 0100 */
#define VALUE3 0x08 /* 0000 1000 */
#define VALUE4 0x10 /* 0001 0000 */
#define VALUE5 0x20 /* 0010 0000 */
#define VALUE6 0x40 /* 0100 0000 */
#define VALUE7 0x80 /* 1000 0000 */
#define MUTE 0 /* ALSA Passes 0 for mute */
#define UNMUTE 1 /* ALSA Passes 1 for unmute */
#define MAX_VOL_PMIC_VENDOR0 0x3f /* max vol in dB for stereo & voice DAC */
#define MIN_VOL_PMIC_VENDOR0 0 /* min vol in dB for stereo & voice DAC */
/* Head phone volume control */
#define MAX_HP_VOL_PMIC_VENDOR1 6 /* max volume in dB for HP */
#define MIN_HP_VOL_PMIC_VENDOR1 (-84) /* min volume in dB for HP */
#define MAX_HP_VOL_INDX_PMIC_VENDOR1 40 /* Number of HP volume control values */
/* Mono Earpiece Volume control */
#define MAX_EP_VOL_PMIC_VENDOR1 0 /* max volume in dB for EP */
#define MIN_EP_VOL_PMIC_VENDOR1 (-75) /* min volume in dB for EP */
#define MAX_EP_VOL_INDX_PMIC_VENDOR1 32 /* Number of EP volume control values */
int sst_sc_reg_access(struct sc_reg_access *sc_access,
int type, int num_val);
extern struct snd_pmic_ops snd_pmic_ops_fs;
extern struct snd_pmic_ops snd_pmic_ops_mx;
extern struct snd_pmic_ops snd_pmic_ops_nc;
extern struct snd_pmic_ops snd_msic_ops;
/* device */
enum SND_INPUT_DEVICE {
AMIC,
DMIC,
HS_MIC,
IN_UNDEFINED
};
enum SND_LINE_OUT_DEVICE {
HEADSET,
IHF,
VIBRA1,
VIBRA2,
NONE,
};
enum SND_OUTPUT_DEVICE {
STEREO_HEADPHONE,
MONO_EARPIECE,
INTERNAL_SPKR,
RECEIVER,
OUT_UNDEFINED
};
enum pmic_controls {
PMIC_SND_HP_MIC_MUTE = 0x0001,
PMIC_SND_AMIC_MUTE = 0x0002,
PMIC_SND_DMIC_MUTE = 0x0003,
PMIC_SND_CAPTURE_VOL = 0x0004,
/* Output controls */
PMIC_SND_LEFT_PB_VOL = 0x0010,
PMIC_SND_RIGHT_PB_VOL = 0x0011,
PMIC_SND_LEFT_HP_MUTE = 0x0012,
PMIC_SND_RIGHT_HP_MUTE = 0x0013,
PMIC_SND_LEFT_SPEAKER_MUTE = 0x0014,
PMIC_SND_RIGHT_SPEAKER_MUTE = 0x0015,
PMIC_SND_RECEIVER_VOL = 0x0016,
PMIC_SND_RECEIVER_MUTE = 0x0017,
PMIC_SND_LEFT_MASTER_VOL = 0x0018,
PMIC_SND_RIGHT_MASTER_VOL = 0x0019,
/* Other controls */
PMIC_SND_MUTE_ALL = 0x0020,
PMIC_MAX_CONTROLS = 0x0020,
};
#endif /* __INTELMID_SND_CTRL_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册