blob: 8bc5cd9e972fc89a2223dc32f01c42cbffd15fea [file] [log] [blame]
Grant Likely84bc2782008-07-29 11:42:28 +01001/*
2 * OF helpers for ALSA SoC Layer
3 *
4 * Copyright (C) 2008, Secret Lab Technologies Ltd.
5 */
6
7#include <linux/module.h>
8#include <linux/moduleparam.h>
9#include <linux/init.h>
10#include <linux/delay.h>
11#include <linux/pm.h>
12#include <linux/bitops.h>
13#include <linux/platform_device.h>
14#include <linux/of.h>
15#include <sound/core.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include <sound/soc-of-simple.h>
20#include <sound/initval.h>
21
22MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
23MODULE_LICENSE("GPL");
24MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
25
26static DEFINE_MUTEX(of_snd_soc_mutex);
27static LIST_HEAD(of_snd_soc_device_list);
28static int of_snd_soc_next_index;
29
30struct of_snd_soc_device {
31 int id;
32 struct list_head list;
33 struct snd_soc_device device;
Mark Brown87506542008-11-18 20:50:34 +000034 struct snd_soc_card card;
Grant Likely84bc2782008-07-29 11:42:28 +010035 struct snd_soc_dai_link dai_link;
36 struct platform_device *pdev;
37 struct device_node *platform_node;
38 struct device_node *codec_node;
39};
40
41static struct snd_soc_ops of_snd_soc_ops = {
42};
43
44static struct of_snd_soc_device *
45of_snd_soc_get_device(struct device_node *codec_node)
46{
47 struct of_snd_soc_device *of_soc;
48
49 list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
50 if (of_soc->codec_node == codec_node)
51 return of_soc;
52 }
53
54 of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
55 if (!of_soc)
56 return NULL;
57
58 /* Initialize the structure and add it to the global list */
59 of_soc->codec_node = codec_node;
60 of_soc->id = of_snd_soc_next_index++;
Mark Brown87506542008-11-18 20:50:34 +000061 of_soc->card.dai_link = &of_soc->dai_link;
62 of_soc->card.num_links = 1;
63 of_soc->device.card = &of_soc->card;
Grant Likely84bc2782008-07-29 11:42:28 +010064 of_soc->dai_link.ops = &of_snd_soc_ops;
65 list_add(&of_soc->list, &of_snd_soc_device_list);
66
67 return of_soc;
68}
69
70static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
71{
72 struct platform_device *pdev;
73 int rc;
74
75 /* Only register the device if both the codec and platform have
76 * been registered */
77 if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
78 return;
79
80 pr_info("platform<-->codec match achieved; registering machine\n");
81
82 pdev = platform_device_alloc("soc-audio", of_soc->id);
83 if (!pdev) {
84 pr_err("of_soc: platform_device_alloc() failed\n");
85 return;
86 }
87
88 pdev->dev.platform_data = of_soc;
89 platform_set_drvdata(pdev, &of_soc->device);
90 of_soc->device.dev = &pdev->dev;
91
92 /* The ASoC device is complete; register it */
93 rc = platform_device_add(pdev);
94 if (rc) {
95 pr_err("of_soc: platform_device_add() failed\n");
96 return;
97 }
98
99}
100
101int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
102 void *codec_data, struct snd_soc_dai *dai,
103 struct device_node *node)
104{
105 struct of_snd_soc_device *of_soc;
106 int rc = 0;
107
108 pr_info("registering ASoC codec driver: %s\n", node->full_name);
109
110 mutex_lock(&of_snd_soc_mutex);
111 of_soc = of_snd_soc_get_device(node);
112 if (!of_soc) {
113 rc = -ENOMEM;
114 goto out;
115 }
116
117 /* Store the codec data */
118 of_soc->device.codec_data = codec_data;
119 of_soc->device.codec_dev = codec_dev;
120 of_soc->dai_link.name = (char *)node->name;
121 of_soc->dai_link.stream_name = (char *)node->name;
122 of_soc->dai_link.codec_dai = dai;
123
124 /* Now try to register the SoC device */
125 of_snd_soc_register_device(of_soc);
126
127 out:
128 mutex_unlock(&of_snd_soc_mutex);
129 return rc;
130}
131EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
132
133int of_snd_soc_register_platform(struct snd_soc_platform *platform,
134 struct device_node *node,
135 struct snd_soc_dai *cpu_dai)
136{
137 struct of_snd_soc_device *of_soc;
138 struct device_node *codec_node;
139 const phandle *handle;
140 int len, rc = 0;
141
142 pr_info("registering ASoC platform driver: %s\n", node->full_name);
143
144 handle = of_get_property(node, "codec-handle", &len);
145 if (!handle || len < sizeof(handle))
146 return -ENODEV;
147 codec_node = of_find_node_by_phandle(*handle);
148 if (!codec_node)
149 return -ENODEV;
150 pr_info("looking for codec: %s\n", codec_node->full_name);
151
152 mutex_lock(&of_snd_soc_mutex);
153 of_soc = of_snd_soc_get_device(codec_node);
154 if (!of_soc) {
155 rc = -ENOMEM;
156 goto out;
157 }
158
159 of_soc->platform_node = node;
160 of_soc->dai_link.cpu_dai = cpu_dai;
Mark Brown87689d52008-12-02 16:01:14 +0000161 of_soc->card.platform = platform;
Mark Brown87506542008-11-18 20:50:34 +0000162 of_soc->card.name = of_soc->dai_link.cpu_dai->name;
Grant Likely84bc2782008-07-29 11:42:28 +0100163
164 /* Now try to register the SoC device */
165 of_snd_soc_register_device(of_soc);
166
167 out:
168 mutex_unlock(&of_snd_soc_mutex);
169 return rc;
170}
171EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);