2 * rk29_aic3262.c -- SoC audio for rockchip
4 * Driver for rockchip aic3262 audio
5 * Copyright (C) 2009 lhh
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
16 #include <linux/clk.h>
17 #include <linux/platform_device.h>
18 #include <linux/i2c.h>
19 #include <linux/i2c/twl.h>
20 #include <linux/regulator/consumer.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 #include <sound/soc.h>
25 #include <sound/soc-dapm.h>
26 #include <sound/jack.h>
27 #include <linux/switch.h>
28 #include <linux/irq.h>
29 #include <linux/interrupt.h>
30 #include <linux/gpio.h>
32 #include <linux/of_gpio.h>
34 #include <asm/mach-types.h>
35 #include <linux/module.h>
36 #include <linux/device.h>
38 #include "../codecs/wm8994.h"
39 #include "card_info.h"
42 #include <linux/clk.h>
43 #include <linux/mfd/tlv320aic3262-registers.h>
44 #include "../codecs/tlv320aic326x.h"
47 #define DBG_AIC3262(x...) printk(KERN_INFO x)
49 #define DBG_AIC3262(x...)
52 //struct regulator *vddhf_reg=NULL;
55 //static struct snd_soc_jack hs_jack;
57 /*Headset jack detection DAPM pins */
58 /*static struct snd_soc_jack_pin hs_jack_pins[] = {
61 .mask = SND_JACK_MICROPHONE,
64 .pin = "Headset Stereophone",
65 .mask = SND_JACK_HEADPHONE,
69 static int spk_event(struct snd_soc_dapm_widget *w,
70 struct snd_kcontrol *kcontrol, int event)
72 //struct snd_soc_codec *codec = w->codec;
74 if (SND_SOC_DAPM_EVENT_ON(event)) {
76 printk(" I am NULL is %d event is %d\n",vddhf_reg,event);
79 ret = regulator_enable(vddhf_reg);
81 printk("failed to enable vddhf \n");
89 ret = regulator_disable(vddhf_reg);
91 printk("failed to disable "
92 "VDDHF regulator %d\n", ret);
102 /* rk29 machine DAPM */
103 static const struct snd_soc_dapm_widget rk29_aic3262_dapm_widgets[] = {
104 SND_SOC_DAPM_MIC("Ext Mic", NULL),
105 SND_SOC_DAPM_SPK("Ext Spk", NULL),
106 SND_SOC_DAPM_MIC("Headset Mic", NULL),
107 SND_SOC_DAPM_HP("Headset Stereophone", NULL),
108 SND_SOC_DAPM_SPK("Earphone Spk", NULL),
109 SND_SOC_DAPM_INPUT("FM Stereo In"),
110 SND_SOC_DAPM_LINE("FM Stereo Out",NULL),
113 static const struct snd_soc_dapm_route audio_map[] = {
114 /* External Mics: MAINMIC, SUBMIC with bias*/
115 {"IN1L", NULL, "Mic Bias Int"},
116 {"IN1R", NULL, "Mic Bias Int"},
117 {"IN4L", NULL, "Mic Bias Int"},
118 {"IN4R", NULL, "Mic Bias Int"},
119 {"Mic Bias Int", NULL, "Ext Mic"},
121 /* External Speakers: HFL, HFR */
122 {"Ext Spk", NULL, "SPKL"},
123 {"Ext Spk", NULL, "SPKR"},
125 /* Headset Mic: HSMIC with bias */
126 {"IN2L", NULL, "Mic Bias Ext"},
127 {"IN2R", NULL, "Mic Bias Ext"},
128 {"Mic Bias Ext", NULL, "Headset Mic"},
130 /* Headset Stereophone (Headphone): HPL, HPR */
131 {"Headset Stereophone", NULL, "HPL"},
132 {"Headset Stereophone", NULL, "HPR"},
134 /* Earphone speaker */
135 {"Earphone Spk", NULL, "RECP"},
136 {"Earphone Spk", NULL, "RECM"},
138 /* Aux/FM Stereo In: IN4L, IN4R */
139 {"IN3L", NULL, "FM Stereo In"},
140 {"IN3R", NULL, "FM Stereo In"},
142 /* Aux/FM Stereo Out: LOL, LOR */
143 {"FM Stereo Out", NULL, "LOL"},
144 {"FM Stereo Out", NULL, "LOR"},
147 static const struct snd_kcontrol_new rk29_aic326x_controls[] = {
148 SOC_DAPM_PIN_SWITCH("Ext Mic"),
149 SOC_DAPM_PIN_SWITCH("Ext Spk"),
150 SOC_DAPM_PIN_SWITCH("Headset Mic"),
151 SOC_DAPM_PIN_SWITCH("Headset Stereophone"),
152 SOC_DAPM_PIN_SWITCH("Earphone Spk"),
153 SOC_DAPM_PIN_SWITCH("FM Stereo In"),
154 SOC_DAPM_PIN_SWITCH("FM Stereo Out"),
157 static int rk29_aic3262_init(struct snd_soc_pcm_runtime *rtd)
159 struct snd_soc_codec *codec = rtd->codec;
160 struct snd_soc_dapm_context *dapm = &codec->dapm;
163 DBG_AIC3262("rk29_aic3262_init\n");
165 /* Headset jack detection */
166 /*ret = snd_soc_jack_new(codec, "Headset Jack",
167 SND_JACK_HEADSET, &hs_jack);
171 ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
173 aic3262_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);*/
175 /* don't wait before switching of HS power */
176 rtd->pmdown_time = 0;
180 static int rk29_aif1_hw_params(struct snd_pcm_substream *substream,
181 struct snd_pcm_hw_params *params)
183 struct snd_soc_pcm_runtime *rtd = substream->private_data;
184 struct snd_soc_dai *codec_dai = rtd->codec_dai;
185 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
186 unsigned int pll_out = 0, dai_fmt = rtd->dai_link->dai_fmt;
187 int div_bclk,div_mclk;
190 DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
192 /* set codec DAI configuration */
193 ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
195 printk("%s():failed to set the format for codec side\n", __FUNCTION__);
199 /* set cpu DAI configuration */
200 ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
202 printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
206 switch(params_rate(params)) {
220 DBG_AIC3262("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
225 div_bclk=(pll_out/4)/params_rate(params)-1;
228 DBG_AIC3262(" %s, pll_out=%d, div_bclk=%d, div_mclk=%d\n",__FUNCTION__,pll_out,div_bclk,div_mclk);
229 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
232 DBG_AIC3262("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n");
235 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
236 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
237 DBG_AIC3262("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
239 //MCLK == 11289600 or 12288000
240 ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
242 DBG_AIC3262("rk29_hw_params_aic3262:failed to set the sysclk for codec side\n");
249 static int rk29_aif2_hw_params(struct snd_pcm_substream *substream,
250 struct snd_pcm_hw_params *params)
252 struct snd_soc_pcm_runtime *rtd = substream->private_data;
253 struct snd_soc_dai *codec_dai = rtd->codec_dai;
254 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
255 unsigned int pll_out = 0;
256 int div_bclk,div_mclk;
259 DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
261 /* set codec DAI configuration */
262 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
263 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
266 printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
269 switch(params_rate(params)) {
283 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
287 div_bclk=(pll_out/4)/params_rate(params)-1;
290 DBG_AIC3262(" %s, pll_out=%d, div_bclk=%d, div_mclk=%d\n",__FUNCTION__,pll_out,div_bclk,div_mclk);
292 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
295 DBG("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n");
298 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
299 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
300 DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
302 /* set the codec system clock */
303 ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
306 printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
310 /* set the codec FLL */
311 ret = snd_soc_dai_set_pll(codec_dai, 0, AIC3262_PLL_CLKIN_MCLK1 , pll_out, 8000*256);
314 printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
321 static int rk29_aif3_hw_params(struct snd_pcm_substream *substream,
322 struct snd_pcm_hw_params *params)
324 struct snd_soc_pcm_runtime *rtd = substream->private_data;
325 struct snd_soc_dai *codec_dai = rtd->codec_dai;
326 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
327 unsigned int pll_out = 0;
328 int div_bclk,div_mclk;
331 DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
333 /* set codec DAI configuration */
334 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
335 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
338 printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
341 switch(params_rate(params)) {
355 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
359 div_bclk=(pll_out/4)/params_rate(params)-1;
362 DBG_AIC3262(" %s, pll_out=%d, div_bclk=%d, div_mclk=%d\n",__FUNCTION__,pll_out,div_bclk,div_mclk);
364 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
367 DBG("rk29_hw_params_aic3262:failed to set the cpu sysclk for codec side\n");
370 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
371 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
372 DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
374 /* set the codec system clock */
375 ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
378 printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
382 /* set the codec FLL */
383 ret = snd_soc_dai_set_pll(codec_dai, 0, AIC3262_PLL_CLKIN_MCLK1 , pll_out, 8000*256);
386 printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
393 static struct snd_soc_ops rk29_aif1_ops = {
394 .hw_params = rk29_aif1_hw_params,
397 static struct snd_soc_ops rk29_aif2_ops = {
398 .hw_params = rk29_aif2_hw_params,
401 static struct snd_soc_ops rk29_aif3_ops = {
402 .hw_params = rk29_aif3_hw_params,
405 static struct snd_soc_dai_link rk29_dai[] = {
408 .name = "AIC3262 I2S1",
409 .stream_name = "AIC3262 PCM",
410 .codec_dai_name = "aic326x-asi1",
411 .ops = &rk29_aif1_ops,
412 .init = rk29_aic3262_init,
416 .name = "AIC3262 I2S2",
417 .stream_name = "AIC3262 PCM",
418 .codec_dai_name = "aic326x-asi2",
419 .ops = &rk29_aif2_ops,
424 .name = "AIC3262 I2S3",
425 .stream_name = "AIC3262 PCM",
426 .codec_dai_name = "aic326x-asi3",
427 .ops = &rk29_aif3_ops,
433 static struct snd_soc_card rockchip_aic3262_snd_card = {
434 .name = "RK_AIC3262",
435 .dai_link = rk29_dai,
436 .num_links = ARRAY_SIZE(rk29_dai),
437 .controls = rk29_aic326x_controls,
438 .num_controls = ARRAY_SIZE(rk29_aic326x_controls),
439 .dapm_widgets = rk29_aic3262_dapm_widgets,
440 .num_dapm_widgets = ARRAY_SIZE(rk29_aic3262_dapm_widgets),
441 .dapm_routes = audio_map,
442 .num_dapm_routes = ARRAY_SIZE(audio_map),
445 static int rockchip_aic3262_audio_probe(struct platform_device *pdev)
448 struct snd_soc_card *card = &rockchip_aic3262_snd_card;
450 card->dev = &pdev->dev;
452 ret = rockchip_of_get_sound_card_info(card);
454 printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
458 ret = snd_soc_register_card(card);
460 printk("%s() register card failed:%d\n", __FUNCTION__, ret);
465 static int rockchip_aic3262_audio_remove(struct platform_device *pdev)
467 struct snd_soc_card *card = platform_get_drvdata(pdev);
469 snd_soc_unregister_card(card);
475 static const struct of_device_id rockchip_aic3262_of_match[] = {
476 { .compatible = "rockchip-aic3262", },
479 MODULE_DEVICE_TABLE(of, rockchip_aic3262_of_match);
480 #endif /* CONFIG_OF */
482 static struct platform_driver rockchip_aic3262_audio_driver = {
484 .name = "rockchip-aic3262",
485 .owner = THIS_MODULE,
486 .pm = &snd_soc_pm_ops,
487 .of_match_table = of_match_ptr(rockchip_aic3262_of_match),
489 .probe = rockchip_aic3262_audio_probe,
490 .remove = rockchip_aic3262_audio_remove,
493 module_platform_driver(rockchip_aic3262_audio_driver);
495 /* Module information */
496 MODULE_AUTHOR("rockchip");
497 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
498 MODULE_LICENSE("GPL");