예제 #1
0
/**
* 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);
    unregister_sst(&pci->dev);
    pci_dev_put(sst_drv_ctx->pci);
    sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
    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);
    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);
    }
    kfree(sst_drv_ctx->runtime_param.param.addr);
    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);
    release_firmware(sst_drv_ctx->fw);
    pm_qos_remove_request(sst_drv_ctx->qos);
    kfree(sst_drv_ctx->qos);
    sst_drv_ctx->fw = NULL;
    kfree(sst_drv_ctx->fw_sg_list.src);
    kfree(sst_drv_ctx->fw_sg_list.dst);
    sst_drv_ctx->fw_sg_list.list_len = 0;
    kfree(sst_drv_ctx->fw_in_mem);
    sst_drv_ctx->fw_in_mem = NULL;
    kfree(sst_drv_ctx);
    sst_drv_ctx = NULL;
    pci_release_regions(pci);
    pci_disable_device(pci);
    pci_set_drvdata(pci, NULL);
}
예제 #2
0
static int intel_sst_runtime_resume(struct device *dev)
{
    u32 csr;

    pr_debug("runtime_resume called\n");
    if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
        pr_err("SST is not in suspended state\n");
        return 0;
    }
    csr = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
    /*
     * To restore the csr_value after S0ix and S3 states.
     * The value 0x30000 is to enable LPE dram high and low addresses.
     * Reference:
     * Penwell Audio Voice Module HAS 1.61 Section - 13.12.1 -
     * CSR - Configuration and Status Register.
     */
    csr |= (sst_drv_ctx->csr_value | 0x30000);
    sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr);

    /* GPIO_PIN 12,13,74,75 needs to be configured in
     * ALT_FUNC_2 mode for SSP3 IOs
     */
    if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID) {
        lnw_gpio_set_alt(CLV_I2S_3_CLK_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_I2S_3_FS_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_I2S_3_TXD_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_I2S_3_RXD_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_VIBRA_PWM_GPIO_PIN, LNW_ALT_2);

        vibra_pwm_configure(true);
    }

    sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
    return 0;
}
/**
* intel_sst_remove - remove function
*
* @pdev:	platform device structure
*
* This function is called by OS when a device is unloaded
* This frees the interrupt etc
*/
int sst_acpi_remove(struct platform_device *pdev)
{
	struct intel_sst_drv *ctx;

	ctx = platform_get_drvdata(pdev);
	sst_debugfs_exit(ctx);
	pm_runtime_get_noresume(ctx->dev);
	pm_runtime_disable(ctx->dev);
	unregister_sst(ctx->dev);
	sst_set_fw_state_locked(ctx, SST_UN_INIT);
	misc_deregister(&lpe_ctrl);
	kfree(ctx->runtime_param.param.addr);
	flush_scheduled_work();
	sst_destroy_workqueue(ctx);
	kfree(ctx->fw_sg_list.src);
	kfree(ctx->fw_sg_list.dst);
	ctx->fw_sg_list.list_len = 0;
	kfree(ctx->fw_in_mem);
	ctx->fw_in_mem = NULL;
	sst_memcpy_free_resources();
	sst_drv_ctx = NULL;
	platform_set_drvdata(pdev, NULL);
	return 0;
}
예제 #4
0
/*
* 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);
    mutex_init(&sst_drv_ctx->mixer_ctrl_lock);

    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;
    sst_drv_ctx->fw = NULL;
    sst_drv_ctx->fw_in_mem = NULL;

    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_waitqueue_head(&sst_drv_ctx->wait_queue);

    sst_drv_ctx->mad_wq = create_singlethread_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->ipc_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);
        }
    }
    if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID) {
        sst_drv_ctx->device_input_mixer = SST_STREAM_DEVICE_IHF
                                          | SST_INPUT_STREAM_PCM;
    }

    /* 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_base = pci_resource_start(pci, 3);
    sst_drv_ctx->iram = pci_ioremap_bar(pci, 3);
    if (!sst_drv_ctx->iram)
        goto do_unmap_sram;
    pr_debug("IRAM Ptr %p\n", sst_drv_ctx->iram);

    /* DRAM */
    sst_drv_ctx->dram_base = pci_resource_start(pci, 4);
    sst_drv_ctx->dram = pci_ioremap_bar(pci, 4);
    if (!sst_drv_ctx->dram)
        goto do_unmap_iram;
    pr_debug("DRAM Ptr %p\n", sst_drv_ctx->dram);

    sst_set_fw_state_locked(sst_drv_ctx, SST_UN_INIT);
    /* Register the ISR */
    ret = request_threaded_irq(pci->irq, intel_sst_interrupt,
                               intel_sst_irq_thread, 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) ||
               (sst_drv_ctx->pci_id == SST_CLV_PCI_ID)) {
        u32 csr;
        u32 csr2;
        u32 clkctl;

        /*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 |= 0x30000;
        /*make sure clksel set to OSC for SSP0,1 (default)*/
        csr &= 0xFFFFFFF3;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr);

        /*set clock output enable for SSP0,1,3*/
        clkctl = sst_shim_read(sst_drv_ctx->shim, SST_CLKCTL);
        if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID)
            clkctl |= (0x7 << 16);
        else
            clkctl |= ((1<<16)|(1<<17));
        sst_shim_write(sst_drv_ctx->shim, SST_CLKCTL, clkctl);

        /* set SSP0 & SSP1 disable DMA Finish*/
        csr2 = sst_shim_read(sst_drv_ctx->shim, SST_CSR2);
        /*set SSP3 disable DMA finsh for SSSP3 */
        csr2 |= BIT(1)|BIT(2);
        sst_shim_write(sst_drv_ctx->shim, SST_CSR2, csr2);
    }

    /* GPIO_PIN 12,13,74,75 needs to be configured in
     * ALT_FUNC_2 mode for SSP3 IOs
     */
    if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID) {
        lnw_gpio_set_alt(CLV_I2S_3_CLK_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_I2S_3_FS_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_I2S_3_TXD_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_I2S_3_RXD_GPIO_PIN, LNW_ALT_2);
        lnw_gpio_set_alt(CLV_VIBRA_PWM_GPIO_PIN, LNW_ALT_2);

        vibra_pwm_configure(true);
    }

    sst_drv_ctx->lpe_stalled = 0;
    pci_set_drvdata(pci, sst_drv_ctx);
    pm_runtime_allow(&pci->dev);
    pm_runtime_put_noidle(&pci->dev);
    register_sst(&pci->dev);

    sst_drv_ctx->qos = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL);
    if (!sst_drv_ctx->qos)
        goto do_free_misc;
    pm_qos_add_request(sst_drv_ctx->qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);

    pr_info("%s successfully done!\n", __func__);
    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;
}
int __devinit sst_acpi_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	acpi_handle handle = ACPI_HANDLE(dev);
	struct acpi_device *device;
	const char *hid;
	int i, ret = 0;
	struct sst_probe_info *info;
	struct intel_sst_drv *ctx;

	ret = acpi_bus_get_device(handle, &device);
	if (ret) {
		pr_err("%s: could not get acpi device - %d\n", __func__, ret);
		return -ENODEV;
	}

	if (acpi_bus_get_status(device) || !device->status.present) {
		pr_err("%s: device has invalid status", __func__);
		return -ENODEV;
	}

	hid = acpi_device_hid(device);
	pr_debug("%s for %s", __func__, hid);
	ret = sst_alloc_drv_context(dev);
	if (ret)
		return ret;
	ctx = sst_drv_ctx;
	ctx->dev = dev;
	ctx->pci_id = SST_BYT_PCI_ID;

	/* need to save shim registers in BYT */
	ctx->shim_regs64 = devm_kzalloc(dev, sizeof(*ctx->shim_regs64),
					GFP_KERNEL);
	if (!ctx->shim_regs64)
		return -ENOMEM;


	ctx->use_32bit_ops = true;

	ret = sst_driver_ops(ctx);
	if (ret != 0)
		return -EINVAL;

	sst_init_locks(ctx);

	ctx->stream_cnt = 0;
	ctx->fw_in_mem = NULL;
	ctx->use_dma = 1;
	ctx->use_lli = 1;

	if (sst_workqueue_init(ctx))
		goto do_free_wq;

	info = sst_get_acpi_driver_data(hid);
	if (!info)
		return -EINVAL;

	memcpy(&ctx->info, info, sizeof(ctx->info));

	ctx->ipc_reg.ipcx = SST_PRH_IPCX;
	ctx->ipc_reg.ipcd = SST_PRH_IPCD;

	pr_debug("Got drv data max stream %d\n",
				ctx->info.max_streams);
	for (i = 1; i <= ctx->info.max_streams; i++) {
		struct stream_info *stream = &ctx->streams[i];
		mutex_init(&stream->lock);
	}

	ret = sst_platform_get_resources(ctx, pdev);
	if (ret)
		goto do_free_wq;

	/*Register LPE Control as misc driver*/
	ret = misc_register(&lpe_ctrl);
	if (ret) {
		pr_err("couldn't register control device\n");
		goto do_free_wq;
	}
	/* mask all SSP and DMA interrupts to IA - enable when needed */
	sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038);

	if (ctx->use_32bit_ops) {
		pr_debug("allocate mem for context save/restore\n ");
		/*allocate mem for fw context save during suspend*/
		ctx->fw_cntx = devm_kzalloc(ctx->dev, FW_CONTEXT_MEM, GFP_KERNEL);
		if (!ctx->fw_cntx) {
			ret = -ENOMEM;
			goto do_free_misc;
		}
		/*setting zero as that is valid mem to restore*/
		ctx->fw_cntx_size = 0;
	}

	platform_set_drvdata(pdev, ctx);
	pm_runtime_enable(dev);
	register_sst(dev);
	sst_debugfs_init(ctx);
	sst_set_fw_state_locked(ctx, SST_UN_INIT);
	sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
	pr_info("%s successfully done!\n", __func__);
	return ret;

