From ea2d29073a4db4f56581c855f509d9869966dce4 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Thu, 22 Mar 2018 11:25:54 +0800 Subject: ASoC: rockchip: add support for multicodecs sound Change-Id: I77d3e9c10d03c2b8809c6d82b5268dba279ee6f0 Signed-off-by: Sugar Zhang --- .../bindings/sound/rockchip,multicodecs.txt | 15 ++ sound/soc/rockchip/Kconfig | 7 + sound/soc/rockchip/Makefile | 2 + sound/soc/rockchip/rockchip_multicodecs.c | 191 +++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip,multicodecs.txt create mode 100644 sound/soc/rockchip/rockchip_multicodecs.c diff --git a/Documentation/devicetree/bindings/sound/rockchip,multicodecs.txt b/Documentation/devicetree/bindings/sound/rockchip,multicodecs.txt new file mode 100644 index 000000000000..45c9ae0388c4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,multicodecs.txt @@ -0,0 +1,15 @@ +ROCKCHIP multicodecs audio + +Required properties: +- compatible: "rockchip,multicodecs-card" +- rockchip,cpu: The phandle of the Rockchip I2S/PDM controller that's + connected to the CODEC +- rockchip,codec: The phandle of audio codecs + +Example: + +sound { + compatible = "rockchip,multicodecs-card"; + rockchip,cpu = <&i2s0_8ch>; + rockchip,codec = <&codec>, <&vad>; +}; diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index a725b4c706ab..7fc51a0a4729 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -78,6 +78,13 @@ config SND_SOC_ROCKCHIP_MAX98090 Say Y or M here if you want to add support for SoC audio on Rockchip boards using the MAX98090 codec, such as Veyron. +config SND_SOC_ROCKCHIP_MULTICODECS + tristate "ASoC support for Rockchip multicodecs" + depends on SND_SOC_ROCKCHIP && CLKDEV_LOOKUP + help + Say Y or M here if you want to add support for SoC audio on Rockchip + boards using multicodecs, such as RK3308 boards. + config SND_SOC_ROCKCHIP_RT5645 tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec" depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 1d9ac6605da0..dddff3eae374 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -13,6 +13,7 @@ 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-multicodecs-objs := rockchip_multicodecs.o snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o snd-soc-rockchip-rt5651-tc358749x-objs := rockchip_rt5651_tc358749x.o snd-soc-rockchip-cdndp-objs := rockchip_cdndp.o @@ -21,6 +22,7 @@ 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_MULTICODECS) += snd-soc-rockchip-multicodecs.o obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5651_TC358749) += snd-soc-rockchip-rt5651-tc358749x.o obj-$(CONFIG_SND_SOC_ROCKCHIP_CDNDP) += snd-soc-rockchip-cdndp.o diff --git a/sound/soc/rockchip/rockchip_multicodecs.c b/sound/soc/rockchip/rockchip_multicodecs.c new file mode 100644 index 000000000000..f57daa415267 --- /dev/null +++ b/sound/soc/rockchip/rockchip_multicodecs.c @@ -0,0 +1,191 @@ +/* + * Rockchip machine ASoC driver for Rockchip Multi-codecs audio + * + * Copyright (C) 2018 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 + +#define DRV_NAME "rk-multicodecs" +#define MAX_CODECS 2 + +static int rk_multicodecs_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_multicodecs_hw_params, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "MULTICODECS", + .stream_name = "MULTICODECS", + .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-multicodecs-sound", + .dai_link = &rk_dailink, + .num_links = 1, + .num_aux_devs = 0, +}; + +static int rk_multicodecs_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_multicodecs_of_match[] = { + { .compatible = "rockchip,multicodecs-card", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_multicodecs_of_match); + +static struct platform_driver rockchip_multicodecs_driver = { + .probe = rk_multicodecs_probe, + .driver = { + .name = DRV_NAME, + .pm = &snd_soc_pm_ops, + .of_match_table = rockchip_multicodecs_of_match, + }, +}; + +module_platform_driver(rockchip_multicodecs_driver); + +MODULE_AUTHOR("Sugar Zhang "); +MODULE_DESCRIPTION("Rockchip General Multicodecs ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3