From c3cccfca9868aaf6e67a77c46a859a18d6384492 Mon Sep 17 00:00:00 2001
From: R, Dharageswari <dharageswari.r@intel.com>
Date: Thu, 29 Apr 2010 20:14:06 +0530
Subject: [PATCH] ADR-Post-Beta-0.05.002.03-1/8-Adding Moorestown Audio Drivers - SST driver

This patch is the first patch in the series of eight patches which add up SST
driver and MAD driver. The SST driver is a driver for the SST DSP engine.This
patch adds the SST driver main file intel_sst.c which contains the init, exit,
probe, interrupt routine, as well as PCI suspend and resume implementations.
intel_sst_dsp.c file implements the SST FW initialization as well as FW and
library download steps.This patch also contains the intel_lpe.h header file
which is placed in include folder for MAD driver (ALSA Sound card driver for
Moorestown given in patch 7/8) to use. This file contains the definition of
interfaces exposed by SST drivers along with definition of all the controls
for the sound card to be used by MAD Driver

Signed-off-by: Vinod Koul <vinod.koul@intel.com>

	new file:   include/sound/intel_lpe.h
	new file:   sound/pci/sst/intel_sst.c
	new file:   sound/pci/sst/intel_sst_dsp.c
Patch-mainline: 2.6.35?
---
 include/sound/intel_lpe.h     |  148 +++++++++
 sound/pci/sst/intel_sst.c     |  527 ++++++++++++++++++++++++++++++
 sound/pci/sst/intel_sst_dsp.c |  706 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1381 insertions(+), 0 deletions(-)
 create mode 100644 include/sound/intel_lpe.h
 create mode 100644 sound/pci/sst/intel_sst.c
 create mode 100644 sound/pci/sst/intel_sst_dsp.c

