From cd3e53d593b972015ec150387092cc5d17575678 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 8 Mar 2017 20:34:27 +0800 Subject: [PATCH] ASoC: rockchip: add machine driver for built-in hdmi and dp this patch is used for rockchip built-in HDMI and DP audio output which are wired to the same i2s line. so we use a DAI link CPU to multicodecs. Change-Id: Ie8d1ede201a4d4b4cd11c8c05cd1f6177d844957 Signed-off-by: Sugar Zhang --- .../bindings/sound/rockchip,hdmi-dp.txt | 17 ++ sound/soc/rockchip/Kconfig | 10 + sound/soc/rockchip/Makefile | 2 + sound/soc/rockchip/rockchip_hdmi_dp.c | 187 ++++++++++++++++++ 4 files changed, 216 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip,hdmi-dp.txt create mode 100644 sound/soc/rockchip/rockchip_hdmi_dp.c diff --git a/Documentation/devicetree/bindings/sound/rockchip,hdmi-dp.txt b/Documentation/devicetree/bindings/sound/rockchip,hdmi-dp.txt new file mode 100644 index 000000000000..0b0d251f6255 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,hdmi-dp.txt @@ -0,0 +1,17 @@ +ROCKCHIP Built-in HDMI and DP audio + +Required properties: +- compatible: "rockchip,rk3399-hdmi-dp" +- rockchip,cpu: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,codec: The phandle of audio codecs, should contain HDMI + or DP, or both. + +Example: + +sound { + compatible = "rockchip,rk3399-hdmi-dp"; + rockchip,cpu = <&i2s2>; + rockchip,codec = <&hdmi>, <&cdn_dp>; +}; + diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index 8e68a5d859f2..ec911e90825e 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -32,6 +32,16 @@ config SND_SOC_ROCKCHIP_DA7219 Say Y or M here if you want to add support for SoC audio on Rockchip boards using the DA7219 codec, such as Veyron. +config SND_SOC_ROCKCHIP_HDMI_DP + tristate "ASoC support for Rockchip built-in HDMI and DP" + depends on SND_SOC_ROCKCHIP && CLKDEV_LOOKUP + depends on ROCKCHIP_CDN_DP || DRM_DW_HDMI_I2S_AUDIO + select SND_SOC_ROCKCHIP_I2S + select SND_SOC_HDMI_CODEC + help + Say Y or M here if you want to add support for SoC audio on Rockchip + boards using built-in HDMI and DP, such as RK3399 boards. + config SND_SOC_ROCKCHIP_MAX98090 tristate "ASoC support for Rockchip boards using a MAX98090 codec" depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 17d084b36fa4..a59339eb4ba0 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -6,11 +6,13 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o snd-soc-rockchip-da7219-objs := rockchip_da7219.o +snd-soc-rockchip-hdmi-dp-objs := rockchip_hdmi_dp.o snd-soc-rockchip-max98090-objs := rockchip_max98090.o snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o snd-soc-rockchip-cdndp-objs := rockchip_cdndp.o obj-$(CONFIG_SND_SOC_ROCKCHIP_DA7219) += snd-soc-rockchip-da7219.o +obj-$(CONFIG_SND_SOC_ROCKCHIP_HDMI_DP) += snd-soc-rockchip-hdmi-dp.o obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o obj-$(CONFIG_SND_SOC_ROCKCHIP_CDNDP) += snd-soc-rockchip-cdndp.o diff --git a/sound/soc/rockchip/rockchip_hdmi_dp.c b/sound/soc/rockchip/rockchip_hdmi_dp.c new file mode 100644 index 000000000000..4dee75c8c581 --- /dev/null +++ b/sound/soc/rockchip/rockchip_hdmi_dp.c @@ -0,0 +1,187 @@ +/* + * Rockchip machine ASoC driver for Rockchip built-in HDMI and DP audio output + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd + * + * Authors: Sugar Zhang , + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_i2s.h" + +#define DRV_NAME "rk-hdmi-dp-sound" +#define MAX_CODECS 2 + +static int rk_hdmi_dp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int mclk; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + + if (ret && ret != -ENOTSUPP) { + dev_err(cpu_dai->dev, "Can't set cpu clock %d\n", ret); + return ret; + } + + return 0; +} + +static struct snd_soc_ops rk_ops = { + .hw_params = rk_hdmi_dp_hw_params, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "HDMI-DP", + .stream_name = "HDMI-DP", + .ops = &rk_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_card_rk = { + .name = "rk-hdmi-dp-sound", + .dai_link = &rk_dailink, + .num_links = 1, + .num_aux_devs = 0, +}; + +static int rk_hdmi_dp_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_card_rk; + struct device_node *np = pdev->dev.of_node; + struct snd_soc_dai_link *link = card->dai_link; + struct snd_soc_dai_link_component *codecs; + struct of_phandle_args args; + struct device_node *node; + int count; + int ret = 0, i = 0, idx = 0; + + card->dev = &pdev->dev; + + count = of_count_phandle_with_args(np, "rockchip,codec", NULL); + if (count < 0 || count > MAX_CODECS) + return -EINVAL; + + /* refine codecs, remove unavailable node */ + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "rockchip,codec", i); + if (!node) + return -ENODEV; + if (of_device_is_available(node)) + idx++; + } + + if (!idx) + return -ENODEV; + + codecs = devm_kcalloc(&pdev->dev, idx, + sizeof(*codecs), GFP_KERNEL); + link->codecs = codecs; + link->num_codecs = idx; + idx = 0; + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "rockchip,codec", i); + if (!node) + return -ENODEV; + if (!of_device_is_available(node)) + continue; + + ret = of_parse_phandle_with_fixed_args(np, "rockchip,codec", + 0, i, &args); + if (ret) + return ret; + + codecs[idx].of_node = node; + ret = snd_soc_get_dai_name(&args, &codecs[idx].dai_name); + if (ret) + return ret; + idx++; + } + + link->cpu_of_node = of_parse_phandle(np, "rockchip,cpu", 0); + if (!link->cpu_of_node) + return -ENODEV; + + link->platform_of_node = link->cpu_of_node; + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (ret) { + dev_err(&pdev->dev, "card register failed %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static const struct of_device_id rockchip_sound_of_match[] = { + { .compatible = "rockchip,rk3399-hdmi-dp", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_sound_of_match); + +static struct platform_driver rockchip_sound_driver = { + .probe = rk_hdmi_dp_probe, + .driver = { + .name = DRV_NAME, + .pm = &snd_soc_pm_ops, + .of_match_table = rockchip_sound_of_match, + }, +}; + +module_platform_driver(rockchip_sound_driver); + +MODULE_AUTHOR("Sugar Zhang "); +MODULE_DESCRIPTION("Rockchip Built-in HDMI and DP machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- 2.34.1