0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/module.h>
0009
0010 #include <sound/soc.h>
0011
0012 #include "spdif.h"
0013
0014
0015
0016
0017
0018 static int set_audio_clock_heirachy(struct platform_device *pdev)
0019 {
0020 struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
0021 int ret = 0;
0022
0023 fout_epll = clk_get(NULL, "fout_epll");
0024 if (IS_ERR(fout_epll)) {
0025 printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
0026 __func__);
0027 return -EINVAL;
0028 }
0029
0030 mout_epll = clk_get(NULL, "mout_epll");
0031 if (IS_ERR(mout_epll)) {
0032 printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
0033 __func__);
0034 ret = -EINVAL;
0035 goto out1;
0036 }
0037
0038 sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
0039 if (IS_ERR(sclk_audio0)) {
0040 printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
0041 __func__);
0042 ret = -EINVAL;
0043 goto out2;
0044 }
0045
0046 sclk_spdif = clk_get(NULL, "sclk_spdif");
0047 if (IS_ERR(sclk_spdif)) {
0048 printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
0049 __func__);
0050 ret = -EINVAL;
0051 goto out3;
0052 }
0053
0054
0055 clk_set_parent(mout_epll, fout_epll);
0056 clk_set_parent(sclk_audio0, mout_epll);
0057 clk_set_parent(sclk_spdif, sclk_audio0);
0058
0059 clk_put(sclk_spdif);
0060 out3:
0061 clk_put(sclk_audio0);
0062 out2:
0063 clk_put(mout_epll);
0064 out1:
0065 clk_put(fout_epll);
0066
0067 return ret;
0068 }
0069
0070
0071
0072
0073
0074 static int set_audio_clock_rate(unsigned long epll_rate,
0075 unsigned long audio_rate)
0076 {
0077 struct clk *fout_epll, *sclk_spdif;
0078
0079 fout_epll = clk_get(NULL, "fout_epll");
0080 if (IS_ERR(fout_epll)) {
0081 printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
0082 return -ENOENT;
0083 }
0084
0085 clk_set_rate(fout_epll, epll_rate);
0086 clk_put(fout_epll);
0087
0088 sclk_spdif = clk_get(NULL, "sclk_spdif");
0089 if (IS_ERR(sclk_spdif)) {
0090 printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
0091 return -ENOENT;
0092 }
0093
0094 clk_set_rate(sclk_spdif, audio_rate);
0095 clk_put(sclk_spdif);
0096
0097 return 0;
0098 }
0099
0100 static int smdk_hw_params(struct snd_pcm_substream *substream,
0101 struct snd_pcm_hw_params *params)
0102 {
0103 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0104 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0105 unsigned long pll_out, rclk_rate;
0106 int ret, ratio;
0107
0108 switch (params_rate(params)) {
0109 case 44100:
0110 pll_out = 45158400;
0111 break;
0112 case 32000:
0113 case 48000:
0114 case 96000:
0115 pll_out = 49152000;
0116 break;
0117 default:
0118 return -EINVAL;
0119 }
0120
0121
0122
0123
0124 ratio = 512;
0125 rclk_rate = params_rate(params) * ratio;
0126
0127
0128 ret = set_audio_clock_rate(pll_out, rclk_rate);
0129 if (ret < 0)
0130 return ret;
0131
0132
0133 ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
0134 rclk_rate, SND_SOC_CLOCK_IN);
0135 if (ret < 0)
0136 return ret;
0137
0138 return ret;
0139 }
0140
0141 static const struct snd_soc_ops smdk_spdif_ops = {
0142 .hw_params = smdk_hw_params,
0143 };
0144
0145 SND_SOC_DAILINK_DEFS(spdif,
0146 DAILINK_COMP_ARRAY(COMP_CPU("samsung-spdif")),
0147 DAILINK_COMP_ARRAY(COMP_CODEC("spdif-dit", "dit-hifi")),
0148 DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-spdif")));
0149
0150 static struct snd_soc_dai_link smdk_dai = {
0151 .name = "S/PDIF",
0152 .stream_name = "S/PDIF PCM Playback",
0153 .ops = &smdk_spdif_ops,
0154 SND_SOC_DAILINK_REG(spdif),
0155 };
0156
0157 static struct snd_soc_card smdk = {
0158 .name = "SMDK-S/PDIF",
0159 .owner = THIS_MODULE,
0160 .dai_link = &smdk_dai,
0161 .num_links = 1,
0162 };
0163
0164 static struct platform_device *smdk_snd_spdif_dit_device;
0165 static struct platform_device *smdk_snd_spdif_device;
0166
0167 static int __init smdk_init(void)
0168 {
0169 int ret;
0170
0171 smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
0172 if (!smdk_snd_spdif_dit_device)
0173 return -ENOMEM;
0174
0175 ret = platform_device_add(smdk_snd_spdif_dit_device);
0176 if (ret)
0177 goto err1;
0178
0179 smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
0180 if (!smdk_snd_spdif_device) {
0181 ret = -ENOMEM;
0182 goto err2;
0183 }
0184
0185 platform_set_drvdata(smdk_snd_spdif_device, &smdk);
0186
0187 ret = platform_device_add(smdk_snd_spdif_device);
0188 if (ret)
0189 goto err3;
0190
0191
0192 ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
0193 if (ret)
0194 goto err4;
0195
0196 return 0;
0197 err4:
0198 platform_device_del(smdk_snd_spdif_device);
0199 err3:
0200 platform_device_put(smdk_snd_spdif_device);
0201 err2:
0202 platform_device_del(smdk_snd_spdif_dit_device);
0203 err1:
0204 platform_device_put(smdk_snd_spdif_dit_device);
0205 return ret;
0206 }
0207
0208 static void __exit smdk_exit(void)
0209 {
0210 platform_device_unregister(smdk_snd_spdif_device);
0211 platform_device_unregister(smdk_snd_spdif_dit_device);
0212 }
0213
0214 module_init(smdk_init);
0215 module_exit(smdk_exit);
0216
0217 MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
0218 MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
0219 MODULE_LICENSE("GPL");