@@ -105,6 +105,16 @@ enum {
105105 PATH_BUSY ,
106106};
107107
108+ enum {
109+ PM_NORMAL = 0 ,
110+ PM_LLP_DOWN , /* light low power down */
111+ PM_LLP_UP ,
112+ PM_DLP_DOWN , /* deep low power down */
113+ PM_DLP_UP ,
114+ PM_DLP_DOWN2 ,
115+ PM_DLP_UP2 ,
116+ };
117+
108118struct rk3308_codec_priv {
109119 const struct device * plat_dev ;
110120 struct device dev ;
@@ -140,12 +150,15 @@ struct rk3308_codec_priv {
140150 int adc_path_state ;
141151 int dac_path_state ;
142152
153+ int pm_state ;
154+
143155 /* Only hpout do fade-in and fade-out */
144156 unsigned int hpout_l_dgain ;
145157 unsigned int hpout_r_dgain ;
146158
147159 bool enable_all_adcs ;
148160 bool hp_plugged ;
161+ bool no_deep_low_power ;
149162 struct delayed_work hpdet_work ;
150163 struct delayed_work loopback_work ;
151164
@@ -1555,9 +1568,8 @@ static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308)
15551568 return 0 ;
15561569}
15571570
1558- static int rk3308_codec_power_on (struct snd_soc_codec * codec )
1571+ static int rk3308_codec_power_on (struct rk3308_codec_priv * rk3308 )
15591572{
1560- struct rk3308_codec_priv * rk3308 = snd_soc_codec_get_drvdata (codec );
15611573 unsigned int v ;
15621574
15631575 /* 1. Supply the power of digital part and reset the Audio Codec */
@@ -1623,9 +1635,8 @@ static int rk3308_codec_power_on(struct snd_soc_codec *codec)
16231635 return 0 ;
16241636}
16251637
1626- static int rk3308_codec_power_off (struct snd_soc_codec * codec )
1638+ static int rk3308_codec_power_off (struct rk3308_codec_priv * rk3308 )
16271639{
1628- struct rk3308_codec_priv * rk3308 = snd_soc_codec_get_drvdata (codec );
16291640 unsigned int v ;
16301641
16311642 /*
@@ -2434,6 +2445,36 @@ static int rk3308_codec_open_capture(struct rk3308_codec_priv *rk3308)
24342445 return 0 ;
24352446}
24362447
2448+ static void rk3308_codec_adc_mclk_disable (struct rk3308_codec_priv * rk3308 )
2449+ {
2450+ regmap_update_bits (rk3308 -> regmap , RK3308_GLB_CON ,
2451+ RK3308_ADC_MCLK_MSK ,
2452+ RK3308_ADC_MCLK_DIS );
2453+ }
2454+
2455+ static void rk3308_codec_adc_mclk_enable (struct rk3308_codec_priv * rk3308 )
2456+ {
2457+ regmap_update_bits (rk3308 -> regmap , RK3308_GLB_CON ,
2458+ RK3308_ADC_MCLK_MSK ,
2459+ RK3308_ADC_MCLK_EN );
2460+ udelay (20 );
2461+ }
2462+
2463+ static void rk3308_codec_dac_mclk_disable (struct rk3308_codec_priv * rk3308 )
2464+ {
2465+ regmap_update_bits (rk3308 -> regmap , RK3308_GLB_CON ,
2466+ RK3308_DAC_MCLK_MSK ,
2467+ RK3308_DAC_MCLK_DIS );
2468+ }
2469+
2470+ static void rk3308_codec_dac_mclk_enable (struct rk3308_codec_priv * rk3308 )
2471+ {
2472+ regmap_update_bits (rk3308 -> regmap , RK3308_GLB_CON ,
2473+ RK3308_DAC_MCLK_MSK ,
2474+ RK3308_DAC_MCLK_EN );
2475+ udelay (20 );
2476+ }
2477+
24372478static int rk3308_codec_close_capture (struct rk3308_codec_priv * rk3308 )
24382479{
24392480 rk3308_codec_alc_disable (rk3308 , ADC_TYPE_NORMAL );
@@ -2458,6 +2499,95 @@ static int rk3308_codec_close_playback(struct rk3308_codec_priv *rk3308)
24582499 return 0 ;
24592500}
24602501
2502+ static int rk3308_codec_llp_down (struct rk3308_codec_priv * rk3308 )
2503+ {
2504+ rk3308_codec_adc_mclk_disable (rk3308 );
2505+ rk3308_codec_dac_mclk_disable (rk3308 );
2506+
2507+ return 0 ;
2508+ }
2509+
2510+ static int rk3308_codec_llp_up (struct rk3308_codec_priv * rk3308 )
2511+ {
2512+ rk3308_codec_adc_mclk_enable (rk3308 );
2513+ rk3308_codec_dac_mclk_enable (rk3308 );
2514+
2515+ return 0 ;
2516+ }
2517+
2518+ static int rk3308_codec_dlp_down (struct rk3308_codec_priv * rk3308 )
2519+ {
2520+ rk3308_codec_micbias_disable (rk3308 );
2521+ rk3308_codec_power_off (rk3308 );
2522+
2523+ return 0 ;
2524+ }
2525+
2526+ static int rk3308_codec_dlp_up (struct rk3308_codec_priv * rk3308 )
2527+ {
2528+ rk3308_codec_power_on (rk3308 );
2529+ rk3308_codec_micbias_enable (rk3308 , RK3308_ADC_MICBIAS_VOLT_0_85 );
2530+
2531+ return 0 ;
2532+ }
2533+
2534+ /* Just used for debug and trace power state */
2535+ static void rk3308_codec_set_pm_state (struct rk3308_codec_priv * rk3308 ,
2536+ int pm_state )
2537+ {
2538+ int ret ;
2539+
2540+ switch (pm_state ) {
2541+ case PM_LLP_DOWN :
2542+ rk3308_codec_llp_down (rk3308 );
2543+ break ;
2544+ case PM_LLP_UP :
2545+ rk3308_codec_llp_up (rk3308 );
2546+ break ;
2547+ case PM_DLP_DOWN :
2548+ rk3308_codec_dlp_down (rk3308 );
2549+ break ;
2550+ case PM_DLP_UP :
2551+ rk3308_codec_dlp_up (rk3308 );
2552+ break ;
2553+ case PM_DLP_DOWN2 :
2554+ clk_disable_unprepare (rk3308 -> mclk_rx );
2555+ clk_disable_unprepare (rk3308 -> mclk_tx );
2556+ clk_disable_unprepare (rk3308 -> pclk );
2557+ break ;
2558+ case PM_DLP_UP2 :
2559+ ret = clk_prepare_enable (rk3308 -> pclk );
2560+ if (ret < 0 ) {
2561+ dev_err (rk3308 -> plat_dev ,
2562+ "Failed to enable acodec pclk: %d\n" , ret );
2563+ goto err ;
2564+ }
2565+
2566+ ret = clk_prepare_enable (rk3308 -> mclk_rx );
2567+ if (ret < 0 ) {
2568+ dev_err (rk3308 -> plat_dev ,
2569+ "Failed to enable i2s mclk_rx: %d\n" , ret );
2570+ goto err ;
2571+ }
2572+
2573+ ret = clk_prepare_enable (rk3308 -> mclk_tx );
2574+ if (ret < 0 ) {
2575+ dev_err (rk3308 -> plat_dev ,
2576+ "Failed to enable i2s mclk_tx: %d\n" , ret );
2577+ goto err ;
2578+ }
2579+ break ;
2580+ default :
2581+ dev_err (rk3308 -> plat_dev , "Invalid pm_state: %d\n" , pm_state );
2582+ goto err ;
2583+ }
2584+
2585+ rk3308 -> pm_state = pm_state ;
2586+
2587+ err :
2588+ return ;
2589+ }
2590+
24612591static int rk3308_hw_params (struct snd_pcm_substream * substream ,
24622592 struct snd_pcm_hw_params * params ,
24632593 struct snd_soc_dai * dai )
@@ -2468,9 +2598,11 @@ static int rk3308_hw_params(struct snd_pcm_substream *substream,
24682598
24692599 if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK ) {
24702600 /* DAC only supports 2 channels */
2601+ rk3308_codec_dac_mclk_enable (rk3308 );
24712602 rk3308_codec_open_playback (rk3308 );
24722603 rk3308_codec_dac_dig_config (rk3308 , params );
24732604 } else {
2605+ rk3308_codec_adc_mclk_enable (rk3308 );
24742606 ret = rk3308_codec_update_adc_grps (rk3308 , params );
24752607 if (ret < 0 )
24762608 return ret ;
@@ -2510,10 +2642,13 @@ static void rk3308_pcm_shutdown(struct snd_pcm_substream *substream,
25102642 struct snd_soc_codec * codec = dai -> codec ;
25112643 struct rk3308_codec_priv * rk3308 = snd_soc_codec_get_drvdata (codec );
25122644
2513- if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK )
2645+ if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK ) {
25142646 rk3308_codec_close_playback (rk3308 );
2515- else
2647+ rk3308_codec_dac_mclk_disable (rk3308 );
2648+ } else {
25162649 rk3308_codec_close_capture (rk3308 );
2650+ rk3308_codec_adc_mclk_disable (rk3308 );
2651+ }
25172652
25182653 regcache_cache_only (rk3308 -> regmap , false);
25192654 regcache_sync (rk3308 -> regmap );
@@ -2557,16 +2692,54 @@ static struct snd_soc_dai_driver rk3308_dai[] = {
25572692
25582693static int rk3308_suspend (struct snd_soc_codec * codec )
25592694{
2560- rk3308_set_bias_level (codec , SND_SOC_BIAS_OFF );
2695+ struct rk3308_codec_priv * rk3308 = snd_soc_codec_get_drvdata (codec );
25612696
2697+ if (rk3308 -> no_deep_low_power )
2698+ goto out ;
2699+
2700+ rk3308_codec_dlp_down (rk3308 );
2701+ clk_disable_unprepare (rk3308 -> mclk_rx );
2702+ clk_disable_unprepare (rk3308 -> mclk_tx );
2703+ clk_disable_unprepare (rk3308 -> pclk );
2704+
2705+ out :
2706+ rk3308_set_bias_level (codec , SND_SOC_BIAS_OFF );
25622707 return 0 ;
25632708}
25642709
25652710static int rk3308_resume (struct snd_soc_codec * codec )
25662711{
2567- rk3308_set_bias_level (codec , SND_SOC_BIAS_STANDBY );
2712+ struct rk3308_codec_priv * rk3308 = snd_soc_codec_get_drvdata (codec );
2713+ int ret = 0 ;
25682714
2569- return 0 ;
2715+ if (rk3308 -> no_deep_low_power )
2716+ goto out ;
2717+
2718+ ret = clk_prepare_enable (rk3308 -> pclk );
2719+ if (ret < 0 ) {
2720+ dev_err (rk3308 -> plat_dev ,
2721+ "Failed to enable acodec pclk: %d\n" , ret );
2722+ goto out ;
2723+ }
2724+
2725+ ret = clk_prepare_enable (rk3308 -> mclk_rx );
2726+ if (ret < 0 ) {
2727+ dev_err (rk3308 -> plat_dev ,
2728+ "Failed to enable i2s mclk_rx: %d\n" , ret );
2729+ goto out ;
2730+ }
2731+
2732+ ret = clk_prepare_enable (rk3308 -> mclk_tx );
2733+ if (ret < 0 ) {
2734+ dev_err (rk3308 -> plat_dev ,
2735+ "Failed to enable i2s mclk_tx: %d\n" , ret );
2736+ goto out ;
2737+ }
2738+
2739+ rk3308_codec_dlp_up (rk3308 );
2740+ out :
2741+ rk3308_set_bias_level (codec , SND_SOC_BIAS_STANDBY );
2742+ return ret ;
25702743}
25712744
25722745static int rk3308_codec_default_gains (struct rk3308_codec_priv * rk3308 )
@@ -2628,6 +2801,7 @@ static int rk3308_codec_prepare(struct rk3308_codec_priv *rk3308)
26282801 rk3308_codec_close_playback (rk3308 );
26292802 rk3308_codec_close_capture (rk3308 );
26302803 rk3308_codec_default_gains (rk3308 );
2804+ rk3308_codec_llp_down (rk3308 );
26312805
26322806 return 0 ;
26332807}
@@ -2640,7 +2814,7 @@ static int rk3308_probe(struct snd_soc_codec *codec)
26402814 rk3308_codec_set_dac_path_state (rk3308 , PATH_IDLE );
26412815
26422816 rk3308_codec_reset (codec );
2643- rk3308_codec_power_on (codec );
2817+ rk3308_codec_power_on (rk3308 );
26442818
26452819 /* From vendor recommend */
26462820 rk3308_codec_micbias_enable (rk3308 , RK3308_ADC_MICBIAS_VOLT_0_85 );
@@ -2661,8 +2835,8 @@ static int rk3308_remove(struct snd_soc_codec *codec)
26612835 rk3308_headphone_ctl (rk3308 , 0 );
26622836 rk3308_speaker_ctl (rk3308 , 0 );
26632837 rk3308_codec_headset_detect_disable (rk3308 );
2664- rk3308_codec_power_off (codec );
26652838 rk3308_codec_micbias_disable (rk3308 );
2839+ rk3308_codec_power_off (rk3308 );
26662840
26672841 rk3308_codec_set_dac_path_state (rk3308 , PATH_IDLE );
26682842
@@ -2792,6 +2966,38 @@ static const struct regmap_config rk3308_codec_regmap_config = {
27922966 .cache_type = REGCACHE_FLAT ,
27932967};
27942968
2969+ static ssize_t pm_state_show (struct device * dev ,
2970+ struct device_attribute * attr ,
2971+ char * buf )
2972+ {
2973+ struct rk3308_codec_priv * rk3308 =
2974+ container_of (dev , struct rk3308_codec_priv , dev );
2975+
2976+ return sprintf (buf , "pm_state: %d\n" , rk3308 -> pm_state );
2977+ }
2978+
2979+ static ssize_t pm_state_store (struct device * dev ,
2980+ struct device_attribute * attr ,
2981+ const char * buf , size_t count )
2982+ {
2983+ struct rk3308_codec_priv * rk3308 =
2984+ container_of (dev , struct rk3308_codec_priv , dev );
2985+ unsigned long pm_state ;
2986+ int ret = kstrtoul (buf , 10 , & pm_state );
2987+
2988+ if (ret < 0 ) {
2989+ dev_err (dev , "Invalid pm_state: %ld, ret: %d\n" ,
2990+ pm_state , ret );
2991+ return - EINVAL ;
2992+ }
2993+
2994+ rk3308_codec_set_pm_state (rk3308 , pm_state );
2995+
2996+ dev_info (dev , "Store pm_state: %d\n" , rk3308 -> pm_state );
2997+
2998+ return count ;
2999+ }
3000+
27953001static ssize_t adc_grps_show (struct device * dev ,
27963002 struct device_attribute * attr ,
27973003 char * buf )
@@ -3068,6 +3274,7 @@ static const struct device_attribute acodec_attrs[] = {
30683274 __ATTR_RW (adc_zerocross ),
30693275 __ATTR_RW (dac_output ),
30703276 __ATTR_RW (enable_all_adcs ),
3277+ __ATTR_RW (pm_state ),
30713278};
30723279
30733280static void rk3308_codec_device_release (struct device * dev )
@@ -3297,6 +3504,9 @@ static int rk3308_platform_probe(struct platform_device *pdev)
32973504 rk3308 -> enable_all_adcs =
32983505 of_property_read_bool (np , "rockchip,enable-all-adcs" );
32993506
3507+ rk3308 -> no_deep_low_power =
3508+ of_property_read_bool (np , "rockchip,no-deep-low-power" );
3509+
33003510 rk3308 -> loopback_grp = LOOPBACK_NO_USE ;
33013511 ret = of_property_read_u32 (np , "rockchip,loopback-grp" ,
33023512 & rk3308 -> loopback_grp );
@@ -3355,6 +3565,7 @@ static int rk3308_platform_probe(struct platform_device *pdev)
33553565 rk3308 -> adc_grp0_using_linein = ADC_GRP0_MICIN ;
33563566 rk3308 -> dac_output = DAC_LINEOUT ;
33573567 rk3308 -> adc_zerocross = 1 ;
3568+ rk3308 -> pm_state = PM_NORMAL ;
33583569
33593570 platform_set_drvdata (pdev , rk3308 );
33603571
0 commit comments