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