diff options
Diffstat (limited to 'sound/soc/kirkwood/kirkwood-i2s.c')
-rw-r--r-- | sound/soc/kirkwood/kirkwood-i2s.c | 108 |
1 files changed, 88 insertions, 20 deletions
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 0f3d73d4ef48..d34d91743e3f 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
@@ -103,7 +103,7 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai, | |||
103 | { | 103 | { |
104 | uint32_t clks_ctrl; | 104 | uint32_t clks_ctrl; |
105 | 105 | ||
106 | if (rate == 44100 || rate == 48000 || rate == 96000) { | 106 | if (IS_ERR(priv->extclk)) { |
107 | /* use internal dco for the supported rates | 107 | /* use internal dco for the supported rates |
108 | * defined in kirkwood_i2s_dai */ | 108 | * defined in kirkwood_i2s_dai */ |
109 | dev_dbg(dai->dev, "%s: dco set rate = %lu\n", | 109 | dev_dbg(dai->dev, "%s: dco set rate = %lu\n", |
@@ -160,9 +160,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
160 | case SNDRV_PCM_FORMAT_S16_LE: | 160 | case SNDRV_PCM_FORMAT_S16_LE: |
161 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; | 161 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; |
162 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | | 162 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | |
163 | KIRKWOOD_PLAYCTL_I2S_EN; | 163 | KIRKWOOD_PLAYCTL_I2S_EN | |
164 | KIRKWOOD_PLAYCTL_SPDIF_EN; | ||
164 | ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | | 165 | ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | |
165 | KIRKWOOD_RECCTL_I2S_EN; | 166 | KIRKWOOD_RECCTL_I2S_EN | |
167 | KIRKWOOD_RECCTL_SPDIF_EN; | ||
166 | break; | 168 | break; |
167 | /* | 169 | /* |
168 | * doesn't work... S20_3LE != kirkwood 20bit format ? | 170 | * doesn't work... S20_3LE != kirkwood 20bit format ? |
@@ -178,9 +180,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
178 | case SNDRV_PCM_FORMAT_S24_LE: | 180 | case SNDRV_PCM_FORMAT_S24_LE: |
179 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; | 181 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; |
180 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | | 182 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | |
181 | KIRKWOOD_PLAYCTL_I2S_EN; | 183 | KIRKWOOD_PLAYCTL_I2S_EN | |
184 | KIRKWOOD_PLAYCTL_SPDIF_EN; | ||
182 | ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | | 185 | ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | |
183 | KIRKWOOD_RECCTL_I2S_EN; | 186 | KIRKWOOD_RECCTL_I2S_EN | |
187 | KIRKWOOD_RECCTL_SPDIF_EN; | ||
184 | break; | 188 | break; |
185 | case SNDRV_PCM_FORMAT_S32_LE: | 189 | case SNDRV_PCM_FORMAT_S32_LE: |
186 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; | 190 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; |
@@ -240,6 +244,11 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
240 | ctl); | 244 | ctl); |
241 | } | 245 | } |
242 | 246 | ||
247 | if (dai->id == 0) | ||
248 | ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ | ||
249 | else | ||
250 | ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ | ||
251 | |||
243 | switch (cmd) { | 252 | switch (cmd) { |
244 | case SNDRV_PCM_TRIGGER_START: | 253 | case SNDRV_PCM_TRIGGER_START: |
245 | /* configure */ | 254 | /* configure */ |
@@ -258,7 +267,8 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
258 | 267 | ||
259 | case SNDRV_PCM_TRIGGER_STOP: | 268 | case SNDRV_PCM_TRIGGER_STOP: |
260 | /* stop audio, disable interrupts */ | 269 | /* stop audio, disable interrupts */ |
261 | ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; | 270 | ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | |
271 | KIRKWOOD_PLAYCTL_SPDIF_MUTE; | ||
262 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 272 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
263 | 273 | ||
264 | value = readl(priv->io + KIRKWOOD_INT_MASK); | 274 | value = readl(priv->io + KIRKWOOD_INT_MASK); |
@@ -272,13 +282,15 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
272 | 282 | ||
273 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 283 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
274 | case SNDRV_PCM_TRIGGER_SUSPEND: | 284 | case SNDRV_PCM_TRIGGER_SUSPEND: |
275 | ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; | 285 | ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | |
286 | KIRKWOOD_PLAYCTL_SPDIF_MUTE; | ||
276 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 287 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
277 | break; | 288 | break; |
278 | 289 | ||
279 | case SNDRV_PCM_TRIGGER_RESUME: | 290 | case SNDRV_PCM_TRIGGER_RESUME: |
280 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 291 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
281 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); | 292 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | |
293 | KIRKWOOD_PLAYCTL_SPDIF_MUTE); | ||
282 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 294 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
283 | break; | 295 | break; |
284 | 296 | ||
@@ -301,7 +313,13 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | |||
301 | case SNDRV_PCM_TRIGGER_START: | 313 | case SNDRV_PCM_TRIGGER_START: |
302 | /* configure */ | 314 | /* configure */ |
303 | ctl = priv->ctl_rec; | 315 | ctl = priv->ctl_rec; |
304 | value = ctl & ~KIRKWOOD_RECCTL_I2S_EN; | 316 | if (dai->id == 0) |
317 | ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */ | ||
318 | else | ||
319 | ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ | ||
320 | |||
321 | value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN | | ||
322 | KIRKWOOD_RECCTL_SPDIF_EN); | ||
305 | writel(value, priv->io + KIRKWOOD_RECCTL); | 323 | writel(value, priv->io + KIRKWOOD_RECCTL); |
306 | 324 | ||
307 | /* enable interrupts */ | 325 | /* enable interrupts */ |
@@ -361,9 +379,8 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
361 | return 0; | 379 | return 0; |
362 | } | 380 | } |
363 | 381 | ||
364 | static int kirkwood_i2s_probe(struct snd_soc_dai *dai) | 382 | static int kirkwood_i2s_init(struct kirkwood_dma_data *priv) |
365 | { | 383 | { |
366 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); | ||
367 | unsigned long value; | 384 | unsigned long value; |
368 | unsigned int reg_data; | 385 | unsigned int reg_data; |
369 | 386 | ||
@@ -404,9 +421,10 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { | |||
404 | .set_fmt = kirkwood_i2s_set_fmt, | 421 | .set_fmt = kirkwood_i2s_set_fmt, |
405 | }; | 422 | }; |
406 | 423 | ||
407 | 424 | static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = { | |
408 | static struct snd_soc_dai_driver kirkwood_i2s_dai = { | 425 | { |
409 | .probe = kirkwood_i2s_probe, | 426 | .name = "i2s", |
427 | .id = 0, | ||
410 | .playback = { | 428 | .playback = { |
411 | .channels_min = 1, | 429 | .channels_min = 1, |
412 | .channels_max = 2, | 430 | .channels_max = 2, |
@@ -422,10 +440,53 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { | |||
422 | .formats = KIRKWOOD_I2S_FORMATS, | 440 | .formats = KIRKWOOD_I2S_FORMATS, |
423 | }, | 441 | }, |
424 | .ops = &kirkwood_i2s_dai_ops, | 442 | .ops = &kirkwood_i2s_dai_ops, |
443 | }, | ||
444 | { | ||
445 | .name = "spdif", | ||
446 | .id = 1, | ||
447 | .playback = { | ||
448 | .channels_min = 1, | ||
449 | .channels_max = 2, | ||
450 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | ||
451 | SNDRV_PCM_RATE_96000, | ||
452 | .formats = KIRKWOOD_I2S_FORMATS, | ||
453 | }, | ||
454 | .capture = { | ||
455 | .channels_min = 1, | ||
456 | .channels_max = 2, | ||
457 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | ||
458 | SNDRV_PCM_RATE_96000, | ||
459 | .formats = KIRKWOOD_I2S_FORMATS, | ||
460 | }, | ||
461 | .ops = &kirkwood_i2s_dai_ops, | ||
462 | }, | ||
425 | }; | 463 | }; |
426 | 464 | ||
427 | static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { | 465 | static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = { |
428 | .probe = kirkwood_i2s_probe, | 466 | { |
467 | .name = "i2s", | ||
468 | .id = 0, | ||
469 | .playback = { | ||
470 | .channels_min = 1, | ||
471 | .channels_max = 2, | ||
472 | .rates = SNDRV_PCM_RATE_8000_192000 | | ||
473 | SNDRV_PCM_RATE_CONTINUOUS | | ||
474 | SNDRV_PCM_RATE_KNOT, | ||
475 | .formats = KIRKWOOD_I2S_FORMATS, | ||
476 | }, | ||
477 | .capture = { | ||
478 | .channels_min = 1, | ||
479 | .channels_max = 2, | ||
480 | .rates = SNDRV_PCM_RATE_8000_192000 | | ||
481 | SNDRV_PCM_RATE_CONTINUOUS | | ||
482 | SNDRV_PCM_RATE_KNOT, | ||
483 | .formats = KIRKWOOD_I2S_FORMATS, | ||
484 | }, | ||
485 | .ops = &kirkwood_i2s_dai_ops, | ||
486 | }, | ||
487 | { | ||
488 | .name = "spdif", | ||
489 | .id = 1, | ||
429 | .playback = { | 490 | .playback = { |
430 | .channels_min = 1, | 491 | .channels_min = 1, |
431 | .channels_max = 2, | 492 | .channels_max = 2, |
@@ -443,6 +504,7 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { | |||
443 | .formats = KIRKWOOD_I2S_FORMATS, | 504 | .formats = KIRKWOOD_I2S_FORMATS, |
444 | }, | 505 | }, |
445 | .ops = &kirkwood_i2s_dai_ops, | 506 | .ops = &kirkwood_i2s_dai_ops, |
507 | }, | ||
446 | }; | 508 | }; |
447 | 509 | ||
448 | static const struct snd_soc_component_driver kirkwood_i2s_component = { | 510 | static const struct snd_soc_component_driver kirkwood_i2s_component = { |
@@ -452,7 +514,7 @@ static const struct snd_soc_component_driver kirkwood_i2s_component = { | |||
452 | static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | 514 | static int kirkwood_i2s_dev_probe(struct platform_device *pdev) |
453 | { | 515 | { |
454 | struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; | 516 | struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; |
455 | struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; | 517 | struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai; |
456 | struct kirkwood_dma_data *priv; | 518 | struct kirkwood_dma_data *priv; |
457 | struct resource *mem; | 519 | struct resource *mem; |
458 | struct device_node *np = pdev->dev.of_node; | 520 | struct device_node *np = pdev->dev.of_node; |
@@ -496,14 +558,17 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
496 | return err; | 558 | return err; |
497 | 559 | ||
498 | priv->extclk = devm_clk_get(&pdev->dev, "extclk"); | 560 | priv->extclk = devm_clk_get(&pdev->dev, "extclk"); |
499 | if (!IS_ERR(priv->extclk)) { | 561 | if (IS_ERR(priv->extclk)) { |
562 | if (PTR_ERR(priv->extclk) == -EPROBE_DEFER) | ||
563 | return -EPROBE_DEFER; | ||
564 | } else { | ||
500 | if (priv->extclk == priv->clk) { | 565 | if (priv->extclk == priv->clk) { |
501 | devm_clk_put(&pdev->dev, priv->extclk); | 566 | devm_clk_put(&pdev->dev, priv->extclk); |
502 | priv->extclk = ERR_PTR(-EINVAL); | 567 | priv->extclk = ERR_PTR(-EINVAL); |
503 | } else { | 568 | } else { |
504 | dev_info(&pdev->dev, "found external clock\n"); | 569 | dev_info(&pdev->dev, "found external clock\n"); |
505 | clk_prepare_enable(priv->extclk); | 570 | clk_prepare_enable(priv->extclk); |
506 | soc_dai = &kirkwood_i2s_dai_extclk; | 571 | soc_dai = kirkwood_i2s_dai_extclk; |
507 | } | 572 | } |
508 | } | 573 | } |
509 | 574 | ||
@@ -521,7 +586,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
521 | } | 586 | } |
522 | 587 | ||
523 | err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, | 588 | err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, |
524 | soc_dai, 1); | 589 | soc_dai, 2); |
525 | if (err) { | 590 | if (err) { |
526 | dev_err(&pdev->dev, "snd_soc_register_component failed\n"); | 591 | dev_err(&pdev->dev, "snd_soc_register_component failed\n"); |
527 | goto err_component; | 592 | goto err_component; |
@@ -532,6 +597,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
532 | dev_err(&pdev->dev, "snd_soc_register_platform failed\n"); | 597 | dev_err(&pdev->dev, "snd_soc_register_platform failed\n"); |
533 | goto err_platform; | 598 | goto err_platform; |
534 | } | 599 | } |
600 | |||
601 | kirkwood_i2s_init(priv); | ||
602 | |||
535 | return 0; | 603 | return 0; |
536 | err_platform: | 604 | err_platform: |
537 | snd_soc_unregister_component(&pdev->dev); | 605 | snd_soc_unregister_component(&pdev->dev); |