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>
22 #define DBG(x...) printk(KERN_INFO x)
27 #include "../codecs/rt5512.h"
29 static struct platform_device *rk29_snd_device;
32 static int rk29_hw_params(struct snd_pcm_substream *substream,
33 struct snd_pcm_hw_params *params)
35 struct snd_soc_pcm_runtime *rtd = substream->private_data;
36 struct snd_soc_dai *codec_dai = rtd->codec_dai;
37 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
38 unsigned int pll_out = 0;
42 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
44 /* set cpu DAI configuration */
45 #if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE)
46 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
47 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
49 #if defined (CONFIG_SND_RK_CODEC_SOC_MASTER)
50 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
51 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
57 /* set codec DAI configuration */
58 #if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE)
59 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
60 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
62 #if defined (CONFIG_SND_RK_CODEC_SOC_MASTER)
63 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
64 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM );
72 switch(params_rate(params)) {
94 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
98 #if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE)
99 snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
100 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, 64-1);//bclk = 2*32*lrck; 2*32fs
101 switch(params_rate(params)) {
104 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);
105 DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
106 __FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));
109 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
110 DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
111 __FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));
115 /*Set the system clk for codec*/
116 ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
119 DBG("rk29_hw_params_rt5512:failed to set the sysclk for codec side\n");
123 switch (params_rate(params))
153 printk("Not yet supported!\n");
156 ret = snd_soc_dai_set_clkdiv(codec_dai, RT5512_CLK_DIV_ID, pll_div*4);
161 #if defined (CONFIG_SND_RK_CODEC_SOC_MASTER)
162 //snd_soc_dai_set_pll(codec_dai,0,pll_out, 22579200);
163 snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
168 //---------------------------------------------------------------------------------
170 * rt5512 DAI operations.
172 static struct snd_soc_ops rk29_ops = {
173 .hw_params = rk29_hw_params,
176 static const struct snd_soc_dapm_widget rt5512_dapm_widgets[] = {
178 SND_SOC_DAPM_MIC("Main Mic", NULL),
179 SND_SOC_DAPM_LINE("LineIn", NULL),
181 SND_SOC_DAPM_SPK("Ext Spk", NULL),
182 SND_SOC_DAPM_HP("Headphone Jack", NULL),
185 static const struct snd_soc_dapm_route rt5512_audio_map[] = {
187 {"MicBias1", NULL,"Main Mic"},
188 {"Mic2", NULL, "MicBias1"},
189 {"MicBias2", NULL, "LineIn"},
190 {"Aux", NULL, "MicBias2"},
192 {"Ext Spk", NULL, "LSpeaker"},
193 {"Ext Spk", NULL, "RSpeaker"},
194 {"Headphone Jack", NULL, "LHeadphone"},
195 {"Headphone Jack", NULL, "RHeadphone"},
200 static struct snd_soc_jack rk29_soc_jack;
204 static struct snd_soc_jack_gpio odroid_soc_jack_gpio[] = {
207 .name "headset event",
208 .report = SND_JACK_HEADSET,
209 .debounce_time = 200,
215 static int rt5512_headset_keys(struct snd_soc_jack *jack)
219 err = snd_jack_set_key(jack->jack, SND_JACK_BTN_0, 0x80);
223 err = snd_jack_set_key(jack->jack, SND_JACK_BTN_1, 0x81);
227 err = snd_jack_set_key(jack->jack, SND_JACK_BTN_2, 0x82);
235 static int rt5512_init(struct snd_soc_pcm_runtime *rtd)
237 struct snd_soc_codec *codec = rtd->codec;
238 struct snd_soc_dapm_context *dapm = &codec->dapm;
239 //struct rt5512_codec_chip *chip = snd_soc_codec_get_drvdata(codec);
242 snd_soc_dapm_new_controls(dapm, rt5512_dapm_widgets,
243 ARRAY_SIZE(rt5512_dapm_widgets));
245 snd_soc_dapm_add_routes(dapm, rt5512_audio_map,
246 ARRAY_SIZE(rt5512_audio_map));
248 snd_soc_dapm_disable_pin(dapm, "Main Mic");
249 snd_soc_dapm_disable_pin(dapm, "LineIn");
250 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
251 snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
257 err = snd_soc_jack_new(codec, "Headset Jack" , SND_JACK_HEADSET, &rk29_soc_jack);
262 // How-to use gpio, just declare snd_soc_jack_gpios, then it will
263 // help you to register a interrupt and set wakeup, and delayed schedule
265 err = snd_soc_jack_add_gpios(&odroid_soc_jack, gpio_count, odroid_soc_jack_gpios);
269 // If use this, when trigger, just use snd_soc_jack_get_type
270 // then snd_soc_jack_report to send the event to upper layer
271 err = snd_soc_jack_add_zones(&odroid_soc_jack, zone_count, tcc_soc_zones);
276 err = rt5512_headset_keys(&rk29_soc_jack);
280 chip->rt_jack = &rk29_soc_jack;
283 snd_soc_dapm_sync(dapm);
287 static struct snd_soc_dai_link rk29_dai[] = {
288 { /* Primary DAI i/f */
289 .name = "RT5512 AIF1",
290 .stream_name = "RT5512 PCM",
291 .cpu_dai_name = "rockchip-i2s.1",
292 .codec_dai_name = "RT5512-aif1",
293 .platform_name = "rockchip-pcm",
294 .codec_name = "rt5512.1-0018",
300 static struct snd_soc_card rockchip_rt5512_snd_card = {
302 .dai_link = rk29_dai,
304 /* If you want to use sec_fifo device,
305 * changes the num_link = 2 or ARRAY_SIZE(odroid_dai). */
306 .num_links = ARRAY_SIZE(rk29_dai),
309 static int rockchip_rt5512_audio_probe(struct platform_device *pdev)
312 struct snd_soc_card *card = &rockchip_rt5512_snd_card;
314 card->dev = &pdev->dev;
316 ret = snd_soc_register_card(card);
319 printk("%s() register card failed:%d\n", __FUNCTION__, ret);
324 static int rockchip_rt5512_audio_remove(struct platform_device *pdev)
326 struct snd_soc_card *card = platform_get_drvdata(pdev);
328 snd_soc_unregister_card(card);
334 static const struct of_device_id rockchip_rt5512_of_match[] = {
335 { .compatible = "rockchip-rt5512", },
338 MODULE_DEVICE_TABLE(of, rockchip_rt5512_of_match);
339 #endif /* CONFIG_OF */
341 static struct platform_driver rockchip_rt5512_audio_driver = {
343 .name = "rockchip-rt5512",
344 .owner = THIS_MODULE,
345 .of_match_table = of_match_ptr(rockchip_rt5512_of_match),
347 .probe = rockchip_rt5512_audio_probe,
348 .remove = rockchip_rt5512_audio_remove,
351 module_platform_driver(rockchip_rt5512_audio_driver);
353 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
354 MODULE_AUTHOR("cy_huang <cy_huang@richtek.com>");
355 MODULE_LICENSE("GPL");