| .. | .. |
|---|
| 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: |
|---|
| .. | .. |
|---|
| 976 | 1026 | return 0; |
|---|
| 977 | 1027 | } |
|---|
| 978 | 1028 | |
|---|
| 979 | | -static int rk817_digital_mute(struct snd_soc_dai *dai, int mute) |
|---|
| 1029 | +static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) |
|---|
| 980 | 1030 | { |
|---|
| 981 | 1031 | struct snd_soc_component *component = dai->component; |
|---|
| 982 | 1032 | struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); |
|---|
| .. | .. |
|---|
| 1090 | 1140 | .hw_params = rk817_hw_params, |
|---|
| 1091 | 1141 | .set_fmt = rk817_set_dai_fmt, |
|---|
| 1092 | 1142 | .set_sysclk = rk817_set_dai_sysclk, |
|---|
| 1093 | | - .digital_mute = rk817_digital_mute, |
|---|
| 1143 | + .mute_stream = rk817_digital_mute, |
|---|
| 1094 | 1144 | .shutdown = rk817_codec_shutdown, |
|---|
| 1145 | + .no_capture_mute = 1, |
|---|
| 1095 | 1146 | }; |
|---|
| 1096 | 1147 | |
|---|
| 1097 | 1148 | static struct snd_soc_dai_driver rk817_dai[] = { |
|---|
| .. | .. |
|---|
| 1144 | 1195 | |
|---|
| 1145 | 1196 | static int rk817_resume(struct snd_soc_component *component) |
|---|
| 1146 | 1197 | { |
|---|
| 1198 | + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); |
|---|
| 1199 | + |
|---|
| 1200 | + if (rk817->resume_path) { |
|---|
| 1201 | + if (rk817->capture_path != MIC_OFF) |
|---|
| 1202 | + rk817_capture_path_config(component, OFF, rk817->capture_path); |
|---|
| 1203 | + if (rk817->playback_path != OFF) |
|---|
| 1204 | + rk817_playback_path_config(component, OFF, rk817->playback_path); |
|---|
| 1205 | + } |
|---|
| 1206 | + |
|---|
| 1147 | 1207 | return 0; |
|---|
| 1148 | 1208 | } |
|---|
| 1149 | 1209 | |
|---|
| .. | .. |
|---|
| 1165 | 1225 | rk817->playback_path = OFF; |
|---|
| 1166 | 1226 | rk817->capture_path = MIC_OFF; |
|---|
| 1167 | 1227 | |
|---|
| 1168 | | - chip_name = snd_soc_component_read32(component, RK817_PMIC_CHIP_NAME); |
|---|
| 1169 | | - chip_ver = snd_soc_component_read32(component, RK817_PMIC_CHIP_VER); |
|---|
| 1228 | + chip_name = snd_soc_component_read(component, RK817_PMIC_CHIP_NAME); |
|---|
| 1229 | + chip_ver = snd_soc_component_read(component, RK817_PMIC_CHIP_VER); |
|---|
| 1170 | 1230 | rk817->chip_ver = (chip_ver & 0x0f); |
|---|
| 1171 | 1231 | dev_info(component->dev, "%s: chip_name:0x%x, chip_ver:0x%x\n", __func__, chip_name, chip_ver); |
|---|
| 1172 | 1232 | |
|---|
| 1173 | 1233 | clk_prepare_enable(rk817->mclk); |
|---|
| 1174 | 1234 | rk817_reset(component); |
|---|
| 1175 | 1235 | clk_disable_unprepare(rk817->mclk); |
|---|
| 1236 | + mutex_init(&rk817->clk_lock); |
|---|
| 1237 | + rk817->clk_capture = 0; |
|---|
| 1238 | + rk817->clk_playback = 0; |
|---|
| 1176 | 1239 | |
|---|
| 1177 | 1240 | snd_soc_add_component_controls(component, rk817_snd_path_controls, |
|---|
| 1178 | 1241 | ARRAY_SIZE(rk817_snd_path_controls)); |
|---|
| .. | .. |
|---|
| 1193 | 1256 | |
|---|
| 1194 | 1257 | rk817_codec_power_down(component, RK817_CODEC_ALL); |
|---|
| 1195 | 1258 | snd_soc_component_exit_regmap(component); |
|---|
| 1259 | + mutex_destroy(&rk817->clk_lock); |
|---|
| 1196 | 1260 | mdelay(10); |
|---|
| 1197 | 1261 | |
|---|
| 1198 | 1262 | } |
|---|