Skip to content

Commit

Permalink
ASoC: SOF: Add MFD support
Browse files Browse the repository at this point in the history
Add MFD support in SOF with a single client device for audio.
The audio client is a registered as a separate platform device
under the SOF PCI device. This patch deals with partitioning
the DSP hardware initialisation parts and the audio specific
code. The hardware initialization, FW load/boot, IPC init
is done at the top-level PCI device probe. The audio client
platform device's probe deals with registering the component
driver, creating the machine driver and loading the topology.

The device hierarchy is altered with the addition of the platform
device for the audio client. The machine driver and the component
driver will now be children of the sof-audio platform device.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  • Loading branch information
ranj063 committed Sep 28, 2019
1 parent f1c5cf5 commit 8e3acba
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 79 deletions.
2 changes: 1 addition & 1 deletion sound/soc/sof/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
82 changes: 6 additions & 76 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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:
Expand Down Expand Up @@ -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);
Expand Down
137 changes: 137 additions & 0 deletions sound/soc/sof/sof-audio.c
Original file line number Diff line number Diff line change
@@ -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");
41 changes: 41 additions & 0 deletions sound/soc/sof/sof-mfd.c
Original file line number Diff line number Diff line change
@@ -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);
21 changes: 21 additions & 0 deletions sound/soc/sof/sof-mfd.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion sound/soc/sof/sof-pci-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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 */
};

Expand Down
4 changes: 3 additions & 1 deletion sound/soc/sof/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8e3acba

Please sign in to comment.