diff -drupN a/sound/soc/sunxi/sunxi-sndhdmi.c b/sound/soc/sunxi/sunxi-sndhdmi.c --- a/sound/soc/sunxi/sunxi-sndhdmi.c 1970-01-01 03:00:00.000000000 +0300 +++ b/sound/soc/sunxi/sunxi-sndhdmi.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,262 @@ +/* + * sound\soc\sunxi\sunxi-sndhdmi.c + * (C) Copyright 2014-2016 + * Allwinner Technology Co., Ltd. + * huangxin + * + * some simple description for this code + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sunxi-pcm.h" + +static struct sndhdmi_priv sunxi_tdmhdmi; + +/* + * sun8iw6 sound machine: + * i2s0 -> sndi2s0, i2s1 -> snddi2s1, + * i2s2 -> sndhdmi, tdm -> snddaudio0. + */ + +static int sunxi_hdmiaudio_set_audio_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + sunxi_tdmhdmi.hdmi_format = ucontrol->value.integer.value[0]; + return 0; +} + +static int sunxi_hdmiaudio_get_audio_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = sunxi_tdmhdmi.hdmi_format; + return 0; +} + +static const char *hdmiaudio_format_function[] = {"null", "pcm", "AC3", + "MPEG1", "MP3", "MPEG2", "AAC", "DTS", "ATRAC", "ONE_BIT_AUDIO", + "DOLBY_DIGITAL_PLUS", "DTS_HD", "MAT", "WMAPRO"}; + +static const struct soc_enum hdmiaudio_format_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hdmiaudio_format_function), + hdmiaudio_format_function), +}; + +/* pcm dts ac3 Audio Mode Select */ +static const struct snd_kcontrol_new sunxi_hdmiaudio_controls[] = { + SOC_ENUM_EXT("hdmi audio format Function", hdmiaudio_format_enum[0], + sunxi_hdmiaudio_get_audio_mode, sunxi_hdmiaudio_set_audio_mode), +}; + +static int sunxi_sndhdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_card *card = rtd->card; + unsigned int freq; + unsigned int clk_div; + int ret; +#ifdef CONFIG_ARCH_SUN8IW6 + unsigned long sample_rate = params_rate(params); +#endif + switch (params_rate(params)) { + case 8000: + case 16000: + case 32000: + case 64000: + case 128000: + case 12000: + case 24000: + case 48000: + case 96000: + case 192000: +#ifdef CONFIG_AHUB_FREQ_REQ + freq = 98304000; +#else + freq = 24576000; +#endif + break; + case 11025: + case 22050: + case 44100: + case 88200: + case 176400: +#ifdef CONFIG_AHUB_FREQ_REQ + freq = 90316800; +#else + freq = 22579200; +#endif + break; + default: + dev_err(card->dev, "unsupport freq\n"); + return -EINVAL; + } + + /*set system clock source freq and set the mode as i2s0 or pcm*/ + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, freq, 0); + if (ret < 0) + return ret; + + /* + * I2S mode normal bit clock + frame\codec clk & FRM slave + */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + clk_div = freq / params_rate(params); +#ifdef CONFIG_ARCH_SUN8IW6 + ret = snd_soc_dai_set_clkdiv(cpu_dai, 0, sample_rate); +#else + ret = snd_soc_dai_set_clkdiv(cpu_dai, 0, clk_div); +#endif + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops sunxi_sndhdmi_ops = { + .hw_params = sunxi_sndhdmi_hw_params, +}; + +static int sunxi_sndhdmi_probe(struct snd_soc_card *card) +{ + int ret; + + ret = snd_soc_add_card_controls(card, sunxi_hdmiaudio_controls, + ARRAY_SIZE(sunxi_hdmiaudio_controls)); + if (ret) + dev_warn(card->dev, + "Failed to register audio mode control.\n"); + return 0; +} + +static struct snd_soc_dai_link sunxi_sndhdmi_dai_link = { + .name = "HDMIAUDIO", + .stream_name = "SUNXI-HDMIAUDIO", + .cpu_dai_name = "sunxi-hdmiaudio.0", + .codec_dai_name = "audiohdmi-dai", + .platform_name = "sunxi-hdmiaudio-pcm-audio.0", + .codec_name = "sunxi-hdmiaudio-codec.0", + .ops = &sunxi_sndhdmi_ops, +}; + +static struct snd_soc_card snd_soc_sunxi_sndhdmi = { + .name = "sndhdmi", + .owner = THIS_MODULE, + .probe = sunxi_sndhdmi_probe, + .dai_link = &sunxi_sndhdmi_dai_link, + .num_links = 1, +}; + +static int sunxi_sndhdmi_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_sunxi_sndhdmi; + struct device_node *np = pdev->dev.of_node; + int ret; + + card->dev = &pdev->dev; + sunxi_tdmhdmi.hdmi_format = 1; + +#ifdef CONFIG_SND_SUNXI_SOC_AHUB + sunxi_sndhdmi_dai_link.cpu_dai_name = NULL; + sunxi_sndhdmi_dai_link.cpu_of_node = of_parse_phandle(np, + "sunxi,cpudai-controller", 0); + if (!sunxi_sndhdmi_dai_link.cpu_of_node) { + dev_err(&pdev->dev, "Property 'sunxi,cpudai-controller' missing or invalid\n"); + return -EINVAL; + } + sunxi_sndhdmi_dai_link.platform_name = "snd-soc-dummy"; +#else + if (np) { + sunxi_sndhdmi_dai_link.cpu_dai_name = NULL; + sunxi_sndhdmi_dai_link.cpu_of_node = of_parse_phandle(np, + "sunxi,hdmi-controller", 0); + if (!sunxi_sndhdmi_dai_link.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'sunxi,hdmi-controller' missing\n"); + ret = -EINVAL; + } + sunxi_sndhdmi_dai_link.platform_name = NULL; + sunxi_sndhdmi_dai_link.platform_of_node = + sunxi_sndhdmi_dai_link.cpu_of_node; + } else { + dev_err(&pdev->dev, "hdmi dt node missing or invalid\n"); + ret = -EINVAL; + } +#endif + snd_soc_card_set_drvdata(card, &sunxi_tdmhdmi); + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + } + + dev_warn(&pdev->dev, "[%s] register card finished.\n", __func__); + + return ret; +} + +static int __exit sunxi_sndhdmi_dev_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + dev_warn(&pdev->dev, "[%s] unregister card finished.\n", __func__); + + return 0; +} + +static const struct of_device_id sunxi_hdmi_of_match[] = { + { .compatible = "allwinner,sunxi-hdmi-machine", }, + {}, +}; + +static struct platform_driver sunxi_hdmiaudio_driver = { + .driver = { + .name = "sndhdmi", + .owner = THIS_MODULE, + .of_match_table = sunxi_hdmi_of_match, + .pm = &snd_soc_pm_ops, + }, + .probe = sunxi_sndhdmi_dev_probe, + .remove = __exit_p(sunxi_sndhdmi_dev_remove), +}; + +#ifdef CONFIG_ARCH_SUN50IW6 +static int __init sunxi_hdmiaudio_driver_init(void) +{ + return platform_driver_register(&sunxi_hdmiaudio_driver); +} +late_initcall(sunxi_hdmiaudio_driver_init); + +static void __exit sunxi_hdmiaudio_driver_exit(void) +{ + platform_driver_unregister(&sunxi_hdmiaudio_driver); +} +module_exit(sunxi_hdmiaudio_driver_exit); +#else +module_platform_driver(sunxi_hdmiaudio_driver); +#endif + +MODULE_AUTHOR("wolfgang huang "); +MODULE_DESCRIPTION("SUNXI HDMI ASoC Machine driver"); +MODULE_LICENSE("GPL");