diff options
author | Misael Lopez Cruz | 2013-07-07 00:07:38 -0500 |
---|---|---|
committer | Misael Lopez Cruz | 2013-07-22 15:04:21 -0500 |
commit | 9c063b5d8efb757e78935fe5ca42fbbf87077fce (patch) | |
tree | 67efe6d31d7e2b836c8774346209646859124709 | |
parent | 9dabab86b73716ba98e4a7cc4516e85a1d5e8507 (diff) | |
download | kernel-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.txt | 60 | ||||
-rw-r--r-- | sound/soc/omap/Kconfig | 9 | ||||
-rw-r--r-- | sound/soc/omap/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/omap/dra7-evm.c | 316 |
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 | |||
3 | Required 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 | |||
14 | Available audio endpoints for the audio-routing table: | ||
15 | |||
16 | Board connectors: | ||
17 | * Main Mic | ||
18 | * Line In | ||
19 | * Headphone | ||
20 | * Line Out | ||
21 | |||
22 | tlv320aic3x 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 | |||
37 | Example: | ||
38 | |||
39 | sound { | ||
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 | ||
134 | config SND_DRA7_SOC_ATL | 134 | config SND_DRA7_SOC_ATL |
135 | tristate | 135 | tristate |
136 | |||
137 | config 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 | |||
29 | snd-soc-omap-twl4030-objs := omap-twl4030.o | 29 | snd-soc-omap-twl4030-objs := omap-twl4030.o |
30 | snd-soc-omap3pandora-objs := omap3pandora.o | 30 | snd-soc-omap3pandora-objs := omap3pandora.o |
31 | snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o | 31 | snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o |
32 | snd-soc-dra7-evm-objs := dra7-evm.o | ||
32 | 33 | ||
33 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 34 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
34 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o | 35 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o |
@@ -39,4 +40,5 @@ obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o | |||
39 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o | 40 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o |
40 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o | 41 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o |
41 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | 42 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o |
43 | obj-$(CONFIG_SND_SOC_DRA7_EVM) += snd-soc-dra7-evm.o | ||
42 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o | 44 | obj-$(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 | |||
32 | struct dra7_snd_data { | ||
33 | unsigned int media_mclk_freq; | ||
34 | int media_slots; | ||
35 | }; | ||
36 | |||
37 | static 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 | |||
64 | err2: | ||
65 | clk_put(parent_clk); | ||
66 | err1: | ||
67 | clk_put(gfclk); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static 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 | |||
79 | static 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 | |||
137 | static struct snd_soc_ops dra7_snd_media_ops = { | ||
138 | .hw_params = dra7_snd_media_hw_params, | ||
139 | }; | ||
140 | |||
141 | static 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 | |||
151 | static 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 */ | ||
208 | static 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 */ | ||
219 | static 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 | |||
225 | static 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 | |||
278 | err_reparent: | ||
279 | snd_soc_unregister_card(card); | ||
280 | err_card: | ||
281 | snd_soc_card_reset_dai_links(card); | ||
282 | return ret; | ||
283 | } | ||
284 | static 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 | |||
294 | static const struct of_device_id dra7_snd_of_match[] = { | ||
295 | {.compatible = "ti,dra7-evm-sound", }, | ||
296 | { }, | ||
297 | }; | ||
298 | MODULE_DEVICE_TABLE(of, dra7_snd_of_match); | ||
299 | |||
300 | static 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 | |||
311 | module_platform_driver(dra7_snd_driver); | ||
312 | |||
313 | MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); | ||
314 | MODULE_DESCRIPTION("ALSA SoC for DRA7 EVM"); | ||
315 | MODULE_LICENSE("GPL"); | ||
316 | MODULE_ALIAS("platform:dra7-evm-sound"); | ||