/** * 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); }
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; }
/* * 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; }