diff options
Diffstat (limited to 'sound/soc/omap')
-rw-r--r-- | sound/soc/omap/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/omap/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/omap/n810.c | 6 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 200 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.h | 16 | ||||
-rw-r--r-- | sound/soc/omap/omap-pcm.c | 4 | ||||
-rw-r--r-- | sound/soc/omap/osk5912.c | 232 |
7 files changed, 402 insertions, 66 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index aea27e70043c..8b7766b998d7 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -13,3 +13,11 @@ config SND_OMAP_SOC_N810 | |||
13 | select SND_SOC_TLV320AIC3X | 13 | select SND_SOC_TLV320AIC3X |
14 | help | 14 | help |
15 | Say Y if you want to add support for SoC audio on Nokia N810. | 15 | Say Y if you want to add support for SoC audio on Nokia N810. |
16 | |||
17 | config SND_OMAP_SOC_OSK5912 | ||
18 | tristate "SoC Audio support for omap osk5912" | ||
19 | depends on SND_OMAP_SOC && MACH_OMAP_OSK | ||
20 | select SND_OMAP_SOC_MCBSP | ||
21 | select SND_SOC_TLV320AIC23 | ||
22 | help | ||
23 | Say Y if you want to add support for SoC audio on osk5912. | ||
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index d8d8d58075e3..e09d1f297f64 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o | |||
7 | 7 | ||
8 | # OMAP Machine Support | 8 | # OMAP Machine Support |
9 | snd-soc-n810-objs := n810.o | 9 | snd-soc-n810-objs := n810.o |
10 | snd-soc-osk5912-objs := osk5912.o | ||
10 | 11 | ||
11 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 12 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
13 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o | ||
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d166b6b2a60d..fae3ad36e0bf 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) | |||
247 | int i, err; | 247 | int i, err; |
248 | 248 | ||
249 | /* Not connected */ | 249 | /* Not connected */ |
250 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); | 250 | snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); |
251 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); | 251 | snd_soc_dapm_nc_pin(codec, "HPLCOM"); |
252 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); | 252 | snd_soc_dapm_nc_pin(codec, "HPRCOM"); |
253 | 253 | ||
254 | /* Add N810 specific controls */ | 254 | /* Add N810 specific controls */ |
255 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { | 255 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { |
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 35310e16d7f3..8485a8a9d0ff 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -43,6 +43,7 @@ | |||
43 | struct omap_mcbsp_data { | 43 | struct omap_mcbsp_data { |
44 | unsigned int bus_id; | 44 | unsigned int bus_id; |
45 | struct omap_mcbsp_reg_cfg regs; | 45 | struct omap_mcbsp_reg_cfg regs; |
46 | unsigned int fmt; | ||
46 | /* | 47 | /* |
47 | * Flags indicating is the bus already activated and configured by | 48 | * Flags indicating is the bus already activated and configured by |
48 | * another substream | 49 | * another substream |
@@ -59,12 +60,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS]; | |||
59 | * Stream DMA parameters. DMA request line and port address are set runtime | 60 | * Stream DMA parameters. DMA request line and port address are set runtime |
60 | * since they are different between OMAP1 and later OMAPs | 61 | * since they are different between OMAP1 and later OMAPs |
61 | */ | 62 | */ |
62 | static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = { | 63 | static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2]; |
63 | { | ||
64 | { .name = "I2S PCM Stereo out", }, | ||
65 | { .name = "I2S PCM Stereo in", }, | ||
66 | }, | ||
67 | }; | ||
68 | 64 | ||
69 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) | 65 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) |
70 | static const int omap1_dma_reqs[][2] = { | 66 | static const int omap1_dma_reqs[][2] = { |
@@ -84,11 +80,22 @@ static const unsigned long omap1_mcbsp_port[][2] = { | |||
84 | static const int omap1_dma_reqs[][2] = {}; | 80 | static const int omap1_dma_reqs[][2] = {}; |
85 | static const unsigned long omap1_mcbsp_port[][2] = {}; | 81 | static const unsigned long omap1_mcbsp_port[][2] = {}; |
86 | #endif | 82 | #endif |
87 | #if defined(CONFIG_ARCH_OMAP2420) | 83 | |
88 | static const int omap2420_dma_reqs[][2] = { | 84 | #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) |
85 | static const int omap24xx_dma_reqs[][2] = { | ||
89 | { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, | 86 | { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, |
90 | { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, | 87 | { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, |
88 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) | ||
89 | { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, | ||
90 | { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, | ||
91 | { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, | ||
92 | #endif | ||
91 | }; | 93 | }; |
94 | #else | ||
95 | static const int omap24xx_dma_reqs[][2] = {}; | ||
96 | #endif | ||
97 | |||
98 | #if defined(CONFIG_ARCH_OMAP2420) | ||
92 | static const unsigned long omap2420_mcbsp_port[][2] = { | 99 | static const unsigned long omap2420_mcbsp_port[][2] = { |
93 | { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, | 100 | { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1, |
94 | OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, | 101 | OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 }, |
@@ -96,10 +103,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = { | |||
96 | OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 }, | 103 | OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 }, |
97 | }; | 104 | }; |
98 | #else | 105 | #else |
99 | static const int omap2420_dma_reqs[][2] = {}; | ||
100 | static const unsigned long omap2420_mcbsp_port[][2] = {}; | 106 | static const unsigned long omap2420_mcbsp_port[][2] = {}; |
101 | #endif | 107 | #endif |
102 | 108 | ||
109 | #if defined(CONFIG_ARCH_OMAP2430) | ||
110 | static const unsigned long omap2430_mcbsp_port[][2] = { | ||
111 | { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, | ||
112 | OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, | ||
113 | { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR, | ||
114 | OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR }, | ||
115 | { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR, | ||
116 | OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR }, | ||
117 | { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR, | ||
118 | OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR }, | ||
119 | { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR, | ||
120 | OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR }, | ||
121 | }; | ||
122 | #else | ||
123 | static const unsigned long omap2430_mcbsp_port[][2] = {}; | ||
124 | #endif | ||
125 | |||
126 | #if defined(CONFIG_ARCH_OMAP34XX) | ||
127 | static const unsigned long omap34xx_mcbsp_port[][2] = { | ||
128 | { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, | ||
129 | OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, | ||
130 | { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR, | ||
131 | OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR }, | ||
132 | { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR, | ||
133 | OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR }, | ||
134 | { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR, | ||
135 | OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR }, | ||
136 | { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR, | ||
137 | OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR }, | ||
138 | }; | ||
139 | #else | ||
140 | static const unsigned long omap34xx_mcbsp_port[][2] = {}; | ||
141 | #endif | ||
142 | |||
103 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) | 143 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) |
104 | { | 144 | { |
105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
@@ -161,20 +201,26 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
161 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 201 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
162 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; | 202 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; |
163 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; | 203 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; |
204 | int wlen; | ||
164 | unsigned long port; | 205 | unsigned long port; |
165 | 206 | ||
166 | if (cpu_class_is_omap1()) { | 207 | if (cpu_class_is_omap1()) { |
167 | dma = omap1_dma_reqs[bus_id][substream->stream]; | 208 | dma = omap1_dma_reqs[bus_id][substream->stream]; |
168 | port = omap1_mcbsp_port[bus_id][substream->stream]; | 209 | port = omap1_mcbsp_port[bus_id][substream->stream]; |
169 | } else if (cpu_is_omap2420()) { | 210 | } else if (cpu_is_omap2420()) { |
170 | dma = omap2420_dma_reqs[bus_id][substream->stream]; | 211 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; |
171 | port = omap2420_mcbsp_port[bus_id][substream->stream]; | 212 | port = omap2420_mcbsp_port[bus_id][substream->stream]; |
213 | } else if (cpu_is_omap2430()) { | ||
214 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | ||
215 | port = omap2430_mcbsp_port[bus_id][substream->stream]; | ||
216 | } else if (cpu_is_omap343x()) { | ||
217 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | ||
218 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; | ||
172 | } else { | 219 | } else { |
173 | /* | ||
174 | * TODO: Add support for 2430 and 3430 | ||
175 | */ | ||
176 | return -ENODEV; | 220 | return -ENODEV; |
177 | } | 221 | } |
222 | omap_mcbsp_dai_dma_params[id][substream->stream].name = | ||
223 | substream->stream ? "Audio Capture" : "Audio Playback"; | ||
178 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; | 224 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; |
179 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; | 225 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; |
180 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; | 226 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; |
@@ -200,19 +246,29 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
200 | switch (params_format(params)) { | 246 | switch (params_format(params)) { |
201 | case SNDRV_PCM_FORMAT_S16_LE: | 247 | case SNDRV_PCM_FORMAT_S16_LE: |
202 | /* Set word lengths */ | 248 | /* Set word lengths */ |
249 | wlen = 16; | ||
203 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); | 250 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); |
204 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); | 251 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); |
205 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); | 252 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); |
206 | regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); | 253 | regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); |
207 | /* Set FS period and length in terms of bit clock periods */ | ||
208 | regs->srgr2 |= FPER(16 * 2 - 1); | ||
209 | regs->srgr1 |= FWID(16 - 1); | ||
210 | break; | 254 | break; |
211 | default: | 255 | default: |
212 | /* Unsupported PCM format */ | 256 | /* Unsupported PCM format */ |
213 | return -EINVAL; | 257 | return -EINVAL; |
214 | } | 258 | } |
215 | 259 | ||
260 | /* Set FS period and length in terms of bit clock periods */ | ||
261 | switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
262 | case SND_SOC_DAIFMT_I2S: | ||
263 | regs->srgr2 |= FPER(wlen * 2 - 1); | ||
264 | regs->srgr1 |= FWID(wlen - 1); | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_DSP_A: | ||
267 | regs->srgr2 |= FPER(wlen * 2 - 1); | ||
268 | regs->srgr1 |= FWID(wlen * 2 - 2); | ||
269 | break; | ||
270 | } | ||
271 | |||
216 | omap_mcbsp_config(bus_id, &mcbsp_data->regs); | 272 | omap_mcbsp_config(bus_id, &mcbsp_data->regs); |
217 | mcbsp_data->configured = 1; | 273 | mcbsp_data->configured = 1; |
218 | 274 | ||
@@ -232,6 +288,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
232 | if (mcbsp_data->configured) | 288 | if (mcbsp_data->configured) |
233 | return 0; | 289 | return 0; |
234 | 290 | ||
291 | mcbsp_data->fmt = fmt; | ||
235 | memset(regs, 0, sizeof(*regs)); | 292 | memset(regs, 0, sizeof(*regs)); |
236 | /* Generic McBSP register settings */ | 293 | /* Generic McBSP register settings */ |
237 | regs->spcr2 |= XINTM(3) | FREE; | 294 | regs->spcr2 |= XINTM(3) | FREE; |
@@ -245,6 +302,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
245 | regs->rcr2 |= RDATDLY(1); | 302 | regs->rcr2 |= RDATDLY(1); |
246 | regs->xcr2 |= XDATDLY(1); | 303 | regs->xcr2 |= XDATDLY(1); |
247 | break; | 304 | break; |
305 | case SND_SOC_DAIFMT_DSP_A: | ||
306 | /* 0-bit data delay */ | ||
307 | regs->rcr2 |= RDATDLY(0); | ||
308 | regs->xcr2 |= XDATDLY(0); | ||
309 | break; | ||
248 | default: | 310 | default: |
249 | /* Unsupported data format */ | 311 | /* Unsupported data format */ |
250 | return -EINVAL; | 312 | return -EINVAL; |
@@ -310,7 +372,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
310 | int clk_id) | 372 | int clk_id) |
311 | { | 373 | { |
312 | int sel_bit; | 374 | int sel_bit; |
313 | u16 reg; | 375 | u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1; |
314 | 376 | ||
315 | if (cpu_class_is_omap1()) { | 377 | if (cpu_class_is_omap1()) { |
316 | /* OMAP1's can use only external source clock */ | 378 | /* OMAP1's can use only external source clock */ |
@@ -320,6 +382,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
320 | return 0; | 382 | return 0; |
321 | } | 383 | } |
322 | 384 | ||
385 | if (cpu_is_omap2420() && mcbsp_data->bus_id > 1) | ||
386 | return -EINVAL; | ||
387 | |||
388 | if (cpu_is_omap343x()) | ||
389 | reg_devconf1 = OMAP343X_CONTROL_DEVCONF1; | ||
390 | |||
323 | switch (mcbsp_data->bus_id) { | 391 | switch (mcbsp_data->bus_id) { |
324 | case 0: | 392 | case 0: |
325 | reg = OMAP2_CONTROL_DEVCONF0; | 393 | reg = OMAP2_CONTROL_DEVCONF0; |
@@ -329,20 +397,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
329 | reg = OMAP2_CONTROL_DEVCONF0; | 397 | reg = OMAP2_CONTROL_DEVCONF0; |
330 | sel_bit = 6; | 398 | sel_bit = 6; |
331 | break; | 399 | break; |
332 | /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */ | 400 | case 2: |
401 | reg = reg_devconf1; | ||
402 | sel_bit = 0; | ||
403 | break; | ||
404 | case 3: | ||
405 | reg = reg_devconf1; | ||
406 | sel_bit = 2; | ||
407 | break; | ||
408 | case 4: | ||
409 | reg = reg_devconf1; | ||
410 | sel_bit = 4; | ||
411 | break; | ||
333 | default: | 412 | default: |
334 | return -EINVAL; | 413 | return -EINVAL; |
335 | } | 414 | } |
336 | 415 | ||
337 | if (cpu_class_is_omap2()) { | 416 | if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) |
338 | if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) { | 417 | omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg); |
339 | omap_ctrl_writel(omap_ctrl_readl(reg) & | 418 | else |
340 | ~(1 << sel_bit), reg); | 419 | omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg); |
341 | } else { | ||
342 | omap_ctrl_writel(omap_ctrl_readl(reg) | | ||
343 | (1 << sel_bit), reg); | ||
344 | } | ||
345 | } | ||
346 | 420 | ||
347 | return 0; | 421 | return 0; |
348 | } | 422 | } |
@@ -376,37 +450,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
376 | return err; | 450 | return err; |
377 | } | 451 | } |
378 | 452 | ||
379 | struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = { | 453 | #define OMAP_MCBSP_DAI_BUILDER(link_id) \ |
380 | { | 454 | { \ |
381 | .name = "omap-mcbsp-dai", | 455 | .name = "omap-mcbsp-dai-(link_id)", \ |
382 | .id = 0, | 456 | .id = (link_id), \ |
383 | .type = SND_SOC_DAI_I2S, | 457 | .type = SND_SOC_DAI_I2S, \ |
384 | .playback = { | 458 | .playback = { \ |
385 | .channels_min = 2, | 459 | .channels_min = 2, \ |
386 | .channels_max = 2, | 460 | .channels_max = 2, \ |
387 | .rates = OMAP_MCBSP_RATES, | 461 | .rates = OMAP_MCBSP_RATES, \ |
388 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 462 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ |
389 | }, | 463 | }, \ |
390 | .capture = { | 464 | .capture = { \ |
391 | .channels_min = 2, | 465 | .channels_min = 2, \ |
392 | .channels_max = 2, | 466 | .channels_max = 2, \ |
393 | .rates = OMAP_MCBSP_RATES, | 467 | .rates = OMAP_MCBSP_RATES, \ |
394 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 468 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ |
395 | }, | 469 | }, \ |
396 | .ops = { | 470 | .ops = { \ |
397 | .startup = omap_mcbsp_dai_startup, | 471 | .startup = omap_mcbsp_dai_startup, \ |
398 | .shutdown = omap_mcbsp_dai_shutdown, | 472 | .shutdown = omap_mcbsp_dai_shutdown, \ |
399 | .trigger = omap_mcbsp_dai_trigger, | 473 | .trigger = omap_mcbsp_dai_trigger, \ |
400 | .hw_params = omap_mcbsp_dai_hw_params, | 474 | .hw_params = omap_mcbsp_dai_hw_params, \ |
401 | }, | 475 | }, \ |
402 | .dai_ops = { | 476 | .dai_ops = { \ |
403 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, | 477 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ |
404 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, | 478 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ |
405 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, | 479 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ |
406 | }, | 480 | }, \ |
407 | .private_data = &mcbsp_data[0].bus_id, | 481 | .private_data = &mcbsp_data[(link_id)].bus_id, \ |
408 | }, | 482 | } |
483 | |||
484 | struct snd_soc_dai omap_mcbsp_dai[] = { | ||
485 | OMAP_MCBSP_DAI_BUILDER(0), | ||
486 | OMAP_MCBSP_DAI_BUILDER(1), | ||
487 | #if NUM_LINKS >= 3 | ||
488 | OMAP_MCBSP_DAI_BUILDER(2), | ||
489 | #endif | ||
490 | #if NUM_LINKS == 5 | ||
491 | OMAP_MCBSP_DAI_BUILDER(3), | ||
492 | OMAP_MCBSP_DAI_BUILDER(4), | ||
493 | #endif | ||
409 | }; | 494 | }; |
495 | |||
410 | EXPORT_SYMBOL_GPL(omap_mcbsp_dai); | 496 | EXPORT_SYMBOL_GPL(omap_mcbsp_dai); |
411 | 497 | ||
412 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); | 498 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); |
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index ed8afb550671..df7ad13ba73d 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h | |||
@@ -38,11 +38,17 @@ enum omap_mcbsp_div { | |||
38 | OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ | 38 | OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /* | 41 | #if defined(CONFIG_ARCH_OMAP2420) |
42 | * REVISIT: Preparation for the ASoC v2. Let the number of available links to | 42 | #define NUM_LINKS 2 |
43 | * be same than number of McBSP ports found in OMAP(s) we are compiling for. | 43 | #endif |
44 | */ | 44 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) |
45 | #define NUM_LINKS 1 | 45 | #undef NUM_LINKS |
46 | #define NUM_LINKS 3 | ||
47 | #endif | ||
48 | #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) | ||
49 | #undef NUM_LINKS | ||
50 | #define NUM_LINKS 5 | ||
51 | #endif | ||
46 | 52 | ||
47 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; | 53 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; |
48 | 54 | ||
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 690bfeaec4a0..e9084fdd2082 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, | |||
97 | prtd->dma_data = dma_data; | 97 | prtd->dma_data = dma_data; |
98 | err = omap_request_dma(dma_data->dma_req, dma_data->name, | 98 | err = omap_request_dma(dma_data->dma_req, dma_data->name, |
99 | omap_pcm_dma_irq, substream, &prtd->dma_ch); | 99 | omap_pcm_dma_irq, substream, &prtd->dma_ch); |
100 | if (!cpu_is_omap1510()) { | 100 | if (!err & !cpu_is_omap1510()) { |
101 | /* | 101 | /* |
102 | * Link channel with itself so DMA doesn't need any | 102 | * Link channel with itself so DMA doesn't need any |
103 | * reprogramming while looping the buffer | 103 | * reprogramming while looping the buffer |
@@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
147 | dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; | 147 | dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; |
148 | dma_params.src_start = runtime->dma_addr; | 148 | dma_params.src_start = runtime->dma_addr; |
149 | dma_params.dst_start = dma_data->port_addr; | 149 | dma_params.dst_start = dma_data->port_addr; |
150 | dma_params.dst_port = OMAP_DMA_PORT_MPUI; | ||
150 | } else { | 151 | } else { |
151 | dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; | 152 | dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; |
152 | dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; | 153 | dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; |
153 | dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; | 154 | dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; |
154 | dma_params.src_start = dma_data->port_addr; | 155 | dma_params.src_start = dma_data->port_addr; |
155 | dma_params.dst_start = runtime->dma_addr; | 156 | dma_params.dst_start = runtime->dma_addr; |
157 | dma_params.src_port = OMAP_DMA_PORT_MPUI; | ||
156 | } | 158 | } |
157 | /* | 159 | /* |
158 | * Set DMA transfer frame size equal to ALSA period size and frame | 160 | * Set DMA transfer frame size equal to ALSA period size and frame |
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c new file mode 100644 index 000000000000..0fe733796898 --- /dev/null +++ b/sound/soc/omap/osk5912.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * osk5912.c -- SoC audio for OSK 5912 | ||
3 | * | ||
4 | * Copyright (C) 2008 Mistral Solutions | ||
5 | * | ||
6 | * Contact: Arun KS <arunks@mistralsolutions.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | #include <mach/hardware.h> | ||
33 | #include <linux/gpio.h> | ||
34 | #include <mach/mcbsp.h> | ||
35 | |||
36 | #include "omap-mcbsp.h" | ||
37 | #include "omap-pcm.h" | ||
38 | #include "../codecs/tlv320aic23.h" | ||
39 | |||
40 | #define CODEC_CLOCK 12000000 | ||
41 | |||
42 | static struct clk *tlv320aic23_mclk; | ||
43 | |||
44 | static int osk_startup(struct snd_pcm_substream *substream) | ||
45 | { | ||
46 | return clk_enable(tlv320aic23_mclk); | ||
47 | } | ||
48 | |||
49 | static void osk_shutdown(struct snd_pcm_substream *substream) | ||
50 | { | ||
51 | clk_disable(tlv320aic23_mclk); | ||
52 | } | ||
53 | |||
54 | static int osk_hw_params(struct snd_pcm_substream *substream, | ||
55 | struct snd_pcm_hw_params *params) | ||
56 | { | ||
57 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
58 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
59 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
60 | int err; | ||
61 | |||
62 | /* Set codec DAI configuration */ | ||
63 | err = snd_soc_dai_set_fmt(codec_dai, | ||
64 | SND_SOC_DAIFMT_DSP_A | | ||
65 | SND_SOC_DAIFMT_NB_IF | | ||
66 | SND_SOC_DAIFMT_CBM_CFM); | ||
67 | if (err < 0) { | ||
68 | printk(KERN_ERR "can't set codec DAI configuration\n"); | ||
69 | return err; | ||
70 | } | ||
71 | |||
72 | /* Set cpu DAI configuration */ | ||
73 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
74 | SND_SOC_DAIFMT_DSP_A | | ||
75 | SND_SOC_DAIFMT_NB_IF | | ||
76 | SND_SOC_DAIFMT_CBM_CFM); | ||
77 | if (err < 0) { | ||
78 | printk(KERN_ERR "can't set cpu DAI configuration\n"); | ||
79 | return err; | ||
80 | } | ||
81 | |||
82 | /* Set the codec system clock for DAC and ADC */ | ||
83 | err = | ||
84 | snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
85 | |||
86 | if (err < 0) { | ||
87 | printk(KERN_ERR "can't set codec system clock\n"); | ||
88 | return err; | ||
89 | } | ||
90 | |||
91 | return err; | ||
92 | } | ||
93 | |||
94 | static struct snd_soc_ops osk_ops = { | ||
95 | .startup = osk_startup, | ||
96 | .hw_params = osk_hw_params, | ||
97 | .shutdown = osk_shutdown, | ||
98 | }; | ||
99 | |||
100 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
101 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
102 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
103 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
104 | }; | ||
105 | |||
106 | static const struct snd_soc_dapm_route audio_map[] = { | ||
107 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
108 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
109 | |||
110 | {"LLINEIN", NULL, "Line In"}, | ||
111 | {"RLINEIN", NULL, "Line In"}, | ||
112 | |||
113 | {"MICIN", NULL, "Mic Jack"}, | ||
114 | }; | ||
115 | |||
116 | static int osk_tlv320aic23_init(struct snd_soc_codec *codec) | ||
117 | { | ||
118 | |||
119 | /* Add osk5912 specific widgets */ | ||
120 | snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, | ||
121 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | ||
122 | |||
123 | /* Set up osk5912 specific audio path audio_map */ | ||
124 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
125 | |||
126 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
127 | snd_soc_dapm_enable_pin(codec, "Line In"); | ||
128 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
129 | |||
130 | snd_soc_dapm_sync(codec); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
136 | static struct snd_soc_dai_link osk_dai = { | ||
137 | .name = "TLV320AIC23", | ||
138 | .stream_name = "AIC23", | ||
139 | .cpu_dai = &omap_mcbsp_dai[0], | ||
140 | .codec_dai = &tlv320aic23_dai, | ||
141 | .init = osk_tlv320aic23_init, | ||
142 | .ops = &osk_ops, | ||
143 | }; | ||
144 | |||
145 | /* Audio machine driver */ | ||
146 | static struct snd_soc_machine snd_soc_machine_osk = { | ||
147 | .name = "OSK5912", | ||
148 | .dai_link = &osk_dai, | ||
149 | .num_links = 1, | ||
150 | }; | ||
151 | |||
152 | /* Audio subsystem */ | ||
153 | static struct snd_soc_device osk_snd_devdata = { | ||
154 | .machine = &snd_soc_machine_osk, | ||
155 | .platform = &omap_soc_platform, | ||
156 | .codec_dev = &soc_codec_dev_tlv320aic23, | ||
157 | }; | ||
158 | |||
159 | static struct platform_device *osk_snd_device; | ||
160 | |||
161 | static int __init osk_soc_init(void) | ||
162 | { | ||
163 | int err; | ||
164 | u32 curRate; | ||
165 | struct device *dev; | ||
166 | |||
167 | if (!(machine_is_omap_osk())) | ||
168 | return -ENODEV; | ||
169 | |||
170 | osk_snd_device = platform_device_alloc("soc-audio", -1); | ||
171 | if (!osk_snd_device) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | platform_set_drvdata(osk_snd_device, &osk_snd_devdata); | ||
175 | osk_snd_devdata.dev = &osk_snd_device->dev; | ||
176 | *(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */ | ||
177 | err = platform_device_add(osk_snd_device); | ||
178 | if (err) | ||
179 | goto err1; | ||
180 | |||
181 | dev = &osk_snd_device->dev; | ||
182 | |||
183 | tlv320aic23_mclk = clk_get(dev, "mclk"); | ||
184 | if (IS_ERR(tlv320aic23_mclk)) { | ||
185 | printk(KERN_ERR "Could not get mclk clock\n"); | ||
186 | return -ENODEV; | ||
187 | } | ||
188 | |||
189 | if (clk_get_usecount(tlv320aic23_mclk) > 0) { | ||
190 | /* MCLK is already in use */ | ||
191 | printk(KERN_WARNING | ||
192 | "MCLK in use at %d Hz. We change it to %d Hz\n", | ||
193 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Configure 12 MHz output on MCLK. | ||
198 | */ | ||
199 | curRate = (uint) clk_get_rate(tlv320aic23_mclk); | ||
200 | if (curRate != CODEC_CLOCK) { | ||
201 | if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) { | ||
202 | printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n"); | ||
203 | err = -ECANCELED; | ||
204 | goto err1; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n", | ||
209 | (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK, | ||
210 | clk_get_usecount(tlv320aic23_mclk)); | ||
211 | |||
212 | return 0; | ||
213 | err1: | ||
214 | clk_put(tlv320aic23_mclk); | ||
215 | platform_device_del(osk_snd_device); | ||
216 | platform_device_put(osk_snd_device); | ||
217 | |||
218 | return err; | ||
219 | |||
220 | } | ||
221 | |||
222 | static void __exit osk_soc_exit(void) | ||
223 | { | ||
224 | platform_device_unregister(osk_snd_device); | ||
225 | } | ||
226 | |||
227 | module_init(osk_soc_init); | ||
228 | module_exit(osk_soc_exit); | ||
229 | |||
230 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
231 | MODULE_DESCRIPTION("ALSA SoC OSK 5912"); | ||
232 | MODULE_LICENSE("GPL"); | ||