do_free_misc:
	misc_deregister(&lpe_ctrl);
do_free_wq:
	sst_destroy_workqueue(ctx);

	sst_drv_ctx = NULL;
	platform_set_drvdata(pdev, NULL);
	pr_err("%s: failed with %d\n", __func__, ret);
	return ret;
}
int sst_acpi_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	acpi_handle handle = ACPI_HANDLE(dev);
	struct acpi_device *device;
	const char *hid;
	int i, ret = 0;
	struct intel_sst_drv *ctx;

	ret = acpi_bus_get_device(handle, &device);
	if (ret) {
		pr_err("%s: could not get acpi device - %d\n", __func__, ret);
		return -ENODEV;
	}

	if (acpi_bus_get_status(device) || !device->status.present) {
		pr_err("%s: device has invalid status", __func__);
		return -ENODEV;
	}

	hid = acpi_device_hid(device);
	pr_debug("%s for %s", __func__, hid);
	ret = sst_alloc_drv_context(dev);
	if (ret)
		return ret;
	ctx = sst_drv_ctx;
	ctx->dev = dev;
	ctx->hid = hid;

	ret = sst_platform_get_resources(hid, ctx, pdev);
	if (ret)
		return ret;
	/* need to save shim registers in BYT */
	ctx->shim_regs64 = devm_kzalloc(dev, sizeof(*ctx->shim_regs64),
					GFP_KERNEL);
	if (!ctx->shim_regs64)
		return -ENOMEM;

	ret = sst_driver_ops(ctx);
	if (ret != 0)
		return -EINVAL;

	sst_init_locks(ctx);

	ctx->stream_cnt = 0;
	ctx->fw_in_mem = NULL;
	ctx->use_dma = 1;
	ctx->use_lli = 1;

	if (sst_workqueue_init(ctx))
		goto do_free_wq;

	ctx->pdata = sst_get_acpi_driver_data(hid);
	if (!ctx->pdata)
		return -EINVAL;
	if (INTEL_MID_BOARD(3, TABLET, BYT, BLK, PRO, CRV2)) {
		/* BYT-CR V2 has only mono speaker, while
		 * byt has stereo speaker, for both
		 * HID is same, so platform data also is
		 * same, hence overriding bdata based on spid
		 */
		ctx->pdata->bdata = &sst_byt_crv2_bdata;
		pr_info("Overriding bdata for byt-crv2\n");
	}

	ctx->use_32bit_ops = ctx->pdata->ipc_info->use_32bit_ops;
	ctx->mailbox_recv_offset = ctx->pdata->ipc_info->mbox_recv_off;

	memcpy(&ctx->info, ctx->pdata->probe_data, sizeof(ctx->info));

	ctx->ipc_reg.ipcx = SST_IPCX + ctx->pdata->ipc_info->ipc_offset;
	ctx->ipc_reg.ipcd = SST_IPCD + ctx->pdata->ipc_info->ipc_offset;

	pr_debug("Got drv data max stream %d\n",
				ctx->info.max_streams);
	for (i = 1; i <= ctx->info.max_streams; i++) {
		struct stream_info *stream = &ctx->streams[i];
		mutex_init(&stream->lock);
	}
	ret = sst_request_firmware_async(ctx);
	if (ret) {
		pr_err("Firmware download failed:%d\n", ret);
		goto do_free_wq;
	}

	ret = devm_request_threaded_irq(ctx->dev, ctx->irq_num, ctx->ops->interrupt,
					ctx->ops->irq_thread, 0, SST_DRV_NAME,
					ctx);
	if (ret)
		return ret;
	pr_debug("Registered IRQ %#x\n", ctx->irq_num);

	/*Register LPE Control as misc driver*/
	ret = misc_register(&lpe_ctrl);
	if (ret) {
		pr_err("couldn't register control device\n");
		goto do_free_wq;
	}
	/* mask all SSP and DMA irq to IA - enabled in acpi kernel driver */
	sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038);

	if (ctx->use_32bit_ops) {
		pr_debug("allocate mem for context save/restore\n ");
		/*allocate mem for fw context save during suspend*/
		ctx->fw_cntx = devm_kzalloc(ctx->dev, FW_CONTEXT_MEM, GFP_KERNEL);
		if (!ctx->fw_cntx) {
			ret = -ENOMEM;
			goto do_free_misc;
		}
		/*setting zero as that is valid mem to restore*/
		ctx->fw_cntx_size = 0;
	}

	platform_set_drvdata(pdev, ctx);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	register_sst(dev);
	sst_debugfs_init(ctx);
	sst_set_fw_state_locked(ctx, SST_UN_INIT);
	sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
	pr_info("%s successfully done!\n", __func__);
	return ret;

do_free_misc:
	misc_deregister(&lpe_ctrl);
do_free_wq:
	sst_destroy_workqueue(ctx);

	sst_drv_ctx = NULL;
	platform_set_drvdata(pdev, NULL);
	pr_err("%s: failed with %d\n", __func__, ret);
	return ret;
}