diff --git a/include/sound/intel_lpe.h b/include/sound/intel_lpe.h
new file mode 100644
index 0000000..70e7a1f
--- /dev/null
+++ b/include/sound/intel_lpe.h
@@ -0,0 +1,148 @@
+#ifndef __INTEL_SST_H__
+#define __INTEL_SST_H__
+/*
+ *  intel_lpe.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
+ */
+
+#define SST_CARD_NAMES "intel_mid_card"
+
+/* 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,
+
+};
+
+struct pcm_stream_info {
+	int str_id;
+	void *mad_substream;
+	void (*period_elapsed) (void *mad_substream);
+	unsigned long long buffer_ptr;
+	int sfreq;
+};
+
+struct stream_buffer {
+	unsigned long	addr;
+	int		length;
+};
+
+static inline long sst_get_time(void)
+{
+	 struct timeval t;
+	 do_gettimeofday(&t);
+	 return t.tv_usec;
+}
+
+#ifndef CONFIG_SND_AUDIO_DBG_PRINT
+#define printk(format, arg...) do {} while (0);
+#endif
+
+struct snd_pmic_ops {
+	int card_status;
+	int num_channel;
+	int input_dev_id;
+	int mute_status;
+	int output_dev_id;
+	int (*set_input_dev) (u8 value);
+	int (*set_output_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, u8 value);
+	int (*get_vol) (int dev_id, u8 *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) (void);
+	int (*power_down_pmic_cp) (void);
+	int (*power_down_pmic) (void);
+};
+
+struct intel_sst_card_ops {
+	char *module_name;
+	int  vendor_id;
+	int (*control_set) (int control_element, void *value);
+	int (*send_buffer) (int str_id, struct stream_buffer *mad_buf);
+	struct snd_pmic_ops *scard_ops;
+};
+
+/* periphral interrupt interface */
+enum lpe_periphral {
+	LPE_DMA = 1,
+	LPE_SSP0,
+	LPE_SSP1
+};
+
+/* 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);
+int lpe_mask_periphral_intr(enum lpe_periphral device);
+int lpe_unmask_periphral_intr(enum lpe_periphral device);
+int lpe_periphral_intr_status(enum lpe_periphral device, int *status);
+#endif /* __INTEL_SST_H__ */
diff --git a/sound/pci/sst/intel_sst.c b/sound/pci/sst/intel_sst.c
new file mode 100644
index 0000000..c6e68b8
--- /dev/null
+++ b/sound/pci/sst/intel_sst.c
@@ -0,0 +1,527 @@
+/*
+ *  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
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#ifdef CONFIG_MSTWN_POWER_MGMT
+#include <linux/intel_mid.h>
+#endif
+#include <sound/intel_lpe.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_DESCRIPTION("Intel (R) Moorestown Audio Engine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SST_DRIVER_VERSION);
+
+struct intel_sst_drv *sst_drv_ctx;
+
+/* 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,
+	.ioctl = intel_sst_ioctl,
+	.mmap = intel_sst_mmap,
+	.aio_read = intel_sst_aio_read,
+	.aio_write = intel_sst_aio_write,
+};
+
+spinlock_t pe_slock;
+unsigned int pe_inprogress = 0;
+
+/**
+* intel_sst_interrupt - Interrupt service routine for SST
+* @irq:		irq number of interrupt
+* @dev_id:	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;
+	int str_id;
+        struct stream_info *stream ;
+
+
+	/* Interrupt arrived, check src */
+	isr.full = readl(drv->shim + SST_ISRX);
+
+	if (isr.part.busy_interrupt) {
+		header.full = readl(drv->shim + SST_IPCD);
+		if (header.part.large)
+			size = header.part.data;
+		if (header.part.msg_id & REPLY_MSG) {
+			sst_drv_ctx->ipc_process_msg.header = header;
+
+			if (header.part.msg_id == IPC_SST_PERIOD_ELAPSED) {
+		   	  	sst_clear_interrupt();
+
+                                /*spin_lock(&pe_slock);*/
+                                if (pe_inprogress == 1) {
+                                        /*spin_unlock(&pe_slock);*/
+                                        return IRQ_HANDLED;
+                                }
+
+                                pe_inprogress = 1;
+                                //spin_unlock(&pe_slock);
+
+			        str_id = header.part.str_id;
+                                stream = &sst_drv_ctx->streams[str_id];
+				if (stream->period_elapsed)
+					stream->period_elapsed(stream->pcm_substream);
+                                //spin_lock(&pe_slock);
+                                pe_inprogress = 0;
+                                //spin_unlock(&pe_slock);
+				return IRQ_HANDLED;
+			} else {
+				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 = readl(drv->shim + SST_IMRX);
+		imr.part.busy_interrupt = 1;
+		/* dummy register for shim workaround */
+		writel(imr.full, sst_drv_ctx->shim + SST_ISRD);
+		writel(imr.full, drv->shim + SST_IMRX);
+		return IRQ_HANDLED;
+	} else if (isr.part.done_interrupt) {
+		/* Clear done bit */
+		header.full = readl(drv->shim + SST_IPCX);
+		header.part.done = 0;
+		/* dummy register for shim workaround */
+		writel(header.full, sst_drv_ctx->shim + SST_ISRD);
+		writel(header.full, drv->shim + SST_IPCX);
+		/* write 1 to clear status register */;
+		isr.part.done_interrupt = 1;
+		/* dummy register for shim workaround */
+		writel(isr.full, sst_drv_ctx->shim + SST_ISRD);
+		writel(isr.full, drv->shim + SST_ISRX);
+		queue_work(sst_drv_ctx->post_msg_wq,
+			&sst_drv_ctx->ipc_post_msg.wq);
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+
+}
+
+
+/* PCI Routines */
+
+static struct pci_device_id intel_sst_ids[] = {
+	{ 0x8086, 0x080A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, intel_sst_ids);
+
+
+/*
+* 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;
+	static struct mutex drv_ctx_lock;
+	mutex_init(&drv_ctx_lock);
+
+	mutex_lock(&drv_ctx_lock);
+	if (sst_drv_ctx) {
+		printk(KERN_ERR
+		"SST 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) {
+		printk(KERN_ERR
+		"SST ERR: intel_sst malloc fail\n");
+			mutex_unlock(&drv_ctx_lock);
+		return -ENOMEM;
+	}
+	mutex_unlock(&drv_ctx_lock);
+
+	mutex_init(&sst_drv_ctx->stream_cnt_lock);
+	sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
+
+	mutex_lock(&sst_drv_ctx->stream_cnt_lock);
+	sst_drv_ctx->stream_cnt = 0;
+	sst_drv_ctx->encoded_cnt = 0;
+	sst_drv_ctx->am_cnt = 0;
+	mutex_unlock(&sst_drv_ctx->stream_cnt_lock);
+	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;
+	}
+	mutex_init(&sst_drv_ctx->list_lock);
+
+	for (i = 1; i < MAX_NUM_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);
+	}
+	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) {
+			printk(KERN_DEBUG "SST DBG:Got memory %p size 0x%x \n",
+				sst_drv_ctx->mmap_mem,
+				sst_drv_ctx->mmap_len);
+			break;
+		}
+		sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
+		if (sst_drv_ctx->mmap_len <= 0) {
+			printk(KERN_ERR
+			"SST ERR: Couldnt get any +\
+			mem...abort!!\n");
+			ret = -ENOMEM;
+			goto free_process_reply_wq;
+		}
+		printk(KERN_DEBUG "SST DBG:Failed...trying %d\n", \
+		sst_drv_ctx->mmap_len);
+	}
+
+	/* Init the device */
+	ret = pci_enable_device(pci);
+	if (ret) {
+		printk(KERN_ERR
+		"SST ERR: device cant 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 =
+			(unsigned long) pci_resource_start(pci, 1);
+	sst_drv_ctx->shim = pci_ioremap_bar(pci, 1);
+	if (!sst_drv_ctx->shim)
+		goto do_release_regions;
+	printk(KERN_DEBUG "SST DBG: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;
+	printk(KERN_DEBUG "SST DBG: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;
+	printk(KERN_DEBUG "SST DBG: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;
+	printk(KERN_DEBUG "SST DBG:DRAM Ptr %p \n", sst_drv_ctx->dram);
+
+	sst_drv_ctx->sst_state = SST_UN_INIT;
+	/* 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;
+	printk(KERN_DEBUG "SST DBG:Registered IRQ 0x%x\n", pci->irq);
+
+	/* Register with /dev */
+	ret = register_chrdev(INTEL_SST_MAJOR, SST_DRV_NAME, &intel_sst_fops);
+	if (ret) {
+		printk(KERN_ERR
+		"SST ERR: couldn't register +\
+		device number\n");
+		goto do_free_irq;
+	}
+
+    sst_drv_ctx->lpe_stalled = 0;
+	printk(KERN_DEBUG "SST DBG:...successfully done!!!\n");
+	return ret;
+
+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);
+	printk(KERN_ERR
+	"SST ERR: Probe failed with 0x%x \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)
+{
+	pci_dev_put(sst_drv_ctx->pci);
+	sst_drv_ctx->sst_state = SST_UN_INIT;
+	unregister_chrdev(INTEL_SST_MAJOR, SST_DRV_NAME);
+	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;
+	kfree(sst_drv_ctx->mmap_mem);
+	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(sst_drv_ctx);
+	pci_release_region(pci, 2);
+	pci_release_region(pci, 3);
+	pci_release_region(pci, 4);
+	pci_release_region(pci, 5);
+	pci_set_drvdata(pci, NULL);
+}
+
+/* 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
+*/
+static int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
+{
+	int i;
+	printk(KERN_DEBUG "SST DBG:intel_sst_suspend called\n");
+
+	/* Pause all running streams */
+	for (i = 1; i < MAX_NUM_STREAMS; i++) {
+		if (sst_drv_ctx->streams[i].status == STREAM_RUNNING) {
+			sst_drv_ctx->active_streams[i] = true;
+			sst_pause_stream(i);
+		} else
+			sst_drv_ctx->active_streams[i] = false;
+	}
+
+	pci_set_drvdata(pci, sst_drv_ctx);
+
+	/* Send msg to FW FIXME */
+
+	/* Disable everything */
+	/* free_irq(pci->irq, sst_drv_ctx); */
+	pci_disable_device(pci);
+	pci_save_state(pci);
+	pci_set_power_state(pci, pci_choose_state(pci, state));
+	return 0;
+}
+
+/**
+* intel_sst_resume - PCI resume function
+* @pci:		PCI device structure
+* @state:	PM message
+*
+* This function is called by OS when a power event occurs
+*/
+static int intel_sst_resume(struct pci_dev *pci)
+{
+	int i;
+
+	printk(KERN_DEBUG "SST DBG:\nintel_sst_resume called\n");
+	sst_drv_ctx = pci_get_drvdata(pci);
+	if (pci->irq)
+		printk(KERN_DEBUG "SST DBG:irq %d \n", pci->irq);
+
+	pci_set_power_state(pci, PCI_D0);
+	pci_restore_state(pci);
+
+	/* ret = request_irq(pci->irq, intel_sst_interrupt,
+		IRQF_SHARED, "intel_sst_engine", sst_drv_ctx);
+	if (ret) {
+		return ret;
+	} */
+
+	/* Send msg to FW FIXME */
+
+	/* Start all paused streams */
+	for (i = 1; i < MAX_NUM_STREAMS; i++) {
+		if (sst_drv_ctx->active_streams[i] == true)
+			sst_resume_stream(i);
+	}
+	return 0;
+}
+
+
+static struct pci_driver driver = {
+	.name = SST_DRV_NAME,
+	.id_table = intel_sst_ids,
+	.probe = intel_sst_probe,
+	.remove = __devexit_p(intel_sst_remove),
+	.suspend = intel_sst_suspend,
+	.resume = intel_sst_resume,
+};
+
+/**
+* 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;
+	printk(KERN_ERR
+	"INFO: ******** SST DRIVER +\
+	loading.. Ver: %s\n", SST_DRIVER_VERSION);
+
+	/* Register with PCI */
+	ret = pci_register_driver(&driver);
+	if (ret)
+		printk(KERN_ERR
+		"SST ERR: PCI register failed \n");
+	sst_spi_mode_enable();
+	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)
+{
+	int i;
+
+	for (i = 0; i < MAX_NUM_STREAMS; i++)
+		sst_free_stream(i);
+
+	/* Send msg to FW TBD */
+	pci_unregister_driver(&driver);
+
+	flush_scheduled_work();
+	printk(KERN_DEBUG "SST DBG:...unloaded\n");
+	return;
+}
+
+module_init(intel_sst_init);
+module_exit(intel_sst_exit);
diff --git a/sound/pci/sst/intel_sst_dsp.c b/sound/pci/sst/intel_sst_dsp.c
new file mode 100644
index 0000000..bc78918
--- /dev/null
+++ b/sound/pci/sst/intel_sst_dsp.c
@@ -0,0 +1,706 @@
+/*
+ *  intel_sst_dsp.h - 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
+ */
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/ipc_defs.h>
+#include <sound/intel_lpe.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_DESCRIPTION("Intel (R) Moorestown Audio Engine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SST_DRIVER_VERSION);
+
+/**
+* this function writes registers through SCU IPC
+*/
+static int sst_scu_ipc_write(u32 addr, u32 value)
+{
+	int retval = 0, retry = 3;
+	struct ipc_reg_data ipc_reg = {0};
+
+	ipc_reg.address = addr;
+	ipc_reg.data = value;
+	ipc_reg.ioc = 1;
+
+	while (retry) {
+		retval = mrst_ipc_write32(&ipc_reg);
+		if (!retval)
+			break;
+		retry--;
+		/* error */
+		printk(KERN_ERR "SST ERR: IPC +\
+			write failed %x\n", retval);
+	}
+	return retval;
+}
+
+/**
+* this function reads registers through SCU IPC
+*/
+static int sst_scu_ipc_read(u32 addr, u32 *value)
+{
+	int retval = 0, retry = 3;
+	struct ipc_reg_data ipc_reg = {0};
+
+	ipc_reg.address = addr;
+	ipc_reg.data = 0;
+	ipc_reg.ioc = 1;
+
+	while (retry) {
+		retval = mrst_ipc_read32(&ipc_reg);
+		if (!retval)
+			break;
+		retry--;
+		printk(KERN_ERR
+			"SST ERR: IPC read failed %x\n ", retval);
+	}
+	*value = ipc_reg.data;
+	printk(KERN_DEBUG "SST DBG:The read value +\
+		from the mrst_ipc is ::0x%08x\n", *value);
+	return retval;
+}
+/**
+* Resetting SST DSP
+*/
+static int intel_sst_reset_dsp(void)
+{
+	union config_status_reg csr;
+	int retval;
+	unsigned int value = 0;
+
+	retval = sst_scu_ipc_read(CHIP_REV_REG, &value);
+	if (retval)
+		return retval;
+
+#if 0
+	/* A2-CHANGES */
+	if (((value & CHIP_REV_ADDR) >> 3) == CHIP_REV_A1) {
+		sst_drv_ctx->chip_rev_id = CHIP_A1_50;
+	/* SCU FW Changes*/
+		retval = sst_scu_ipc_write(AUD_SHIM_BASE_ADDR,
+				AUD_SHIM_RATIO_1_1);
+	} else {
+		if (DSP_CLOCK_SPEED == CLK_100MHZ) {
+			sst_drv_ctx->chip_rev_id = CHIP_A2_100;
+	/* SCU FW Changes*/
+			retval = sst_scu_ipc_write(AUD_SHIM_BASE_ADDR,
+				AUD_SHIM_RATIO);
+		} else if (DSP_CLOCK_SPEED == CLK_50MHZ) {
+			sst_drv_ctx->chip_rev_id = CHIP_A2_50;
+	/* SCU FW Changes*/
+
+			retval = sst_scu_ipc_write(AUD_SHIM_BASE_ADDR,
+				AUD_SHIM_RATIO_1_1);
+		} else {
+			printk(KERN_ERR "SST ERR: +\
+				Invalid clock speed\n ");
+			return -EIO;
+		}
+	} /*else {
+		printk(KERN_ERR
+		"SST ERR: Invalid chip revision Type\n");
+		return -EIO;
+	}*/
+#endif
+	/* to fix SPI driver bug, which sets to 1 */
+	csr.full = 0x3a2;
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+	/* ----------- */
+
+	csr.full = readl(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;
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+
+	printk(KERN_DEBUG "SST DBG:Chip version +\
+		is:: %d\n", value);
+	return retval;
+}
+
+/**
+* Start the SST DSP processor
+*/
+static int sst_start(void)
+{
+	union config_status_reg csr;
+
+	csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+	csr.part.bypass = 0;
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+
+#if 0
+	retval = sst_scu_ipc_write(
+			sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
+	if (retval != 0)
+		printk(KERN_ERR
+			"SST ERR: scu ipc write start failed %d ", retval);
+	csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+	csr.part.sst_reset = 0;
+	csr.part.run_stall = 0;
+	if ((sst_drv_ctx->chip_rev_id == CHIP_A2_50) ||
+			(sst_drv_ctx->chip_rev_id == CHIP_A2_100)) {
+		csr.part.strb_cntr_rst = 1;
+		if (sst_drv_ctx->chip_rev_id == CHIP_A2_100)
+			csr.part.sst_clk = 1;
+	}
+#endif
+	csr.part.run_stall = 0;
+	csr.part.sst_reset = 0;
+	csr.part.strb_cntr_rst = 1;
+	printk(KERN_DEBUG "SST DBG:Setting SST to execute 0x%x \n", csr.full);
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+
+#if 0
+	return sst_scu_ipc_write(
+			sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
+#endif
+	return 0;
+}
+
+/**
+* Parse modules that need to be placed in SST IRAM and DRAM
+*/
+static int sst_parse_module(struct fw_module_header *module)
+{
+	struct dma_block_info *block;
+	u32 count;
+	void __iomem *ram;
+
+	printk(KERN_DEBUG "SST DBG:module sign=%s sz=0x%x blks=0x%x typ=0x%x ep=0x%x sz=0x%x\n",
+			module->signature, module->mod_size,
+			module->blocks, module->type,
+			module->entry_point, sizeof(*module));
+
+	block = (void *)module + sizeof(*module);
+
+	for (count = 0; count < module->blocks; count++) {
+		if (block->size <= 0) {
+			printk(KERN_ERR "SST 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:
+			printk(KERN_ERR
+				"SST ERR:wrng ram typ0x%x +\
+				inblock0x%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 - FW parse and load
+* 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 */
+		printk(KERN_ERR
+			"SST ERR: InvalidFW sgn/filesiz mismtch\n ");
+		return -EINVAL;
+	}
+	printk(KERN_DEBUG "SST DBG:header sign=%s size=0x%x modules=0x%x fmt=0x%x size=0x%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 ;
+	}
+
+	printk(KERN_DEBUG "SST DBG:done....\n");
+	return 0;
+}
+
+/**
+* sst_load_fw - function to reset FW
+* @fw:		Pointer to loaded FW
+* This function is called when the FW is loaded
+*/
+int sst_load_fw(const struct firmware *fw, void *context)
+{
+	int ret_val;
+
+	printk(KERN_DEBUG "SST DBG:called \n");
+	BUG_ON(!fw);
+
+	/* TBD: Checksum, tamper check etc */
+	ret_val = intel_sst_reset_dsp();
+	if (ret_val)
+		return ret_val;
+	/* putting the sst state to init */
+	sst_drv_ctx->sst_state = SST_UN_INIT;
+
+	ret_val = sst_parse_fw_image(fw);
+	if (ret_val)
+		return ret_val;
+
+	sst_drv_ctx->sst_state = SST_FW_LOADED;
+	/*  7. ask scu to reset the bypass bits */
+	/*  8.bring sst out of reset  */
+	ret_val = sst_start();
+	if (ret_val)
+		return ret_val;
+
+	printk(KERN_DEBUG "SST DBG:...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);
+	printk(KERN_DEBUG "SST DBG: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, 0);
+	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));
+	mutex_lock(&sst_drv_ctx->list_lock);
+	list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+	mutex_unlock(&sst_drv_ctx->list_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;
+		printk(KERN_ERR
+			"SST ERR: Prep codec downloaded failed %d\n", retval);
+		return -EIO;
+	}
+	printk(KERN_DEBUG "SST DBG:FW responded, ready for download now...\n");
+	/* downloading on success */
+	sst_drv_ctx->sst_state = SST_FW_LOADED;
+	csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+	printk(KERN_DEBUG "SST DBG:CSR reg 0x%x \n", csr.full);
+	csr.part.run_stall = 1;
+	printk(KERN_DEBUG "SST DBG:HALT CSR reg setting to 0x%x \n", csr.full);
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+#if 0
+	retval = sst_scu_ipc_write(
+			sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
+	if (retval) {
+		/* error */
+		sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+		printk(KERN_ERR
+			"SST ERR: IPC failed to Halt SST 0x%x\n", retval);
+		return -EAGAIN;
+	}
+#endif
+	csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+	csr.part.bypass = 0x7;
+	printk(KERN_DEBUG "SST DBG:Bypass CSR reg +\
+		setting to 0x%x \n", csr.full);
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+#if 0
+	retval = sst_scu_ipc_write(
+			sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
+	if (retval) {
+		/* error */
+		sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+		printk(KERN_ERR
+			"SST ERR: IPC failed to Bypass SST 0x%x\n", retval);
+		csr.part.bypass = 0x0;
+		/* bring LPE out of run stall */
+		/* send error mesages to FW- TBD FIXME */
+		csr.part.run_stall = 0x0;
+		printk(KERN_DEBUG "SST DBG:Bypass CSR reg +\
+			setting to 0x%x \n", csr.full);
+		retval = sst_scu_ipc_write(sst_drv_ctx->shim_phy_add + SST_CSR,
+			       csr.full);
+		if (retval) {
+			/* prepare to download firmware again
+			for the next time TBD FIXME
+			sst_drv_ctx->sst_state = SST_UN_INIT;*/
+		}
+		return -EAGAIN;
+	}
+#endif
+	sst_parse_fw_image(fw_lib);
+
+	/* set the FW to running again */
+	csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+	csr.part.bypass = 0x0;
+	printk(KERN_DEBUG "SST DBG:Bypass CSR reg +\
+			setting to 0x%x \n", csr.full);
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+#if 0
+	retval = sst_scu_ipc_write(
+			sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
+	if (retval) {
+		sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+		printk(KERN_ERR\
+			"SST ERR: BypassCSR regclear failed 0x%x\n", retval);
+		/* bring LPE out of run stall */
+		/* send error mesages to FW- TBD FIXME */
+		csr.part.run_stall = 0x0;
+		printk(KERN_DEBUG "SST DBG:Bypass CSR +\
+			reg setting to 0x%x \n", csr.full);
+		retval = sst_scu_ipc_write(sst_drv_ctx->shim_phy_add + SST_CSR,
+			       csr.full);
+		if (retval) {
+			/* prepare to download firmware again
+			for the next time TBD FIXME
+			sst_drv_ctx->sst_state = SST_UN_INIT;*/
+		}
+		return -EAGAIN;
+	}
+#endif
+	csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+	csr.part.run_stall = 0;
+	printk(KERN_DEBUG "SST DBG:Stalll CSR reg +\
+			setting to 0x%x \n", csr.full);
+	writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
+	writel(csr.full, sst_drv_ctx->shim + SST_CSR);
+#if 0
+	retval = sst_scu_ipc_write(
+			sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
+	if (retval) {
+		sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+		printk(KERN_ERR
+			"SST ERR: Stall CSR reg clear failed 0x%x \n", retval);
+		if (retval) {
+			/* prepare to download firmware again
+			for the next time TBD FIXME
+			sst_drv_ctx->sst_state = SST_UN_INIT;*/
+		}
+		return -EAGAIN;
+	}
+#endif
+	/* 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, 0);
+	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));
+	mutex_lock(&sst_drv_ctx->list_lock);
+	list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+	mutex_unlock(&sst_drv_ctx->list_lock);
+	sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+	printk(KERN_DEBUG "SST DBG:Waiting for FW to respond on 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 */
+		sst_drv_ctx->sst_state = SST_FW_RUNNING;
+		/* shouldnt we set it to error state??? TBD */
+		sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+		return -EIO;
+	}
+
+	printk(KERN_DEBUG "SST DBG:FW responded sucess on Download complete \n");
+	sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+	sst_drv_ctx->sst_state = SST_FW_RUNNING;
+	return 0;
+
+}
+
+/**
+* This function is called befoer 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) {
+		printk(KERN_ERR\
+			"SST ERR: Module no mismatch found\n ");
+		err = -EINVAL;
+		goto exit;
+	}
+	module = (void *)fw_lib->data + sizeof(*header);
+	*entry_point = module->entry_point;
+	printk(KERN_DEBUG "SST DBG:Module entry point 0x%x \n", *entry_point);
+	printk(KERN_DEBUG "SST DBG: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:
+			printk(KERN_ERR
+				"SST ERR: Invalid blk 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) {
+		printk(KERN_ERR
+			"SST ERR: library exceeds size allocated \n");
+		err = -EINVAL;
+		goto exit;
+	} else
+		printk(KERN_DEBUG "SST DBG:Library is safe for download...\n");
+
+	printk(KERN_DEBUG "SST DBG:iram 0x%x, dram 0x%x, allowed iram 0x%x, allowed 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 libary download
+* This function prepares the library to download
+*/
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops, u32 pvt_id)
+{
+	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));
+
+	printk(KERN_DEBUG "SST DBG:Lib Type 0x%x, Slot 0x%x, ops 0x%x \n",
+			lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
+	printk(KERN_DEBUG "SST DBG: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);
+
+	printk(KERN_DEBUG "SST DBG:IRAM Size 0x%x, offset 0x%x, DRAM Size 0x%x, offset 0x%x \n",
+		lib->slot_info.iram_size, lib->slot_info.iram_offset,
+		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:
+		printk(KERN_ERR "SST ERR: +\
+			Invalid codec type \n");
+		error = -EINVAL;
+		goto wake;
+	}
+
+	if (ops == STREAM_OPS_CAPTURE)
+		dir = "enc_";
+	else
+		dir = "dec_";
+	strncpy(buf, type, strlen(type));
+	strncpy(buf + strlen(type), dir, strlen(dir));
+	len = strlen(type) + strlen(dir);
+	len += snprintf(buf + len, sizeof(buf) - len, "%d",
+			lib->slot_info.slot_num);
+	len += snprintf(buf + len, sizeof(buf) - len, ".bin");
+
+	printk(KERN_DEBUG "SST DBG:Requesting %s \n", buf);
+
+	error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
+	if (error) {
+		printk(KERN_ERR
+			"SST 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 */
+	printk(KERN_DEBUG "SST DBG: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;
+}
+
+/* This Function set the bit banging*/
+int sst_spi_mode_enable()
+{
+
+   void __iomem *logical_ptr_to_bang;
+   u32 regbase = SPI_MODE_ENABLE_BASE_ADDR, range = 0x38;
+   u32 data;
+   u32 mask = 0x400000;
+   int retval;
+   int i = 0;
+
+
+   logical_ptr_to_bang = ioremap_nocache(regbase, range);
+   if (!logical_ptr_to_bang) {
+		dev_err(&sst_drv_ctx->pci->dev, \
+			"SST ERR: SSP0 bit bang -IOREMAP Failed \n");
+		return -1;
+   }
+
+    /* spi mode enable */
+   iowrite32(0x0000000f, logical_ptr_to_bang);
+   iowrite32(0x33301dc3, logical_ptr_to_bang + 0x4);
+   iowrite32(0x02010007, logical_ptr_to_bang + 0x2c);
+   iowrite32(0x00000000, logical_ptr_to_bang + 0x30);
+   iowrite32(0x00000000, logical_ptr_to_bang + 0x34);
+   iowrite32(0x0000008f, logical_ptr_to_bang);
+
+
+   retval = sst_scu_ipc_write(0xff12b004, 0x3);
+   retval = sst_scu_ipc_write(0xff12b000, 0x01070034);
+   retval = sst_scu_ipc_write(0xff12b004, 0x99);
+   retval = sst_scu_ipc_write(0xff12b000, 0x01070038);
+
+   data = ioread32(logical_ptr_to_bang+0x8);
+   dev_err(&sst_drv_ctx->pci->dev,\
+	"SST ERR: SSP0 bit bang SSCR val = 0x%08x \n", data);
+   data = data & mask;
+   while (data == mask) {
+	retval = sst_scu_ipc_write(0xff12b004, 0x3);
+	retval = sst_scu_ipc_write(0xff12b000, 0x01070034);
+	retval = sst_scu_ipc_write(0xff12b004, 0x2);
+	retval = sst_scu_ipc_write(0xff12b000, 0x01070034);
+	data  = ioread32(logical_ptr_to_bang+0x8);
+	data  = data & mask;
+	i++;
+    }
+   dev_err(&sst_drv_ctx->pci->dev,  \
+	"SST ERR: SSP0 bit bang while loop counter= %4d \n ", i);
+   retval = sst_scu_ipc_write(0xff12b004, 0x0);
+   retval = sst_scu_ipc_write(0xff12b000, 0x01070038);
+
+   return retval;
+}
-- 
1.6.2.2

