diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 3639f7c006600b..d65f8ab2c893de 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -3,7 +3,7 @@ ccflags-y += -DDEBUG snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o utils.o + control.o trace.o utils.o sof-mfd.o sof-audio.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8661c2cca76b9a..fd3bd576a141fc 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -15,6 +15,7 @@ #include <sound/sof.h> #include "sof-priv.h" #include "ops.h" +#include "sof-mfd.h" /* see SOF_DBG_ flags */ int sof_core_debug; @@ -258,47 +259,9 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, return pages; } -/* - * SOF Driver enumeration. - */ -static int sof_machine_check(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *plat_data = sdev->pdata; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - struct snd_soc_acpi_mach *machine; - int ret; -#endif - - if (plat_data->machine) - return 0; - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); - return -ENODEV; -#else - /* fallback to nocodec mode */ - dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); - machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); - if (!machine) - return -ENOMEM; - - ret = sof_nocodec_setup(sdev->dev, plat_data, machine, - plat_data->desc, plat_data->desc->ops); - if (ret < 0) - return ret; - - plat_data->machine = machine; - - return 0; -#endif -} - static int sof_probe_continue(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; - const char *drv_name; - const void *mach; - int size; int ret; /* probe the DSP hardware */ @@ -308,17 +271,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return ret; } - /* check machine info */ - ret = sof_machine_check(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to get machine info %d\n", - ret); - goto dbg_err; - } - - /* set up platform component driver */ - snd_sof_new_platform_drv(sdev); - /* register any debug/trace capabilities */ ret = snd_sof_dbg_init(sdev); if (ret < 0) { @@ -374,32 +326,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) /* hereafter all FW boot flows are for PM reasons */ sdev->first_boot = false; - /* now register audio DSP platform driver and dai */ - ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, - sof_ops(sdev)->drv, - sof_ops(sdev)->num_drv); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to register DSP DAI driver %d\n", ret); - goto fw_run_err; - } - - drv_name = plat_data->machine->drv_name; - mach = (const void *)plat_data->machine; - size = sizeof(*plat_data->machine); - - /* register machine driver, pass machine info as pdata */ - plat_data->pdev_mach = - platform_device_register_data(sdev->dev, drv_name, - PLATFORM_DEVID_NONE, mach, size); - - if (IS_ERR(plat_data->pdev_mach)) { - ret = PTR_ERR(plat_data->pdev_mach); - goto fw_run_err; - } - - dev_dbg(sdev->dev, "created machine %s\n", - dev_name(&plat_data->pdev_mach->dev)); + /* register audio client */ + sof_client_dev_register(sdev, "sof-audio", &sdev->sof_audio.pdev); if (plat_data->sof_probe_complete) plat_data->sof_probe_complete(sdev->dev); @@ -423,7 +351,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) * They will be released with an explicit call to * snd_sof_device_remove() when the PCI/ACPI device is removed */ - fw_run_err: fw_load_err: ipc_err: @@ -511,6 +438,9 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); + /* unregister audio client device */ + sof_client_dev_unregister(&sdev->sof_audio.pdev); + snd_sof_fw_unload(sdev); snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c new file mode 100644 index 00000000000000..100806e4ddf0b1 --- /dev/null +++ b/sound/soc/sof/sof-audio.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> +// + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <sound/sof.h> +#include "sof-priv.h" +#include "ops.h" + +/* + * SOF Driver enumeration. + */ +static int sof_machine_check(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + struct snd_soc_acpi_mach *machine; + int ret; +#endif + + if (plat_data->machine) + return 0; + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; +#else + /* fallback to nocodec mode */ + dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); + machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + ret = sof_nocodec_setup(sdev->dev, plat_data, machine, + plat_data->desc, plat_data->desc->ops); + if (ret < 0) + return ret; + + plat_data->machine = machine; + + return 0; +#endif +} + +static int sof_audio_probe(struct platform_device *pdev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(&pdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; + struct snd_soc_acpi_mach *machine = plat_data->machine; + const char *drv_name; + int size; + int ret; + + /* check machine info */ + ret = sof_machine_check(sdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: failed to get machine info %d\n", + ret); + goto err; + } + + /* set platform name */ + machine->mach_params.platform = dev_name(&pdev->dev); + plat_data->platform = dev_name(&pdev->dev); + + /* set up platform component driver */ + snd_sof_new_platform_drv(sdev); + + /* now register audio DSP platform driver and dai */ + ret = devm_snd_soc_register_component(&pdev->dev, &sdev->plat_drv, + sof_ops(sdev)->drv, + sof_ops(sdev)->num_drv); + if (ret < 0) { + dev_err(&pdev->dev, + "error: failed to register DSP DAI driver %d\n", ret); + goto err; + } + + drv_name = plat_data->machine->drv_name; + size = sizeof(*plat_data->machine); + + /* register machine driver, pass machine info as pdata */ + plat_data->pdev_mach = + platform_device_register_data(&pdev->dev, drv_name, + PLATFORM_DEVID_NONE, + (const void *)machine, size); + + if (IS_ERR(plat_data->pdev_mach)) { + ret = PTR_ERR(plat_data->pdev_mach); + goto err; + } + + dev_dbg(&pdev->dev, "created machine %s\n", + dev_name(&plat_data->pdev_mach->dev)); + + /* enable runtime PM */ + pm_runtime_set_autosuspend_delay(&pdev->dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + + pm_runtime_enable(&pdev->dev); + + pm_runtime_mark_last_busy(&pdev->dev); + + pm_runtime_put_noidle(&pdev->dev); + + return 0; + +err: + snd_sof_remove(sdev); + snd_sof_fw_unload(sdev); + snd_sof_ipc_free(sdev); + snd_sof_free_debug(sdev); + return ret; +} + +static struct platform_driver sof_audio_driver = { + .driver = { + .name = "sof-audio", + }, + + .probe = sof_audio_probe, +}; + +module_platform_driver(sof_audio_driver); + +MODULE_DESCRIPTION("SOF Audio Client Platform Driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:sof-audio"); diff --git a/sound/soc/sof/sof-mfd.c b/sound/soc/sof/sof-mfd.c new file mode 100644 index 00000000000000..138eefd424650c --- /dev/null +++ b/sound/soc/sof/sof-mfd.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> +// +#include <linux/device.h> +#include "sof-mfd.h" + +void sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, + struct platform_device *pdev) +{ + int ret; + + pdev = platform_device_alloc(name, -1); + if (!pdev) { + dev_err(sdev->dev, "error: Failed to allocate %s\n", name); + return; + } + + pdev->dev.parent = sdev->dev; + dev_set_drvdata(&pdev->dev, sdev); + ret = platform_device_add(pdev); + if (ret) { + dev_err(sdev->dev, "error: Failed to register %s: %d\n", name, + ret); + platform_device_put(pdev); + pdev = NULL; + } + dev_dbg(sdev->dev, "%s client registered\n", name); +} +EXPORT_SYMBOL(sof_client_dev_register); + +void sof_client_dev_unregister(struct platform_device *pdev) +{ + platform_device_del(pdev); +} +EXPORT_SYMBOL(sof_client_dev_unregister); diff --git a/sound/soc/sof/sof-mfd.h b/sound/soc/sof/sof-mfd.h new file mode 100644 index 00000000000000..30899031b8d92d --- /dev/null +++ b/sound/soc/sof/sof-mfd.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> + */ +#include <linux/platform_device.h> +#include "sof-priv.h" + +#ifndef __SOUND_SOC_SOF_MFD_H +#define __SOUND_SOC_SOF_MFD_H + +/* client register/unregister */ +void sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, + struct platform_device *pdev); +void sof_client_dev_unregister(struct platform_device *pdev); + +#endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 25537e23ec4bf3..202ef7be074dd2 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -326,6 +326,7 @@ static int sof_pci_probe(struct pci_dev *pci, dev_warn(dev, "warning: No matching ASoC machine driver found\n"); } else { mach->mach_params.platform = dev_name(dev); + dev_dbg(dev, "ranjani %s\n", dev_name(dev)); sof_pdata->fw_filename = mach->sof_fw_filename; sof_pdata->tplg_filename = mach->sof_tplg_filename; } @@ -335,7 +336,6 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->machine = mach; sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; sof_pdata->dev = dev; - sof_pdata->platform = dev_name(dev); /* alternate fw and tplg filenames ? */ if (fw_path) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 9d5151f7cc2fc8..b29c1f947ddf2b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -370,6 +370,11 @@ struct snd_sof_dai { struct list_head list; /* list in sdev dai list */ }; +/* SOF MFD client device */ +struct sof_mfd_client { + struct platform_device pdev; +}; + /* * SOF Device Level. */ @@ -458,6 +463,9 @@ struct snd_sof_dev { bool msi_enabled; + /* client devices */ + struct sof_mfd_client sof_audio; + void *private; /* core does not touch this */ }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 46aab02977530c..b9132d0dbfdf69 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2844,7 +2844,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, dev_err(sdev->dev, "error: no platforms\n"); return -EINVAL; } - link->platforms->name = dev_name(sdev->dev); + + /* set platform name */ + link->platforms->name = dev_name(scomp->dev); /* * Set nonatomic property for FE dai links as their trigger action