diff options
Diffstat (limited to 'sound/soc/tegra/tegra_i2s.c')
-rw-r--r-- | sound/soc/tegra/tegra_i2s.c | 164 |
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 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/of.h> #include <mach/iomap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> -#include "tegra_das.h" #include "tegra_i2s.h" #define DRV_NAME "tegra-i2s" @@ -99,13 +99,11 @@ static const struct file_operations tegra_i2s_debug_fops = { .release = single_release, }; -static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) +static void tegra_i2s_debug_add(struct tegra_i2s *i2s) { - char name[] = DRV_NAME ".0"; - - snprintf(name, sizeof(name), DRV_NAME".%1d", id); - i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, - i2s, &tegra_i2s_debug_fops); + i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO, + snd_soc_debugfs_root, i2s, + &tegra_i2s_debug_fops); } static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) @@ -306,93 +304,54 @@ static int tegra_i2s_probe(struct snd_soc_dai *dai) return 0; } -static struct snd_soc_dai_ops tegra_i2s_dai_ops = { +static const struct snd_soc_dai_ops tegra_i2s_dai_ops = { .set_fmt = tegra_i2s_set_fmt, .hw_params = tegra_i2s_hw_params, .trigger = tegra_i2s_trigger, }; -static struct snd_soc_dai_driver tegra_i2s_dai[] = { - { - .name = DRV_NAME ".0", - .probe = tegra_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &tegra_i2s_dai_ops, - .symmetric_rates = 1, +static const struct snd_soc_dai_driver tegra_i2s_dai_template = { + .probe = tegra_i2s_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - { - .name = DRV_NAME ".1", - .probe = tegra_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &tegra_i2s_dai_ops, - .symmetric_rates = 1, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &tegra_i2s_dai_ops, + .symmetric_rates = 1, }; static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) { struct tegra_i2s * i2s; struct resource *mem, *memregion, *dmareq; + u32 of_dma[2]; + u32 dma_ch; int ret; - if ((pdev->id < 0) || - (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) { - dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); - return -EINVAL; - } - - /* - * FIXME: Until a codec driver exists for the tegra DAS, hard-code a - * 1:1 mapping between audio controllers and audio ports. - */ - ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id, - TEGRA_DAS_DAP_SEL_DAC1 + pdev->id); - if (ret) { - dev_err(&pdev->dev, "Can't set up DAP connection\n"); - return ret; - } - ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id, - TEGRA_DAS_DAC_SEL_DAP1 + pdev->id); - if (ret) { - dev_err(&pdev->dev, "Can't set up DAC connection\n"); - return ret; - } - - i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL); + i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL); if (!i2s) { dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); ret = -ENOMEM; - goto exit; + goto err; } dev_set_drvdata(&pdev->dev, i2s); + i2s->dai = tegra_i2s_dai_template; + i2s->dai.name = dev_name(&pdev->dev); + i2s->clk_i2s = clk_get(&pdev->dev, NULL); if (IS_ERR(i2s->clk_i2s)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); ret = PTR_ERR(i2s->clk_i2s); - goto err_free; + goto err; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -404,104 +363,93 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) { - dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; + if (of_property_read_u32_array(pdev->dev.of_node, + "nvidia,dma-request-selector", + of_dma, 2) < 0) { + dev_err(&pdev->dev, "No DMA resource\n"); + ret = -ENODEV; + goto err_clk_put; + } + dma_ch = of_dma[1]; + } else { + dma_ch = dmareq->start; } - memregion = request_mem_region(mem->start, resource_size(mem), - DRV_NAME); + memregion = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), DRV_NAME); if (!memregion) { dev_err(&pdev->dev, "Memory region already claimed\n"); ret = -EBUSY; goto err_clk_put; } - i2s->regs = ioremap(mem->start, resource_size(mem)); + i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); if (!i2s->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_release; + goto err_clk_put; } i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; i2s->capture_dma_data.wrap = 4; i2s->capture_dma_data.width = 32; - i2s->capture_dma_data.req_sel = dmareq->start; + i2s->capture_dma_data.req_sel = dma_ch; i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; i2s->playback_dma_data.wrap = 4; i2s->playback_dma_data.width = 32; - i2s->playback_dma_data.req_sel = dmareq->start; + i2s->playback_dma_data.req_sel = dma_ch; i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED; - ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]); + ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; - goto err_unmap; + goto err_clk_put; } - tegra_i2s_debug_add(i2s, pdev->id); + tegra_i2s_debug_add(i2s); return 0; -err_unmap: - iounmap(i2s->regs); -err_release: - release_mem_region(mem->start, resource_size(mem)); err_clk_put: clk_put(i2s->clk_i2s); -err_free: - kfree(i2s); -exit: +err: return ret; } static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) { struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev); - struct resource *res; snd_soc_unregister_dai(&pdev->dev); tegra_i2s_debug_remove(i2s); - iounmap(i2s->regs); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - clk_put(i2s->clk_i2s); - kfree(i2s); - return 0; } +static const struct of_device_id tegra_i2s_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-i2s", }, + {}, +}; + static struct platform_driver tegra_i2s_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = tegra_i2s_of_match, }, .probe = tegra_i2s_platform_probe, .remove = __devexit_p(tegra_i2s_platform_remove), }; - -static int __init snd_tegra_i2s_init(void) -{ - return platform_driver_register(&tegra_i2s_driver); -} -module_init(snd_tegra_i2s_init); - -static void __exit snd_tegra_i2s_exit(void) -{ - platform_driver_unregister(&tegra_i2s_driver); -} -module_exit(snd_tegra_i2s_exit); +module_platform_driver(tegra_i2s_driver); MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); MODULE_DESCRIPTION("Tegra I2S ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_i2s_of_match); |