From 8244bcbb0938e5d1b9f5a82ef9e9bfc12123bdbd Mon Sep 17 00:00:00 2001 From: zhangjun Date: Thu, 11 May 2017 11:31:14 +0800 Subject: [PATCH] ASoC: rockchip: add machine driver for built-in hdmi and codec IC this patch is used for rockchip built-in HDMI and audio codec IC which are wired to the same i2s line(such as rk3368). so we use a DAI link CPU to multicodecs. Change-Id: Ibc5fdeb2091836dc28675aacdc099d76e0b7d752 Signed-off-by: zhangjun --- .../bindings/sound/rockchip,hdmi-analog.txt | 24 ++ sound/soc/rockchip/Kconfig | 8 + sound/soc/rockchip/Makefile | 2 + sound/soc/rockchip/rockchip_hdmi_analog.c | 205 ++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip,hdmi-analog.txt create mode 100644 sound/soc/rockchip/rockchip_hdmi_analog.c diff --git a/Documentation/devicetree/bindings/sound/rockchip,hdmi-analog.txt b/Documentation/devicetree/bindings/sound/rockchip,hdmi-analog.txt new file mode 100644 index 000000000000..415d18e3cbd5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,hdmi-analog.txt @@ -0,0 +1,24 @@ +ROCKCHIP Built-in HDMI and external audio codec which use the same +I2S interface(such as RK3368) +Use simple-audio-card can be if only HDMI or codec ic + +Required properties: +- compatible: "rockchip,rk3368-hdmi-analog" +- rockchip,cpu: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,codec: The phandle of audio codecs, should contain both + codec ic and HDMI + +Example: + +sound { + compatible = "rockchip,rk3368-hdmi-analog"; + rockchip,cpu = <&i2s_8ch>; + rockchip,codec = <&es8316>, <&hdmi>; + rockchip,widgets = "Microphone", "Mic Jack", + "Headphone", "Headphone Jack"; + rockchip,routing = "Mic Jack", "micbias", + "Headphone Jack", "HPOL", + "Headphone Jack", "HPOR"; +}; + diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index 65a36639eda3..c1b44c9768f4 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -41,6 +41,14 @@ 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_ANALOG + tristate "ASoC support for Rockchip built-in HDMI and CODEC IC" + 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 CODEC IC, such as RK3368 boards. + config SND_SOC_ROCKCHIP_HDMI_DP tristate "ASoC support for Rockchip built-in HDMI and DP" depends on SND_SOC_ROCKCHIP && CLKDEV_LOOKUP diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 181fea7597d2..d1051e8f6d64 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_PDM) += snd-soc-rockchip-pdm.o obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o snd-soc-rockchip-da7219-objs := rockchip_da7219.o +snd-soc-rockchip-hdmi-analog-objs := rockchip_hdmi_analog.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 @@ -15,6 +16,7 @@ snd-soc-rockchip-rt5651-tc358749x-objs := rockchip_rt5651_tc358749x.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_ANALOG) += snd-soc-rockchip-hdmi-analog.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 diff --git a/sound/soc/rockchip/rockchip_hdmi_analog.c b/sound/soc/rockchip/rockchip_hdmi_analog.c new file mode 100644 index 000000000000..e4a4a993e29a --- /dev/null +++ b/sound/soc/rockchip/rockchip_hdmi_analog.c @@ -0,0 +1,205 @@ +/* + * Rockchip machine ASoC driver for Rockchip built-in HDMI and external codec IC + * which use the same i2s interface + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd + * + * Authors: Zhangjun , + * + * 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-analog-sound" +#define MAX_CODECS 2 + +static int rk_hdmi_analog_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; + case 176400: + mclk = 11289600 * 2; + break; + case 192000: + mclk = 12288000 * 2; + 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_analog_hw_params, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "HDMI-ANALOG", + .stream_name = "HDMI-ANALOG", + .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-analog-snd", + .dai_link = &rk_dailink, + .num_links = 1, + .num_aux_devs = 0, +}; + +static int rk_hdmi_analog_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 = snd_soc_of_parse_audio_simple_widgets(card, "rockchip,widgets"); + if (ret) { + dev_err(&pdev->dev, + "Unable to parse 'rockchip,widget' property\n"); + } + + ret = snd_soc_of_parse_audio_routing(card, "rockchip,routing"); + if (ret) { + dev_err(&pdev->dev, + "Unable to parse 'rockchip,routing' property\n"); + } + + 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,rk3368-hdmi-analog", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_sound_of_match); + +static struct platform_driver rockchip_sound_driver = { + .probe = rk_hdmi_analog_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("Zhangjun "); +MODULE_DESCRIPTION("Rockchip Built-in HDMI and Codec IC machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- 2.34.1