diff options
Diffstat (limited to 'sound/soc/intel/sst/sst_pci.c')
-rw-r--r-- | sound/soc/intel/sst/sst_pci.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/sst/sst_pci.c new file mode 100644 index 0000000..3a0b3bf --- /dev/null +++ b/sound/soc/intel/sst/sst_pci.c @@ -0,0 +1,209 @@ +/* + * sst_pci.c - SST (LPE) driver init file for pci enumeration. + * + * Copyright (C) 2008-14 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/fs.h> +#include <linux/firmware.h> +#include <linux/pm_runtime.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <asm/platform_sst_audio.h> +#include "../sst-mfld-platform.h" +#include "sst.h" + +static int sst_platform_get_resources(struct intel_sst_drv *ctx) +{ + int ddr_base, ret = 0; + struct pci_dev *pci = ctx->pci; + + ret = pci_request_regions(pci, SST_DRV_NAME); + if (ret) + return ret; + + /* map registers */ + /* DDR base */ + if (ctx->dev_id == SST_MRFLD_PCI_ID) { + ctx->ddr_base = pci_resource_start(pci, 0); + /* check that the relocated IMR base matches with FW Binary */ + ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); + if (!ctx->pdata->lib_info) { + dev_err(ctx->dev, "lib_info pointer NULL\n"); + ret = -EINVAL; + goto do_release_regions; + } + if (ddr_base != ctx->pdata->lib_info->mod_base) { + dev_err(ctx->dev, + "FW LSP DDR BASE does not match with IFWI\n"); + ret = -EINVAL; + goto do_release_regions; + } + ctx->ddr_end = pci_resource_end(pci, 0); + + ctx->ddr = pcim_iomap(pci, 0, + pci_resource_len(pci, 0)); + if (!ctx->ddr) { + ret = -EINVAL; + goto do_release_regions; + } + dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr); + } else { + ctx->ddr = NULL; + } + /* SHIM */ + ctx->shim_phy_add = pci_resource_start(pci, 1); + ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1)); + if (!ctx->shim) { + ret = -EINVAL; + goto do_release_regions; + } + dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim); + + /* Shared SRAM */ + ctx->mailbox_add = pci_resource_start(pci, 2); + ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2)); + if (!ctx->mailbox) { + ret = -EINVAL; + goto do_release_regions; + } + dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox); + + /* IRAM */ + ctx->iram_end = pci_resource_end(pci, 3); + ctx->iram_base = pci_resource_start(pci, 3); + ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3)); + if (!ctx->iram) { + ret = -EINVAL; + goto do_release_regions; + } + dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram); + + /* DRAM */ + ctx->dram_end = pci_resource_end(pci, 4); + ctx->dram_base = pci_resource_start(pci, 4); + ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4)); + if (!ctx->dram) { + ret = -EINVAL; + goto do_release_regions; + } + dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram); +do_release_regions: + pci_release_regions(pci); + return 0; +} + +/* + * intel_sst_probe - PCI probe function + * + * @pci: PCI device structure + * @pci_id: PCI device ID structure + * + */ +static int intel_sst_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + int ret = 0; + struct intel_sst_drv *sst_drv_ctx; + struct sst_platform_info *sst_pdata = pci->dev.platform_data; + + dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device); + ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device); + if (ret < 0) + return ret; + + sst_drv_ctx->pdata = sst_pdata; + sst_drv_ctx->irq_num = pci->irq; + snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name), + "%s%04x%s", "fw_sst_", + sst_drv_ctx->dev_id, ".bin"); + + ret = sst_context_init(sst_drv_ctx); + if (ret < 0) + return ret; + + /* Init the device */ + ret = pcim_enable_device(pci); + if (ret) { + dev_err(sst_drv_ctx->dev, + "device can't be enabled. Returned err: %d\n", ret); + goto do_free_drv_ctx; + } + sst_drv_ctx->pci = pci_dev_get(pci); + ret = sst_platform_get_resources(sst_drv_ctx); + if (ret < 0) + goto do_free_drv_ctx; + + pci_set_drvdata(pci, sst_drv_ctx); + sst_configure_runtime_pm(sst_drv_ctx); + + return ret; + +do_free_drv_ctx: + sst_context_cleanup(sst_drv_ctx); + dev_err(sst_drv_ctx->dev, "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 intel_sst_remove(struct pci_dev *pci) +{ + struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci); + + sst_context_cleanup(sst_drv_ctx); + pci_dev_put(sst_drv_ctx->pci); + pci_release_regions(pci); + pci_set_drvdata(pci, NULL); +} + +/* PCI Routines */ +static struct pci_device_id intel_sst_ids[] = { + { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0}, + { 0, } +}; + +static struct pci_driver sst_driver = { + .name = SST_DRV_NAME, + .id_table = intel_sst_ids, + .probe = intel_sst_probe, + .remove = intel_sst_remove, +#ifdef CONFIG_PM + .driver = { + .pm = &intel_sst_pm, + }, +#endif +}; + +module_pci_driver(sst_driver); + +MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver"); +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_LICENSE("GPL v2"); +MODULE_ALIAS("sst"); |