Skip to content

Commit

Permalink
sound: soc: xilinx: Add ZynqMP DP subsystem audio drivers
Browse files Browse the repository at this point in the history
The DisplayPort subsystem of Xilinx ZynqMP SOC supports audio through,
DPDMA - Audio buffer manager - Audio blender - DP. The DPDMA driver
is implemented based on DMA engine API, and the audio driver is based
on snd dmaengine pcm helpers.

Signed-off-by: Hyun Kwon <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
  • Loading branch information
xlnx-hyunkwon authored and Michal Simek committed Mar 9, 2015
1 parent f9f0f1d commit dad01aa
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 0 deletions.
1 change: 1 addition & 0 deletions sound/soc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ source "sound/soc/spear/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/ux500/Kconfig"
source "sound/soc/xilinx/Kconfig"

# Supported codecs
source "sound/soc/codecs/Kconfig"
Expand Down
1 change: 1 addition & 0 deletions sound/soc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += ux500/
obj-$(CONFIG_SND_SOC) += xilinx/
5 changes: 5 additions & 0 deletions sound/soc/xilinx/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
config SND_SOC_XILINX_DP
tristate "Audio support for the the Xilinx DisplayPort"
select SND_DMAENGINE_PCM
help
Audio support the for Xilinx DisplayPort.
3 changes: 3 additions & 0 deletions sound/soc/xilinx/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
snd-soc-xilinx-dp-objs := xilinx-dp-pcm.o xilinx-dp-codec.o xilinx-dp-card.o

obj-$(CONFIG_SND_SOC_XILINX_DP) += snd-soc-xilinx-dp.o
102 changes: 102 additions & 0 deletions sound/soc/xilinx/xilinx-dp-card.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Xilinx DisplayPort SoC Sound Card support
*
* Copyright (C) 2015 Xilinx, Inc.
*
* Author: Hyun Woo Kwon <[email protected]>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>

#include <sound/soc.h>

static struct snd_soc_dai_link xilinx_dp_dai_links[] = {
{
.name = "xilinx-dp0",
.codec_dai_name = "xilinx-dp-snd-codec-dai",
},
{
.name = "xilinx-dp1",
.codec_dai_name = "xilinx-dp-snd-codec-dai",
},

};

static struct snd_soc_card xilinx_dp_card = {
.name = "DisplayPort monitor",
.owner = THIS_MODULE,
.dai_link = xilinx_dp_dai_links,
.num_links = 2,
};

static int xilinx_dp_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &xilinx_dp_card;
struct device_node *node = pdev->dev.of_node;
struct device_node *codec, *pcm;
int ret;

card->dev = &pdev->dev;

codec = of_parse_phandle(node, "xlnx,dp-snd-codec", 0);
if (!codec)
return -ENODEV;

pcm = of_parse_phandle(node, "xlnx,dp-snd-pcm", 0);
if (!pcm)
return -ENODEV;
xilinx_dp_dai_links[0].platform_of_node = pcm;
xilinx_dp_dai_links[0].cpu_of_node = codec;
xilinx_dp_dai_links[0].codec_of_node = codec;

pcm = of_parse_phandle(node, "xlnx,dp-snd-pcm", 1);
if (!pcm)
return -ENODEV;
xilinx_dp_dai_links[1].platform_of_node = pcm;
xilinx_dp_dai_links[1].cpu_of_node = codec;
xilinx_dp_dai_links[1].codec_of_node = codec;

ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
return ret;

dev_info(&pdev->dev, "Xilinx DisplayPort Sound Card probed\n");

return 0;
}

static int xilinx_dp_remove(struct platform_device *pdev)
{
return 0;
}

static const struct of_device_id xilinx_dp_of_match[] = {
{ .compatible = "xlnx,dp-snd-card", },
{},
};
MODULE_DEVICE_TABLE(of, xilinx_dp_of_match);

static struct platform_driver xilinx_dp_aud_driver = {
.driver = {
.name = "xilinx-dp-snd-card",
.of_match_table = xilinx_dp_of_match,
.pm = &snd_soc_pm_ops,
},
.probe = xilinx_dp_probe,
.remove = xilinx_dp_remove,
};
module_platform_driver(xilinx_dp_aud_driver);

MODULE_DESCRIPTION("Xilinx DisplayPort Sound Card module");
MODULE_LICENSE("GPL v2");
118 changes: 118 additions & 0 deletions sound/soc/xilinx/xilinx-dp-codec.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Xilinx DisplayPort Sound Codec support
*
* Copyright (C) 2015 Xilinx, Inc.
*
* Author: Hyun Woo Kwon <[email protected]>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <linux/clk.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#include <sound/soc.h>

