Commit | Line | Data |
---|---|---|
310355c1 VB |
1 | /* |
2 | * ASoC driver for TI DAVINCI EVM platform | |
3 | * | |
d6b52039 | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
310355c1 VB |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/moduleparam.h> | |
14 | #include <linux/timer.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/platform_device.h> | |
17 | #include <sound/core.h> | |
18 | #include <sound/pcm.h> | |
19 | #include <sound/soc.h> | |
20 | #include <sound/soc-dapm.h> | |
21 | ||
310355c1 | 22 | #include <asm/dma.h> |
f492ec9f DB |
23 | #include <asm/mach-types.h> |
24 | ||
25 | #include <mach/asp.h> | |
26 | #include <mach/edma.h> | |
27 | #include <mach/mux.h> | |
310355c1 VB |
28 | |
29 | #include "../codecs/tlv320aic3x.h" | |
30 | #include "davinci-pcm.h" | |
31 | #include "davinci-i2s.h" | |
32 | ||
310355c1 | 33 | |
d6f83396 TK |
34 | #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ |
35 | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) | |
310355c1 VB |
36 | static int evm_hw_params(struct snd_pcm_substream *substream, |
37 | struct snd_pcm_hw_params *params) | |
38 | { | |
39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
9cb132d7 LG |
40 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
41 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | |
310355c1 | 42 | int ret = 0; |
05d5e991 DB |
43 | unsigned sysclk; |
44 | ||
45 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ | |
46 | if (machine_is_davinci_dm355_evm()) | |
47 | sysclk = 27000000; | |
48 | ||
49 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by | |
50 | * board-dm644x-evm.c using GPIOs from U18. There are six | |
51 | * options; here we "know" we use a 48 KHz sample rate. | |
52 | */ | |
53 | else if (machine_is_davinci_evm()) | |
54 | sysclk = 12288000; | |
55 | ||
56 | else | |
57 | return -EINVAL; | |
310355c1 VB |
58 | |
59 | /* set codec DAI configuration */ | |
9e031624 | 60 | ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); |
310355c1 VB |
61 | if (ret < 0) |
62 | return ret; | |
63 | ||
64 | /* set cpu DAI configuration */ | |
9e031624 | 65 | ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); |
310355c1 VB |
66 | if (ret < 0) |
67 | return ret; | |
68 | ||
69 | /* set the codec system clock */ | |
05d5e991 | 70 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); |
310355c1 VB |
71 | if (ret < 0) |
72 | return ret; | |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
77 | static struct snd_soc_ops evm_ops = { | |
78 | .hw_params = evm_hw_params, | |
79 | }; | |
80 | ||
81 | /* davinci-evm machine dapm widgets */ | |
82 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |
83 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | |
84 | SND_SOC_DAPM_LINE("Line Out", NULL), | |
85 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | |
86 | SND_SOC_DAPM_LINE("Line In", NULL), | |
87 | }; | |
88 | ||
89 | /* davinci-evm machine audio_mapnections to the codec pins */ | |
acf497f9 | 90 | static const struct snd_soc_dapm_route audio_map[] = { |
310355c1 VB |
91 | /* Headphone connected to HPLOUT, HPROUT */ |
92 | {"Headphone Jack", NULL, "HPLOUT"}, | |
93 | {"Headphone Jack", NULL, "HPROUT"}, | |
94 | ||
95 | /* Line Out connected to LLOUT, RLOUT */ | |
96 | {"Line Out", NULL, "LLOUT"}, | |
97 | {"Line Out", NULL, "RLOUT"}, | |
98 | ||
99 | /* Mic connected to (MIC3L | MIC3R) */ | |
100 | {"MIC3L", NULL, "Mic Bias 2V"}, | |
101 | {"MIC3R", NULL, "Mic Bias 2V"}, | |
102 | {"Mic Bias 2V", NULL, "Mic Jack"}, | |
103 | ||
104 | /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ | |
105 | {"LINE1L", NULL, "Line In"}, | |
106 | {"LINE2L", NULL, "Line In"}, | |
107 | {"LINE1R", NULL, "Line In"}, | |
108 | {"LINE2R", NULL, "Line In"}, | |
310355c1 VB |
109 | }; |
110 | ||
111 | /* Logic for a aic3x as connected on a davinci-evm */ | |
112 | static int evm_aic3x_init(struct snd_soc_codec *codec) | |
113 | { | |
310355c1 | 114 | /* Add davinci-evm specific widgets */ |
acf497f9 MB |
115 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
116 | ARRAY_SIZE(aic3x_dapm_widgets)); | |
310355c1 VB |
117 | |
118 | /* Set up davinci-evm specific audio path audio_map */ | |
acf497f9 | 119 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
310355c1 VB |
120 | |
121 | /* not connected */ | |
a5302181 LG |
122 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); |
123 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); | |
124 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); | |
310355c1 VB |
125 | |
126 | /* always connected */ | |
a5302181 LG |
127 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
128 | snd_soc_dapm_enable_pin(codec, "Line Out"); | |
129 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | |
130 | snd_soc_dapm_enable_pin(codec, "Line In"); | |
310355c1 | 131 | |
a5302181 | 132 | snd_soc_dapm_sync(codec); |
310355c1 VB |
133 | |
134 | return 0; | |
135 | } | |
136 | ||
137 | /* davinci-evm digital audio interface glue - connects codec <--> CPU */ | |
138 | static struct snd_soc_dai_link evm_dai = { | |
139 | .name = "TLV320AIC3X", | |
140 | .stream_name = "AIC3X", | |
141 | .cpu_dai = &davinci_i2s_dai, | |
142 | .codec_dai = &aic3x_dai, | |
143 | .init = evm_aic3x_init, | |
144 | .ops = &evm_ops, | |
145 | }; | |
146 | ||
147 | /* davinci-evm audio machine driver */ | |
87506549 | 148 | static struct snd_soc_card snd_soc_card_evm = { |
310355c1 | 149 | .name = "DaVinci EVM", |
87689d56 | 150 | .platform = &davinci_soc_platform, |
310355c1 VB |
151 | .dai_link = &evm_dai, |
152 | .num_links = 1, | |
153 | }; | |
154 | ||
155 | /* evm audio private data */ | |
156 | static struct aic3x_setup_data evm_aic3x_setup = { | |
f492ec9f | 157 | .i2c_bus = 1, |
310355c1 VB |
158 | .i2c_address = 0x1b, |
159 | }; | |
160 | ||
161 | /* evm audio subsystem */ | |
162 | static struct snd_soc_device evm_snd_devdata = { | |
87506549 | 163 | .card = &snd_soc_card_evm, |
310355c1 VB |
164 | .codec_dev = &soc_codec_dev_aic3x, |
165 | .codec_data = &evm_aic3x_setup, | |
166 | }; | |
167 | ||
f492ec9f | 168 | /* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */ |
310355c1 VB |
169 | static struct resource evm_snd_resources[] = { |
170 | { | |
f492ec9f DB |
171 | .start = DAVINCI_ASP0_BASE, |
172 | .end = DAVINCI_ASP0_BASE + SZ_8K - 1, | |
310355c1 VB |
173 | .flags = IORESOURCE_MEM, |
174 | }, | |
175 | }; | |
176 | ||
177 | static struct evm_snd_platform_data evm_snd_data = { | |
f492ec9f DB |
178 | .tx_dma_ch = DAVINCI_DMA_ASP0_TX, |
179 | .rx_dma_ch = DAVINCI_DMA_ASP0_RX, | |
180 | }; | |
181 | ||
182 | /* DM335 EVM uses ASP1; line-out is a stereo mini-jack */ | |
183 | static struct resource dm335evm_snd_resources[] = { | |
184 | { | |
185 | .start = DAVINCI_ASP1_BASE, | |
186 | .end = DAVINCI_ASP1_BASE + SZ_8K - 1, | |
187 | .flags = IORESOURCE_MEM, | |
188 | }, | |
189 | }; | |
190 | ||
191 | static struct evm_snd_platform_data dm335evm_snd_data = { | |
192 | .tx_dma_ch = DAVINCI_DMA_ASP1_TX, | |
193 | .rx_dma_ch = DAVINCI_DMA_ASP1_RX, | |
310355c1 VB |
194 | }; |
195 | ||
196 | static struct platform_device *evm_snd_device; | |
197 | ||
198 | static int __init evm_init(void) | |
199 | { | |
f492ec9f DB |
200 | struct resource *resources; |
201 | unsigned num_resources; | |
202 | struct evm_snd_platform_data *data; | |
203 | int index; | |
310355c1 VB |
204 | int ret; |
205 | ||
f492ec9f DB |
206 | if (machine_is_davinci_evm()) { |
207 | davinci_cfg_reg(DM644X_MCBSP); | |
208 | ||
209 | resources = evm_snd_resources; | |
210 | num_resources = ARRAY_SIZE(evm_snd_resources); | |
211 | data = &evm_snd_data; | |
212 | index = 0; | |
213 | } else if (machine_is_davinci_dm355_evm()) { | |
214 | /* we don't use ASP1 IRQs, or we'd need to mux them ... */ | |
215 | davinci_cfg_reg(DM355_EVT8_ASP1_TX); | |
216 | davinci_cfg_reg(DM355_EVT9_ASP1_RX); | |
217 | ||
218 | resources = dm335evm_snd_resources; | |
219 | num_resources = ARRAY_SIZE(dm335evm_snd_resources); | |
220 | data = &dm335evm_snd_data; | |
221 | index = 1; | |
222 | } else | |
223 | return -EINVAL; | |
224 | ||
225 | evm_snd_device = platform_device_alloc("soc-audio", index); | |
310355c1 VB |
226 | if (!evm_snd_device) |
227 | return -ENOMEM; | |
228 | ||
229 | platform_set_drvdata(evm_snd_device, &evm_snd_devdata); | |
230 | evm_snd_devdata.dev = &evm_snd_device->dev; | |
f492ec9f | 231 | platform_device_add_data(evm_snd_device, data, sizeof(*data)); |
310355c1 | 232 | |
f492ec9f DB |
233 | ret = platform_device_add_resources(evm_snd_device, resources, |
234 | num_resources); | |
310355c1 VB |
235 | if (ret) { |
236 | platform_device_put(evm_snd_device); | |
237 | return ret; | |
238 | } | |
239 | ||
240 | ret = platform_device_add(evm_snd_device); | |
241 | if (ret) | |
242 | platform_device_put(evm_snd_device); | |
243 | ||
244 | return ret; | |
245 | } | |
246 | ||
247 | static void __exit evm_exit(void) | |
248 | { | |
249 | platform_device_unregister(evm_snd_device); | |
250 | } | |
251 | ||
252 | module_init(evm_init); | |
253 | module_exit(evm_exit); | |
254 | ||
255 | MODULE_AUTHOR("Vladimir Barinov"); | |
256 | MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); | |
257 | MODULE_LICENSE("GPL"); |