aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMisael Lopez Cruz2013-07-07 00:07:38 -0500
committerMisael Lopez Cruz2013-07-22 15:04:21 -0500
commit9c063b5d8efb757e78935fe5ca42fbbf87077fce (patch)
tree67efe6d31d7e2b836c8774346209646859124709
parent9dabab86b73716ba98e4a7cc4516e85a1d5e8507 (diff)
downloadkernel-audio-9c063b5d8efb757e78935fe5ca42fbbf87077fce.tar.gz
kernel-audio-9c063b5d8efb757e78935fe5ca42fbbf87077fce.tar.xz
kernel-audio-9c063b5d8efb757e78935fe5ca42fbbf87077fce.zip
ASoC: DRA7: dra7-evm: Add initial support for DRA7 EVM
Add initial support for DRA7 EVM, it includes the media DAI link that connects McASP3 and tlv320aic3106 in I2S mode. DRA7xx is a high-performance, infotainment application device, based on enhanced OMAP architecture integrated on a 28-nm technology. Change-Id: I3be3e94e2f9c5736f236e965297d3cb9d646c7fc Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
-rw-r--r--Documentation/devicetree/bindings/sound/dra7-evm.txt60
-rw-r--r--sound/soc/omap/Kconfig9
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/dra7-evm.c316
4 files changed, 387 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/dra7-evm.txt b/Documentation/devicetree/bindings/sound/dra7-evm.txt
new file mode 100644
index 000000000000..1eeed6e6d67a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/dra7-evm.txt
@@ -0,0 +1,60 @@
1* Texas Instruments DRA7 EVM sound
2
3Required properties:
4- compatible: "ti,dra7-evm-sound"
5- ti,mode: Name of the sound card
6- ti,media-cpu: phandle for the McASP node in media link
7- ti,media-codec: phandle for the analog codec in media link
8- ti,media-mclk-freq: MCLK frequency for the analog codec in media link
9- ti,media-slots: Number of slots
10- ti,audio-routing: List of connections between audio components.
11 Each entry is a pair of strings, the first being the connection's sink,
12 the second being the connection's source.
13
14Available audio endpoints for the audio-routing table:
15
16Board connectors:
17 * Main Mic
18 * Line In
19 * Headphone
20 * Line Out
21
22tlv320aic3x pins:
23 * LLOUT
24 * RLOUT
25 * MONO_LOUT
26 * HPLOUT
27 * HPROUT
28 * HPLCOM
29 * HPCOM
30 * MIC3L
31 * MIC3R
32 * LINE1L
33 * LINE1R
34 * LINE2L
35 * LINE2R
36
37Example:
38
39sound {
40 compatible = "ti,dra7-evm-sound";
41 ti,model = "DRA7-EVM";
42
43 /* Media DAI link */
44 ti,media-cpu = <&mcasp3>;
45 ti,media-codec = <&tlv320aic3106>;
46 ti,media-mclk-freq = <1411200>;
47 ti,media-slots = <2>;
48
49 /* Audio routing */
50 ti,audio-routing =
51 "LINE1L", "Line In",
52 "LINE1R", "Line In",
53 "MIC3L", "Main Mic",
54 "MIC3R", "Main Mic",
55 "Main Mic", "Mic Bias 2V",
56 "Headphone", "HPLOUT",
57 "Headphone", "HPROUT",
58 "Line Out", "LLOUT",
59 "Line Out", "RLOUT";
60};
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 31b6aa320f5b..030187652914 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -133,3 +133,12 @@ config SND_OMAP_SOC_OMAP3_PANDORA
133 133
134config SND_DRA7_SOC_ATL 134config SND_DRA7_SOC_ATL
135 tristate 135 tristate
136
137config SND_SOC_DRA7_EVM
138 tristate "SoC Audio support for DRA7 EVM"
139 depends on SND_OMAP_SOC && SOC_DRA7XX
140 select SND_DAVINCI_SOC_MCASP
141 select SND_SOC_TLV320AIC3X
142 select SND_DRA7_SOC_ATL
143 help
144 Say Y if you want to add support for SoC audio on DRA7 EVM
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index ff334799e662..fc9c78177f5b 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -29,6 +29,7 @@ snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
29snd-soc-omap-twl4030-objs := omap-twl4030.o 29snd-soc-omap-twl4030-objs := omap-twl4030.o
30snd-soc-omap3pandora-objs := omap3pandora.o 30snd-soc-omap3pandora-objs := omap3pandora.o
31snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o 31snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
32snd-soc-dra7-evm-objs := dra7-evm.o
32 33
33obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o 34obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
34obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o 35obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -39,4 +40,5 @@ obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
39obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o 40obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
40obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o 41obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
41obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o 42obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
43obj-$(CONFIG_SND_SOC_DRA7_EVM) += snd-soc-dra7-evm.o
42obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o 44obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
diff --git a/sound/soc/omap/dra7-evm.c b/sound/soc/omap/dra7-evm.c
new file mode 100644
index 000000000000..7dfd431c3088
--- /dev/null
+++ b/sound/soc/omap/dra7-evm.c
@@ -0,0 +1,316 @@
1/*
2 * dr7-evm.c -- SoC audio for TI DRA7 EVM
3 *
4 * Author: Misael Lopez Cruz <misael.lopez@ti.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include <linux/platform_device.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/clk.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/soc.h>
29#include <sound/pcm_params.h>
30#include <sound/soc-dapm.h>
31
32struct dra7_snd_data {
33 unsigned int media_mclk_freq;
34 int media_slots;
35};
36
37static int dra7_mcasp_reparent(struct snd_soc_card *card,
38 const char *fclk_name,
39 const char *parent_name)
40{
41 struct clk *gfclk, *parent_clk;
42 int ret;
43
44 gfclk = clk_get(card->dev, fclk_name);
45 if (IS_ERR(gfclk)) {
46 dev_err(card->dev, "failed to get %s\n", fclk_name);
47 return PTR_ERR(gfclk);
48 }
49
50 parent_clk = clk_get(card->dev, parent_name);
51 if (IS_ERR(parent_clk)) {
52 dev_err(card->dev, "failed to get new parent clock %s\n",
53 parent_name);
54 ret = PTR_ERR(parent_clk);
55 goto err1;
56 }
57
58 ret = clk_set_parent(gfclk, parent_clk);
59 if (ret) {
60 dev_err(card->dev, "failed to reparent %s\n", fclk_name);
61 goto err2;
62 }
63
64err2:
65 clk_put(parent_clk);
66err1:
67 clk_put(gfclk);
68 return ret;
69}
70
71static unsigned int dra7_get_bclk(struct snd_pcm_hw_params *params, int slots)
72{
73 int sample_size = snd_pcm_format_width(params_format(params));
74 int rate = params_rate(params);
75
76 return sample_size * slots * rate;
77}
78
79static int dra7_snd_media_hw_params(struct snd_pcm_substream *substream,
80 struct snd_pcm_hw_params *params)
81{
82 struct snd_soc_pcm_runtime *rtd = substream->private_data;
83 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
84 struct snd_soc_dai *codec_dai = rtd->codec_dai;
85 struct snd_soc_card *card = rtd->card;
86 struct dra7_snd_data *card_data = snd_soc_card_get_drvdata(card);
87 unsigned int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
88 unsigned int bclk_freq;
89 int ret;
90
91 bclk_freq = dra7_get_bclk(params, card_data->media_slots);
92 if (card_data->media_mclk_freq % bclk_freq) {
93 dev_err(card->dev, "can't produce exact sample freq\n");
94 return -EPERM;
95 }
96
97 /* McASP driver requires inverted frame for I2S */
98 ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_NB_IF);
99 if (ret < 0) {
100 dev_err(card->dev, "can't set CPU DAI format %d\n", ret);
101 return ret;
102 }
103
104 /* Set McASP BCLK divider (clkid = 1) */
105 ret = snd_soc_dai_set_clkdiv(cpu_dai, 1,
106 card_data->media_mclk_freq / bclk_freq);
107 if (ret < 0) {
108 dev_err(card->dev, "can't set CPU DAI clock divider %d\n", ret);
109 return ret;
110 }
111
112 /* Set McASP sysclk from AHCLKX sourced from ATL */
113 ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
114 card_data->media_mclk_freq,
115 SND_SOC_CLOCK_IN);
116 if (ret < 0) {
117 dev_err(card->dev, "can't set CPU DAI sysclk %d\n", ret);
118 return ret;
119 }
120
121 ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_NB_NF);
122 if (ret < 0) {
123 dev_err(card->dev, "can't set CODEC DAI format %d\n", ret);
124 return ret;
125 }
126
127 /* Set MCLK as clock source for tlv320aic3106 */
128 ret = snd_soc_dai_set_sysclk(codec_dai, 0,
129 card_data->media_mclk_freq,
130 SND_SOC_CLOCK_IN);
131 if (ret < 0)
132 dev_err(card->dev, "can't set CODEC sysclk %d\n", ret);
133
134 return ret;
135}
136
137static struct snd_soc_ops dra7_snd_media_ops = {
138 .hw_params = dra7_snd_media_hw_params,
139};
140
141static struct snd_soc_dai_link dra7_snd_dai[] = {
142 {
143 /* Media: McASP3 + tlv320aic3106 */
144 .name = "Media",
145 .codec_dai_name = "tlv320aic3x-hifi",
146 .platform_name = "omap-pcm-audio",
147 .ops = &dra7_snd_media_ops,
148 },
149};
150
151static int dra7_snd_add_dai_link(struct snd_soc_card *card,
152 struct snd_soc_dai_link *dai_link,
153 const char *prefix)
154{
155 struct dra7_snd_data *card_data = snd_soc_card_get_drvdata(card);
156 struct device_node *node = card->dev->of_node;
157 struct device_node *dai_node;
158 char prop[32];
159 int ret;
160
161 if (!node) {
162 dev_err(card->dev, "card node is invalid\n");
163 return -EINVAL;
164 }
165
166 snprintf(prop, sizeof(prop), "%s-mclk-freq", prefix);
167 of_property_read_u32(node, prop,
168 &card_data->media_mclk_freq);
169
170 snprintf(prop, sizeof(prop), "%s-cpu", prefix);
171 dai_node = of_parse_phandle(node, prop, 0);
172 if (!dai_node) {
173 dev_err(card->dev, "cpu dai node is invalid\n");
174 return -EINVAL;
175 }
176
177 dai_link->cpu_of_node = dai_node;
178
179 snprintf(prop, sizeof(prop), "%s-codec", prefix);
180 dai_node = of_parse_phandle(node, prop, 0);
181 if (!dai_node) {
182 dev_err(card->dev, "codec dai node is invalid\n");
183 return -EINVAL;
184 }
185
186 dai_link->codec_of_node = dai_node;
187
188 snprintf(prop, sizeof(prop), "%s-slots", prefix);
189 of_property_read_u32(node, prop, &card_data->media_slots);
190 if ((card_data->media_slots < 1) ||
191 (card_data->media_slots > 32)) {
192 dev_err(card->dev, "invalid media slot count %d\n",
193 card_data->media_slots);
194 return -EINVAL;
195 }
196
197 ret = snd_soc_card_new_dai_links(card, dai_link, 1);
198 if (ret < 0) {
199 dev_err(card->dev, "failed to add dai link %s\n",
200 dai_link->name);
201 return ret;
202 }
203
204 return 0;
205}
206
207/* DRA7 CPU board widgets */
208static const struct snd_soc_dapm_widget dra7_snd_dapm_widgets[] = {
209 /* CPU board input */
210 SND_SOC_DAPM_MIC("Main Mic", NULL),
211 SND_SOC_DAPM_LINE("Line In", NULL),
212
213 /* CPU board outputs */
214 SND_SOC_DAPM_HP("Headphone", NULL),
215 SND_SOC_DAPM_LINE("Line Out", NULL),
216};
217
218/* Audio machine driver */
219static struct snd_soc_card dra7_snd_card = {
220 .owner = THIS_MODULE,
221 .dapm_widgets = dra7_snd_dapm_widgets,
222 .num_dapm_widgets = ARRAY_SIZE(dra7_snd_dapm_widgets),
223};
224
225static int dra7_snd_probe(struct platform_device *pdev)
226{
227 struct device_node *node = pdev->dev.of_node;
228 struct snd_soc_card *card = &dra7_snd_card;
229 struct dra7_snd_data *card_data;
230 int ret;
231
232 card->dev = &pdev->dev;
233
234 card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL);
235 if (card_data == NULL)
236 return -ENOMEM;
237
238 if (!node) {
239 dev_err(card->dev, "missing of_node\n");
240 return -ENODEV;
241 }
242
243 ret = snd_soc_of_parse_card_name(card, "ti,model");
244 if (ret) {
245 dev_err(card->dev, "card name is not provided\n");
246 return -ENODEV;
247 }
248
249 ret = snd_soc_of_parse_audio_routing(card,
250 "ti,audio-routing");
251 if (ret) {
252 dev_err(card->dev, "failed to parse DAPM routing\n");
253 return ret;
254 }
255
256 snd_soc_card_set_drvdata(card, card_data);
257
258 ret = dra7_snd_add_dai_link(card, &dra7_snd_dai[0], "ti,media");
259 if (ret) {
260 dev_err(card->dev, "failed to add media dai link %d\n", ret);
261 return ret;
262 }
263
264 ret = snd_soc_register_card(card);
265 if (ret) {
266 dev_err(card->dev, "failed to register sound card %d\n", ret);
267 goto err_card;
268 }
269
270 ret = dra7_mcasp_reparent(card, "mcasp3_ahclkx_mux", "atl_clkin2_ck");
271 if (ret) {
272 dev_err(card->dev, "failed to reparent McASP3 %d\n", ret);
273 goto err_reparent;
274 }
275
276 return 0;
277
278err_reparent:
279 snd_soc_unregister_card(card);
280err_card:
281 snd_soc_card_reset_dai_links(card);
282 return ret;
283}
284static int dra7_snd_remove(struct platform_device *pdev)
285{
286 struct snd_soc_card *card = platform_get_drvdata(pdev);
287
288 snd_soc_unregister_card(card);
289 snd_soc_card_reset_dai_links(card);
290
291 return 0;
292}
293
294static const struct of_device_id dra7_snd_of_match[] = {
295 {.compatible = "ti,dra7-evm-sound", },
296 { },
297};
298MODULE_DEVICE_TABLE(of, dra7_snd_of_match);
299
300static struct platform_driver dra7_snd_driver = {
301 .driver = {
302 .name = "dra7-evm-sound",
303 .owner = THIS_MODULE,
304 .pm = &snd_soc_pm_ops,
305 .of_match_table = dra7_snd_of_match,
306 },
307 .probe = dra7_snd_probe,
308 .remove = dra7_snd_remove,
309};
310
311module_platform_driver(dra7_snd_driver);
312
313MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
314MODULE_DESCRIPTION("ALSA SoC for DRA7 EVM");
315MODULE_LICENSE("GPL");
316MODULE_ALIAS("platform:dra7-evm-sound");