4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
9 #include <linux/module.h>
10 #include <linux/device.h>
12 #include <linux/of_gpio.h>
13 #include <sound/core.h>
14 #include <sound/pcm.h>
15 #include <sound/soc.h>
16 #include <sound/soc-dapm.h>
17 #include <sound/jack.h>
18 #include <linux/delay.h>
19 #include "card_info.h"
23 #define DBG(x...) printk(KERN_INFO x)
28 #include "../codecs/rt5512.h"
30 static struct platform_device *rk29_snd_device;
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;
40 unsigned int pll_div, dai_fmt = rtd->dai_link->dai_fmt;
43 DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
45 /* set codec DAI configuration */
46 ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
48 printk("%s():failed to set the format for codec side\n", __FUNCTION__);
52 /* set cpu DAI configuration */
53 ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
55 printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
59 switch(params_rate(params)) {
81 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
85 if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
87 snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
88 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, 64-1);//bclk = 2*32*lrck; 2*32fs
89 switch(params_rate(params)) {
92 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);
93 DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
94 __FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));
97 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
98 DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
99 __FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));
103 /*Set the system clk for codec*/
104 ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
107 DBG("rk29_hw_params_rt5512:failed to set the sysclk for codec side\n");
111 switch (params_rate(params))
141 printk("Not yet supported!\n");
144 ret = snd_soc_dai_set_clkdiv(codec_dai, RT5512_CLK_DIV_ID, pll_div*4);
149 if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
150 snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
154 //---------------------------------------------------------------------------------
156 * rt5512 DAI operations.
158 static struct snd_soc_ops rk29_ops = {
159 .hw_params = rk29_hw_params,
162 static const struct snd_soc_dapm_widget rt5512_dapm_widgets[] = {
164 SND_SOC_DAPM_MIC("Main Mic", NULL),
165 SND_SOC_DAPM_LINE("LineIn", NULL),
167 SND_SOC_DAPM_SPK("Ext Spk", NULL),
168 SND_SOC_DAPM_HP("Headphone Jack", NULL),
171 static const struct snd_soc_dapm_route rt5512_audio_map[] = {
173 {"MicBias1", NULL,"Main Mic"},
174 {"Mic2", NULL, "MicBias1"},
175 {"MicBias2", NULL, "LineIn"},
176 {"Aux", NULL, "MicBias2"},
178 {"Ext Spk", NULL, "LSpeaker"},
179 {"Ext Spk", NULL, "RSpeaker"},
180 {"Headphone Jack", NULL, "LHeadphone"},
181 {"Headphone Jack", NULL, "RHeadphone"},
186 static struct snd_soc_jack rk29_soc_jack;
190 static struct snd_soc_jack_gpio odroid_soc_jack_gpio[] = {
193 .name "headset event",
194 .report = SND_JACK_HEADSET,
195 .debounce_time = 200,
201 static int rt5512_headset_keys(struct snd_soc_jack *jack)
205 err = snd_jack_set_key(jack->jack, SND_JACK_BTN_0, 0x80);
209 err = snd_jack_set_key(jack->jack, SND_JACK_BTN_1, 0x81);
213 err = snd_jack_set_key(jack->jack, SND_JACK_BTN_2, 0x82);
221 static int rt5512_init(struct snd_soc_pcm_runtime *rtd)
223 struct snd_soc_codec *codec = rtd->codec;
224 struct snd_soc_dapm_context *dapm = &codec->dapm;
225 //struct rt5512_codec_chip *chip = snd_soc_codec_get_drvdata(codec);
228 snd_soc_dapm_new_controls(dapm, rt5512_dapm_widgets,
229 ARRAY_SIZE(rt5512_dapm_widgets));
231 snd_soc_dapm_add_routes(dapm, rt5512_audio_map,
232 ARRAY_SIZE(rt5512_audio_map));
234 snd_soc_dapm_disable_pin(dapm, "Main Mic");
235 snd_soc_dapm_disable_pin(dapm, "LineIn");
236 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
237 snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
243 err = snd_soc_jack_new(codec, "Headset Jack" , SND_JACK_HEADSET, &rk29_soc_jack);
248 // How-to use gpio, just declare snd_soc_jack_gpios, then it will
249 // help you to register a interrupt and set wakeup, and delayed schedule
251 err = snd_soc_jack_add_gpios(&odroid_soc_jack, gpio_count, odroid_soc_jack_gpios);
255 // If use this, when trigger, just use snd_soc_jack_get_type
256 // then snd_soc_jack_report to send the event to upper layer
257 err = snd_soc_jack_add_zones(&odroid_soc_jack, zone_count, tcc_soc_zones);
262 err = rt5512_headset_keys(&rk29_soc_jack);
266 chip->rt_jack = &rk29_soc_jack;
269 snd_soc_dapm_sync(dapm);
273 static struct snd_soc_dai_link rk29_dai[] = {
274 { /* Primary DAI i/f */
275 .name = "RT5512 AIF1",
276 .stream_name = "RT5512 PCM",
277 .codec_dai_name = "RT5512-aif1",
283 static struct snd_soc_card rockchip_rt5512_snd_card = {
285 .dai_link = rk29_dai,
287 /* If you want to use sec_fifo device,
288 * changes the num_link = 2 or ARRAY_SIZE(odroid_dai). */
289 .num_links = ARRAY_SIZE(rk29_dai),
292 static int rockchip_rt5512_audio_probe(struct platform_device *pdev)
295 struct snd_soc_card *card = &rockchip_rt5512_snd_card;
297 card->dev = &pdev->dev;
299 ret = rockchip_of_get_sound_card_info(card);
301 printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
305 ret = snd_soc_register_card(card);
307 printk("%s() register card failed:%d\n", __FUNCTION__, ret);
312 static int rockchip_rt5512_audio_remove(struct platform_device *pdev)
314 struct snd_soc_card *card = platform_get_drvdata(pdev);
316 snd_soc_unregister_card(card);
322 static const struct of_device_id rockchip_rt5512_of_match[] = {
323 { .compatible = "rockchip-rt5512", },
326 MODULE_DEVICE_TABLE(of, rockchip_rt5512_of_match);
327 #endif /* CONFIG_OF */
329 static struct platform_driver rockchip_rt5512_audio_driver = {
331 .name = "rockchip-rt5512",
332 .owner = THIS_MODULE,
333 .pm = &snd_soc_pm_ops,
334 .of_match_table = of_match_ptr(rockchip_rt5512_of_match),
336 .probe = rockchip_rt5512_audio_probe,
337 .remove = rockchip_rt5512_audio_remove,
340 module_platform_driver(rockchip_rt5512_audio_driver);
342 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
343 MODULE_AUTHOR("cy_huang <cy_huang@richtek.com>");
344 MODULE_LICENSE("GPL");