ASoC: Intel: sst-acpi: Request firmware before SST platform driver probing
authorJarkko Nikula <jarkko.nikula@linux.intel.com>
Wed, 19 Feb 2014 08:30:38 +0000 (10:30 +0200)
committerMark Brown <broonie@linaro.org>
Wed, 19 Feb 2014 12:20:42 +0000 (21:20 +0900)
We originally thought to request SST audio DSP firmware during the SST
platform driver initialization. However plain request_firmware doesn't
work in driver probe paths if userspace is not ready to handle it. For
instance when drivers are built-in.

Implementing asynchronous firmware request in SST platform driver
initialization complicates code needlessly since it anyway will fail if
firmware is missing.

This is more simple to handle by requesting firmware asynchronously in
sst_acpi_probe() and register SST platform only after firmware is loaded.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
sound/soc/intel/sst-acpi.c
sound/soc/intel/sst-dsp.h

index aba73ca8a923e2eb207bc897b4db3faaf7737a09..64154a77d9047181caca3444e6097bb202136f32 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
@@ -56,6 +57,32 @@ struct sst_acpi_priv {
        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;
@@ -79,7 +106,6 @@ static int sst_acpi_probe(struct platform_device *pdev)
        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) {
@@ -118,37 +144,33 @@ static int sst_acpi_probe(struct platform_device *pdev)
                }
        }
 
-       /* 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;
 }
index d134359fecac4cf7d4131b6564f9f108e824b3b5..3730fd32445538ef9049cc95cfd9ebfaca34d86e 100644 (file)
@@ -152,7 +152,7 @@ struct sst_pdata {
        int irq;
 
        /* Firmware */
-       const char *fw_filename;
+       const struct firmware *fw;
 
        /* DMA */
        u32 dma_base;