aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra/tegra_i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra_i2s.c')
-rw-r--r--sound/soc/tegra/tegra_i2s.c164
1 files changed, 56 insertions, 108 deletions
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
index 6728fab8c41..33509de5254 100644
--- a/sound/soc/tegra/tegra_i2s.c
+++ b/sound/soc/tegra/tegra_i2s.c
@@ -36,13 +36,13 @@
36#include <linux/seq_file.h> 36#include <linux/seq_file.h>
37#include <linux/slab.h> 37#include <linux/slab.h>
38#include <linux/io.h> 38#include <linux/io.h>
39#include <linux/of.h>
39#include <mach/iomap.h> 40#include <mach/iomap.h>
40#include <sound/core.h> 41#include <sound/core.h>
41#include <sound/pcm.h> 42#include <sound/pcm.h>
42#include <sound/pcm_params.h> 43#include <sound/pcm_params.h>
43#include <sound/soc.h> 44#include <sound/soc.h>
44 45
45#include "tegra_das.h"
46#include "tegra_i2s.h" 46#include "tegra_i2s.h"
47 47
48#define DRV_NAME "tegra-i2s" 48#define DRV_NAME "tegra-i2s"
@@ -99,13 +99,11 @@ static const struct file_operations tegra_i2s_debug_fops = {
99 .release = single_release, 99 .release = single_release,
100}; 100};
101 101
102static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) 102static void tegra_i2s_debug_add(struct tegra_i2s *i2s)
103{ 103{
104 char name[] = DRV_NAME ".0"; 104 i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
105 105 snd_soc_debugfs_root, i2s,
106 snprintf(name, sizeof(name), DRV_NAME".%1d", id); 106 &tegra_i2s_debug_fops);
107 i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root,
108 i2s, &tegra_i2s_debug_fops);
109} 107}
110 108
111static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) 109static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
@@ -306,93 +304,54 @@ static int tegra_i2s_probe(struct snd_soc_dai *dai)
306 return 0; 304 return 0;
307} 305}
308 306
309static struct snd_soc_dai_ops tegra_i2s_dai_ops = { 307static const struct snd_soc_dai_ops tegra_i2s_dai_ops = {
310 .set_fmt = tegra_i2s_set_fmt, 308 .set_fmt = tegra_i2s_set_fmt,
311 .hw_params = tegra_i2s_hw_params, 309 .hw_params = tegra_i2s_hw_params,
312 .trigger = tegra_i2s_trigger, 310 .trigger = tegra_i2s_trigger,
313}; 311};
314 312
315static struct snd_soc_dai_driver tegra_i2s_dai[] = { 313static const struct snd_soc_dai_driver tegra_i2s_dai_template = {
316 { 314 .probe = tegra_i2s_probe,
317 .name = DRV_NAME ".0", 315 .playback = {
318 .probe = tegra_i2s_probe, 316 .channels_min = 2,
319 .playback = { 317 .channels_max = 2,
320 .channels_min = 2, 318 .rates = SNDRV_PCM_RATE_8000_96000,
321 .channels_max = 2, 319 .formats = SNDRV_PCM_FMTBIT_S16_LE,
322 .rates = SNDRV_PCM_RATE_8000_96000,
323 .formats = SNDRV_PCM_FMTBIT_S16_LE,
324 },
325 .capture = {
326 .channels_min = 2,
327 .channels_max = 2,
328 .rates = SNDRV_PCM_RATE_8000_96000,
329 .formats = SNDRV_PCM_FMTBIT_S16_LE,
330 },
331 .ops = &tegra_i2s_dai_ops,
332 .symmetric_rates = 1,
333 }, 320 },
334 { 321 .capture = {
335 .name = DRV_NAME ".1", 322 .channels_min = 2,
336 .probe = tegra_i2s_probe, 323 .channels_max = 2,
337 .playback = { 324 .rates = SNDRV_PCM_RATE_8000_96000,
338 .channels_min = 2, 325 .formats = SNDRV_PCM_FMTBIT_S16_LE,
339 .channels_max = 2,
340 .rates = SNDRV_PCM_RATE_8000_96000,
341 .formats = SNDRV_PCM_FMTBIT_S16_LE,
342 },
343 .capture = {
344 .channels_min = 2,
345 .channels_max = 2,
346 .rates = SNDRV_PCM_RATE_8000_96000,
347 .formats = SNDRV_PCM_FMTBIT_S16_LE,
348 },
349 .ops = &tegra_i2s_dai_ops,
350 .symmetric_rates = 1,
351 }, 326 },
327 .ops = &tegra_i2s_dai_ops,
328 .symmetric_rates = 1,
352}; 329};
353 330
354static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) 331static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
355{ 332{
356 struct tegra_i2s * i2s; 333 struct tegra_i2s * i2s;
357 struct resource *mem, *memregion, *dmareq; 334 struct resource *mem, *memregion, *dmareq;
335 u32 of_dma[2];
336 u32 dma_ch;
358 int ret; 337 int ret;
359 338
360 if ((pdev->id < 0) || 339 i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL);
361 (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) {
362 dev_err(&pdev->dev, "ID %d out of range\n", pdev->id);
363 return -EINVAL;
364 }
365
366 /*
367 * FIXME: Until a codec driver exists for the tegra DAS, hard-code a
368 * 1:1 mapping between audio controllers and audio ports.
369 */
370 ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id,
371 TEGRA_DAS_DAP_SEL_DAC1 + pdev->id);
372 if (ret) {
373 dev_err(&pdev->dev, "Can't set up DAP connection\n");
374 return ret;
375 }
376 ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id,
377 TEGRA_DAS_DAC_SEL_DAP1 + pdev->id);
378 if (ret) {
379 dev_err(&pdev->dev, "Can't set up DAC connection\n");
380 return ret;
381 }
382
383 i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL);
384 if (!i2s) { 340 if (!i2s) {
385 dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); 341 dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
386 ret = -ENOMEM; 342 ret = -ENOMEM;
387 goto exit; 343 goto err;
388 } 344 }
389 dev_set_drvdata(&pdev->dev, i2s); 345 dev_set_drvdata(&pdev->dev, i2s);
390 346
347 i2s->dai = tegra_i2s_dai_template;
348 i2s->dai.name = dev_name(&pdev->dev);
349
391 i2s->clk_i2s = clk_get(&pdev->dev, NULL); 350 i2s->clk_i2s = clk_get(&pdev->dev, NULL);
392 if (IS_ERR(i2s->clk_i2s)) { 351 if (IS_ERR(i2s->clk_i2s)) {
393 dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); 352 dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
394 ret = PTR_ERR(i2s->clk_i2s); 353 ret = PTR_ERR(i2s->clk_i2s);
395 goto err_free; 354 goto err;
396 } 355 }
397 356
398 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 357 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -404,104 +363,93 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
404 363
405 dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); 364 dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
406 if (!dmareq) { 365 if (!dmareq) {
407 dev_err(&pdev->dev, "No DMA resource\n"); 366 if (of_property_read_u32_array(pdev->dev.of_node,
408 ret = -ENODEV; 367 "nvidia,dma-request-selector",
409 goto err_clk_put; 368 of_dma, 2) < 0) {
369 dev_err(&pdev->dev, "No DMA resource\n");
370 ret = -ENODEV;
371 goto err_clk_put;
372 }
373 dma_ch = of_dma[1];
374 } else {
375 dma_ch = dmareq->start;
410 } 376 }
411 377
412 memregion = request_mem_region(mem->start, resource_size(mem), 378 memregion = devm_request_mem_region(&pdev->dev, mem->start,
413 DRV_NAME); 379 resource_size(mem), DRV_NAME);
414 if (!memregion) { 380 if (!memregion) {
415 dev_err(&pdev->dev, "Memory region already claimed\n"); 381 dev_err(&pdev->dev, "Memory region already claimed\n");
416 ret = -EBUSY; 382 ret = -EBUSY;
417 goto err_clk_put; 383 goto err_clk_put;
418 } 384 }
419 385
420 i2s->regs = ioremap(mem->start, resource_size(mem)); 386 i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
421 if (!i2s->regs) { 387 if (!i2s->regs) {
422 dev_err(&pdev->dev, "ioremap failed\n"); 388 dev_err(&pdev->dev, "ioremap failed\n");
423 ret = -ENOMEM; 389 ret = -ENOMEM;
424 goto err_release; 390 goto err_clk_put;
425 } 391 }
426 392
427 i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; 393 i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
428 i2s->capture_dma_data.wrap = 4; 394 i2s->capture_dma_data.wrap = 4;
429 i2s->capture_dma_data.width = 32; 395 i2s->capture_dma_data.width = 32;
430 i2s->capture_dma_data.req_sel = dmareq->start; 396 i2s->capture_dma_data.req_sel = dma_ch;
431 397
432 i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; 398 i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
433 i2s->playback_dma_data.wrap = 4; 399 i2s->playback_dma_data.wrap = 4;
434 i2s->playback_dma_data.width = 32; 400 i2s->playback_dma_data.width = 32;
435 i2s->playback_dma_data.req_sel = dmareq->start; 401 i2s->playback_dma_data.req_sel = dma_ch;
436 402
437 i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED; 403 i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
438 404
439 ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]); 405 ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
440 if (ret) { 406 if (ret) {
441 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); 407 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
442 ret = -ENOMEM; 408 ret = -ENOMEM;
443 goto err_unmap; 409 goto err_clk_put;
444 } 410 }
445 411
446 tegra_i2s_debug_add(i2s, pdev->id); 412 tegra_i2s_debug_add(i2s);
447 413
448 return 0; 414 return 0;
449 415
450err_unmap:
451 iounmap(i2s->regs);
452err_release:
453 release_mem_region(mem->start, resource_size(mem));
454err_clk_put: 416err_clk_put:
455 clk_put(i2s->clk_i2s); 417 clk_put(i2s->clk_i2s);
456err_free: 418err:
457 kfree(i2s);
458exit:
459 return ret; 419 return ret;
460} 420}
461 421
462static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) 422static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
463{ 423{
464 struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev); 424 struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
465 struct resource *res;
466 425
467 snd_soc_unregister_dai(&pdev->dev); 426 snd_soc_unregister_dai(&pdev->dev);
468 427
469 tegra_i2s_debug_remove(i2s); 428 tegra_i2s_debug_remove(i2s);
470 429
471 iounmap(i2s->regs);
472
473 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
474 release_mem_region(res->start, resource_size(res));
475
476 clk_put(i2s->clk_i2s); 430 clk_put(i2s->clk_i2s);
477 431
478 kfree(i2s);
479
480 return 0; 432 return 0;
481} 433}
482 434
435static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
436 { .compatible = "nvidia,tegra20-i2s", },
437 {},
438};
439
483static struct platform_driver tegra_i2s_driver = { 440static struct platform_driver tegra_i2s_driver = {
484 .driver = { 441 .driver = {
485 .name = DRV_NAME, 442 .name = DRV_NAME,
486 .owner = THIS_MODULE, 443 .owner = THIS_MODULE,
444 .of_match_table = tegra_i2s_of_match,
487 }, 445 },
488 .probe = tegra_i2s_platform_probe, 446 .probe = tegra_i2s_platform_probe,
489 .remove = __devexit_p(tegra_i2s_platform_remove), 447 .remove = __devexit_p(tegra_i2s_platform_remove),
490}; 448};
491 449module_platform_driver(tegra_i2s_driver);
492static int __init snd_tegra_i2s_init(void)
493{
494 return platform_driver_register(&tegra_i2s_driver);
495}
496module_init(snd_tegra_i2s_init);
497
498static void __exit snd_tegra_i2s_exit(void)
499{
500 platform_driver_unregister(&tegra_i2s_driver);
501}
502module_exit(snd_tegra_i2s_exit);
503 450
504MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 451MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
505MODULE_DESCRIPTION("Tegra I2S ASoC driver"); 452MODULE_DESCRIPTION("Tegra I2S ASoC driver");
506MODULE_LICENSE("GPL"); 453MODULE_LICENSE("GPL");
507MODULE_ALIAS("platform:" DRV_NAME); 454MODULE_ALIAS("platform:" DRV_NAME);
455MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);