| .. | .. |
|---|
| 67 | 67 | struct regmap *regmap; |
|---|
| 68 | 68 | struct rk808 *rk817; |
|---|
| 69 | 69 | struct clk *mclk; |
|---|
| 70 | + struct mutex clk_lock; |
|---|
| 70 | 71 | |
|---|
| 72 | + unsigned int clk_capture; |
|---|
| 73 | + unsigned int clk_playback; |
|---|
| 71 | 74 | unsigned int stereo_sysclk; |
|---|
| 72 | 75 | unsigned int rate; |
|---|
| 73 | 76 | |
|---|
| .. | .. |
|---|
| 79 | 82 | bool pdmdata_out_enable; |
|---|
| 80 | 83 | bool use_ext_amplifier; |
|---|
| 81 | 84 | bool adc_for_loopback; |
|---|
| 85 | + bool resume_path; |
|---|
| 82 | 86 | |
|---|
| 83 | 87 | bool out_l2spk_r2hp; |
|---|
| 84 | 88 | long int playback_path; |
|---|
| .. | .. |
|---|
| 506 | 510 | static const char * const rk817_capture_path_mode[] = { |
|---|
| 507 | 511 | "MIC OFF", "Main Mic", "Hands Free Mic", "BT Sco Mic"}; |
|---|
| 508 | 512 | |
|---|
| 509 | | -static const char * const rk817_call_path_mode[] = { |
|---|
| 510 | | - "OFF", "RCV", "SPK", "HP", "HP_NO_MIC", "BT"}; /* 0-5 */ |
|---|
| 511 | | - |
|---|
| 512 | | -static const char * const rk817_modem_input_mode[] = {"OFF", "ON"}; |
|---|
| 513 | +static const char * const rk817_binary_mode[] = {"OFF", "ON"}; |
|---|
| 513 | 514 | |
|---|
| 514 | 515 | static SOC_ENUM_SINGLE_DECL(rk817_playback_path_type, |
|---|
| 515 | 516 | 0, 0, rk817_playback_path_mode); |
|---|
| .. | .. |
|---|
| 517 | 518 | static SOC_ENUM_SINGLE_DECL(rk817_capture_path_type, |
|---|
| 518 | 519 | 0, 0, rk817_capture_path_mode); |
|---|
| 519 | 520 | |
|---|
| 520 | | -static SOC_ENUM_SINGLE_DECL(rk817_call_path_type, |
|---|
| 521 | | - 0, 0, rk817_call_path_mode); |
|---|
| 522 | | - |
|---|
| 523 | | -static SOC_ENUM_SINGLE_DECL(rk817_modem_input_type, |
|---|
| 524 | | - 0, 0, rk817_modem_input_mode); |
|---|
| 521 | +static SOC_ENUM_SINGLE_DECL(rk817_resume_path_type, |
|---|
| 522 | + 0, 0, rk817_binary_mode); |
|---|
| 525 | 523 | |
|---|
| 526 | 524 | static int rk817_playback_path_config(struct snd_soc_component *component, |
|---|
| 527 | 525 | long pre_path, long target_path) |
|---|
| .. | .. |
|---|
| 533 | 531 | DBG("%s : set playback_path %ld, pre_path %ld\n", |
|---|
| 534 | 532 | __func__, rk817->playback_path, pre_path); |
|---|
| 535 | 533 | |
|---|
| 536 | | - if (rk817->playback_path != OFF) |
|---|
| 537 | | - clk_prepare_enable(rk817->mclk); |
|---|
| 538 | | - else |
|---|
| 539 | | - clk_disable_unprepare(rk817->mclk); |
|---|
| 534 | + mutex_lock(&rk817->clk_lock); |
|---|
| 535 | + if (rk817->playback_path != OFF) { |
|---|
| 536 | + if (rk817->clk_playback == 0) { |
|---|
| 537 | + clk_prepare_enable(rk817->mclk); |
|---|
| 538 | + rk817->clk_playback++; |
|---|
| 539 | + } |
|---|
| 540 | + } else { |
|---|
| 541 | + if (rk817->clk_playback > 0) { |
|---|
| 542 | + clk_disable_unprepare(rk817->mclk); |
|---|
| 543 | + rk817->clk_playback--; |
|---|
| 544 | + } |
|---|
| 545 | + } |
|---|
| 546 | + mutex_unlock(&rk817->clk_lock); |
|---|
| 540 | 547 | |
|---|
| 541 | 548 | switch (rk817->playback_path) { |
|---|
| 542 | 549 | case OFF: |
|---|
| .. | .. |
|---|
| 720 | 727 | DBG("%s : set capture_path %ld, pre_path %ld\n", __func__, |
|---|
| 721 | 728 | rk817->capture_path, pre_path); |
|---|
| 722 | 729 | |
|---|
| 723 | | - if (rk817->capture_path != MIC_OFF) |
|---|
| 724 | | - clk_prepare_enable(rk817->mclk); |
|---|
| 725 | | - else |
|---|
| 726 | | - clk_disable_unprepare(rk817->mclk); |
|---|
| 730 | + mutex_lock(&rk817->clk_lock); |
|---|
| 731 | + if (rk817->capture_path != MIC_OFF) { |
|---|
| 732 | + if (rk817->clk_capture == 0) { |
|---|
| 733 | + clk_prepare_enable(rk817->mclk); |
|---|
| 734 | + rk817->clk_capture++; |
|---|
| 735 | + } |
|---|
| 736 | + } else { |
|---|
| 737 | + if (rk817->clk_capture > 0) { |
|---|
| 738 | + clk_disable_unprepare(rk817->mclk); |
|---|
| 739 | + rk817->clk_capture--; |
|---|
| 740 | + } |
|---|
| 741 | + } |
|---|
| 742 | + mutex_unlock(&rk817->clk_lock); |
|---|
| 727 | 743 | |
|---|
| 728 | 744 | switch (rk817->capture_path) { |
|---|
| 729 | 745 | case MIC_OFF: |
|---|
| .. | .. |
|---|
| 842 | 858 | ucontrol->value.integer.value[0]); |
|---|
| 843 | 859 | } |
|---|
| 844 | 860 | |
|---|
| 861 | +static int rk817_resume_path_get(struct snd_kcontrol *kcontrol, |
|---|
| 862 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 863 | +{ |
|---|
| 864 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 865 | + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); |
|---|
| 866 | + |
|---|
| 867 | + DBG("%s : resume_path %ld\n", __func__, rk817->resume_path); |
|---|
| 868 | + |
|---|
| 869 | + ucontrol->value.integer.value[0] = rk817->resume_path; |
|---|
| 870 | + |
|---|
| 871 | + return 0; |
|---|
| 872 | +} |
|---|
| 873 | + |
|---|
| 874 | +static int rk817_resume_path_put(struct snd_kcontrol *kcontrol, |
|---|
| 875 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 876 | +{ |
|---|
| 877 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 878 | + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); |
|---|
| 879 | + |
|---|
| 880 | + rk817->resume_path = ucontrol->value.integer.value[0]; |
|---|
| 881 | + |
|---|
| 882 | + return 0; |
|---|
| 883 | +} |
|---|
| 884 | + |
|---|
| 845 | 885 | static struct snd_kcontrol_new rk817_snd_path_controls[] = { |
|---|
| 846 | 886 | SOC_ENUM_EXT("Playback Path", rk817_playback_path_type, |
|---|
| 847 | 887 | rk817_playback_path_get, rk817_playback_path_put), |
|---|
| 848 | 888 | |
|---|
| 849 | 889 | SOC_ENUM_EXT("Capture MIC Path", rk817_capture_path_type, |
|---|
| 850 | 890 | rk817_capture_path_get, rk817_capture_path_put), |
|---|
| 891 | + |
|---|
| 892 | + SOC_ENUM_EXT("Resume Path", rk817_resume_path_type, |
|---|
| 893 | + rk817_resume_path_get, rk817_resume_path_put), |
|---|
| 851 | 894 | }; |
|---|
| 852 | 895 | |
|---|
| 853 | 896 | static int rk817_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
|---|
| .. | .. |
|---|
| 892 | 935 | struct snd_pcm_hw_params *params, |
|---|
| 893 | 936 | struct snd_soc_dai *dai) |
|---|
| 894 | 937 | { |
|---|
| 895 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
|---|
| 896 | | - struct snd_soc_component *component = rtd->codec_dai->component; |
|---|
| 938 | + struct snd_soc_component *component = dai->component; |
|---|
| 897 | 939 | struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); |
|---|
| 898 | 940 | unsigned int rate = params_rate(params); |
|---|
| 899 | 941 | unsigned char apll_cfg3_val; |
|---|
| .. | .. |
|---|
| 946 | 988 | * is before playback/capture_path_put, therefore, we need to configure |
|---|
| 947 | 989 | * APLL_CFG3/DTOP_DIGEN_CLKE/DDAC_SR_LMT0 for different sample rates. |
|---|
| 948 | 990 | */ |
|---|
| 949 | | - snd_soc_component_write(component, RK817_CODEC_APLL_CFG3, apll_cfg3_val); |
|---|
| 950 | | - /* The 0x00 contains ADC_DIG_CLK_DIS and DAC_DIG_CLK_DIS */ |
|---|
| 951 | | - snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, |
|---|
| 952 | | - dtop_digen_clke, 0x00); |
|---|
| 953 | | - snd_soc_component_update_bits(component, RK817_CODEC_DDAC_SR_LMT0, |
|---|
| 954 | | - DACSRT_MASK, dtop_digen_sr_lmt0); |
|---|
| 955 | | - snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, |
|---|
| 956 | | - dtop_digen_clke, dtop_digen_clke); |
|---|
| 991 | + if (!((substream->stream == SNDRV_PCM_STREAM_CAPTURE) && rk817->pdmdata_out_enable)) { |
|---|
| 992 | + snd_soc_component_write(component, RK817_CODEC_APLL_CFG3, apll_cfg3_val); |
|---|
| 993 | + /* The 0x00 contains ADC_DIG_CLK_DIS and DAC_DIG_CLK_DIS */ |
|---|
| 994 | + snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, |
|---|
| 995 | + dtop_digen_clke, 0x00); |
|---|
| 996 | + snd_soc_component_update_bits(component, RK817_CODEC_DDAC_SR_LMT0, |
|---|
| 997 | + DACSRT_MASK, dtop_digen_sr_lmt0); |
|---|
| 998 | + snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, |
|---|
| 999 | + dtop_digen_clke, dtop_digen_clke); |
|---|
| 1000 | + snd_soc_component_update_bits(component, RK817_CODEC_APLL_CFG5, |
|---|
| 1001 | + PLL_PW_DOWN, PLL_PW_DOWN); |
|---|
| 1002 | + usleep_range(50, 60); |
|---|
| 1003 | + snd_soc_component_update_bits(component, RK817_CODEC_APLL_CFG5, |
|---|
| 1004 | + PLL_PW_DOWN, PLL_PW_UP); |
|---|
| 1005 | + usleep_range(500, 600); |
|---|
| 1006 | + } |
|---|
| 957 | 1007 | |
|---|
| 958 | 1008 | switch (params_format(params)) { |
|---|
| 959 | 1009 | case SNDRV_PCM_FORMAT_S16_LE: |
|---|
| .. | .. |
|---|
| 1144 | 1194 | |
|---|
| 1145 | 1195 | static int rk817_resume(struct snd_soc_component *component) |
|---|
| 1146 | 1196 | { |
|---|
| 1197 | + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); |
|---|
| 1198 | + |
|---|
| 1199 | + if (rk817->resume_path) { |
|---|
| 1200 | + if (rk817->capture_path != MIC_OFF) |
|---|
| 1201 | + rk817_capture_path_config(component, OFF, rk817->capture_path); |
|---|
| 1202 | + if (rk817->playback_path != OFF) |
|---|
| 1203 | + rk817_playback_path_config(component, OFF, rk817->playback_path); |
|---|
| 1204 | + } |
|---|
| 1205 | + |
|---|
| 1147 | 1206 | return 0; |
|---|
| 1148 | 1207 | } |
|---|
| 1149 | 1208 | |
|---|
| .. | .. |
|---|
| 1173 | 1232 | clk_prepare_enable(rk817->mclk); |
|---|
| 1174 | 1233 | rk817_reset(component); |
|---|
| 1175 | 1234 | clk_disable_unprepare(rk817->mclk); |
|---|
| 1235 | + mutex_init(&rk817->clk_lock); |
|---|
| 1236 | + rk817->clk_capture = 0; |
|---|
| 1237 | + rk817->clk_playback = 0; |
|---|
| 1176 | 1238 | |
|---|
| 1177 | 1239 | snd_soc_add_component_controls(component, rk817_snd_path_controls, |
|---|
| 1178 | 1240 | ARRAY_SIZE(rk817_snd_path_controls)); |
|---|
| .. | .. |
|---|
| 1193 | 1255 | |
|---|
| 1194 | 1256 | rk817_codec_power_down(component, RK817_CODEC_ALL); |
|---|
| 1195 | 1257 | snd_soc_component_exit_regmap(component); |
|---|
| 1258 | + mutex_destroy(&rk817->clk_lock); |
|---|
| 1196 | 1259 | mdelay(10); |
|---|
| 1197 | 1260 | |
|---|
| 1198 | 1261 | } |
|---|