2 * rk29_rt5631.c -- SoC audio for rockchip
4 * Driver for rockchip rt5631 audio
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
14 #include <linux/module.h>
15 #include <linux/device.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/soc.h>
19 #include <sound/soc-dapm.h>
21 #include <mach/hardware.h>
22 #include <mach/rk29_iomap.h>
23 #include "../codecs/rt5631.h"
28 #define DBG(x...) printk(KERN_INFO x)
33 static int rk29_hw_params(struct snd_pcm_substream *substream,
34 struct snd_pcm_hw_params *params)
36 struct snd_soc_pcm_runtime *rtd = substream->private_data;
37 struct snd_soc_dai *codec_dai = rtd->codec_dai;
38 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
39 unsigned int pll_out = 0;
42 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
43 /*by Vincent Hsiung for EQ Vol Change*/
44 #define HW_PARAMS_FLAG_EQVOL_ON 0x21
45 #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
46 if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
48 ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
49 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
54 /* set codec DAI configuration */
55 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
56 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
57 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
59 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
60 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
61 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM );
66 /* set cpu DAI configuration */
67 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
68 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
69 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
71 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
72 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
73 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
81 switch(params_rate(params)) {
95 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
99 DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
101 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
102 #if 0 //use pll from blck
103 /*Set the pll of rt5631,the Pll source from BITCLK on CPU is master mode*/
105 ret=snd_soc_dai_set_pll(codec_dai,0,params_rate(params)*64,pll_out);
108 DBG("rk29_hw_params_rt5631:failed to set the pll for codec side\n");
112 /*Set the system clk for codec*/
113 ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
116 DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n");
122 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
124 // snd_soc_dai_set_pll(codec_dai,0,pll_out, 22579200);
125 snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
130 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
131 snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
132 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
133 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
136 DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
141 static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
143 SND_SOC_DAPM_MIC("Mic Jack", NULL),
144 SND_SOC_DAPM_SPK("Ext Spk", NULL),
145 SND_SOC_DAPM_HP("Headphone Jack", NULL),
149 static const struct snd_soc_dapm_route audio_map[]={
151 /* Mic Jack --> MIC_IN*/
152 {"Mic Bias1", NULL, "Mic Jack"},
153 {"MIC1", NULL, "Mic Bias1"},
154 /* HP_OUT --> Headphone Jack */
155 {"Headphone Jack", NULL, "HPOL"},
156 {"Headphone Jack", NULL, "HPOR"},
157 /* LINE_OUT --> Ext Speaker */
158 {"Ext Spk", NULL, "SPOL"},
159 {"Ext Spk", NULL, "SPOR"},
164 * Logic for a rt5631 as connected on a rockchip board.
166 static int rk29_rt5631_init(struct snd_soc_pcm_runtime *rtd)
168 struct snd_soc_codec *codec = rtd->codec;
169 struct snd_soc_dapm_context *dapm = &codec->dapm;
171 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
173 /* Add specific widgets */
174 snd_soc_dapm_new_controls(dapm, rt5631_dapm_widgets,
175 ARRAY_SIZE(rt5631_dapm_widgets));
176 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
177 /* Set up specific audio path audio_mapnects */
178 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
179 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
180 snd_soc_dapm_nc_pin(dapm, "HP_L");
181 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
182 snd_soc_dapm_nc_pin(dapm, "HP_R");
183 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
184 snd_soc_dapm_sync(dapm);
185 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
190 static struct snd_soc_ops rk29_ops = {
191 .hw_params = rk29_hw_params,
194 static struct snd_soc_dai_link rk29_dai = {
196 .stream_name = "RT5631 PCM",
197 .codec_name = "RT5631.0-001a",
198 .platform_name = "rockchip-audio",
199 .cpu_dai_name = "rk29_i2s.0",
200 .codec_dai_name = "RT5631 HiFi",
201 .init = rk29_rt5631_init,
205 static struct snd_soc_card snd_soc_card_rk29 = {
206 .name = "RK29_RT5631",
207 .dai_link = &rk29_dai,
211 static struct platform_device *rk29_snd_device;
213 static int __init audio_card_init(void)
217 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
218 rk29_snd_device = platform_device_alloc("soc-audio", -1);
219 if (!rk29_snd_device) {
220 printk("platform device allocation failed\n");
224 platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
225 ret = platform_device_add(rk29_snd_device);
227 printk("platform device add failed\n");
228 platform_device_put(rk29_snd_device);
233 static void __exit audio_card_exit(void)
235 platform_device_unregister(rk29_snd_device);
238 module_init(audio_card_init);
239 module_exit(audio_card_exit);
240 /* Module information */
241 MODULE_AUTHOR("rockchip");
242 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
243 MODULE_LICENSE("GPL");