diff options
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 200 |
1 files changed, 143 insertions, 57 deletions
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>"); |