#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/platform_device.h>
struct sst_acpi_desc *desc;
};
+static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
+{
+ struct platform_device *pdev = context;
+ struct device *dev = &pdev->dev;
+ struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+ struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+ struct sst_acpi_desc *desc = sst_acpi->desc;
+
+ sst_pdata->fw = fw;
+ if (!fw) {
+ dev_err(dev, "Cannot load firmware %s\n", desc->fw_filename);
+ return;
+ }
+
+ /* register PCM and DAI driver */
+ sst_acpi->pdev_pcm =
+ platform_device_register_data(dev, desc->drv_name, -1,
+ sst_pdata, sizeof(*sst_pdata));
+ if (IS_ERR(sst_acpi->pdev_pcm)) {
+ dev_err(dev, "Cannot register device %s. Error %d\n",
+ desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
+ }
+
+ return;
+}
+
static int sst_acpi_probe(struct platform_device *pdev)
{
const struct acpi_device_id *id;
desc = mach->res_desc;
sst_pdata = &sst_acpi->sst_pdata;
sst_pdata->id = desc->sst_id;
- sst_pdata->fw_filename = desc->fw_filename;
sst_acpi->desc = desc;
if (desc->resindex_dma_base >= 0) {
}
}
- /* register PCM and DAI driver */
- sst_acpi->pdev_pcm =
- platform_device_register_data(dev, desc->drv_name, -1,
- sst_pdata, sizeof(*sst_pdata));
- if (IS_ERR(sst_acpi->pdev_pcm))
- return PTR_ERR(sst_acpi->pdev_pcm);
-
- /* register machine driver */
platform_set_drvdata(pdev, sst_acpi);
+ /* register machine driver */
sst_acpi->pdev_mach =
platform_device_register_data(dev, mach->drv_name, -1,
sst_pdata, sizeof(*sst_pdata));
- if (IS_ERR(sst_acpi->pdev_mach)) {
- ret = PTR_ERR(sst_acpi->pdev_mach);
- goto sst_err;
- }
+ if (IS_ERR(sst_acpi->pdev_mach))
+ return PTR_ERR(sst_acpi->pdev_mach);
- return ret;
+ /* continue SST probing after firmware is loaded */
+ ret = request_firmware_nowait(THIS_MODULE, true, desc->fw_filename,
+ dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
+ if (ret)
+ platform_device_unregister(sst_acpi->pdev_mach);
-sst_err:
- platform_device_unregister(sst_acpi->pdev_pcm);
return ret;
}
static int sst_acpi_remove(struct platform_device *pdev)
{
struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+ struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
platform_device_unregister(sst_acpi->pdev_mach);
- platform_device_unregister(sst_acpi->pdev_pcm);
+ if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
+ platform_device_unregister(sst_acpi->pdev_pcm);
+ release_firmware(sst_pdata->fw);
return 0;
}