875065491f
One of the issues with the ASoC v1 API which has been addressed in the ASoC v2 work that Liam Girdwood has done is that the ALSA card provided by ASoC is distributed around the ASoC structures. For example, machine wide data such as the struct snd_card are maintained as part of the CODEC data structure, preventing the use of multiple codecs. This has been addressed by refactoring the data structures so that all the data for the ALSA card is contained in a single structure snd_soc_card which replaces the existing snd_soc_machine and snd_soc_device. Begin the process of backporting this by renaming struct snd_soc_machine to struct snd_soc_card, better reflecting its function and bringing it closer to standard ALSA terminology. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
172 lines
4.2 KiB
C
172 lines
4.2 KiB
C
/*
|
|
* OF helpers for ALSA SoC Layer
|
|
*
|
|
* Copyright (C) 2008, Secret Lab Technologies Ltd.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/init.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of.h>
|
|
#include <sound/core.h>
|
|
#include <sound/pcm.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc-of-simple.h>
|
|
#include <sound/initval.h>
|
|
|
|
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
|
|
|
|
static DEFINE_MUTEX(of_snd_soc_mutex);
|
|
static LIST_HEAD(of_snd_soc_device_list);
|
|
static int of_snd_soc_next_index;
|
|
|
|
struct of_snd_soc_device {
|
|
int id;
|
|
struct list_head list;
|
|
struct snd_soc_device device;
|
|
struct snd_soc_card card;
|
|
struct snd_soc_dai_link dai_link;
|
|
struct platform_device *pdev;
|
|
struct device_node *platform_node;
|
|
struct device_node *codec_node;
|
|
};
|
|
|
|
static struct snd_soc_ops of_snd_soc_ops = {
|
|
};
|
|
|
|
static struct of_snd_soc_device *
|
|
of_snd_soc_get_device(struct device_node *codec_node)
|
|
{
|
|
struct of_snd_soc_device *of_soc;
|
|
|
|
list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
|
|
if (of_soc->codec_node == codec_node)
|
|
return of_soc;
|
|
}
|
|
|
|
of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
|
|
if (!of_soc)
|
|
return NULL;
|
|
|
|
/* Initialize the structure and add it to the global list */
|
|
of_soc->codec_node = codec_node;
|
|
of_soc->id = of_snd_soc_next_index++;
|
|
of_soc->card.dai_link = &of_soc->dai_link;
|
|
of_soc->card.num_links = 1;
|
|
of_soc->device.card = &of_soc->card;
|
|
of_soc->dai_link.ops = &of_snd_soc_ops;
|
|
list_add(&of_soc->list, &of_snd_soc_device_list);
|
|
|
|
return of_soc;
|
|
}
|
|
|
|
static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
|
|
{
|
|
struct platform_device *pdev;
|
|
int rc;
|
|
|
|
/* Only register the device if both the codec and platform have
|
|
* been registered */
|
|
if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
|
|
return;
|
|
|
|
pr_info("platform<-->codec match achieved; registering machine\n");
|
|
|
|
pdev = platform_device_alloc("soc-audio", of_soc->id);
|
|
if (!pdev) {
|
|
pr_err("of_soc: platform_device_alloc() failed\n");
|
|
return;
|
|
}
|
|
|
|
pdev->dev.platform_data = of_soc;
|
|
platform_set_drvdata(pdev, &of_soc->device);
|
|
of_soc->device.dev = &pdev->dev;
|
|
|
|
/* The ASoC device is complete; register it */
|
|
rc = platform_device_add(pdev);
|
|
if (rc) {
|
|
pr_err("of_soc: platform_device_add() failed\n");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
|
|
void *codec_data, struct snd_soc_dai *dai,
|
|
struct device_node *node)
|
|
{
|
|
struct of_snd_soc_device *of_soc;
|
|
int rc = 0;
|
|
|
|
pr_info("registering ASoC codec driver: %s\n", node->full_name);
|
|
|
|
mutex_lock(&of_snd_soc_mutex);
|
|
of_soc = of_snd_soc_get_device(node);
|
|
if (!of_soc) {
|
|
rc = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
/* Store the codec data */
|
|
of_soc->device.codec_data = codec_data;
|
|
of_soc->device.codec_dev = codec_dev;
|
|
of_soc->dai_link.name = (char *)node->name;
|
|
of_soc->dai_link.stream_name = (char *)node->name;
|
|
of_soc->dai_link.codec_dai = dai;
|
|
|
|
/* Now try to register the SoC device */
|
|
of_snd_soc_register_device(of_soc);
|
|
|
|
out:
|
|
mutex_unlock(&of_snd_soc_mutex);
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
|
|
|
|
int of_snd_soc_register_platform(struct snd_soc_platform *platform,
|
|
struct device_node *node,
|
|
struct snd_soc_dai *cpu_dai)
|
|
{
|
|
struct of_snd_soc_device *of_soc;
|
|
struct device_node *codec_node;
|
|
const phandle *handle;
|
|
int len, rc = 0;
|
|
|
|
pr_info("registering ASoC platform driver: %s\n", node->full_name);
|
|
|
|
handle = of_get_property(node, "codec-handle", &len);
|
|
if (!handle || len < sizeof(handle))
|
|
return -ENODEV;
|
|
codec_node = of_find_node_by_phandle(*handle);
|
|
if (!codec_node)
|
|
return -ENODEV;
|
|
pr_info("looking for codec: %s\n", codec_node->full_name);
|
|
|
|
mutex_lock(&of_snd_soc_mutex);
|
|
of_soc = of_snd_soc_get_device(codec_node);
|
|
if (!of_soc) {
|
|
rc = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
of_soc->platform_node = node;
|
|
of_soc->dai_link.cpu_dai = cpu_dai;
|
|
of_soc->device.platform = platform;
|
|
of_soc->card.name = of_soc->dai_link.cpu_dai->name;
|
|
|
|
/* Now try to register the SoC device */
|
|
of_snd_soc_register_device(of_soc);
|
|
|
|
out:
|
|
mutex_unlock(&of_snd_soc_mutex);
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
|