From 3fc434b8edfa6f5a63aefc1af3269ea451bd21eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=99=88=E9=87=91=E6=B3=89?= Date: Wed, 31 Jul 2013 11:01:49 +0800 Subject: [PATCH] rk616 codec: add tiny alsa route(playback capture incall) support --- include/linux/mfd/rk616.h | 1 + sound/soc/codecs/rk616_codec.c | 337 +++++++++++++++++++++++---------- sound/soc/codecs/rk616_codec.h | 1 + sound/soc/rk29/rk30_i2s.c | 8 +- sound/soc/rk29/rk_rk616.c | 35 ++-- 5 files changed, 270 insertions(+), 112 deletions(-) diff --git a/include/linux/mfd/rk616.h b/include/linux/mfd/rk616.h index 937d5ecf630c..166a27fe4f02 100755 --- a/include/linux/mfd/rk616.h +++ b/include/linux/mfd/rk616.h @@ -245,6 +245,7 @@ struct rk616_platform_data { int hdmi_irq; int spk_ctl_gpio; int hp_ctl_gpio; + int mic_sel_gpio; }; struct rk616_route { diff --git a/sound/soc/codecs/rk616_codec.c b/sound/soc/codecs/rk616_codec.c index 6659f1844931..83ae80b2c44f 100755 --- a/sound/soc/codecs/rk616_codec.c +++ b/sound/soc/codecs/rk616_codec.c @@ -61,6 +61,7 @@ struct rk616_codec_priv { int spk_ctl_gpio; int hp_ctl_gpio; + int mic_sel_gpio; long int playback_path; long int capture_path; @@ -76,7 +77,6 @@ static struct mfd_rk616 *rk616_mfd = NULL; #define RK616_CODEC_WORK_NULL 0 #define RK616_CODEC_WORK_POWER_DOWN 1 -#define RK616_CODEC_WORK_POWER_UP 2 static struct workqueue_struct *rk616_codec_workq; @@ -85,6 +85,11 @@ static DECLARE_DELAYED_WORK(capture_delayed_work, rk616_codec_capture_work); static int rk616_codec_work_capture_type = RK616_CODEC_WORK_NULL; static bool rk616_for_mid = 1, is_hdmi_in = false; +bool rk616_get_for_mid(void) +{ + return rk616_for_mid; +} + static int rk616_get_parameter(void) { int val; @@ -896,7 +901,7 @@ static const struct snd_kcontrol_new rk616_snd_controls[] = { RK616_HML_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv), SOC_SINGLE_TLV("HPMIX MUX to HPMIXL Volume", RK616_HPMIX_VOL2, RK616_HML_F_HMM_VOL_SFT, 7, 0, mix_vol_tlv), - SOC_SINGLE_TLV("HPMIX MUX to MIXINR Volume", RK616_HPMIX_VOL2, + SOC_SINGLE_TLV("HPMIX MUX to HPMIXR Volume", RK616_HPMIX_VOL2, RK616_HMR_F_HMM_VOL_SFT, 7, 0, mix_vol_tlv), SOC_ENUM("Micbias1 Voltage", rk616_micbias_enum[0]), @@ -1016,47 +1021,91 @@ static int rk616_playback_path_put(struct snd_kcontrol *kcontrol, } if (rk616_priv->playback_path == ucontrol->value.integer.value[0]){ - printk("%s : playback_path is not changed!\n",__func__); + DBG("%s : playback_path is not changed!\n",__func__); //return 0; } rk616_priv->playback_path = ucontrol->value.integer.value[0]; - DBG("%s : set playback_path = %ld, hdmi %s\n", __func__, - rk616_priv->playback_path, get_hdmi_state() ? "in" : "out"); + printk("%s : set playback_path = %ld\n", __func__, + rk616_priv->playback_path); + + // mute output for pop noise + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_LOW); + } + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_LOW); + } if(get_hdmi_state()) return 0; switch (rk616_priv->playback_path) { case OFF: - snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_sync(&codec->dapm); break; case RCV: + //close incall route + snd_soc_update_bits(codec, RK616_PGA_AGC_CTL, + 0x0f, 0x0c); + snd_soc_update_bits(codec, RK616_MIXINL_CTL, + RK616_MIL_F_IN3L | RK616_MIL_MUTE, + RK616_MIL_F_IN3L | RK616_MIL_MUTE); + snd_soc_update_bits(codec, RK616_MIXINL_VOL2, + RK616_MIL_F_IN3L_VOL_MASK, 4); + snd_soc_update_bits(codec, RK616_PGAL_CTL, + 0xff, 0xcc); + snd_soc_update_bits(codec, RK616_HPMIX_CTL, + RK616_HML_F_PGAL | RK616_HMR_F_PGAL, + RK616_HML_F_PGAL | RK616_HMR_F_PGAL); break; case SPK_PATH: case RING_SPK: - snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_VOL_MASK, SPKOUT_VOLUME); //, volume (bit 0-4) + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_VOL_MASK, SPKOUT_VOLUME); + + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_HIGH); + } break; case HP_PATH: case HP_NO_MIC: case RING_HP: case RING_HP_NO_MIC: - snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_VOL_MASK, HPOUT_VOLUME); //, volume (bit 0-4) + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_VOL_MASK, HPOUT_VOLUME); + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_HIGH); + } break; case BT: break; case SPK_HP: case RING_SPK_HP: - snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_VOL_MASK, HPOUT_VOLUME); //, volume (bit 0-4) + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_VOL_MASK, HPOUT_VOLUME); + + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_HIGH); + } + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_HIGH); + } break; default: return -EINVAL; @@ -1084,7 +1133,7 @@ static int rk616_capture_path_get(struct snd_kcontrol *kcontrol, static int rk616_capture_path_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + //struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); if (!rk616_priv) { printk("%s : rk616_priv is NULL\n", __func__); @@ -1092,33 +1141,31 @@ static int rk616_capture_path_put(struct snd_kcontrol *kcontrol, } if (rk616_priv->capture_path == ucontrol->value.integer.value[0]){ - printk("%s : capture_path is not changed!\n", __func__); + DBG("%s : capture_path is not changed!\n", __func__); //return 0; } rk616_priv->capture_path = ucontrol->value.integer.value[0]; - DBG("%s : set capture_path = %ld\n", __func__, rk616_priv->capture_path); + printk("%s : set capture_path = %ld\n", __func__, rk616_priv->capture_path); switch (rk616_priv->capture_path) { case MIC_OFF: - snd_soc_dapm_disable_pin(&codec->dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(&codec->dapm, "Headset Jack"); - snd_soc_dapm_sync(&codec->dapm); break; case Main_Mic: - snd_soc_dapm_enable_pin(&codec->dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(&codec->dapm,"Headset Jack"); - snd_soc_dapm_sync(&codec->dapm); + if (rk616_priv && rk616_priv->mic_sel_gpio != INVALID_GPIO) { + DBG("%s : set mic sel gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->mic_sel_gpio, GPIO_HIGH); + } break; case Hands_Free_Mic: - snd_soc_dapm_enable_pin(&codec->dapm, "Headset Jack"); - snd_soc_dapm_disable_pin(&codec->dapm, "Mic Jack"); - snd_soc_dapm_sync(&codec->dapm); + if (rk616_priv && rk616_priv->mic_sel_gpio != INVALID_GPIO) { + DBG("%s : set mic sel gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->mic_sel_gpio, GPIO_LOW); + } break; case BT_Sco_Mic: break; - default: return -EINVAL; } @@ -1134,7 +1181,7 @@ static int rk616_voice_call_path_get(struct snd_kcontrol *kcontrol, return -EINVAL; } - DBG("%s : playback_path = %ld\n", __func__, + DBG("%s : voice_call_path = %ld\n", __func__, ucontrol->value.integer.value[0]); ucontrol->value.integer.value[0] = rk616_priv->voice_call_path; @@ -1153,33 +1200,111 @@ static int rk616_voice_call_path_put(struct snd_kcontrol *kcontrol, } if (rk616_priv->voice_call_path == ucontrol->value.integer.value[0]){ - printk("%s : playback_path is not changed!\n",__func__); + DBG("%s : voice_call_path is not changed!\n",__func__); //return 0; } rk616_priv->voice_call_path = ucontrol->value.integer.value[0]; - DBG("%s : set playback_path = %ld\n", __func__, + printk("%s : set voice_call_path = %ld\n", __func__, rk616_priv->voice_call_path); + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_LOW); + } + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_LOW); + } + switch (rk616_priv->voice_call_path) { case OFF: - snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_sync(&codec->dapm); break; case RCV: + snd_soc_write(codec, RK616_MICBIAS_CTL, 0x7f); //open micbias 1 + if (rk616_priv && rk616_priv->mic_sel_gpio != INVALID_GPIO) { + DBG("%s : set mic sel gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->mic_sel_gpio, GPIO_HIGH); + } + + //close incall route + snd_soc_update_bits(codec, RK616_PGA_AGC_CTL, + 0x0f, 0x0c); + snd_soc_update_bits(codec, RK616_MIXINL_CTL, + RK616_MIL_F_IN3L | RK616_MIL_MUTE, + RK616_MIL_F_IN3L | RK616_MIL_MUTE); + snd_soc_update_bits(codec, RK616_MIXINL_VOL2, + RK616_MIL_F_IN3L_VOL_MASK, 4); + snd_soc_update_bits(codec, RK616_PGAL_CTL, + 0xff, 0xcc); + snd_soc_update_bits(codec, RK616_HPMIX_CTL, + RK616_HML_F_PGAL | RK616_HMR_F_PGAL, + RK616_HML_F_PGAL | RK616_HMR_F_PGAL); + + // open spk for key tone + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_HIGH); + } break; case SPK_PATH: - snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_write(codec, RK616_MICBIAS_CTL, 0x7f); //open micbias 1 + if (rk616_priv && rk616_priv->mic_sel_gpio != INVALID_GPIO) { + DBG("%s : set mic sel gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->mic_sel_gpio, GPIO_HIGH); + } + + snd_soc_update_bits(codec, RK616_PGA_AGC_CTL, + 0x0f, 0x09); //set for capture pop noise + snd_soc_update_bits(codec, RK616_MIXINL_CTL, + RK616_MIL_F_IN3L | RK616_MIL_MUTE, 0); //IN3L to MIXINL, unmute IN3L + snd_soc_update_bits(codec, RK616_MIXINL_VOL2, + RK616_MIL_F_IN3L_VOL_MASK, 7); //IN3L to MIXINL vol + snd_soc_update_bits(codec, RK616_PGAL_CTL, + 0xff, 0x9f); //PU unmute PGAL,PGAL vol + snd_soc_update_bits(codec, RK616_HPMIX_CTL, + RK616_HML_F_PGAL | RK616_HMR_F_PGAL, 0); + + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_VOL_MASK, SPKOUT_VOLUME); //, volume (bit 0-4) + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_VOL_MASK, SPKOUT_VOLUME); + + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_HIGH); + } break; case HP_PATH: case HP_NO_MIC: - snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk"); - snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_write(codec, RK616_MICBIAS_CTL, 0x7f); //open micbias 1 + if (rk616_priv && rk616_priv->mic_sel_gpio != INVALID_GPIO) { + DBG("%s : set mic sel gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->mic_sel_gpio, GPIO_LOW); + } + + snd_soc_update_bits(codec, RK616_PGA_AGC_CTL, + 0x0f, 0x09); //set for capture pop noise + snd_soc_update_bits(codec, RK616_MIXINL_CTL, + RK616_MIL_F_IN3L | RK616_MIL_MUTE, 0); //IN3L to MIXINL, unmute IN3L + snd_soc_update_bits(codec, RK616_MIXINL_VOL2, + RK616_MIL_F_IN3L_VOL_MASK, 7); //IN3L to MIXINL vol + snd_soc_update_bits(codec, RK616_PGAL_CTL, + 0xff, 0x9f); //PU unmute PGAL,PGAL vol + snd_soc_update_bits(codec, RK616_HPMIX_CTL, + RK616_HML_F_PGAL | RK616_HMR_F_PGAL, 0); + + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_VOL_MASK, HPOUT_VOLUME); //, volume (bit 0-4) + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_VOL_MASK, HPOUT_VOLUME); + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio HIGH\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_HIGH); + } break; case BT: break; @@ -1595,7 +1720,7 @@ static const struct snd_soc_dapm_route rk616_dapm_routes[] = { {"HPMIXR", "DACR Switch", "DACR"}, {"HPMIXL", "HPMix Mux Switch", "HPMix Mux"}, - {"HPMIXL", "IN1P Switch", "PGAR"}, + {"HPMIXL", "IN1P Switch", "IN1P"}, {"HPMIXL", "PGAL Switch", "PGAL"}, {"HPMIXL", "DACL Switch", "DACL"}, @@ -1788,6 +1913,7 @@ static int rk616_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } +#ifdef CONFIG_SND_RK29_CODEC_SOC_MASTER // bclk = codec_clk / 4 // lrck = bclk / (wl * 2) div = (((rk616->stereo_sysclk / 4) / rate) / 2); @@ -1797,6 +1923,11 @@ static int rk616_hw_params(struct snd_pcm_substream *substream, printk("%s : need PLL\n", __func__); return -EINVAL; } +#else + //If codec is slave mode, it don't need to set div + //according to sysclk and rate. + div = 32; +#endif switch (div) { case 16: @@ -1906,6 +2037,12 @@ static int rk616_digital_mute(struct snd_soc_dai *dai, int mute) struct snd_soc_codec *codec = dai->codec; unsigned int is_spk_pd, is_hp_pd; + if (rk616_for_mid) + { + DBG("%s immediately return for mid\n",__func__); + return 0; + } + is_spk_pd = RK616_PWRD & snd_soc_read(codec, RK616_SPKL_CTL); is_spk_pd &= RK616_PWRD & snd_soc_read(codec, RK616_SPKR_CTL); @@ -1956,10 +2093,6 @@ static struct rk616_reg_val_typ playback_power_up_list[] = { {0x890, 3<<5|SPKOUT_VOLUME}, //power up SPKOUTR (bit 7), volume (bit 0-4) {0x88c, SPKOUT_VOLUME}, //unmute SPKOUTL (bit 5), volume (bit 0-4) {0x890, SPKOUT_VOLUME}, //unmute SPKOUTR (bit 5), volume (bit 0-4) - {0x894, 3<<5|HPOUT_VOLUME}, //power up HPOUTL (bit 7), volume (bit 0-4) - {0x898, 3<<5|HPOUT_VOLUME}, //power up HPOUTR (bit 7), volume (bit 0-4) - {0x894, HPOUT_VOLUME}, //unmute HPOUTL (bit 5), volume (bit 0-4) - {0x898, HPOUT_VOLUME}, //unmute HPOUTR (bit 5), volume (bit 0-4) }; #define RK616_CODEC_PLAYBACK_POWER_UP_LIST_LEN ARRAY_SIZE(playback_power_up_list) @@ -2038,6 +2171,17 @@ static int rk616_codec_power_up(int type) type == RK616_CODEC_CAPTURE ? "capture" : ""); if (type == RK616_CODEC_PLAYBACK) { + // mute output for pop noise + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_LOW); + } + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_LOW); + } + for (i = 0; i < RK616_CODEC_PLAYBACK_POWER_UP_LIST_LEN; i++) { snd_soc_write(codec, playback_power_up_list[i].reg, playback_power_up_list[i].value); @@ -2076,6 +2220,20 @@ static int rk616_codec_power_down(int type) type == RK616_CODEC_CAPTURE ? "capture" : "", type == RK616_CODEC_ALL ? "all" : ""); + // mute output for pop noise + if (type == RK616_CODEC_PLAYBACK || + type == RK616_CODEC_ALL) { + if (rk616_priv && rk616_priv->spk_ctl_gpio != INVALID_GPIO) { + DBG("%s : set spk ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->spk_ctl_gpio, GPIO_LOW); + } + + if (rk616_priv && rk616_priv->hp_ctl_gpio != INVALID_GPIO) { + DBG("%s : set hp ctl gpio LOW\n", __func__); + gpio_set_value(rk616_priv->hp_ctl_gpio, GPIO_LOW); + } + } + if (type == RK616_CODEC_CAPTURE) { for (i = 0; i < RK616_CODEC_CAPTURE_POWER_DOWN_LIST_LEN; i++) { snd_soc_write(codec, capture_power_down_list[i].reg, @@ -2102,9 +2260,6 @@ static void rk616_codec_capture_work(struct work_struct *work) case RK616_CODEC_WORK_POWER_DOWN: rk616_codec_power_down(RK616_CODEC_CAPTURE); break; - case RK616_CODEC_WORK_POWER_UP: - rk616_codec_power_up(RK616_CODEC_CAPTURE); - break; default: break; } @@ -2134,30 +2289,21 @@ static int rk616_startup(struct snd_pcm_substream *substream, DBG("%s : substream->stream : %s \n", __func__, playback ? "PLAYBACK":"CAPTURE"); - if (playback) + if (playback) { rk616->playback_active++; - else - rk616->capture_active++; - if (playback) { - if (rk616->playback_active > 0) { - if (!is_codec_playback_running) - rk616_codec_power_up(RK616_CODEC_PLAYBACK); - else - DBG(" Warning : playback has been opened, so return! \n"); + if (rk616->playback_active > 0 && !is_codec_playback_running) { + rk616_codec_power_up(RK616_CODEC_PLAYBACK); } } else {//capture + rk616->capture_active++; if (rk616->capture_active > 0 && !is_codec_capture_running) { - if (rk616_codec_work_capture_type != RK616_CODEC_WORK_POWER_UP) { - cancel_delayed_work_sync(&capture_delayed_work); - if (rk616_codec_work_capture_type == RK616_CODEC_WORK_NULL) { - rk616_codec_power_up(RK616_CODEC_CAPTURE); - } else { - DBG(" Warning : capture being closed, so interrupt the shutdown process ! \n"); - rk616_codec_work_capture_type = RK616_CODEC_WORK_NULL; - } + cancel_delayed_work_sync(&capture_delayed_work); + if (rk616_codec_work_capture_type == RK616_CODEC_WORK_NULL) { + rk616_codec_power_up(RK616_CODEC_CAPTURE); } else { - DBG("Warning : capture being opened, so return ! \n"); + DBG("Capture is being closed, so interrupt work process ! \n"); + rk616_codec_work_capture_type = RK616_CODEC_WORK_NULL; } } } @@ -2187,19 +2333,18 @@ static void rk616_shutdown(struct snd_pcm_substream *substream, DBG("%s : substream->stream : %s \n", __func__, playback ? "PLAYBACK":"CAPTURE"); - if (playback) + if (playback) { rk616->playback_active--; - else - rk616->capture_active--; - if (playback) { if (rk616->playback_active <= 0) { if (is_codec_playback_running == true) rk616_codec_power_down(RK616_CODEC_PLAYBACK); else - DBG(" Warning : playback has been closed, so return !\n"); + DBG("Playback has been closed, so return !\n"); } } else {//capture + rk616->capture_active--; + if (rk616->capture_active <= 0) { if ((rk616_codec_work_capture_type != RK616_CODEC_WORK_POWER_DOWN) && (is_codec_capture_running == true)) { @@ -2209,18 +2354,13 @@ static void rk616_shutdown(struct snd_pcm_substream *substream, * so power up codec. * If rk616_codec_work_capture_type is RK616_CODEC_WORK_POWER_UP it means * codec haven't be powered up, so we don't need to power down codec. - * If is playback call power down, power down immediatly, because audioflinger + * If it is playback call power down, power down immediatly, because audioflinger * already has delay 3s. */ - if (rk616_codec_work_capture_type == RK616_CODEC_WORK_NULL) { - rk616_codec_work_capture_type = RK616_CODEC_WORK_POWER_DOWN; - queue_delayed_work(rk616_codec_workq, &capture_delayed_work,msecs_to_jiffies(3000)); - } else { - rk616_codec_work_capture_type = RK616_CODEC_WORK_NULL; - DBG(" Warning : capture being opened, so interrupt the open process ! \n"); - } + rk616_codec_work_capture_type = RK616_CODEC_WORK_POWER_DOWN; + queue_delayed_work(rk616_codec_workq, &capture_delayed_work,msecs_to_jiffies(3000)); } else { - DBG(" Warning : capture has been closed or it being closed, so return !\n"); + DBG("Capture is already going to be closed, so return!\n"); } } } @@ -2321,11 +2461,6 @@ static int rk616_resume(struct snd_soc_codec *codec) return 0; } -static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf) -{ - return sprintf(buf, "Headset\n"); -} - static int rk616_probe(struct snd_soc_codec *codec) { struct rk616_codec_priv *rk616; @@ -2396,10 +2531,28 @@ static int rk616_probe(struct snd_soc_codec *codec) rk616_reset(codec); - if (!rk616_for_mid) - { + if (rk616_for_mid) { + if (rk616_mfd && rk616_mfd->pdata && rk616_mfd->pdata->mic_sel_gpio) { + gpio_request(rk616_mfd->pdata->mic_sel_gpio, NULL); + gpio_direction_output(rk616_mfd->pdata->mic_sel_gpio, GPIO_LOW); + rk616->mic_sel_gpio = rk616_mfd->pdata->mic_sel_gpio; + } else { + printk("%s : rk616 or pdata or mic_sel_gpio is NULL!\n", __func__); + rk616->mic_sel_gpio = INVALID_GPIO; + } + snd_soc_add_controls(codec, rk616_snd_path_controls, + ARRAY_SIZE(rk616_snd_path_controls)); + } else { codec->dapm.bias_level = SND_SOC_BIAS_OFF; rk616_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + snd_soc_add_controls(codec, rk616_snd_controls, + ARRAY_SIZE(rk616_snd_controls)); + snd_soc_dapm_new_controls(&codec->dapm, rk616_dapm_widgets, + ARRAY_SIZE(rk616_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, rk616_dapm_routes, + ARRAY_SIZE(rk616_dapm_routes)); + } #ifdef CONFIG_MACH_RK_FAC @@ -2465,12 +2618,6 @@ static struct snd_soc_codec_driver soc_codec_dev_rk616 = { .reg_cache_default = rk616_reg_defaults, .volatile_register = rk616_volatile_register, .readable_register = rk616_codec_register, - .controls = rk616_snd_controls, - .num_controls = ARRAY_SIZE(rk616_snd_controls), - .dapm_widgets = rk616_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rk616_dapm_widgets), - .dapm_routes = rk616_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rk616_dapm_routes), }; static __devinit int rk616_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/rk616_codec.h b/sound/soc/codecs/rk616_codec.h index a541fd63c77d..1b45e850055b 100755 --- a/sound/soc/codecs/rk616_codec.h +++ b/sound/soc/codecs/rk616_codec.h @@ -779,6 +779,7 @@ struct rk616_init_bit_typ { unsigned int init_bit; }; +bool rk616_get_for_mid(void); bool get_hdmi_state(void); #endif //__RK616_CODEC_H__ diff --git a/sound/soc/rk29/rk30_i2s.c b/sound/soc/rk29/rk30_i2s.c index 73338e28ea2e..999413745361 100755 --- a/sound/soc/rk29/rk30_i2s.c +++ b/sound/soc/rk29/rk30_i2s.c @@ -89,7 +89,7 @@ static struct rk29_i2s_info rk29_i2s[MAX_I2S]; struct snd_soc_dai_driver rk29_i2s_dai[MAX_I2S]; EXPORT_SYMBOL_GPL(rk29_i2s_dai); -#ifdef CONFIG_RK_HDMI +#if defined (CONFIG_RK_HDMI) && defined (CONFIG_SND_RK_SOC_HDMI_I2S) extern int hdmi_get_hotplug(void); #endif /* @@ -125,7 +125,7 @@ static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on) opr &= ~I2S_TRAN_DMA_ENABLE; writel(opr, &(pheadi2s->I2S_DMACR)); if(!i2s->i2s_tx_status && !i2s->i2s_rx_status//sync stop i2s rx tx lcrk -#ifdef CONFIG_RK_HDMI +#if defined (CONFIG_RK_HDMI) && defined (CONFIG_SND_RK_SOC_HDMI_I2S) && hdmi_get_hotplug() == 0 //HDMI_HPD_REMOVED #endif ) @@ -175,7 +175,7 @@ static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on) opr &= ~I2S_RECE_DMA_ENABLE; writel(opr, &(pheadi2s->I2S_DMACR)); if(!i2s->i2s_tx_status && !i2s->i2s_rx_status //sync stop i2s rx tx lcrk -#ifdef CONFIG_RK_HDMI +#if defined (CONFIG_RK_HDMI) && defined (CONFIG_SND_RK_SOC_HDMI_I2S) && hdmi_get_hotplug() == 0 //HDMI_HPD_REMOVED #endif ) @@ -418,7 +418,7 @@ int rockchip_i2s_resume(struct snd_soc_dai *cpu_dai) #endif #ifdef ANDROID_REC -#define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) #else #define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ diff --git a/sound/soc/rk29/rk_rk616.c b/sound/soc/rk29/rk_rk616.c index eb69177cdd13..b595d6b1a0aa 100755 --- a/sound/soc/rk29/rk_rk616.c +++ b/sound/soc/rk29/rk_rk616.c @@ -67,6 +67,11 @@ static int rk616_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; + // if is for mid that using tiny alsa, + // it don't need this controls and route, so return. + if (rk616_get_for_mid()) + return 0; + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); snd_soc_add_controls(codec, rk_controls, @@ -94,7 +99,7 @@ static int rk_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - unsigned int pll_out = 0; + unsigned int pll_out = 0, div = 4; int ret; DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); @@ -126,7 +131,6 @@ static int rk_hifi_hw_params(struct snd_pcm_substream *substream, return ret; switch(params_rate(params)) { - case 8000: case 16000: case 24000: case 32000: @@ -138,22 +142,26 @@ static int rk_hifi_hw_params(struct snd_pcm_substream *substream, case 44100: pll_out = 11289600; break; + case 8000: + pll_out = 12000000; + div = 6; + break; default: DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); return -EINVAL; break; } + DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + #if defined(CONFIG_RK616_USE_MCLK_12M) - /* MCLK must be 12M when HDMI is in */ + /* MCLK must be 12M when RK616 HDMI is in */ if (get_hdmi_state() && pll_out != 12000000) { - DBG("%s : HDMI is in, don't set sys clk\n",__FUNCTION__); - return 0; + DBG("%s : HDMI is in, don't set sys clk %u\n",__FUNCTION__, pll_out); + goto __setdiv; } #endif - DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); - /*Set the system clk for codec*/ ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) { @@ -161,11 +169,12 @@ static int rk_hifi_hw_params(struct snd_pcm_substream *substream, return ret; } +__setdiv: snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); - snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1); - snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out / div)/params_rate(params)-1); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div - 1); - DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params)); + DBG("Enter:%s, %d, pll_out/div/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/div)/params_rate(params)); return 0; } @@ -204,11 +213,11 @@ static int rk_voice_hw_params(struct snd_pcm_substream *substream, break; } - /* MCLK must be 12M when HDMI is in */ + /* MCLK must be 12M when RK616 HDMI is in */ #if defined(CONFIG_RK616_USE_MCLK_12M) if (get_hdmi_state() && pll_out != 12000000) { - DBG("%s : HDMI is in, don't set sys clk\n",__FUNCTION__); - return 0; + DBG("%s : HDMI is in, set mclk to 12Mn",__FUNCTION__); + pll_out = 12000000; } #endif -- 2.34.1