/**
* struct xilinx_dp_codec - DisplayPort codec
* @aud_clk: audio clock
*/
struct xilinx_dp_codec {
struct clk *aud_clk;
};

static struct snd_soc_dai_driver xilinx_dp_codec_dai = {
.name = "xilinx-dp-snd-codec-dai",
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_44100,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};

static const struct snd_soc_codec_driver xilinx_dp_codec_codec_driver = {
};

static int xilinx_dp_codec_probe(struct platform_device *pdev)
{
struct xilinx_dp_codec *codec;
int rate, ret;

codec = devm_kzalloc(&pdev->dev, sizeof(*codec), GFP_KERNEL);
if (!codec)
return -ENOMEM;

codec->aud_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(codec->aud_clk))
return PTR_ERR(codec->aud_clk);

ret = clk_prepare_enable(codec->aud_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable the aud_clk\n");
return ret;
}

rate = clk_get_rate(codec->aud_clk) / 512;
if (rate == 44100) {
xilinx_dp_codec_dai.playback.rates = SNDRV_PCM_RATE_44100;
} else if (rate == 48000) {
xilinx_dp_codec_dai.playback.rates = SNDRV_PCM_RATE_48000;
} else {
ret = -EINVAL;
goto error_clk;
}

ret = snd_soc_register_codec(&pdev->dev, &xilinx_dp_codec_codec_driver,
&xilinx_dp_codec_dai, 1);
if (ret)
goto error_clk;

platform_set_drvdata(pdev, codec);

dev_info(&pdev->dev, "Xilinx DisplayPort Sound Codec probed\n");

return 0;

error_clk:
clk_disable_unprepare(codec->aud_clk);
return ret;
}

static int xilinx_dp_codec_dev_remove(struct platform_device *pdev)
{
struct xilinx_dp_codec *codec = platform_get_drvdata(pdev);

snd_soc_unregister_codec(&pdev->dev);
clk_disable_unprepare(codec->aud_clk);

return 0;
}

static const struct of_device_id xilinx_dp_codec_of_match[] = {
{ .compatible = "xlnx,dp-snd-codec", },
{ /* end of table */ },
};
MODULE_DEVICE_TABLE(of, xilinx_dp_codec_of_match);

static struct platform_driver xilinx_dp_codec_driver = {
.driver = {
.name = "xilinx-dp-snd-codec",
.of_match_table = xilinx_dp_codec_of_match,
},
.probe = xilinx_dp_codec_probe,
.remove = xilinx_dp_codec_dev_remove,
};
module_platform_driver(xilinx_dp_codec_driver);

MODULE_DESCRIPTION("Xilinx DisplayPort Sound Codec module");
MODULE_LICENSE("GPL v2");
81 changes: 81 additions & 0 deletions sound/soc/xilinx/xilinx-dp-pcm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Xilinx DisplayPort Sound PCM support
*
* Copyright (C) 2015 Xilinx, Inc.
*
* Author: Hyun Woo Kwon <[email protected]>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/soc.h>

static const struct snd_pcm_hardware xilinx_pcm_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 256,
.period_bytes_max = 1024 * 1024,
.periods_min = 2,
.periods_max = 256,
};

static const struct snd_dmaengine_pcm_config xilinx_dmaengine_pcm_config = {
.pcm_hardware = &xilinx_pcm_hw,
.prealloc_buffer_size = 64 * 1024,
};

static int xilinx_dp_pcm_probe(struct platform_device *pdev)
{
int ret;

ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
&xilinx_dmaengine_pcm_config, 0);
if (ret)
return ret;

dev_info(&pdev->dev, "Xilinx DisplayPort Sound PCM probed\n");

return 0;
}

static int xilinx_dp_pcm_dev_remove(struct platform_device *pdev)
{
return 0;
}

static const struct of_device_id xilinx_dp_pcm_of_match[] = {
{ .compatible = "xlnx,dp-snd-pcm", },
{ /* end of table */ },
};
MODULE_DEVICE_TABLE(of, xilinx_dp_pcm_of_match);

static struct platform_driver xilinx_dp_pcm_driver = {
.driver = {
.name = "xilinx-dp-snd-pcm",
.of_match_table = xilinx_dp_pcm_of_match,
},
.probe = xilinx_dp_pcm_probe,
.remove = xilinx_dp_pcm_dev_remove,
};
module_platform_driver(xilinx_dp_pcm_driver);

MODULE_DESCRIPTION("Xilinx DisplayPort Sound PCM module");
MODULE_LICENSE("GPL v2");

0 comments on commit dad01aa

Please sign in to comment.