3232#include <linux/timer.h>
3333#include <linux/workqueue.h>
3434#include <linux/sched.h>
35+ #include <linux/switch.h>
3536#include <sound/q6afe-v2.h>
3637#include <sound/pcm.h>
3738#include <sound/pcm_params.h>
3839#include <sound/soc.h>
3940#include <sound/soc-dapm.h>
4041#include <sound/tlv.h>
4142#include <sound/q6core.h>
43+ #include <sound/jack.h>
4244#include <soc/qcom/subsystem_notif.h>
4345#include "msm8x16-wcd.h"
4446#include "wcd-mbhc-v2.h"
@@ -132,6 +134,12 @@ static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
132134static const DECLARE_TLV_DB_SCALE (analog_gain , 0 , 25 , 1 ) ;
133135static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai [];
134136
137+ #ifdef CONFIG_MACH_WT88047
138+ static struct switch_dev accdet_data ;
139+ static int accdet_state ;
140+ static struct delayed_work analog_switch_enable ;
141+ #endif
142+
135143#define MSM8X16_WCD_ACQUIRE_LOCK (x ) \
136144 mutex_lock_nested(&x, SINGLE_DEPTH_NESTING);
137145
@@ -4110,11 +4118,64 @@ static int enable_ext_spk(struct snd_soc_dapm_widget *w, bool enable)
41104118}
41114119#endif
41124120
4121+ #ifdef CONFIG_MACH_WT88047
4122+ static void msm8x16_analog_switch_delayed_enable (struct work_struct * work )
4123+ {
4124+ int state = 0 ;
4125+
4126+ state = gpio_get_value (EXT_SPK_AMP_GPIO );
4127+ pr_debug ("%s: Enable analog switch, external PA state: %d\n" , __func__ , state );
4128+
4129+ if (!state )
4130+ gpio_direction_output (EXT_SPK_AMP_HEADSET_GPIO , true);
4131+ }
4132+
4133+ void msm8x16_wcd_codec_set_headset_state (u32 state )
4134+ {
4135+ switch_set_state ((struct switch_dev * )& accdet_data , state );
4136+ accdet_state = state ;
4137+ }
4138+
4139+ int msm8x16_wcd_codec_get_headset_state (void )
4140+ {
4141+ pr_debug ("%s accdet_state = %d\n" , __func__ , accdet_state );
4142+ return accdet_state ;
4143+ }
4144+
4145+ static void enable_ldo17 (int enable )
4146+ {
4147+ static struct regulator * reg_l17 ;
4148+ static int status ;
4149+ int rc = 0 ;
4150+
4151+ if (!!status == !!enable )
4152+ return ;
4153+
4154+ if (enable )
4155+ reg_l17 = regulator_get (0 , "8916_l17" );
4156+ if (reg_l17 != 0 ) {
4157+ if (enable ) {
4158+ regulator_set_optimum_mode (reg_l17 , 100 * 1000 );
4159+ regulator_set_voltage (reg_l17 , 2850000 , 2850000 );
4160+ rc = regulator_enable (reg_l17 );
4161+ } else {
4162+ rc = regulator_disable (reg_l17 );
4163+ regulator_put (reg_l17 );
4164+ reg_l17 = 0 ;
4165+ }
4166+ status = enable ;
4167+ }
4168+ }
4169+ #endif
4170+
41134171static int msm8x16_wcd_hph_pa_event (struct snd_soc_dapm_widget * w ,
41144172 struct snd_kcontrol * kcontrol , int event )
41154173{
41164174 struct snd_soc_codec * codec = w -> codec ;
41174175 struct msm8x16_wcd_priv * msm8x16_wcd = snd_soc_codec_get_drvdata (codec );
4176+ #ifdef CONFIG_MACH_WT88047
4177+ int state = 0 ;
4178+ #endif
41184179
41194180 dev_dbg (codec -> dev , "%s: %s event = %d\n" , __func__ , w -> name , event );
41204181
@@ -4131,6 +4192,10 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
41314192 break ;
41324193
41334194 case SND_SOC_DAPM_POST_PMU :
4195+ #ifdef CONFIG_MACH_WT88047
4196+ enable_ldo17 (1 );
4197+ state = msm8x16_wcd_codec_get_headset_state ();
4198+ #endif
41344199 usleep_range (7000 , 7100 );
41354200 if (w -> shift == 5 ) {
41364201 snd_soc_update_bits (codec ,
@@ -4146,6 +4211,13 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
41464211 enable_ext_spk (w , true);
41474212#endif
41484213 }
4214+ #ifdef CONFIG_MACH_WT88047
4215+ usleep_range (10000 , 10100 );
4216+ if (!state )
4217+ gpio_direction_output (EXT_SPK_AMP_HEADSET_GPIO , false);
4218+ else
4219+ schedule_delayed_work (& analog_switch_enable , msecs_to_jiffies (500 ));
4220+ #endif
41494221 break ;
41504222
41514223 case SND_SOC_DAPM_PRE_PMD :
@@ -4198,6 +4270,9 @@ static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
41984270 "%s: sleep 10 ms after %s PA disable.\n" , __func__ ,
41994271 w -> name );
42004272 usleep_range (10000 , 10100 );
4273+ #ifdef CONFIG_MACH_WT88047
4274+ enable_ldo17 (0 );
4275+ #endif
42014276 break ;
42024277 }
42034278 return 0 ;
@@ -5574,6 +5649,18 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
55745649 wcd_mbhc_init (& msm8x16_wcd_priv -> mbhc , codec , & mbhc_cb , & intr_ids ,
55755650 wcd_mbhc_registers , true);
55765651
5652+ #ifdef CONFIG_MACH_WT88047
5653+ accdet_data .name = "h2w" ;
5654+ accdet_data .index = 0 ;
5655+ accdet_data .state = 0 ;
5656+
5657+ ret = switch_dev_register (& accdet_data );
5658+ if (ret ) {
5659+ dev_err (codec -> dev , "%s: Failed to register h2w\n" , __func__ );
5660+ return - ENOMEM ;
5661+ }
5662+ #endif
5663+
55775664 msm8x16_wcd_priv -> mclk_enabled = false;
55785665 msm8x16_wcd_priv -> clock_active = false;
55795666 msm8x16_wcd_priv -> config_mode_active = false;
@@ -5596,6 +5683,9 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
55965683 registered_codec = NULL ;
55975684 return - ENOMEM ;
55985685 }
5686+ #ifdef CONFIG_MACH_WT88047
5687+ INIT_DELAYED_WORK (& analog_switch_enable , msm8x16_analog_switch_delayed_enable );
5688+ #endif
55995689 return 0 ;
56005690}
56015691
@@ -6014,6 +6104,43 @@ static void msm8x16_wcd_device_exit(struct msm8x16_wcd *msm8x16)
60146104 kfree (msm8x16 );
60156105}
60166106
6107+ #ifdef CONFIG_MACH_WT88047
6108+ int msm8x16_wcd_restart_mbhc (struct snd_soc_codec * codec )
6109+ {
6110+ struct msm8x16_wcd_priv * msm8x16_wcd_priv =
6111+ snd_soc_codec_get_drvdata (codec );
6112+ int ret = 0 ;
6113+ bool detection_type ;
6114+ u32 jack_mask = SND_JACK_HEADSET | SND_JACK_OC_HPHL |
6115+ SND_JACK_OC_HPHR | SND_JACK_LINEOUT |
6116+ SND_JACK_UNSUPPORTED ;
6117+ /* Read mbhc reg if set for insert or remove and
6118+ set to corresponding detection type on restart */
6119+ detection_type = (snd_soc_read (codec ,
6120+ MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1 )) & 0x20 ;
6121+ if (!detection_type )
6122+ snd_soc_jack_report_no_dapm (
6123+ & msm8x16_wcd_priv -> mbhc .headset_jack ,
6124+ 0 , jack_mask );
6125+ wcd_mbhc_stop (& msm8x16_wcd_priv -> mbhc );
6126+ wcd_mbhc_deinit (& msm8x16_wcd_priv -> mbhc );
6127+ ret = wcd_mbhc_init (& msm8x16_wcd_priv -> mbhc , codec , & mbhc_cb , & intr_ids ,
6128+ wcd_mbhc_registers , true);
6129+
6130+ if (ret )
6131+ dev_err (codec -> dev , "%s: mbhc initialization failed\n" ,
6132+ __func__ );
6133+ else
6134+ wcd_mbhc_start (& msm8x16_wcd_priv -> mbhc ,
6135+ msm8x16_wcd_priv -> mbhc .mbhc_cfg );
6136+ /* Set the detection type appropriately */
6137+ snd_soc_update_bits (codec , MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1 ,
6138+ 0x20 , (!detection_type << 5 ));
6139+ return 0 ;
6140+ }
6141+ EXPORT_SYMBOL (msm8x16_wcd_restart_mbhc );
6142+ #endif
6143+
60176144static int msm8x16_wcd_spmi_remove (struct spmi_device * spmi )
60186145{
60196146 struct msm8x16_wcd * msm8x16 = dev_get_drvdata (& spmi -> dev );
0 commit comments