cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

smdk_spdif.c (5067B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// smdk_spdif.c - S/PDIF audio for SMDK
      4//
      5// Copyright (C) 2010 Samsung Electronics Co., Ltd.
      6
      7#include <linux/clk.h>
      8#include <linux/module.h>
      9
     10#include <sound/soc.h>
     11
     12#include "spdif.h"
     13
     14/* Audio clock settings are belonged to board specific part. Every
     15 * board can set audio source clock setting which is matched with H/W
     16 * like this function-'set_audio_clock_heirachy'.
     17 */
     18static int set_audio_clock_heirachy(struct platform_device *pdev)
     19{
     20	struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
     21	int ret = 0;
     22
     23	fout_epll = clk_get(NULL, "fout_epll");
     24	if (IS_ERR(fout_epll)) {
     25		printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
     26				__func__);
     27		return -EINVAL;
     28	}
     29
     30	mout_epll = clk_get(NULL, "mout_epll");
     31	if (IS_ERR(mout_epll)) {
     32		printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
     33				__func__);
     34		ret = -EINVAL;
     35		goto out1;
     36	}
     37
     38	sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
     39	if (IS_ERR(sclk_audio0)) {
     40		printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
     41				__func__);
     42		ret = -EINVAL;
     43		goto out2;
     44	}
     45
     46	sclk_spdif = clk_get(NULL, "sclk_spdif");
     47	if (IS_ERR(sclk_spdif)) {
     48		printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
     49				__func__);
     50		ret = -EINVAL;
     51		goto out3;
     52	}
     53
     54	/* Set audio clock hierarchy for S/PDIF */
     55	clk_set_parent(mout_epll, fout_epll);
     56	clk_set_parent(sclk_audio0, mout_epll);
     57	clk_set_parent(sclk_spdif, sclk_audio0);
     58
     59	clk_put(sclk_spdif);
     60out3:
     61	clk_put(sclk_audio0);
     62out2:
     63	clk_put(mout_epll);
     64out1:
     65	clk_put(fout_epll);
     66
     67	return ret;
     68}
     69
     70/* We should haved to set clock directly on this part because of clock
     71 * scheme of Samsudng SoCs did not support to set rates from abstrct
     72 * clock of it's hierarchy.
     73 */
     74static int set_audio_clock_rate(unsigned long epll_rate,
     75				unsigned long audio_rate)
     76{
     77	struct clk *fout_epll, *sclk_spdif;
     78
     79	fout_epll = clk_get(NULL, "fout_epll");
     80	if (IS_ERR(fout_epll)) {
     81		printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
     82		return -ENOENT;
     83	}
     84
     85	clk_set_rate(fout_epll, epll_rate);
     86	clk_put(fout_epll);
     87
     88	sclk_spdif = clk_get(NULL, "sclk_spdif");
     89	if (IS_ERR(sclk_spdif)) {
     90		printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
     91		return -ENOENT;
     92	}
     93
     94	clk_set_rate(sclk_spdif, audio_rate);
     95	clk_put(sclk_spdif);
     96
     97	return 0;
     98}
     99
    100static int smdk_hw_params(struct snd_pcm_substream *substream,
    101		struct snd_pcm_hw_params *params)
    102{
    103	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    104	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    105	unsigned long pll_out, rclk_rate;
    106	int ret, ratio;
    107
    108	switch (params_rate(params)) {
    109	case 44100:
    110		pll_out = 45158400;
    111		break;
    112	case 32000:
    113	case 48000:
    114	case 96000:
    115		pll_out = 49152000;
    116		break;
    117	default:
    118		return -EINVAL;
    119	}
    120
    121	/* Setting ratio to 512fs helps to use S/PDIF with HDMI without
    122	 * modify S/PDIF ASoC machine driver.
    123	 */
    124	ratio = 512;
    125	rclk_rate = params_rate(params) * ratio;
    126
    127	/* Set audio source clock rates */
    128	ret = set_audio_clock_rate(pll_out, rclk_rate);
    129	if (ret < 0)
    130		return ret;
    131
    132	/* Set S/PDIF uses internal source clock */
    133	ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
    134					rclk_rate, SND_SOC_CLOCK_IN);
    135	if (ret < 0)
    136		return ret;
    137
    138	return ret;
    139}
    140
    141static const struct snd_soc_ops smdk_spdif_ops = {
    142	.hw_params = smdk_hw_params,
    143};
    144
    145SND_SOC_DAILINK_DEFS(spdif,
    146	DAILINK_COMP_ARRAY(COMP_CPU("samsung-spdif")),
    147	DAILINK_COMP_ARRAY(COMP_CODEC("spdif-dit", "dit-hifi")),
    148	DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-spdif")));
    149
    150static struct snd_soc_dai_link smdk_dai = {
    151	.name = "S/PDIF",
    152	.stream_name = "S/PDIF PCM Playback",
    153	.ops = &smdk_spdif_ops,
    154	SND_SOC_DAILINK_REG(spdif),
    155};
    156
    157static struct snd_soc_card smdk = {
    158	.name = "SMDK-S/PDIF",
    159	.owner = THIS_MODULE,
    160	.dai_link = &smdk_dai,
    161	.num_links = 1,
    162};
    163
    164static struct platform_device *smdk_snd_spdif_dit_device;
    165static struct platform_device *smdk_snd_spdif_device;
    166
    167static int __init smdk_init(void)
    168{
    169	int ret;
    170
    171	smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
    172	if (!smdk_snd_spdif_dit_device)
    173		return -ENOMEM;
    174
    175	ret = platform_device_add(smdk_snd_spdif_dit_device);
    176	if (ret)
    177		goto err1;
    178
    179	smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
    180	if (!smdk_snd_spdif_device) {
    181		ret = -ENOMEM;
    182		goto err2;
    183	}
    184
    185	platform_set_drvdata(smdk_snd_spdif_device, &smdk);
    186
    187	ret = platform_device_add(smdk_snd_spdif_device);
    188	if (ret)
    189		goto err3;
    190
    191	/* Set audio clock hierarchy manually */
    192	ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
    193	if (ret)
    194		goto err4;
    195
    196	return 0;
    197err4:
    198	platform_device_del(smdk_snd_spdif_device);
    199err3:
    200	platform_device_put(smdk_snd_spdif_device);
    201err2:
    202	platform_device_del(smdk_snd_spdif_dit_device);
    203err1:
    204	platform_device_put(smdk_snd_spdif_dit_device);
    205	return ret;
    206}
    207
    208static void __exit smdk_exit(void)
    209{
    210	platform_device_unregister(smdk_snd_spdif_device);
    211	platform_device_unregister(smdk_snd_spdif_dit_device);
    212}
    213
    214module_init(smdk_init);
    215module_exit(smdk_exit);
    216
    217MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
    218MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
    219MODULE_LICENSE("GPL");